Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot test redirects when unit testing Laravel 5

Here is my test code:

public function testRegistrationFailsIfNameIsEmpty()
{
    $this->flushSession();
    $response = $this->call('POST', '/signup', ['fullname' => '']);
    $this->assertSessionHasErrors('fullname'); // Passes, expected
    $this->assertTrue($response->isRedirection()); // Passes, expected
    $this->assertRedirectedTo('/signup'); // Fails, unexpected.
}

When I call that method, it's validating the input, and if the validation fails, it redirects me back to /signup to show the validation errors. I've manually tested this in the browser, and it works as expected.

However, when I run the above unit test, the last assertion fails, and it thinks I've been redirected to just / rather than /signup.

I have no idea why it's doing this. If I test that a redirect happened at all, the test passes because a redirect does happen, it just thinks the redirect is to / instead of /signup.

I've disabled all middleware so I know it's not something like guest middleware thinking I'm logged in when I'm not.

EDIT: Test Results:

There was 1 failure:

1) RegistrationTest::testRegistrationFailsIfNameIsEmpty
Failed asserting that two strings are equal.

--- Expected
+++ Actual
@@ @@
-'http://localhost/signup'
+'http://localhost'
like image 423
AgmLauncher Avatar asked Apr 13 '15 20:04

AgmLauncher


3 Answers

Using request()->validate() will return you to the calling url if validation fails. When running unit tests, there is no calling page so you will be directed to home.

https://laravel.com/docs/5.5/validation#quick-writing-the-validation-logic

if validation fails, an exception will be thrown and the proper error response will automatically be sent back to the user. In the case of a traditional HTTP request, a redirect response will be generated

So you either need to test that your redirect is to home, or fudge the calling url. Though then you're just testing the validator rather than your code, which doesn't really add anything:

session()->setPreviousUrl('/calling/url');

https://www.neontsunami.com/posts/testing-the-redirect-url-in-laravel

Edit: Actually, this can be useful when the test expects the redirect to go to a route with a named parameter.

Edit for Laravel 5.8:

The test should be called with:

$this->from('/calling/url')
    ->get('/some/route')
    ->assertRedirect('/somewhere/else');
like image 141
markdwhite Avatar answered Nov 16 '22 21:11

markdwhite


I had this same issue when testing a Laravel app. It seems that when you use $this->call in the test and then your controller uses something like Redirect::back(), the redirect is sent to '/'. I believe this is because you weren't on any page when you made "$this->call" so the application is unsure where to redirect you, unless you are explicit about the redirect in the controller, i.e. redirect('somePage').

However when doing something like $this->actingAs($user)->visit('somePage')->press('someButton'), you are correctly sent back to the expected page when using Redirect::back(). Likely because the app knows what page you started on.

like image 3
MattStrauss Avatar answered Nov 16 '22 19:11

MattStrauss


You have to set ->from(route('RouteName')) in order to make sure the redirection assertion is properly set

like image 1
Brian Wong Avatar answered Nov 16 '22 20:11

Brian Wong