diff options
author | Matthew Somerville <matthew@mysociety.org> | 2016-01-20 18:10:08 +0000 |
---|---|---|
committer | Matthew Somerville <matthew@mysociety.org> | 2016-01-22 19:26:34 +0000 |
commit | 5adabce92647a6b9e12887af7959efcfef4877d4 (patch) | |
tree | 4f19d797d574111ab076fb4e8ba2a20784ce3e2e | |
parent | 602385ff93129621b74a3cba16b448baa466cd8f (diff) |
Add tests of social login.
-rw-r--r-- | t/Facebook.pm | 52 | ||||
-rw-r--r-- | t/app/controller/auth_social.t | 143 |
2 files changed, 195 insertions, 0 deletions
diff --git a/t/Facebook.pm b/t/Facebook.pm new file mode 100644 index 000000000..8c258699b --- /dev/null +++ b/t/Facebook.pm @@ -0,0 +1,52 @@ +package t::Facebook; + +use JSON; +use Web::Simple; +use MooX::Types::MooseLike::Base qw(:all); + +has json => ( + is => 'lazy', + default => sub { + JSON->new->pretty->allow_blessed->convert_blessed; + }, +); + +has returns_email => ( + is => 'rw', + isa => Bool, + default => 1, +); + +sub dispatch_request { + my $self = shift; + + sub (GET + /v2.2/dialog/oauth + ?*) { + my ($self) = @_; + return [ 200, [ 'Content-Type' => 'text/html' ], [ 'FB login page' ] ]; + }, + + sub (GET + /v2.2/oauth/access_token + ?*) { + my ($self) = @_; + return [ 200, [ 'Content-Type' => 'text/plain' ], [ 'access_token=access_token&expires=never' ] ]; + }, + + sub (GET + /me + ?fields=) { + my ($self, $fields) = @_; + my $data = { + id => '123456789', + name => 'Fiona Tester', + }; + $data->{email} = 'facebook@example.org' if $self->returns_email; + my $json = $self->json->encode($data); + return [ 200, [ 'Content-Type' => 'text/html' ], [ $json ] ]; + }, + + sub (GET + /search + ?q=) { + my ($self, $q) = @_; + my $response = $self->query($q); + my $json = $self->json->encode($response); + return [ 200, [ 'Content-Type' => 'application/json' ], [ $json ] ]; + }, +} + +__PACKAGE__->run_if_script; diff --git a/t/app/controller/auth_social.t b/t/app/controller/auth_social.t new file mode 100644 index 000000000..173572b02 --- /dev/null +++ b/t/app/controller/auth_social.t @@ -0,0 +1,143 @@ +use strict; +use warnings; +use Test::More; +use LWP::Protocol::PSGI; +use LWP::Simple; +use JSON::MaybeXS; + +use t::Facebook; +use t::MapIt; + +use FixMyStreet::TestMech; +my $mech = FixMyStreet::TestMech->new; + +# disable info logs for this test run +FixMyStreet::App->log->disable('info'); +END { FixMyStreet::App->log->enable('info'); } + +my ($report) = $mech->create_problems_for_body(1, '2345', 'Test'); + +LWP::Protocol::PSGI->register(t::MapIt->to_psgi_app, host => 'mapit.uk'); + +FixMyStreet::override_config { + FACEBOOK_APP_ID => 'facebook-app-id', + ALLOWED_COBRANDS => [ { fixmystreet => '.' } ], + MAPIT_URL => 'http://mapit.uk/', +}, sub { + +my $fb_email = 'facebook@example.org'; +my $fb_uid = 123456789; + +for my $fb_state ( 'refused', 'no email', 'existing UID', 'okay' ) { + for my $page ( 'my', 'report', 'update' ) { + subtest "test FB '$fb_state' login for page '$page'" => sub { + $mech->log_out_ok; + if ($fb_state eq 'existing UID') { + my $user = $mech->create_user_ok($fb_email); + $user->update({ facebook_id => $fb_uid }); + } else { + $mech->delete_user($fb_email); + } + + # Set up a mock to catch (most, see below) requests to Facebook + my $fb = t::Facebook->new; + $fb->returns_email(0) if $fb_state eq 'no email' || $fb_state eq 'existing UID'; + LWP::Protocol::PSGI->register($fb->to_psgi_app, host => 'www.facebook.com'); + LWP::Protocol::PSGI->register($fb->to_psgi_app, host => 'graph.facebook.com'); + + # Due to https://metacpan.org/pod/Test::WWW::Mechanize::Catalyst#External-Redirects-and-allow_external + # the redirect to Facebook's OAuth page can mess up the session + # cookie. So let's pretend we always on www.facebook.com, which + # sorts that out. + $mech->host('www.facebook.com'); + + # Fetch the page with the form via which we wish to log in + my $fields; + if ($page eq 'my') { + $mech->get_ok('/my'); + } elsif ($page eq 'report') { + $mech->get_ok('/'); + $mech->submit_form_ok( { with_fields => { pc => 'SW1A1AA' } }, "submit location" ); + $mech->follow_link_ok( { text_regex => qr/skip this step/i, }, "follow 'skip this step' link" ); + $fields = { + title => 'Test title', + detail => 'Test detail', + }; + } else { + $mech->get_ok('/report/' . $report->id); + $fields = { + update => 'Test update', + }; + } + $mech->submit_form(with_fields => $fields, button => 'facebook_sign_in'); + + # As well as the cookie issue above, caused by this external + # redirect rewriting the host, the redirect gets handled directly + # by Catalyst, not our mocked handler, so will be a 404. Check + # the redirect happened instead. + is $mech->res->previous->code, 302, 'FB button redirected'; + like $mech->res->previous->header('Location'), qr{facebook\.com.*dialog/oauth.*facebook-app-id}, 'FB redirect to oauth URL'; + + # Okay, now call the callback Facebook would send us to + if ($fb_state eq 'refused') { + $mech->get_ok('/auth/Facebook?error_code=ERROR'); + } else { + $mech->get_ok('/auth/Facebook?code=response-code'); + } + + # Check we're showing the right form, regardless of what came back + if ($page eq 'report') { + $mech->content_contains('/report/new'); + } elsif ($page eq 'update') { + $mech->content_contains('/report/update'); + } + + if ($fb_state eq 'refused') { + $mech->content_contains('Sorry, we could not log you in. Please fill in the form below.'); + $mech->not_logged_in_ok; + } elsif ($fb_state eq 'no email') { + $mech->content_contains('We need your email address, please give it below.'); + # We don't have an email, so check that we can still submit it, + # and the ID carries through the confirmation + if ($page eq 'update') { + $fields->{rznvy} = $fb_email; + } else { + $fields->{email} = $fb_email; + } + $fields->{name} = 'Ffion Tester'; + $mech->submit_form(with_fields => $fields); + $mech->content_contains('Nearly done! Now check your email'); + + my $email = $mech->get_email; + ok $email, "got an email"; + $mech->clear_emails_ok; + my ( $url, $url_token ) = $email->body =~ m{(https?://\S+/[CMP]/)(\S+)}; + ok $url, "extracted confirm url '$url'"; + + my $user = FixMyStreet::App->model( 'DB::User' )->find( { email => $fb_email } ); + if ($page eq 'my') { + is $user, undef, 'No user yet exists'; + } else { + is $user->facebook_id, undef, 'User has no facebook ID'; + } + $mech->get_ok( $url . $url_token ); + $user = FixMyStreet::App->model( 'DB::User' )->find( { email => $fb_email } ); + is $user->facebook_id, $fb_uid, 'User now has correct facebook ID'; + + } elsif ($page ne 'my') { + # /my auth login goes directly there, no message like this + $mech->content_contains('You have successfully signed in; please check and confirm your details are accurate'); + $mech->logged_in_ok; + } else { + is $mech->uri->path, '/my', 'Successfully on /my page'; + } + } + } +} + +}; + +END { + $mech->delete_problems_for_body('2345'); + done_testing(); +} |