nmartins's avatar

Laravel 7: Unable to test Mock Socialite

I'm using Laravel 7 and I'm unable to do integration tests with Socialite. I have seen that there many examples of getting it to work on Laravel 5.x but can't find any for version 7.

The test fails because the mocked user info object is returning null variables.

Controller:

public function callback($provider)
{
    $getInfo = Socialite::driver($provider)->user();
    
    \Illuminate\Support\Facades\Log::debug(gettype($getInfo->name));
     
    $user = $this->createUser($getInfo, $provider);

    auth()->login($user);

    return redirect()->to('/home');
}

Route:

Route::get('/callback/{provider}', 'SocialController@callback')->name('SocialiteCallback');

Test:

use RefreshDatabase;

/**
 * @test
 */
public function testSocialiteTwitterLogin() {
    $abstractUser = Mockery::mock('Laravel\Socialite\Two\User');

    $abstractUser
            ->shouldReceive('getId')
            ->andReturn(rand())
            ->shouldReceive('getNickName')
            ->andReturn(uniqid())
            ->shouldReceive('getName')
            ->andReturn(uniqid())
            ->shouldReceive('getEmail')
            ->andReturn(uniqid() . '@gmail.com')
            ->shouldReceive('getAvatar')
            ->andReturn('https://en.gravatar.com/userimage');
    
    $provider = Mockery::mock('Laravel\Socialite\Contracts\Provider');
    $provider->shouldReceive('user')
            ->andReturn($abstractUser);

    Socialite::shouldReceive('driver')
        ->with('twitter')
        ->andReturn($provider);

    //Socialite::shouldReceive('driver->user')->andReturn($abstractUser);

    $this->get(route('SocialiteCallback', ['provider' => 'twitter']))
            ->assertStatus(302)
            ->assertRedirect(route('home'));
}

The actual fail error log is:

[2020-06-16 16:44:48] testing.ERROR: SQLSTATE[HY000]: General error: 1 no such table: users (SQL: select * from "users" where "provider_id" is null limit 1) {"exception":"[object] (Illuminate\Database\QueryException(code: HY000): SQLSTATE[HY000]: General error: 1 no such table: users (SQL: select * from "users" where "provider_id" is null limit 1) at /var/www/laravel/vendor/laravel/framework/src/Illuminate/Database/Connection.php:671)

My other tests for user authentication with Database Factory work fine so I don't know why the above doesn't work.

0 likes
6 replies
bugsysha's avatar

Two points:

  1. I do not understand the point of this fully mocked test. Looks like you are testing a redirect?
  2. At first glance, everything looks OK. Only thing is that you have @test annotation and test prefix in the test method name.

How are you running your tests?

nmartins's avatar

Yes I'm testing a redirect from a Twitter OAuth callback.

I'm running tests with 'phpunit' or 'artisan test' commands.

bugsysha's avatar

So much trouble to test redirect?

Post here full class so we can see imports and stuff, and also post phpunit.xml file.

nmartins's avatar

I think this problem is not related to PhpUnit. Problem is the Mock is not generating the user variables for Socialite. Just for debugging I have changed the Controller to define hardcoded values ($getInfo) and the test passes.

Test class:

namespace Tests\Feature;

use Tests\TestCase;
use Socialite;
use Mockery;
use Illuminate\Foundation\Testing\RefreshDatabase;

class OAuthTest extends TestCase {

    use RefreshDatabase;

    public function testSocialiteTwitterLogin() {
        $abstractUser = Mockery::mock('Laravel\Socialite\Two\User');

        $abstractUser
                ->shouldReceive('getId')
                ->andReturn(rand())
                ->shouldReceive('getNickName')
                ->andReturn(uniqid())
                ->shouldReceive('getName')
                ->andReturn(uniqid())
                ->shouldReceive('getEmail')
                ->andReturn(uniqid() . '@gmail.com')
                ->shouldReceive('getAvatar')
                ->andReturn('https://en.gravatar.com/userimage');
        
        $provider = Mockery::mock('Laravel\Socialite\Contracts\Provider');
        $provider->shouldReceive('user')
                ->andReturn($abstractUser);

        Socialite::shouldReceive('driver')
            ->with('twitter')
            ->andReturn($provider);

        //Socialite::shouldReceive('driver->user')->andReturn($abstractUser);

        $this->get(route('SocialiteCallback', ['provider' => 'twitter']))
                ->assertStatus(302)
                ->assertRedirect(route('home'));
    }

}

phpunit.xml

<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
         bootstrap="vendor/autoload.php"
         colors="true"
>
    <testsuites>
        <testsuite name="Unit">
            <directory suffix="Test.php">./tests/Unit</directory>
        </testsuite>
        <testsuite name="Feature">
            <directory suffix="Test.php">./tests/Feature</directory>
        </testsuite>
    </testsuites>
    <filter>
        <whitelist processUncoveredFilesFromWhitelist="true">
            <directory suffix=".php">./app</directory>
        </whitelist>
    </filter>
    <php>
        <server name="APP_ENV" value="testing"/>
        <server name="BCRYPT_ROUNDS" value="4"/>
        <server name="CACHE_DRIVER" value="array"/>
        <server name="DB_CONNECTION" value="sqlite"/>
        <server name="DB_DATABASE" value=":memory:"/>
        <server name="MAIL_MAILER" value="array"/>
        <server name="QUEUE_CONNECTION" value="sync"/>
        <server name="SESSION_DRIVER" value="array"/>
        <server name="TELESCOPE_ENABLED" value="false"/>
    </php>
</phpunit>

1 like
bugsysha's avatar

no such table: users

The error you've posted suggests that migrations were not executed.

nmartins's avatar

As I've mentioned before the tests work, including database tests.

Please or to participate in this conversation.