Log
Log

Reputation: 483

Queue::fake not work with Laravel5 codeception module

I write test for Laravel app with codeception and modules Laravel5, REST.

One of api test:

public function testEmailRegistration(ApiTester $I) {

...

// Not correct data
$I->sendPOST($route, [
    'first_name' => (string)$this->faker->randomNumber(),
    'password' => $this->faker->password(1, 7),
    'email' => 'not_valid_email',
]);

$I->seeResponseCodeIs(HttpCode::UNPROCESSABLE_ENTITY);

// Correct data
\Illuminate\Support\Facades\Queue::fake();

$I->sendPOST($route, [
    'first_name' => $firstName,
    'password' => $password,
    'email' => $email,
]);

\Illuminate\Support\Facades\Queue::assertPushed(\App\Jobs\SendEmail::class);

...

}

I send requests on incorrect and correct data and make some assertions. In addition I check, that job is present in queue.

After execute test I give error:

[Error] Call to undefined method Illuminate\Queue\SyncQueue::assertPushed()

After Queue:fake facade \Illuminate\Support\Facades\Queue must resolves to QueueFake, but in fact is still QueueManager, thus assertPushed function is undefined.

Execution of $I->sendPOST() reset call Queue::fake. It happened in laravel 5 module \Codeception\Lib\Connector\Laravel5, method doRequest.

protected function doRequest($request)
{
        if (!$this->firstRequest) {
            $this->initialize($request);
        }
        $this->firstRequest = false;

        $this->applyBindings();
        $this->applyContextualBindings();
        $this->applyInstances();
        $this->applyApplicationHandlers();

        $request = Request::createFromBase($request);
        $response = $this->kernel->handle($request);
        $this->app->make('Illuminate\Contracts\Http\Kernel')->terminate($request, $response);

        return $response;
}

Each call of doRequest except the first init app again and some configurations as Queue::fake are cleared.

One of decision is one request per test. Is there another variant to work Queue::fake when in test make more then one request?

Upvotes: 1

Views: 438

Answers (1)

guessimtoolate
guessimtoolate

Reputation: 8632

I am not sure why the Laravel module does this but I found a work-around that allows you to use fakes:

public function someTest(ApiTester $I): void
{
    // what the SomeFacade::fake method call does is basically create
    // a fake object and swaps it for the original implementation in 
    // the app container, so the we're recreating that behavior here
    // only this will be persisted even after the request is issued:
    $notification_fake = new NotificationFake();
    // `haveInstance` is a method from Laravel Codeception Module 
    // which sets an object in the app container for you:
    $I->haveInstance(ChannelManager::class, $notification_fake);

    // making the request
    $I->sendPUT('some url', $some_payload);

    // assertions
    $I->canSeeResponseCodeIs(Response::HTTP_OK);
    $notification_fake->assertSentToTimes($expected_user, MyNotification::class, 1);
}

note that this test method is only for illustrative purposes and it misses so of the details, hence the undefined variables and such.

Also note that I user the notification fake which get registered at Illuminate\Notifications\ChannelManager, unlike most fakes that you can register under their aliased name e.g. queue. So you have to check what is being instantiated and how to swap it on your own. You can either find this in respective service providers for each service. Most of the time it's lowercase name of the facade.

Upvotes: 1

Related Questions