Codeception / module-laravel

Modern Laravel module for Codeception

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Laravel facades are reset between functional test requests

challet opened this issue · comments

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.

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.