Eddie212's avatar

Testing Laravel Socialite callback

I am pretty new to testing and, in particular, mocks. I have a controller (albeit incomplete)

class RegistrationController extends Controller
{

    public function __construct(Identity $identity, User $user){
        $this->identity = $identity;
        $this->user = $user;
    }

    /**
     * Redirect the user to the social provider ie facebook/google etc
     *
     * @param string $provider
     * @return \Illuminate\Http\RedirectResponse
     */
    public function redirectToSocialProvider($provider)
    {
        // Check to see if the provider is supported, if not
        // redirect the user back to where they came from
        if(!array_key_exists($provider, Config::get('social'))) return redirect('/');

        return Socialite::driver($provider)->fields([
                'first_name',
                'last_name',
                'email',
                'gender',
                'birthday',
            ])->redirect();
    }

    /**
     * Handle the call back from social providers
     *
     * @param string $provider
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|void
     */
    public function handleSocialProviderCallback($provider)
    {
        // Check to see if the provider is supported, if not
        // abort the signup
        if(!array_key_exists($provider, Config::get('social'))) return redirect('/');

        $method = 'handle'.studly_case($provider . "Callback");

        if (method_exists($this, $method)) {
            return $this->{$method}();
        } else {
            return $this->handleMissingCallbackMethod();
        }

    }

    /**
     * Handle Facebook callback
     */
    public function handleFacebookCallback()
    {
        // Get the user information from facebook
        $providerUser = Socialite::driver('facebook')->fields([
                'first_name',
                'last_name',
                'email',
                'gender',
                'birthday'
            ])->scopes([
                'email', 'user_birthday'
            ])->user();

    }

    /**
     * Handle any missing call back methods
     */
    private function handleMissingCallbackMethod()
    {
        //
    }

}

with routes

Route::get('auth/register/{provider}', 'RegistrationController@redirectToSocialProvider');
Route::get('auth/register/{provider}/callback', ['as' => 'users.provider.callback', 'uses' => 'RegistrationController@handleSocialProviderCallback']);

How would I test the callback route to ensure that the user() method is being called on laravel socialite in the "handleFacebookCallback" method for example.

0 likes
6 replies
ifpingram's avatar
Level 4

I am not familiar with Socialite, but to write a test with the Facade mocked for the user() function you will need to use the following:

<?php

class RegistrationControllerTest extends TestCase
{
    public function testItCallsTheFacebookCallback()
    {
        // replace the return value of true with whatever values you wish to return for your test
        Socialite::shouldReceive('driver->fields->scopes->user')->andReturn(true); 

        $this->visit('/auth/register/facebook/callback');
    }
}

See the Mockery docs about Mocking Demeter Chains and Fluent Interfaces for details about what is happening in the shouldReceive() method.

1 like
florenxe's avatar

@Eddie212

can you please share how you implemented that! Thanks this is what i had:

Socialite::shouldReceive('driver->facebook')->andReturn(true);
$this->visit('/auth/login/facebook');

I still had the same error i have been having for the past four days!

PHP Fatal error: Call to undefined method Laravel\Socialite\Contracts\Factory::shouldReceive()

Eddie212's avatar

Sorry its been a while and I do not have the code anymore, it should be more along the lines of:

use Laravel\Socialite\Facades\Socialite; 

and

Socialite::shouldReceive('driver')->with('facebook')->andReturn(true);
$this->visit('/auth/login/facebook');
1 like
SUPAD's avatar

To help anyone who follow the same research path as i did, here is a good way to mock Socialite callback :

         $abstractUser = Mockery::mock('Laravel\Socialite\Two\User');         
         $abstractUser->shouldReceive('getId') 
         ->andReturn(1234567890)
         ->shouldReceive('getEmail')
         ->andReturn(str_random(10).'@test.com')
         ->shouldReceive('getNickname')
         ->andReturn('Pseudo')
         ->shouldReceive('getName')
         ->andReturn('Arlette Laguiller')
         ->shouldReceive('getAvatar')
         ->andReturn('https://en.gravatar.com/userimage');

         $provider = Mockery::mock('Laravel\Socialite\Contracts\Provider');
         $provider->shouldReceive('user')->andReturn($abstractUser);

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

         $this->visit(route("authFacebookCallback"))
         ->seePageIs(route("home"));

Answer found here : http://stackoverflow.com/questions/35294257/how-to-test-laravel-socialite

5 likes
epmdevs's avatar

Thanks @supad, your code and reference url has helped to cover this feature with tests.

Please or to participate in this conversation.