12

I'm testing a form where user must introduce some text between let's say 100 and 500 characters.

I use to emulate the user input:

$this->actingAs($user)
->visit('myweb/create')
->type($this->faker->text(1000),'description')
->press('Save')
->see('greater than');

Here I'm looking for the greater than piece of text in the response... It depends on the translation specified for that validation error.

How could do the same test without having to depend on the text of the validation error and do it depending only on the error itself?

Controller:

public function store(Request $request)
{
    $success = doStuff($request);
    if ($success){
        Flash::success('Created');
    } else {
        Flash::error('Fail');
    }

    return Redirect::back():
}

dd(Session::all()):

 `array:3 [
  "_token" => "ONoTlU2w7Ii2Npbr27dH5WSXolw6qpQncavQn72e"
  "_sf2_meta" => array:3 [
    "u" => 1453141086
    "c" => 1453141086
    "l" => "0"
  ]
  "flash" => array:2 [
    "old" => []
    "new" => []
  ]
]

5 Answers 5

11

you can do it like so -

$this->assertSessionHas('flash_notification.level', 'danger'); if you are looking for a particular error or success key.

or use $this->assertSessionHasErrors();

Sign up to request clarification or add additional context in comments.

3 Comments

Does not work even if I'm truly getting the validation error. assertSessionHasErrors() validates to false. Session missing key: errors Failed asserting that false is true.
may be something related with laravel 5.1 and not my controller, look: laracasts.com/discuss/channels/testing/…
@AyoAkinyemi What you are showing is not a validation error testing, it is flash messages testing
9

I think there is more clear way to get an exact error message from session.

    /** @var ViewErrorBag $errors */
    $errors = request()->session()->get('errors');
    /** @var array $messages */
    $messages = $errors->getBag('default')->getMessages();
    $emailErrorMessage = array_shift($messages['email']);

    $this->assertEquals('Already in use', $emailErrorMessage);

Pre-requirements: code was tested on Laravel Framework 5.5.14

2 Comments

how did you make request() function working in a unittest?
@YevgeniyAfanasyev You call request() after calling a $this->post(), $this->get() etc. in your test. You'll be calling the request that was just made.
2

get the MessageBag object from from session erros and get all the validation error names using $errors->get('name')

    $errors = session('errors');
    $this->assertSessionHasErrors();
    $this->assertEquals($errors->get('name')[0],"The title field is required.");

This works for Laravel 5 +

Comments

0

Your test doesn't have a post call. Here is an example using Jeffery Way's flash package

Controller:

public function store(Request $request, Post $post)
{
    $post->fill($request->all());
    $post->user_id = $request->user()->id;

    $created = false;

    try {
        $created = $post->save();
    } catch (ValidationException $e) {
        flash()->error($e->getErrors()->all());
    }

    if ($created) {
        flash()->success('New post has been created.');
    }

    return back();
}

Test:

public function testStoreSuccess()
{
    $data = [
        'title' => 'A dog is fit',
        'status' => 'active',
        'excerpt' => 'Farm dog',
        'content' => 'blah blah blah',
    ];

    $this->call('POST', 'post', $data);

    $this->assertTrue(Post::where($data)->exists());
    $this->assertResponseStatus(302);
    $this->assertSessionHas('flash_notification.level', 'success');
    $this->assertSessionHas('flash_notification.message', 'New post has been created.');
}

8 Comments

pressing the save button (->press('Save')) shall be sending a post request too. BTW tried yours but now assertions fail because of the token: testing.ERROR: exception 'Illuminate\Session\TokenMismatchException' in /var/www/html/anuncios.com/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php:53
add these traits... DatabaseTransactions, WithoutMiddleware to your test class.
ok, (I can also do $this->be($some_user);). Still, assertion fails, no flash message thrown, I updated the question with a var_dump of the session after posting. Could be because the error is passed by the FormRequest and not specifically calling Flash facade? `
hmm...interesting... is there a way we can chat about this?
well if we keep commenting a chat might open automatically, idk any other way
|
0

try to split your tests into units, say if you testing a controller function

you may catch valication exception, like so:

} catch (ValidationException $ex) {

if it was generated manually, this is how it should be generated:

throw ValidationException::withMessages([
            'abc' => ['my message'],
        ])->status(400);

you can assert it liks so

$this->assertSame('my message', $ex->errors()['abc'][0]);

if you cannot catch it, but prefer testing routs like so:

    $response = $this->json('POST', route('user-post'), [
        'name'        => $faker->name,
        'email'       => $faker->email,            
    ]);

then you use $response to assert that the validation has happened, like so

$this->assertSame($response->errors->{'name'}[0], 'The name field is required.');

PS

in the example I used

$faker = \Faker\Factory::create();

ValidationException is used liks this

use Illuminate\Validation\ValidationException;

just remind you that you don't have to generate exceptions manually, use validate method for common cases:

$request->validate(['name' => [
            'required',
        ],
    ]);

my current laravel version is 5.7

3 Comments

> I'm using phpunit 7.5 and Lumen 5.8 - when using a unit test for your Request or rules, you can do $this->expectException$this->expectException('Illuminate\Validation\ValidationException'); and $this->expectExceptionMessage = "The name field is required"; - see also stackoverflow.com/questions/18647836/…
as a note, the exception doesn't contain the validation message (I only get The given data was invalid)
exception doesn't contain the validation message - because a single exception can carry information of multiple validation failures, the exception has an array of messages $ex->errors()

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.