kfirba's avatar
Level 50

Auth::attempt always fails in tests

Hello!

I've written a test that ensures that the registration and authentication both work. However, when I try to login in the tests, it always returns false even though I can var_dump the user that has been added in the step before.

My code:

/**
     * @When I register :name :username
     * @param $name
     * @param $username
     */
    public function iRegister($name, $username)
    {
        $password = bcrypt('password');
        (new Registrar)->create(compact('name', 'username', 'password'));
    }

    /**
     * @Then I should have an account
     */
    public function iShouldHaveAnAccount()
    {
        $user = User::find(1);
        PHPUnit::assertEquals('John', $user->name);
    }

    /**
     * @Given I have an account :name :email
     */
    public function iHaveAnAccount($name, $username)
    {
    // registers a new user since I'm using in memory DB for tests
        $this->iRegister($name, $username);
    }

    /**
     * @When I sign in
     */
    public function iSignIn()
    {
    // this function fakes a call to the controller method, it for some reason also doesn't work as I'm being
    // redirected back to the login page instead of the successful authentication page.
    // Even if I try to manually do Auth::attempt() here without faking the call, it still returns false.
        $data = [
            'username' => 'johny',
            'password' => 'password',
        ];
        $this->call('POST', 'auth/login', $data);
    }

    /**
     * @Then I should be logged in
     */
    public function iShouldBeLoggedIn()
    {
    // always evaluates to false
        PHPUnit::assertTrue(Auth::check());
    }

Basically, the call method is taken from TestCase:

private function call($method, $uri, $parameters = [], $cookies = [], $files = [], $server = [], $content = null)
    {
        $request = Request::create($uri, $method, $parameters, $cookies, $files, $server, $content);

        return $this->response = app()->make('Illuminate\Contracts\Http\Kernel')->handle($request);
    }

The call methods eventually triggers the postLogin method on the controller:

public function postLogin(Request $request)
    {
        $this->validate($request, [
            'username' => 'required', 'password' => 'required',
        ]);

        $credentials = $request->only('username', 'password');

        if ($this->auth->attempt($credentials, $request->has('remember')))
        {
            return redirect()->intended($this->redirectPath());
        }

        return redirect('/auth/login')
                    ->withInput($request->only('username'))
                    ->withErrors([
                        'username' => 'Some message',
                    ]);
    }

When I try to dd() the arguments I do get the right arguments in the function. However, when it tries to login the user, it always fails. I've also manually tried to run Auth::attempt() from my tests and still, it fails.

I've changed the default postLogin() method a little bit to check against username and password instead of email and password, I don't believe it should be a reason.

By the way, I've taken care of the CSRF mismatch token exception by adding a middleware before the VerifyCsrfToken:

public function handle($request, Closure $next)
    {
        if ( 'testing' === $this->app->environment() ) {
            $input = $request->all();
            $input['_token'] = $request->session()->token();
            // we need to update _token value to make sure we get the POST / PUT tests passed.
            $request->replace( $input );
        }

        return $next($request);
    }

Any clue why is it happening?

P.S. I've eliminated the possibility that it is because of an in memory DB. I've tried the same code with a simple sqlite3 database and still got the same false result even tho I could view the user in the DB.

P.P.S When I add the user to DB other than my testing one and trying to login using the application UI it works just as expected, no issues there.

0 likes
0 replies

Please or to participate in this conversation.