vincent15000's avatar

Testing a middleware checks the IP address

Hello,

I need to test this middleware.

Something to know : I have added an ip_address field in the personal_access_tokens table.

public function handle(Request $request, Closure $next): Response
{
    $user = $request->user();

    if (!$user) {
        throw new AuthenticationException('Unauthenticated.');
    }

    $current_ip_address = $request->ip();

    if ($user->currentAccessToken()->ip_address !== $current_ip_address) {
        $user->currentAccessToken()->delete();

        throw new AuthenticationException('User can\'t be authenticated from two different locations at the same time.');
    }

    return $next($request);
}

Here is the test.

public function test_with_the_wrong_ip_address(): void
{
	Exceptions::fake();

    $response = $this->postJson('/api/v1/auth/login', [
        'email' => '[email protected]',
        'password' => 'musique',
    ]);

    $response->assertValid()->assertOk();

    $token = $response->json()['token'];

    PersonalAccessToken::first()->forceFill(['ip_address' => '91.272.36.154'])->update();

    $this->assertDatabaseHas('personal_access_tokens', [
        'ip_address' => '91.272.36.154',
    ]);

    $response = $this
        ->withToken($token)
        ->withServerVariables(['REMOTE_ADDR' => '91.272.36.155']) // 155 instead of 154
        ->getJson('/api/v1/branches/select');

	Exceptions::assertReported(AuthenticationException::class);
}

The test fails whereas it should pass.

Can you help me understand why ?

Thanks for your help ;).

V

0 likes
5 replies
s4muel's avatar

seems ok on the first sight, where exactly does the test fail?

2 likes
vincent15000's avatar

@s4muel It fails just on the expectation : Exceptions::assertReported(AuthenticationException::class);.

tykus's avatar
tykus
Best Answer
Level 104

@vincent15000 AFAIK an AuthenticationException does not actually ever get reported; you just making an assertion against something that would never happen. It is on the internal don't report list.

        AuthenticationException::class,
        AuthorizationException::class,
        BackedEnumCaseNotFoundException::class,
        HttpException::class,
        HttpResponseException::class,
        ModelNotFoundException::class,
        MultipleRecordsFoundException::class,
        RecordsNotFoundException::class,
        RequestExceptionInterface::class,
        TokenMismatchException::class,
        ValidationException::class,

You can use PHPUnit's expectException method instead:

// ...

    $this->expectException(AuthenticationException::class);

    $response = $this
        ->withoutExceptionHandling()
        ->withToken($token)
        ->withServerVariables(['REMOTE_ADDR' => '91.272.36.155']) // 155 instead of 154
        ->getJson('/api/v1/branches/select');
}

Or go further to make assertions against the exception message.

2 likes
vincent15000's avatar

@tykus Aren't $this->expectException(AuthenticationException::class); and ->withoutExceptionHandling() contradictory ?

tykus's avatar

@vincent15000 no, expecting an exception to be thrown is distinct from preventing the framework handling the exception

Please or to participate in this conversation.