13

I'm doing the following to test a POST call to Laravel. I'm expecting that POST to questions, in accordance with my routes, will be dispatches as the store action method. This works in the browser.

My test:

public function setUp()
    {   
        parent::setUp();

        Session::start();
    }

    public function testStoreAction()
    {
        $response = $this->call('POST', 'questions', array(
            '_token' => csrf_token(),
        ));

        $this->assertRedirectedTo('questions');
    }

However, I tells me that the redirect doesn't match. Also, I can see that it isn't going to the store action method at all. I want to know what action method it is going to, and why it isn't going to the store method (if I look at route:list I can see there is a POST questions/ route that should go to questions.store; this also works in the browser, but not in my tests). Also, am I writing the call correctly for this resource? I added the token here as it was throwing an exception as it should, in some tests I will let the token check pass.

Martyn
  • 6,031
  • 12
  • 55
  • 121
  • can you provide the actual error description, thanks – Michael Coleman Mar 01 '15 at 05:38
  • 1
    It is unlikely that your POST parameters are only the csrf token. Probably in your controller you have some kind of validation that makes the request to redirect back to the previous location (302 response code). You can check if this is the case by debugging the session with `dd(Session::get('errors'))` – mauricius Jul 17 '15 at 14:23

5 Answers5

7

You could try this:

public function testStoreAction()
{
    Session::start();
    $response = $this->call('POST', 'questions', array(
        '_token' => csrf_token(),
    ));
    $this->assertEquals(302, $response->getStatusCode());
    $this->assertRedirectedTo('questions');
}
Daniel Ojeda
  • 111
  • 1
  • 9
2

The most recommended way to test your routes is to check for 200 response. This is very helpful when you have multiple tests, like you are checking all of your post routes at once.

To do so, just use:

public function testStoreAction()
{
    $response = $this->call('POST', 'questions', array(
        '_token' => csrf_token(),
    ));

    $this->assertEquals(200, $response->getStatusCode());
}
Raviraj Chauhan
  • 655
  • 5
  • 7
  • 2
    But this action doesn't return a 200 code, I'm redirecting the user (30x) and I want to confirm that they went to the correct URL (questions). – Martyn Mar 06 '15 at 02:58
1

I use

$response->assertSessionHasErrors(['key'=>'error-message']);

in order to assert validation works. But to use this, you must start from the page that is going to send the post request. Like this:

$user = User::where('name','Ahmad')->first(); //you can use factory. I never use factory while testing because it is slow. I only use factory to feed my database and migrate to make all my test faster.
$this->actingAs($user)->get('/user/create'); //This part is missing from most who get errors "key errors is missing"
$response = $this->post('/user/store', [
                '_token' => csrf_token()
            ]);
//If you use custom error message, you can add as array value as below.
$response->assertSessionHasErrors(['name' => 'Name is required. Cannot be empty']);
$response->assertSessionHasErrors(['email' => 'Email is required. Make sure key in correct email']);

Then if you want to test that the errors also being displayed correctly back. Run again above test with some changes as per below:

$this->actingAs($user)->get('/user/create'); 
$response = $this->followingRedirects()->post('/user/store', [
                '_token' => csrf_token()
            ]); //Add followingRedirects()
$response->assertSeeText('Name is required. Cannot be empty');
$response->assertSeeText('Email is required. Make sure key in correct email');

My guess is that if you dont start with the page to show the error, (the create / update page where you put the form), chain of session during the process will miss some important keys.

Apit John Ismail
  • 2,047
  • 20
  • 19
-1

I was getting a TokenMismatchException and this fixed it, maybe it helps you too

public function testStoreAction()
{
    $response = $this->withSession(['_token' => 'covfefe'])
        ->post('questions', [
            '_token' => 'covfefe',
        ));

    $this->assertRedirectedTo('questions');
}
Gjaa
  • 1,461
  • 1
  • 19
  • 20
-1

Laravel Unit cases without middleware

    use WithoutMiddleware;

    protected $candidate = false;

    public function setUp(): void
    {
        parent::setUp();        

        $this->candidate = new Candidate();
    }   

    /** @test */
    public function it_can_get_job_list()
    {
        $this->actingAs($this->user, 'api');

        $response = $this->candidate->getJobsList();

        $this->assertNotNull($response);

        $this->assertArrayHasKey('data', $response->toArray());

        $this->assertNotEmpty($response);

        $this->assertInternalType('object', $response);
    }