Codeception / module-laravel

Modern Laravel module for Codeception
MIT License
5 stars 13 forks source link

Laravel facades are reset between functional test requests #18

Open challet opened 7 years ago

challet commented 7 years ago

Hi,

Using the Laravel module for testing a website, the Notification facade is firstly set to be a mock. Then, when sending a request, this setting is unset through a call to Facade::clearResolvedInstances().

Here is an extract from the stack trace :

#0  Illuminate\Support\Facades\Facade::clearResolvedInstances() called at [/var/www/vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/RegisterFacades.php:19]
Codeception/Codeception#1  Illuminate\Foundation\Bootstrap\RegisterFacades->bootstrap() called at [/var/www/vendor/laravel/framework/src/Illuminate/Foundation/Application.php:208]
Codeception/Codeception#2  Illuminate\Foundation\Application->bootstrapWith() called at [/var/www/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:162]
Codeception/Codeception#3  Illuminate\Foundation\Http\Kernel->bootstrap() called at [/var/www/vendor/codeception/codeception/src/Codeception/Lib/Connector/Laravel5.php:187]
Codeception/Codeception#4  Codeception\Lib\Connector\Laravel5->initialize() called at [/var/www/vendor/codeception/codeception/src/Codeception/Lib/Connector/Laravel5.php:100]
Codeception/Codeception#5  Codeception\Lib\Connector\Laravel5->doRequest() called at [/var/www/vendor/symfony/browser-kit/Client.php:316]
Codeception/Codeception#6  Symfony\Component\BrowserKit\Client->request() called at [/var/www/vendor/codeception/codeception/src/Codeception/Lib/InnerBrowser.php:195]
Codeception/Codeception#7  Codeception\Lib\InnerBrowser->clientRequest() called at [/var/www/vendor/codeception/codeception/src/Codeception/Lib/InnerBrowser.php:848]
Codeception/Codeception#8  Codeception\Lib\InnerBrowser->proceedSubmitForm() called at [/var/www/vendor/codeception/codeception/src/Codeception/Lib/InnerBrowser.php:859]
Codeception/Codeception#9  Codeception\Lib\InnerBrowser->submitForm()

And here is a sample code leading to it :

$I = new FunctionalTester($scenario);

Notification::fake();
var_dump(get_class(Notification::getFacadeRoot())); // string(49) "Illuminate\Support\Testing\Fakes\NotificationFake"
$user = \App\User::first();
$I->amOnAction('App\Http\Controllers\Auth\ForgotPasswordController@showLinkRequestForm');
$I->submitForm('[action$="/auth/reset/request"]', [
    'email' => $user->email
]);
var_dump(get_class(Notification::getFacadeRoot())); // string(39) "Illuminate\Notifications\ChannelManager"
Notification::assertSentTo($user, App\Notifications\Notification::class);

Leading to the final error : [Error] Call to undefined method Illuminate\Notifications\Channels\MailChannel::assertSentTo() ("ChannelManager" looks inside "MailChannel" if it doesn't have the method)

Notification::fake couldn't be called again since it creates a new instance and would lose the previous data.

AndrewFeeney commented 5 years ago

As of Codeception 3.0.2 this still appears to be a problem.

I agree that this is unexpected behaviour from a user's perspective, and it's not ideal to not be able to use the Laravel framework's built in test helpers.

A quick one liner I found that can be used as a workaround with the Queue facade is the following:

     $I->haveInstance('queue', Queue::fake());

Note that you'll have to replace the 'queue' string here with the relevant facade accessor for the facade which you are using. (We can't just call getFacadeAccessor() on the facade because it's protected.