diff options
Diffstat (limited to 't/app/controller')
-rw-r--r-- | t/app/controller/about.t | 31 | ||||
-rw-r--r-- | t/app/controller/admin.t | 652 | ||||
-rw-r--r-- | t/app/controller/alert.t | 66 | ||||
-rw-r--r-- | t/app/controller/alert_new.t | 486 | ||||
-rw-r--r-- | t/app/controller/around.t | 106 | ||||
-rw-r--r-- | t/app/controller/auth.t | 227 | ||||
-rw-r--r-- | t/app/controller/contact.t | 275 | ||||
-rw-r--r-- | t/app/controller/council.t | 14 | ||||
-rw-r--r-- | t/app/controller/index.t | 58 | ||||
-rw-r--r-- | t/app/controller/json.t | 109 | ||||
-rw-r--r-- | t/app/controller/my.t | 19 | ||||
-rw-r--r-- | t/app/controller/page_not_found.t | 20 | ||||
-rw-r--r-- | t/app/controller/questionnaire.t | 292 | ||||
-rw-r--r-- | t/app/controller/report_display.t | 265 | ||||
-rw-r--r-- | t/app/controller/report_import.t | 242 | ||||
-rw-r--r-- | t/app/controller/report_new.t | 501 | ||||
-rw-r--r-- | t/app/controller/report_updates.t | 885 | ||||
-rw-r--r-- | t/app/controller/reports.t | 34 | ||||
-rw-r--r-- | t/app/controller/sample.jpg | bin | 0 -> 22588 bytes | |||
-rw-r--r-- | t/app/controller/tilma.t | 12 |
20 files changed, 4294 insertions, 0 deletions
diff --git a/t/app/controller/about.t b/t/app/controller/about.t new file mode 100644 index 000000000..a5fb215d3 --- /dev/null +++ b/t/app/controller/about.t @@ -0,0 +1,31 @@ +use strict; +use warnings; + +use Test::More; +use Test::WWW::Mechanize::Catalyst 'FixMyStreet::App'; + +ok( my $mech = Test::WWW::Mechanize::Catalyst->new, 'Created mech object' ); + +# check that we can get the page +$mech->get_ok('/about'); +$mech->content_like(qr{About us ::\s+FixMyStreet}); +$mech->content_contains('html lang="en-gb"'); + +SKIP: { + skip( "Need 'emptyhomes' in ALLOWED_COBRANDS config", 8 ) + unless FixMyStreet::App->config->{ALLOWED_COBRANDS} =~ m{emptyhomes}; + + # check that geting the page as EHA produces a different page + ok $mech->host("reportemptyhomes.co.uk"), 'change host to reportemptyhomes'; + $mech->get_ok('/about'); + $mech->content_like(qr{About us ::\s+Report Empty Homes}); + $mech->content_contains('html lang="en-gb"'); + + # check that geting the page as EHA in welsh produces a different page + ok $mech->host("cy.reportemptyhomes.co.uk"), 'host to cy.reportemptyhomes'; + $mech->get_ok('/about'); + $mech->content_like(qr{Amdanom ni ::\s+Adrodd am Eiddo Gwag}); + $mech->content_contains('html lang="cy"'); +} + +done_testing(); diff --git a/t/app/controller/admin.t b/t/app/controller/admin.t new file mode 100644 index 000000000..c5416832f --- /dev/null +++ b/t/app/controller/admin.t @@ -0,0 +1,652 @@ +use strict; +use warnings; +use Test::More; + +use FixMyStreet::TestMech; + +my $mech = FixMyStreet::TestMech->new; + +my $secret = FixMyStreet::App->model('DB::Secret')->search(); + +# don't explode if there's nothing in the secret table +if ( $secret == 0 ) { + diag "You need to put an entry in the secret table for the admin tests to run"; + plan skip_all => 'No entry in secret table'; +} + +$mech->get_ok('/admin'); +$mech->title_like(qr/Summary/); + +$mech->get_ok('/admin/council_contacts/2650'); +$mech->content_contains('Aberdeen City Council'); +$mech->content_contains('AB15 8RN'); + +subtest 'check contact creation' => sub { + my $contact = FixMyStreet::App->model('DB::Contact')->find( + { area_id => 2650, category => 'test category' } + ); + + $contact->delete if $contact; + + my $history = FixMyStreet::App->model('DB::ContactsHistory')->search( + { area_id => 2650, category => 'test category' } + ); + + $history->delete_all; + + $mech->get_ok('/admin/council_contacts/2650'); + + $mech->submit_form_ok( { with_fields => { + category => 'test category', + email => 'test@example.com', + note => 'test note', + } } ); + + $mech->content_contains( 'test category' ); + $mech->content_contains( '<td>test@example.com' ); + $mech->content_contains( '<td>test note' ); +}; + +subtest 'check contact editing' => sub { + $mech->get_ok('/admin/council_edit/2650/test%20category'); + + $mech->submit_form_ok( { with_fields => { + email => 'test2@example.com', + note => 'test2 note', + } } ); + + $mech->content_contains( 'test category' ); + $mech->content_contains( '<td>test2@example.com' ); + $mech->content_contains( '<td>test2 note' ); + + $mech->get_ok('/admin/council_edit/2650/test%20category'); + $mech->content_contains( '<td><strong>test2@example.com' ); +}; + +subtest 'check contact updating' => sub { + $mech->get_ok('/admin/council_edit/2650/test%20category'); + $mech->content_like(qr{test2\@example.com</strong>[^<]*</td>[^<]*<td>No}s); + + $mech->get_ok('/admin/council_contacts/2650'); + + $mech->form_number( 1 ); + $mech->tick( 'confirmed', 'test category' ); + $mech->submit_form_ok({form_number => 1}); + + $mech->content_like(qr'test2@example.com</td>[^<]*<td>Yes's); + $mech->get_ok('/admin/council_edit/2650/test%20category'); + $mech->content_like(qr{test2\@example.com[^<]*</td>[^<]*<td><strong>Yes}s); +}; + +my $user = + FixMyStreet::App->model('DB::User') + ->find_or_create( { email => 'test@example.com', name => 'Test User' } ); +ok $user, "created test user"; + +my $user2 = + FixMyStreet::App->model('DB::User') + ->find_or_create( { email => 'test2@example.com', name => 'Test User 2' } ); +ok $user2, "created second test user"; + + +my $user3 = + FixMyStreet::App->model('DB::User') + ->find( { email => 'test3@example.com', name => 'Test User 2' } ); + +if ( $user3 ) { + $mech->delete_user( $user3 ); +} + +my $dt = DateTime->new( + year => 2011, + month => 04, + day => 16, + hour => 15, + minute => 47, + second => 23 +); + +my $report = FixMyStreet::App->model('DB::Problem')->find_or_create( + { + postcode => 'SW1A 1AA', + council => '2504', + areas => ',105255,11806,11828,2247,2504,', + category => 'Other', + title => 'Report to Edit', + detail => 'Detail for Report to Edit', + used_map => 't', + name => 'Test User', + anonymous => 'f', + state => 'confirmed', + confirmed => $dt->ymd . ' ' . $dt->hms, + lang => 'en-gb', + service => '', + cobrand => 'default', + cobrand_data => '', + send_questionnaire => 't', + latitude => '51.5016605453401', + longitude => '-0.142497580865087', + user_id => $user->id, + whensent => $dt->ymd . ' ' . $dt->hms, + } +); + +my $log_entries = FixMyStreet::App->model('DB::AdminLog')->search( + { + object_type => 'problem', + object_id => $report->id + }, + { + order_by => { -desc => 'id' }, + } +); + +is $log_entries->count, 0, 'no admin log entries'; + +my $report_id = $report->id; +ok $report, "created test report - $report_id"; + +foreach my $test ( + { + description => 'edit report title', + fields => { + title => 'Report to Edit', + detail => 'Detail for Report to Edit', + state => 'confirmed', + name => 'Test User', + email => $user->email, + anonymous => 0, + }, + changes => { + title => 'Edited Report', + }, + log_count => 1, + log_entries => [ qw/edit/ ], + resend => 0, + }, + { + description => 'edit report description', + fields => { + title => 'Edited Report', + detail => 'Detail for Report to Edit', + state => 'confirmed', + name => 'Test User', + email => $user->email, + anonymous => 0, + }, + changes => { + detail => 'Edited Detail', + }, + log_count => 2, + log_entries => [ qw/edit edit/ ], + resend => 0, + }, + { + description => 'edit report user name', + fields => { + title => 'Edited Report', + detail => 'Edited Detail', + state => 'confirmed', + name => 'Test User', + email => $user->email, + anonymous => 0, + }, + changes => { + name => 'Edited User', + }, + log_count => 3, + log_entries => [ qw/edit edit edit/ ], + resend => 0, + user => $user, + }, + { + description => 'edit report user email', + fields => { + title => 'Edited Report', + detail => 'Edited Detail', + state => 'confirmed', + name => 'Edited User', + email => $user->email, + anonymous => 0, + }, + changes => { + email => $user2->email, + }, + log_count => 4, + log_entries => [ qw/edit edit edit edit/ ], + resend => 0, + user => $user2, + }, + { + description => 'change state to unconfirmed', + fields => { + title => 'Edited Report', + detail => 'Edited Detail', + state => 'confirmed', + name => 'Edited User', + email => $user2->email, + anonymous => 0, + }, + changes => { + state => 'unconfirmed' + }, + log_count => 5, + log_entries => [ qw/state_change edit edit edit edit/ ], + resend => 0, + }, + { + description => 'change state to confirmed', + fields => { + title => 'Edited Report', + detail => 'Edited Detail', + state => 'unconfirmed', + name => 'Edited User', + email => $user2->email, + anonymous => 0, + }, + changes => { + state => 'confirmed' + }, + log_count => 6, + log_entries => [ qw/state_change state_change edit edit edit edit/ ], + resend => 0, + }, + { + description => 'change state to fixed', + fields => { + title => 'Edited Report', + detail => 'Edited Detail', + state => 'confirmed', + name => 'Edited User', + email => $user2->email, + anonymous => 0, + }, + changes => { + state => 'fixed' + }, + log_count => 7, + log_entries => [ qw/state_change state_change state_change edit edit edit edit/ ], + resend => 0, + }, + { + description => 'change state to hidden', + fields => { + title => 'Edited Report', + detail => 'Edited Detail', + state => 'fixed', + name => 'Edited User', + email => $user2->email, + anonymous => 0, + }, + changes => { + state => 'hidden' + }, + log_count => 8, + log_entries => [ qw/state_change state_change state_change state_change edit edit edit edit/ ], + resend => 0, + }, + { + description => 'edit and change state', + fields => { + title => 'Edited Report', + detail => 'Edited Detail', + state => 'hidden', + name => 'Edited User', + email => $user2->email, + anonymous => 0, + }, + changes => { + state => 'confirmed', + anonymous => 1, + }, + log_count => 10, + log_entries => [ qw/edit state_change state_change state_change state_change state_change edit edit edit edit/ ], + resend => 0, + }, + { + description => 'resend', + fields => { + title => 'Edited Report', + detail => 'Edited Detail', + state => 'confirmed', + name => 'Edited User', + email => $user2->email, + anonymous => 1, + }, + changes => { + }, + log_count => 11, + log_entries => [ qw/resend edit state_change state_change state_change state_change state_change edit edit edit edit/ ], + resend => 1, + }, +) { + subtest $test->{description} => sub { + $log_entries->reset; + $mech->get_ok("/admin/report_edit/$report_id"); + + is_deeply( $mech->visible_form_values(), $test->{fields}, 'initial form values' ); + + my $new_fields = { + %{ $test->{fields} }, + %{ $test->{changes} }, + }; + + if ( $test->{resend} ) { + $mech->click_ok( 'resend' ); + } else { + $mech->submit_form_ok( { with_fields => $new_fields }, 'form_submitted' ); + } + + is_deeply( $mech->visible_form_values(), $new_fields, 'changed form values' ); + is $log_entries->count, $test->{log_count}, 'log entry count'; + is $log_entries->next->action, $_, 'log entry added' for @{ $test->{log_entries} }; + + $report->discard_changes; + + if ( $report->state eq 'confirmed' ) { + $mech->content_contains( 'type="submit" name="resend"', 'no resend button' ); + } else { + $mech->content_lacks( 'type="submit" name="resend"', 'no resend button' ); + } + + is $report->$_, $test->{changes}->{$_}, "$_ updated" for grep { $_ ne 'email' } keys %{ $test->{changes} }; + + if ( $test->{user} ) { + is $report->user->id, $test->{user}->id, 'user changed'; + } + + if ( $test->{resend} ) { + $mech->content_contains( 'That problem will now be resent' ); + is $report->whensent, undef, 'mark report to resend'; + } + }; +} + +subtest 'change email to new user' => sub { + $log_entries->delete; + $mech->get_ok("/admin/report_edit/$report_id"); + my $fields = { + title => $report->title, + detail => $report->detail, + state => $report->state, + name => $report->name, + email => $report->user->email, + anonymous => 1, + }; + + is_deeply( $mech->visible_form_values(), $fields, 'initial form values' ); + + my $changes = { + email => 'test3@example.com' + }; + + $user3 = + FixMyStreet::App->model('DB::User') + ->find( { email => 'test3@example.com', name => 'Test User 2' } ); + + ok !$user3, 'user not in database'; + + my $new_fields = { + %{ $fields }, + %{ $changes }, + }; + + $mech->submit_form_ok( + { + with_fields => $new_fields, + } + ); + + is $log_entries->count, 1, 'created admin log entries'; + is $log_entries->first->action, 'edit', 'log action'; + is_deeply( $mech->visible_form_values(), $new_fields, 'changed form values' ); + + $user3 = + FixMyStreet::App->model('DB::User') + ->find( { email => 'test3@example.com', name => 'Test User 2' } ); + + $report->discard_changes; + + ok $user3, 'new user created'; + is $report->user_id, $user3->id, 'user changed to new user'; +}; + +$log_entries->delete; + +my $update = FixMyStreet::App->model('DB::Comment')->create( + { + text => 'this is an update', + user => $user, + state => 'confirmed', + problem => $report, + mark_fixed => 0, + anonymous => 1, + } +); + +$log_entries = FixMyStreet::App->model('DB::AdminLog')->search( + { + object_type => 'update', + object_id => $update->id + }, + { + order_by => { -desc => 'id' }, + } +); + +is $log_entries->count, 0, 'no admin log entries'; + +for my $test ( + { + desc => 'edit update text', + fields => { + text => 'this is an update', + state => 'confirmed', + name => '', + anonymous => 1, + email => 'test@example.com', + }, + changes => { + text => 'this is a changed update', + }, + log_count => 1, + log_entries => [qw/edit/], + }, + { + desc => 'edit update name', + fields => { + text => 'this is a changed update', + state => 'confirmed', + name => '', + anonymous => 1, + email => 'test@example.com', + }, + changes => { + name => 'A User', + }, + log_count => 2, + log_entries => [qw/edit edit/], + }, + { + desc => 'edit update anonymous', + fields => { + text => 'this is a changed update', + state => 'confirmed', + name => 'A User', + anonymous => 1, + email => 'test@example.com', + }, + changes => { + anonymous => 0, + }, + log_count => 3, + log_entries => [qw/edit edit edit/], + }, + { + desc => 'edit update user', + fields => { + text => 'this is a changed update', + state => 'confirmed', + name => 'A User', + anonymous => 0, + email => $update->user->email, + email => 'test@example.com', + }, + changes => { + email => 'test2@example.com', + }, + log_count => 4, + log_entries => [qw/edit edit edit edit/], + user => $user2, + }, + { + desc => 'edit update state', + fields => { + text => 'this is a changed update', + state => 'confirmed', + name => 'A User', + anonymous => 0, + email => 'test2@example.com', + }, + changes => { + state => 'unconfirmed', + }, + log_count => 5, + log_entries => [qw/state_change edit edit edit edit/], + }, + { + desc => 'edit update state and text', + fields => { + text => 'this is a changed update', + state => 'unconfirmed', + name => 'A User', + anonymous => 0, + email => 'test2@example.com', + }, + changes => { + text => 'this is a twice changed update', + state => 'hidden', + }, + log_count => 7, + log_entries => [qw/edit state_change state_change edit edit edit edit/], + }, +) { + subtest $test->{desc} => sub { + $log_entries->reset; + $mech->get_ok('/admin/update_edit/' . $update->id ); + + is_deeply $mech->visible_form_values, $test->{fields}, 'initial form values'; + + my $to_submit = { + %{ $test->{fields} }, + %{ $test->{changes} } + }; + + $mech->submit_form_ok( { with_fields => $to_submit } ); + + is_deeply $mech->visible_form_values, $to_submit, 'submitted form values'; + + is $log_entries->count, $test->{log_count}, 'number of log entries'; + is $log_entries->next->action, $_, 'log action' for @{ $test->{log_entries} }; + + $update->discard_changes; + + is $update->$_, $test->{changes}->{$_} for grep { $_ ne 'email' } keys %{ $test->{changes} }; + + if ( $test->{user} ) { + is $update->user->id, $test->{user}->id, 'update user'; + } + }; +} + +subtest 'editing update email creates new user if required' => sub { + my $user = FixMyStreet::App->model('DB::User')->find( + { email => 'test4@example.com' } + ); + + $user->delete if $user; + + my $fields = { + text => 'this is a changed update', + state => 'hidden', + name => 'A User', + anonymous => 0, + email => 'test4@example.com', + }; + + $mech->submit_form_ok( { with_fields => $fields } ); + + $user = FixMyStreet::App->model('DB::User')->find( + { email => 'test4@example.com' } + ); + + is_deeply $mech->visible_form_values, $fields, 'submitted form values'; + + ok $user, 'new user created'; + + $update->discard_changes; + is $update->user->id, $user->id, 'update set to new user'; +}; + +subtest 'hiding comment marked as fixed reopens report' => sub { + $update->mark_fixed( 1 ); + $update->update; + + $report->state('fixed'); + $report->update; + + + my $fields = { + text => 'this is a changed update', + state => 'hidden', + name => 'A User', + anonymous => 0, + email => 'test2@example.com', + }; + + $mech->submit_form_ok( { with_fields => $fields } ); + + $report->discard_changes; + is $report->state, 'confirmed', 'report reopened'; + $mech->content_contains('Problem marked as open'); +}; + +$log_entries->delete; + +subtest 'report search' => sub { + $update->state('confirmed'); + $update->user($report->user); + $update->update; + + $mech->get_ok('/admin/search_reports'); + $mech->get_ok('/admin/search_reports?search=' . $report->id ); + + $mech->content_contains( $report->title ); + my $r_id = $report->id; + $mech->content_like( qr{href="http://[^/]*[^.]/report/$r_id/">$r_id</a>} ); + + $mech->get_ok('/admin/search_reports?search=' . $report->user->email); + + my $u_id = $update->id; + $mech->content_like( qr{href="http://[^/]*[^.]/report/$r_id/">$r_id</a>} ); + $mech->content_like( qr{href="http://[^/]*[^.]/report/$r_id/#update_$u_id">$u_id</a>} ); + + $update->state('hidden'); + $update->update; + + $mech->get_ok('/admin/search_reports?search=' . $report->user->email); + $mech->content_like( qr{<tr [^>]*hidden[^>]*> \s* <td> \s* $u_id \s* </td>}xs ); + + $report->state('hidden'); + $report->update; + + $mech->get_ok('/admin/search_reports?search=' . $report->user->email); + $mech->content_like( qr{<tr [^>]*hidden[^>]*> \s* <td> \s* $r_id \s* </td>}xs ); +}; + +$mech->delete_user( $user ); +$mech->delete_user( $user2 ); +$mech->delete_user( $user3 ); +$mech->delete_user( 'test4@example.com' ); + +done_testing(); diff --git a/t/app/controller/alert.t b/t/app/controller/alert.t new file mode 100644 index 000000000..b8e38ec92 --- /dev/null +++ b/t/app/controller/alert.t @@ -0,0 +1,66 @@ +use strict; +use warnings; +use Test::More; + + +use Catalyst::Test 'FixMyStreet::App'; +use Test::WWW::Mechanize::Catalyst 'FixMyStreet::App'; + +ok( my $mech = Test::WWW::Mechanize::Catalyst->new, 'Created mech object' ); + +# check that we can get the page +$mech->get_ok('/alert'); +$mech->title_like(qr/^Local RSS feeds and email alerts/); +$mech->content_contains('Local RSS feeds and email alerts'); +$mech->content_contains('html lang="en-gb"'); + +# check that we can get list page +$mech->get_ok('/alert/list'); +$mech->title_like(qr/^Local RSS feeds and email alerts/); +$mech->content_contains('Local RSS feeds and email alerts'); +$mech->content_contains('html lang="en-gb"'); + +$mech->get_ok('/alert/list?pc=EH99 1SP'); +$mech->title_like(qr/^Local RSS feeds and email alerts/); +$mech->content_contains('Here are the types of local problem alerts for ‘EH99 1SP’'); +$mech->content_contains('html lang="en-gb"'); +$mech->content_contains('Problems within 8.5km'); +$mech->content_contains('rss/pc/EH991SP/2'); +$mech->content_contains('rss/pc/EH991SP/5'); +$mech->content_contains('rss/pc/EH991SP/10'); +$mech->content_contains('rss/pc/EH991SP/20'); +$mech->content_contains('Problems within City of Edinburgh'); +$mech->content_contains('Problems within City Centre ward'); +$mech->content_contains('/rss/reports/City+of+Edinburgh'); +$mech->content_contains('/rss/reports/City+of+Edinburgh/City+Centre'); +$mech->content_contains('council:2651:City_of_Edinburgh'); +$mech->content_contains('ward:2651:20728:City_of_Edinburgh:City_Centre'); + +$mech->get_ok('/alert/list?pc=High Street'); +$mech->content_contains('We found more than one match for that location'); + +$mech->get_ok('/alert/list?pc='); +$mech->content_contains('hat location does not appear to be covered by a council'); + +$mech->get_ok('/alert/list?pc=GL502PR'); +$mech->content_contains('Problems within the boundary of'); + +$mech->get_ok('/alert/subscribe?rss=1&type=local&pc=ky16+8yg&rss=Give+me+an+RSS+feed&rznvy=' ); +$mech->content_contains('Please select the feed you want'); + +$mech->get_ok('/alert/subscribe?rss=1&feed=invalid:1000:A_Locationtype=local&pc=ky16+8yg&rss=Give+me+an+RSS+feed&rznvy='); +$mech->content_contains('Illegal feed selection'); + +$mech->get_ok('/alert/subscribe?rss=1&feed=area:1000:Birmingham'); +is $mech->uri->path, '/rss/reports/Birmingham'; + +$mech->get_ok('/alert/subscribe?rss=1&feed=area:1000:1001:Cheltenham:Lansdown'); +is $mech->uri->path, '/rss/area/Cheltenham/Lansdown'; + +$mech->get_ok('/alert/subscribe?rss=1&feed=council:1000:Gloucestershire'); +is $mech->uri->path, '/rss/reports/Gloucestershire'; + +$mech->get_ok('/alert/subscribe?rss=1&feed=ward:1000:1001:Cheltenham:Lansdown'); +is $mech->uri->path, '/rss/reports/Cheltenham/Lansdown'; + +done_testing(); diff --git a/t/app/controller/alert_new.t b/t/app/controller/alert_new.t new file mode 100644 index 000000000..5bf7e31dd --- /dev/null +++ b/t/app/controller/alert_new.t @@ -0,0 +1,486 @@ +use strict; +use warnings; +use Test::More; + +use FixMyStreet::TestMech; + +my $mech = FixMyStreet::TestMech->new; + +foreach my $test ( + { + email => 'test@example.com', + type => 'area_problems', + content => 'your alert will not be activated', + email_text => 'confirm the alert', + uri => +'/alert/subscribe?type=local&rznvy=test@example.com&feed=area:1000:A_Location', + param1 => 1000 + }, + { + email => 'test@example.com', + type => 'council_problems', + content => 'your alert will not be activated', + email_text => 'confirm the alert', + uri => +'/alert/subscribe?type=local&rznvy=test@example.com&feed=council:1000:A_Location', + param1 => 1000, + param2 => 1000, + }, + { + email => 'test@example.com', + type => 'ward_problems', + content => 'your alert will not be activated', + email_text => 'confirm the alert', + uri => +'/alert/subscribe?type=local&rznvy=test@example.com&feed=ward:1000:1001:A_Location:Diff_Location', + param1 => 1000, + param2 => 1001, + }, + { + email => 'test@example.com', + type => 'local_problems', + content => 'your alert will not be activated', + email_text => 'confirm the alert', + uri => +'/alert/subscribe?type=local&rznvy=test@example.com&feed=local:10.2:20.1', + param1 => 20.1, + param2 => 10.2, + }, + { + email => 'test@example.com', + type => 'new_updates', + content => 'your alert will not be activated', + email_text => 'confirm the alert', + uri => '/alert/subscribe?type=updates&rznvy=test@example.com&id=1', + param1 => 1, + } + ) +{ + subtest "$test->{type} alert correctly created" => sub { + $mech->clear_emails_ok; + + my $type = $test->{type}; + + my $user = + FixMyStreet::App->model('DB::User') + ->find( { email => $test->{email} } ); + + # we don't want an alert + if ($user) { + $mech->delete_user($user); + } + + $mech->get_ok( $test->{uri} ); + $mech->content_contains( $test->{content} ); + + $user = + FixMyStreet::App->model('DB::User') + ->find( { email => $test->{email} } ); + + ok $user, 'user created for alert'; + + my $alert = FixMyStreet::App->model('DB::Alert')->find( + { + user => $user, + alert_type => $type, + parameter => $test->{param1}, + parameter2 => $test->{param2}, + confirmed => 0, + } + ); + + ok $alert, "Found the alert"; + + my $email = $mech->get_email; + ok $email, "got an email"; + like $email->body, qr/$test->{email_text}/i, "Correct email text"; + + my ( $url, $url_token ) = $email->body =~ m{(http://\S+/A/)(\S+)}; + ok $url, "extracted confirm url '$url'"; + + my $token = FixMyStreet::App->model('DB::Token')->find( + { + token => $url_token, + scope => 'alert' + } + ); + ok $token, 'Token found in database'; + ok $alert->id == $token->data->{id}, 'token alertid matches alert id'; + + $mech->clear_emails_ok; + + my $existing_id = $alert->id; + my $existing_token = $url_token; + + $mech->get_ok( $test->{uri} ); + + $email = $mech->get_email; + ok $email, 'got a second email'; + + ($url_token) = $email->body =~ m{http://\S+/A/(\S+)}; + ok $url_token ne $existing_token, 'sent out a new token'; + + $token = FixMyStreet::App->model('DB::Token')->find( + { + token => $url_token, + scope => 'alert' + } + ); + + ok $token, 'new token found in database'; + ok $token->data->{id} == $existing_id, 'subscribed to existing alert'; + + $mech->get_ok("/A/$url_token"); + $mech->content_contains('successfully confirmed'); + + $alert = + FixMyStreet::App->model('DB::Alert')->find( { id => $existing_id, } ); + + ok $alert->confirmed, 'alert set to confirmed'; + $mech->delete_user($user); + }; +} + +foreach my $test ( + { + email => 'test-new@example.com', + type => 'area', + content => 'your alert will not be activated', + email_text => 'confirm the alert', + uri => +'/alert/subscribe?type=local&rznvy=test-new@example.com&feed=area:1000:A_Location', + param1 => 1000 + } + ) +{ + subtest "use existing unlogged in user in a alert" => sub { + $mech->log_out_ok(); + + my $type = $test->{type} . '_problems'; + + my $user = + FixMyStreet::App->model('DB::User') + ->find_or_create( { email => $test->{email} } ); + + my $alert = FixMyStreet::App->model('DB::Alert')->find( + { + user => $user, + alert_type => $type + } + ); + # clear existing data so we can be sure we're creating it + ok $alert->delete() if $alert; + + $mech->get_ok( $test->{uri} ); + + $alert = FixMyStreet::App->model('DB::Alert')->find( + { + user => $user, + alert_type => $type, + parameter => $test->{param1}, + parameter2 => $test->{param2}, + confirmed => 0, + } + ); + + $mech->content_contains( 'Now check your email' ); + + ok $alert, 'New alert created with existing user'; + $mech->delete_user($user); + }; +} + +foreach my $test ( + { + desc => 'logged in user signing up', + user => 'test-login@example.com', + email => 'test-login@example.com', + type => 'council', + param1 => 2651, + param2 => 2651, + confirmed => 1, + }, + { + desc => 'logged in user signing up with different email', + user => 'loggedin@example.com', + email => 'test-login@example.com', + type => 'council', + param1 => 2651, + param2 => 2651, + confirmed => 0, + delete => 1, + } + ) +{ + subtest $test->{desc} => sub { + my $type = $test->{type} . '_problems'; + + my $user = + FixMyStreet::App->model('DB::User') + ->find_or_create( { email => $test->{user} } ); + + my $alert_user = + FixMyStreet::App->model('DB::User') + ->find( { email => $test->{email} } ); + + $mech->log_in_ok( $test->{user} ); + + $mech->clear_emails_ok; + + my $alert; + if ($alert_user) { + $alert = FixMyStreet::App->model('DB::Alert')->find( + { + user => $alert_user, + alert_type => $type + } + ); + + # clear existing data so we can be sure we're creating it + $alert->delete() if $alert; + } + + $mech->get_ok('/alert/list?pc=EH991SP'); + + my $form_values = $mech->visible_form_values(); + ok $form_values->{rznvy} eq $test->{user}, + 'auto filled in correct email'; + + $mech->set_visible( [ radio => 'council:2651:City_of_Edinburgh' ], + [ text => $test->{email} ] ); + $mech->click('alert'); + + $alert = FixMyStreet::App->model('DB::Alert')->find( + { + user => $alert_user, + alert_type => $type, + parameter => $test->{param1}, + parameter2 => $test->{param2}, + confirmed => $test->{confirmed}, + } + ); + + ok $alert, 'New alert created with logged in user'; + + $mech->email_count_is( $test->{confirmed} ? 0 : 1 ); + + if ( $test->{delete} ) { + $mech->delete_user($user); + $mech->delete_user($alert_user); + } + }; +} + +for my $test ( + { + email => 'test@example.com', + type => 'new_updates', + content => 'your alert will not be activated', + email_text => 'confirm the alert', + uri => '/alert/subscribe?type=updates&rznvy=test@example.com&id=1', + param1 => 1, + } + ) +{ + subtest "cannot sign up for alert if in abuse table" => sub { + $mech->clear_emails_ok; + + my $type = $test->{type}; + + my $user = + FixMyStreet::App->model('DB::User') + ->find( { email => $test->{email} } ); + + # we don't want an alert + my $alert; + if ($user) { + $mech->delete_user($user); + } + + my $abuse = + FixMyStreet::App->model('DB::Abuse') + ->find_or_create( { email => $test->{email} } ); + + $mech->get_ok( $test->{uri} ); + $mech->content_contains( $test->{content} ); + + $user = + FixMyStreet::App->model('DB::User') + ->find( { email => $test->{email} } ); + + ok $user, 'user created for alert'; + + $alert = FixMyStreet::App->model('DB::Alert')->find( + { + user => $user, + alert_type => $type, + parameter => $test->{param1}, + parameter2 => $test->{param2}, + confirmed => 0, + } + ); + + ok $alert, "Found the alert"; + + my $email = $mech->get_email; + ok $email, "got an email"; + like $email->body, qr/$test->{email_text}/i, "Correct email text"; + + my ( $url, $url_token ) = $email->body =~ m{(http://\S+/A/)(\S+)}; + ok $url, "extracted confirm url '$url'"; + + my $token = FixMyStreet::App->model('DB::Token')->find( + { + token => $url_token, + scope => 'alert' + } + ); + ok $token, 'Token found in database'; + ok $alert->id == $token->data->{id}, 'token alertid matches alert id'; + + $mech->clear_emails_ok; + + $mech->get_ok("/A/$url_token"); + $mech->content_contains('error confirming'); + + $alert->discard_changes; + + ok !$alert->confirmed, 'alert not set to confirmed'; + + $abuse->delete; + $mech->delete_user($user); + }; +} + +subtest "Test two-tier council alerts" => sub { + for my $alert ( + { feed => "local:51.896269:-2.093063", result => '/rss/l/51.896269,-2.093063' }, + { feed => "area:2326:Cheltenham", result => '/rss/area/Cheltenham' }, + { feed => "area:2326:4544:Cheltenham:Lansdown", result => '/rss/area/Cheltenham/Lansdown' }, + { feed => "area:2226:Gloucestershire", result => '/rss/area/Gloucestershire' }, + { feed => "area:2226:14949:Gloucestershire:Lansdown%2C_Park_and_Warden_Hill", + result => '/rss/area/Gloucestershire/Lansdown%2C+Park+and+Warden+Hill' + }, + { feed => "council:2326:Cheltenham", result => '/rss/reports/Cheltenham' }, + { feed => "ward:2326:4544:Cheltenham:Lansdown", result => '/rss/reports/Cheltenham/Lansdown' }, + { feed => "council:2226:Gloucestershire", result => '/rss/reports/Gloucestershire' }, + { feed => "ward:2226:14949:Gloucestershire:Lansdown%2C_Park_and_Warden_Hill", + result => '/rss/reports/Gloucestershire/Lansdown%2C+Park+and+Warden+Hill' + }, + ) { + $mech->get_ok( '/alert/list?pc=GL502PR' ); + $mech->submit_form_ok( { + button => 'rss', + with_fields => { + feed => $alert->{feed}, + } + } ); + is $mech->uri->path, $alert->{result}; + } +}; + +subtest "Test normal alert signups and that alerts are sent" => sub { + my $user1 = FixMyStreet::App->model('DB::User') + ->find_or_create( { email => 'reporter@example.com', name => 'Reporter User' } ); + ok $user1, "created test user"; + $user1->alerts->delete; + + my $user2 = FixMyStreet::App->model('DB::User') + ->find_or_create( { email => 'alerts@example.com', name => 'Alert User' } ); + ok $user2, "created test user"; + $user2->alerts->delete; + + for my $alert ( + { feed => 'local:55.951963:-3.189944', email_confirm => 1 }, + { feed => 'council:2651:City_of_Edinburgh', }, + ) { + $mech->get_ok( '/alert' ); + $mech->submit_form_ok( { with_fields => { pc => 'EH11BB' } } ); + $mech->submit_form_ok( { + button => 'alert', + with_fields => { + rznvy => $user2->email, + feed => $alert->{feed}, + } + } ); + if ( $alert->{email_confirm} ) { + my $email = $mech->get_email; + $mech->clear_emails_ok; + my ( $url, $url_token ) = $email->body =~ m{http://\S+(/A/(\S+))}; + my $token = FixMyStreet::App->model('DB::Token')->find( { token => $url_token, scope => 'alert' } ); + $mech->get_ok( $url ); + $mech->content_contains('successfully confirmed'); + } else { + $mech->content_contains('successfully created'); + } + } + + my $dt = DateTime->now()->add( days => 2); + + my $report_time = '2011-03-01 12:00:00'; + my $report = FixMyStreet::App->model('DB::Problem')->find_or_create( { + postcode => 'EH1 1BB', + council => '2651', + areas => ',11808,135007,14419,134935,2651,20728,', + category => 'Street lighting', + title => 'Testing', + detail => 'Testing Detail', + used_map => 1, + name => $user1->name, + anonymous => 0, + state => 'confirmed', + confirmed => $dt, + lastupdate => $dt, + whensent => $dt->clone->add( minutes => 5 ), + lang => 'en-gb', + service => '', + cobrand => 'default', + cobrand_data => '', + send_questionnaire => 1, + latitude => '55.951963', + longitude => '-3.189944', + user_id => $user1->id, + } ); + my $report_id = $report->id; + ok $report, "created test report - $report_id"; + + my $alert = FixMyStreet::App->model('DB::Alert')->create( { + parameter => $report_id, + alert_type => 'new_updates', + user => $user1, + } )->confirm; + ok $alert, 'created alert for reporter'; + + my $update = FixMyStreet::App->model('DB::Comment')->create( { + problem_id => $report_id, + user_id => $user2->id, + name => 'Other User', + mark_fixed => 'false', + text => 'This is some update text', + state => 'confirmed', + confirmed => $dt->clone->add( hours => 7 ), + anonymous => 'f', + } ); + my $update_id = $update->id; + ok $update, "created test update - $update_id"; + + FixMyStreet::App->model('DB::AlertType')->email_alerts(); + $mech->email_count_is(3); + my @emails = $mech->get_email; + my $count; + for (@emails) { + $count++ if $_->body =~ /The following updates have been left on this problem:/; + $count++ if $_->body =~ /The following new problems have been reported to City of\s*Edinburgh Council:/; + $count++ if $_->body =~ /The following nearby problems have been added:/; + } + is $count, 3, 'Three emails with the right things in them'; + + my ( $url, $url_token ) = $emails[0]->body =~ m{http://\S+(/A/(\S+))}; + $mech->get_ok( $url ); + $mech->content_contains('successfully deleted'); + + $mech->delete_user($user1); + $mech->delete_user($user2); +}; + +done_testing(); diff --git a/t/app/controller/around.t b/t/app/controller/around.t new file mode 100644 index 000000000..33c959b48 --- /dev/null +++ b/t/app/controller/around.t @@ -0,0 +1,106 @@ +use strict; +use warnings; +use Test::More; + +use FixMyStreet::TestMech; +my $mech = FixMyStreet::TestMech->new; + +subtest "check that if no query we get sent back to the homepage" => sub { + $mech->get_ok('/around'); + is $mech->uri->path, '/around', "still at '/around'"; +}; + +# x,y requests were generated by the old map code. We keep the behavior for +# historic links +subtest "redirect x,y requests to lat/lon (301 - permanent)" => sub { + + $mech->get_ok('/around?x=3281&y=1113'); + + # did we redirect to lat,lon? + is $mech->uri->path, '/around', "still on /around"; + is_deeply { $mech->uri->query_form }, + { lat => 51.4998246332569, lon => -0.140137309739907, }, + "lat,lon correctly set"; + + # was it a 301? + is $mech->res->code, 200, "got 200 for final destination"; + is $mech->res->previous->code, 301, "got 301 for redirect"; + +}; + +# test various locations on inital search box +foreach my $test ( + { + pc => '', # + errors => [], + pc_alternatives => [], + }, + { + pc => 'xxxxxxxxxxxxxxxxxxxxxxxxxxx', + errors => ['Sorry, we could not find that location.'], + pc_alternatives => [], + }, + { + pc => 'glenthorpe', + errors => [], + pc_alternatives => [ + 'Glenthorpe Crescent, Leeds LS9 7', + 'Glenthorpe Rd, Merton, Greater London SM4 4', + 'Glenthorpe Ave, Leeds LS9 7', + 'Glenthorne Rd, Hammersmith, Greater London W6 0', + 'Glenthorne Ave, Yeovil, Somerset BA21 4', + 'Glenthorne Rd, Kenwyn, Cornwall TR3 6', + 'Glenthorne Dr, Cheslyn Hay, Staffordshire WS6 7', + 'Glenthorne Gardens, Ilford, Greater London IG5 0', + 'Glenthorne Ave, Croydon, Greater London CR0 7', + ], + }, + { + pc => 'Glenthorpe Ct, Katy, TX 77494, USA', + errors => + ['Sorry, we could not find that location.'], + pc_alternatives => [], + }, + ) +{ + subtest "test bad pc value '$test->{pc}'" => sub { + $mech->get_ok('/'); + $mech->submit_form_ok( { with_fields => { pc => $test->{pc} } }, + "bad location" ); + is_deeply $mech->page_errors, $test->{errors}, + "expected errors for pc '$test->{pc}'"; + is_deeply $mech->pc_alternatives, $test->{pc_alternatives}, + "expected alternatives for pc '$test->{pc}'"; + }; +} + +# check that exact queries result in the correct lat,lng +foreach my $test ( + { + pc => 'SW1A 1AA', + latitude => '51.50101', + longitude => '-0.141587', + }, + { + pc => 'Manchester', + latitude => '53.480713', + longitude => '-2.234376', + }, + { + pc => 'Glenthorpe Rd, Merton, Greater London SM4 4, UK', + latitude => '51.3938', + longitude => '-0.22096', + }, + ) +{ + subtest "check lat/lng for '$test->{pc}'" => sub { + $mech->get_ok('/'); + $mech->submit_form_ok( { with_fields => { pc => $test->{pc} } }, + "good location" ); + is_deeply $mech->form_errors, [], "no errors for pc '$test->{pc}'"; + is_deeply $mech->extract_location, $test, + "got expected location for pc '$test->{pc}'"; + }; +} + +done_testing(); diff --git a/t/app/controller/auth.t b/t/app/controller/auth.t new file mode 100644 index 000000000..a44716a1e --- /dev/null +++ b/t/app/controller/auth.t @@ -0,0 +1,227 @@ +use strict; +use warnings; + +use Test::More; + +use FixMyStreet::TestMech; +my $mech = FixMyStreet::TestMech->new; + +my $test_email = 'test@example.com'; +my $test_password = 'foobar'; +$mech->delete_user($test_email); + +END { + $mech->delete_user($test_email); + done_testing(); +} + +$mech->get_ok('/auth'); + +# check that we can't reach a page that is only available to authenticated users +$mech->not_logged_in_ok; + +# check that submitting form with no / bad email creates an error. +$mech->get_ok('/auth'); + +for my $test ( + [ '' => 'enter your email' ], + [ 'not an email' => 'check your email address is correct' ], + [ 'bob@foo' => 'check your email address is correct' ], + [ 'bob@foonaoedudnueu.co.uk' => 'check your email address is correct' ], + ) +{ + my ( $email, $error_message ) = @$test; + pass "--- testing bad email '$email' gives error '$error_message'"; + $mech->get_ok('/auth'); + $mech->content_lacks($error_message); + $mech->submit_form_ok( + { + form_name => 'general_auth', + fields => { email => $email, }, + button => 'email_login', + }, + "try to create an account with email '$email'" + ); + is $mech->uri->path, '/auth', "still on auth page"; + $mech->content_contains($error_message); +} + +# create a new account +$mech->clear_emails_ok; +$mech->get_ok('/auth'); +$mech->submit_form_ok( + { + form_name => 'general_auth', + fields => { email => $test_email, }, + button => 'email_login', + }, + "create an account for '$test_email'" +); +is $mech->uri->path, '/auth/token', "redirected to welcome page"; + +# check that we are not logged in yet +$mech->not_logged_in_ok; + +# check that we got one email +{ + $mech->email_count_is(1); + my $email = $mech->get_email; + $mech->clear_emails_ok; + is $email->header('Subject'), "Your FixMyStreet.com account details", + "subject is correct"; + is $email->header('To'), $test_email, "to is correct"; + + # extract the link + my ($link) = $email->body =~ m{(http://\S+)}; + ok $link, "Found a link in email '$link'"; + + # check that the user does not exist + sub get_user { + FixMyStreet::App->model('DB::User')->find( { email => $test_email } ); + } + ok !get_user(), "no user exists"; + + # visit the confirm link (with bad token) and check user no confirmed + $mech->get_ok( $link . 'XXX' ); + ok !get_user(), "no user exists"; + $mech->not_logged_in_ok; + + # visit the confirm link and check user is confirmed + $mech->get_ok($link); + ok get_user(), "user created"; + is $mech->uri->path, '/my', "redirected to the 'my' section of site"; + $mech->logged_in_ok; + + # logout and try to use the token again + $mech->log_out_ok; + $mech->get_ok($link); + is $mech->uri, $link, "not logged in"; + $mech->content_contains( 'Link too old or already used', + 'token now invalid' ); + $mech->not_logged_in_ok; +} + +# get a login email and change password +{ + $mech->clear_emails_ok; + $mech->get_ok('/auth'); + $mech->submit_form_ok( + { + form_name => 'general_auth', + fields => { email => "$test_email", }, + button => 'email_login', + }, + "email_login with '$test_email'" + ); + is $mech->uri->path, '/auth/token', "redirected to token page"; + + # rest is as before so no need to test + + # follow link and change password - check not prompted for old password + $mech->not_logged_in_ok; + + $mech->email_count_is(1); + my $email = $mech->get_email; + $mech->clear_emails_ok; + my ($link) = $email->body =~ m{(http://\S+)}; + $mech->get_ok($link); + + $mech->follow_link_ok( { url => '/auth/change_password' } ); + + ok my $form = $mech->form_name('change_password'), + "found change password form"; + is_deeply [ sort grep { $_ } map { $_->name } $form->inputs ], # + [ 'confirm', 'new_password' ], + "check we got expected fields (ie not old_password)"; + + # check the various ways the form can be wrong + for my $test ( + { new => '', conf => '', err => 'enter a password', }, + { new => 'secret', conf => '', err => 'do not match', }, + { new => '', conf => 'secret', err => 'do not match', }, + { new => 'secret', conf => 'not_secret', err => 'do not match', }, + ) + { + $mech->get_ok('/auth/change_password'); + $mech->content_lacks( $test->{err}, "did not find expected error" ); + $mech->submit_form_ok( + { + form_name => 'change_password', + fields => + { new_password => $test->{new}, confirm => $test->{conf}, }, + }, + "change_password with '$test->{new}' and '$test->{conf}'" + ); + $mech->content_contains( $test->{err}, "found expected error" ); + } + + my $user = + FixMyStreet::App->model('DB::User')->find( { email => $test_email } ); + ok $user, "got a user"; + ok !$user->password, "user has no password"; + + $mech->get_ok('/auth/change_password'); + $mech->submit_form_ok( + { + form_name => 'change_password', + fields => + { new_password => $test_password, confirm => $test_password, }, + }, + "change_password with '$test_password' and '$test_password'" + ); + is $mech->uri->path, '/auth/change_password', + "still on change password page"; + $mech->content_contains( 'password has been changed', + "found password changed" ); + + $user->discard_changes(); + ok $user->password, "user now has a password"; +} + +foreach my $remember_me ( '1', '0' ) { + subtest "login using valid details (remember_me => '$remember_me')" => sub { + $mech->get_ok('/auth'); + $mech->submit_form_ok( + { + form_name => 'general_auth', + fields => { + email => $test_email, + password => $test_password, + remember_me => ( $remember_me ? 1 : undef ), + }, + button => 'login', + }, + "login with '$test_email' & '$test_password" + ); + is $mech->uri->path, '/my', "redirected to correct page"; + + # check that the cookie has no expiry set + my $expiry = $mech->session_cookie_expiry; + is( $expiry, 0, "no expiry time" ); + #$remember_me + # ? cmp_ok( $expiry, '>', 86400, "long expiry time" ) + # : is( $expiry, 0, "no expiry time" ); + + # logout + $mech->log_out_ok; + }; +} + +# try to login with bad details +$mech->get_ok('/auth'); +$mech->submit_form_ok( + { + form_name => 'general_auth', + fields => { + email => $test_email, + password => 'not the password', + }, + button => 'login', + }, + "login with '$test_email' & '$test_password" +); +is $mech->uri->path, '/auth', "redirected to correct page"; +$mech->content_contains( 'Email or password wrong', 'found error message' ); + +# more test: +# TODO: test that email are always lowercased diff --git a/t/app/controller/contact.t b/t/app/controller/contact.t new file mode 100644 index 000000000..bbb3a0f83 --- /dev/null +++ b/t/app/controller/contact.t @@ -0,0 +1,275 @@ +use strict; +use warnings; +use Test::More; + +use FixMyStreet::TestMech; + +my $mech = FixMyStreet::TestMech->new; + +$mech->get_ok('/contact'); +$mech->title_like(qr/Contact Us/); +$mech->content_contains("We'd love to hear what you think about this site"); + +my $problem_main; + +for my $test ( + { + name => 'A User', + email => 'problem_report_test@example.com', + title => 'Some problem or other', + detail => 'More detail on the problem', + postcode => 'EH99 1SP', + confirmed => '2011-05-04 10:44:28.145168', + anonymous => 0, + meta => 'Reported by A User at 10:44, Wednesday 4 May 2011', + main => 1, + }, + { + name => 'A User', + email => 'problem_report_test@example.com', + title => 'A different problem', + detail => 'More detail on the different problem', + postcode => 'EH99 1SP', + confirmed => '2011-05-03 13:24:28.145168', + anonymous => 1, + meta => 'Reported anonymously at 13:24, Tuesday 3 May 2011', + }, + { + name => 'A User', + email => 'problem_report_test@example.com', + title => 'A different problem', + detail => 'More detail on the different problem', + postcode => 'EH99 1SP', + confirmed => '2011-05-03 13:24:28.145168', + anonymous => 1, + meta => 'Reported anonymously at 13:24, Tuesday 3 May 2011', + update => { + name => 'Different User', + email => 'commenter@example.com', + text => 'This is an update', + }, + }, + ) +{ + subtest 'check reporting a problem displays correctly' => sub { + my $user = FixMyStreet::App->model('DB::User')->find_or_create( + { + name => $test->{name}, + email => $test->{email} + } + ); + + my $problem = FixMyStreet::App->model('DB::Problem')->create( + { + title => $test->{title}, + detail => $test->{detail}, + postcode => $test->{postcode}, + confirmed => $test->{confirmed}, + name => $test->{name}, + anonymous => $test->{anonymous}, + state => 'confirmed', + user => $user, + latitude => 0, + longitude => 0, + areas => 0, + used_map => 0, + } + ); + + my $update; + + if ( $test->{update} ) { + my $update_info = $test->{update}; + my $update_user = FixMyStreet::App->model('DB::User')->find_or_create( + { + name => $update_info->{name}, + email => $update_info->{email} + } + ); + + $update = FixMyStreet::App->model('DB::Comment')->create( + { + problem_id => $problem->id, + user => $update_user, + state => 'confirmed', + text => $update_info->{text}, + confirmed => \'ms_current_timestamp()', + mark_fixed => 'f', + anonymous => 'f', + } + ); + } + + ok $problem, 'succesfully create a problem'; + + if ( $update ) { + $mech->get_ok( '/contact?id=' . $problem->id . '&update_id=' . $update->id ); + $mech->content_contains('reporting the following update'); + $mech->content_contains( $test->{update}->{text} ); + } else { + $mech->get_ok( '/contact?id=' . $problem->id ); + $mech->content_contains('reporting the following problem'); + $mech->content_contains( $test->{title} ); + $mech->content_contains( $test->{meta} ); + } + + $update->delete if $update; + if ($test->{main}) { + $problem_main = $problem; + } else { + $problem->delete; + } + }; +} + +for my $test ( + { + fields => { + em => ' ', + name => '', + subject => '', + message => '', + }, + page_errors => + [ 'There were problems with your report. Please see below.', ], + field_errors => [ + 'Please enter your name', + 'Please enter your email', + 'Please enter a subject', + 'Please write a message', + ] + }, + { + fields => { + em => 'invalidemail', + name => '', + subject => '', + message => '', + }, + page_errors => + [ 'There were problems with your report. Please see below.', ], + field_errors => [ + 'Please enter your name', + 'Please enter a valid email address', + 'Please enter a subject', + 'Please write a message', + ] + }, + { + fields => { + em => 'test@example.com', + name => 'A name', + subject => '', + message => '', + }, + page_errors => + [ 'There were problems with your report. Please see below.', ], + field_errors => [ 'Please enter a subject', 'Please write a message', ] + }, + { + fields => { + em => 'test@example.com', + name => 'A name', + subject => 'A subject', + message => '', + }, + page_errors => + [ 'There were problems with your report. Please see below.', ], + field_errors => [ 'Please write a message', ] + }, + { + fields => { + em => 'test@example.com', + name => 'A name', + subject => ' ', + message => '', + }, + page_errors => + [ 'There were problems with your report. Please see below.', ], + field_errors => [ 'Please enter a subject', 'Please write a message', ] + }, + { + fields => { + em => 'test@example.com', + name => 'A name', + subject => 'A subject', + message => ' ', + }, + page_errors => + [ 'There were problems with your report. Please see below.', ], + field_errors => [ 'Please write a message', ] + }, + { + url => '/contact?id=' . $problem_main->id, + fields => { + em => 'test@example.com', + name => 'A name', + subject => 'A subject', + message => 'A message', + id => 'invalid', + }, + page_errors => [ 'Illegal ID' ], + field_errors => [] + }, + ) +{ + subtest 'check submit page error handling' => sub { + $mech->get_ok( $test->{url} ? $test->{url} : '/contact' ); + $mech->submit_form_ok( { with_fields => $test->{fields} } ); + is_deeply $mech->page_errors, $test->{page_errors}, 'page errors'; + is_deeply $mech->form_errors, $test->{field_errors}, 'field_errors'; + + # we santise this when we submit so need to remove it + delete $test->{fields}->{id} + if $test->{fields}->{id} and $test->{fields}->{id} eq 'invalid'; + is_deeply $mech->visible_form_values, $test->{fields}, 'form values'; + }; +} + +for my $test ( + { + fields => { + em => 'test@example.com', + name => 'A name', + subject => 'A subject', + message => 'A message', + }, + }, + { + fields => { + em => 'test@example.com', + name => 'A name', + subject => 'A subject', + message => 'A message', + id => $problem_main->id, + }, + }, + + ) +{ + subtest 'check email sent correctly' => sub { + $mech->clear_emails_ok; + if ($test->{fields}{id}) { + $mech->get_ok('/contact?id=' . $test->{fields}{id}); + } else { + $mech->get_ok('/contact'); + } + $mech->submit_form_ok( { with_fields => $test->{fields} } ); + $mech->content_contains('Thanks for your feedback'); + $mech->email_count_is(1); + + my $email = $mech->get_email; + + is $email->header('Subject'), 'FMS message: ' . $test->{fields}->{subject}, 'subject'; + is $email->header('From'), "\"$test->{fields}->{name}\" <$test->{fields}->{em}>", 'from'; + like $email->body, qr/$test->{fields}->{message}/, 'body'; + like $email->body, qr/Sent by contact.cgi on \S+. IP address (?:\d{1,3}\.){3,}\d{1,3}/, 'body footer'; + my $problem_id = $test->{fields}{id}; + like $email->body, qr/Complaint about report $problem_id/, 'reporting a report' + if $test->{fields}{id}; + }; +} + +$problem_main->delete; + +done_testing(); diff --git a/t/app/controller/council.t b/t/app/controller/council.t new file mode 100644 index 000000000..11898995a --- /dev/null +++ b/t/app/controller/council.t @@ -0,0 +1,14 @@ +use strict; +use warnings; +use Test::More; + + +use Catalyst::Test 'FixMyStreet::App'; +use_ok( 'FixMyStreet::App::Controller::Council' ); + +TODO: { + local $TODO = 'need to write some tests for this'; + +} + +done_testing(); diff --git a/t/app/controller/index.t b/t/app/controller/index.t new file mode 100644 index 000000000..cebeaf676 --- /dev/null +++ b/t/app/controller/index.t @@ -0,0 +1,58 @@ +use strict; +use warnings; +use Test::More; + +use FixMyStreet::TestMech; +my $mech = FixMyStreet::TestMech->new; + +# check that the homepage loads +$mech->get_ok('/'); + +subtest "check that the form goes to /around" => sub { + $mech->get_ok('/'); + is $mech->uri->path, '/', "still on '/'"; + + # submit form + $mech->submit_form_ok( { with_fields => { pc => 'SW1A 1AA', } } ); + + # check that we are at /around + is $mech->uri->path, '/around', "Got to /around"; + is_deeply { $mech->uri->query_form }, { pc => 'SW1A 1AA' }, + "query passed along"; +}; + +subtest "does pc, (x,y), (e,n) or (lat,lon) go to /around" => sub { + + foreach my $test ( # + { + in => { pc => 'SW1A 1AA' }, + out => { pc => 'SW1A 1AA' }, + }, + { + in => { lat => 51.50100, lon => -0.14158 }, + out => { lat => 51.50100, lon => -0.14158 }, + }, + { + in => { x => 3281, y => 1113, }, + out => { lat => 51.4998246332569, lon => -0.140137309739907 }, + }, + { + in => { e => 1234, n => 4567 }, + out => { lat => 49.808509, lon => -7.544784 }, + }, + ) + { + + my $uri = URI->new('http://localhost/'); + $uri->query_form( $test->{in} ); + + # get the uri and check for 302 + $mech->get_ok($uri); + + # check that we are at /around + is $mech->uri->path, '/around', "Got to /around"; + is_deeply { $mech->uri->query_form }, $test->{out}, "query correct"; + } +}; + +done_testing(); diff --git a/t/app/controller/json.t b/t/app/controller/json.t new file mode 100644 index 000000000..d6820e1be --- /dev/null +++ b/t/app/controller/json.t @@ -0,0 +1,109 @@ +use strict; +use warnings; + +use Test::More; + +use FixMyStreet::TestMech; +my $mech = FixMyStreet::TestMech->new; + +subtest "check that a bad request produces the appropriate response" => sub { + + my $bad_date = "Invalid dates supplied"; + my $mad_date = "Start date after end date"; + my $bad_type = "Invalid type supplied"; + + my %tests = ( + '?' => $bad_date, + '?foo=bar' => $bad_date, + '?start_date=&end_date=' => $bad_date, + '?start_date=bad&end_date=2000-02-01' => $bad_date, + '?start_date=2000-01-01&end_date=bad' => $bad_date, + '?start_date=2000-02-31&end_date=2000-02-01' => $bad_date, + '?start_date=2000-01-01&end_date=2000-02-31' => $bad_date, + + '?start_date=2000-02-01&end_date=2000-01-01' => $mad_date, + + '?start_date=2000-01-01&end_date=2000-02-01' => $bad_type, + '/foo?type=foo&start_date=2000-01-01&end_date=2000-02-01' => $bad_type, + ); + + foreach my $q ( sort keys %tests ) { + is_deeply # + $mech->get_ok_json("/json/problems$q"), # + { error => $tests{$q} }, # + "correct error for query '$q'"; + } + +}; + +is_deeply # + $mech->get_ok_json( + "/json/problems/new?start_date=2000-01-01&end_date=2000-02-01"), # + [], # + "correct response"; + +# put an entry in the database for this test +my $user = $mech->create_user_ok('test@example.com'); + +my $problem_args = { + postcode => 'sw1a 1aa', + council => '2501', + areas => ',105164,11806,11827,2247,2501,34817,42011,66045,70786,8519,', + category => 'test category', + title => 'Test title', + detail => 'Test detail', + used_map => 't', + name => 'Test Name', + created => '2000-01-01 12:00:00', + confirmed => '2000-01-01 12:01:00', + state => 'confirmed', + lang => 'en-gb', + service => '', + cobrand => '', + cobrand_data => '', + lastupdate => '2000-01-01 12:00:00', + whensent => undef, + send_questionnaire => 't', + latitude => '51.4531988729771', + longitude => '-0.23021896608596', +}; +my $problem = $user->add_to_problems( { %$problem_args, anonymous => 0 } ); +my $anon_problem = $user->add_to_problems( { %$problem_args, anonymous => 1, confirmed => '2000-01-01 12:02:00' } ); + +ok $problem, "created normal test problem"; +ok $anon_problem, "created anon test problem"; + +is_deeply # + $mech->get_ok_json( + "/json/problems/new?start_date=2000-01-01&end_date=2000-02-01"), # + [ + { + 'anonymous' => 0, + 'category' => 'test category', + 'confirmed' => '2000-01-01 12:01:00', + 'council' => 'Wandsworth Borough Council', + 'detail' => 'Test detail', + 'id' => $problem->id, + 'name' => 'Test Name', + 'service' => 'Web interface', + 'title' => 'Test title', + 'whensent' => undef + }, + { + 'anonymous' => 1, + 'category' => 'test category', + 'confirmed' => '2000-01-01 12:02:00', + 'council' => 'Wandsworth Borough Council', + 'detail' => 'Test detail', + 'id' => $anon_problem->id, + 'name' => '', + 'service' => 'Web interface', + 'title' => 'Test title', + 'whensent' => undef + } + ], + "correct response"; + +$mech->delete_user($user); + +done_testing(); diff --git a/t/app/controller/my.t b/t/app/controller/my.t new file mode 100644 index 000000000..1ed6806a4 --- /dev/null +++ b/t/app/controller/my.t @@ -0,0 +1,19 @@ +use strict; +use warnings; + +use Test::More tests => 11; + +use FixMyStreet::TestMech; +my $mech = FixMyStreet::TestMech->new; + +$mech->get_ok('/my'); +is $mech->uri->path, '/auth', "got sent to the login page"; + +# login +my $user = $mech->log_in_ok( 'test@example.com' ); +$mech->get_ok('/my'); +is $mech->uri->path, '/my', "stayed on '/my/' page"; + +# cleanup +$mech->delete_user( $user ); + diff --git a/t/app/controller/page_not_found.t b/t/app/controller/page_not_found.t new file mode 100644 index 000000000..05e983109 --- /dev/null +++ b/t/app/controller/page_not_found.t @@ -0,0 +1,20 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use Test::More tests => 4; + +use Test::WWW::Mechanize::Catalyst 'FixMyStreet::App'; + +my $mech = Test::WWW::Mechanize::Catalyst->new; + +# homepage ok +$mech->get_ok('/'); + +# get 404 page +my $path_to_404 = '/bad/path/page_error_404_not_found'; +my $res = $mech->get($path_to_404); +ok !$res->is_success(), "want a bad response"; +is $res->code, 404, "got 404"; +$mech->content_contains($path_to_404); diff --git a/t/app/controller/questionnaire.t b/t/app/controller/questionnaire.t new file mode 100644 index 000000000..a245be343 --- /dev/null +++ b/t/app/controller/questionnaire.t @@ -0,0 +1,292 @@ +use strict; +use warnings; +use Test::More; + +use FixMyStreet::TestMech; +use FixMyStreet::App::Controller::Questionnaire; + +ok( my $mech = FixMyStreet::TestMech->new, 'Created mech object' ); + +# create a test user and report +$mech->delete_user('test@example.com'); + +my $user = + FixMyStreet::App->model('DB::User') + ->find_or_create( { email => 'test@example.com', name => 'Test User' } ); +ok $user, "created test user"; + +my $report_time = '2011-03-01 12:00:00'; + +my $report = FixMyStreet::App->model('DB::Problem')->find_or_create( + { + postcode => 'EH1 1BB', + council => '2651', + areas => ',11808,135007,14419,134935,2651,20728,', + category => 'Street lighting', + title => 'Testing', + detail => 'Testing Detail', + used_map => 1, + name => $user->name, + anonymous => 0, + state => 'confirmed', + confirmed => $report_time, + lastupdate => $report_time, + whensent => '2011-03-01 12:05:00', + lang => 'en-gb', + service => '', + cobrand => 'default', + cobrand_data => '', + send_questionnaire => 1, + latitude => '55.951963', + longitude => '-3.189944', + user_id => $user->id, + } +); +my $report_id = $report->id; +ok $report, "created test report - $report_id"; + +# Call the questionaire sending function... +FixMyStreet::App->model('DB::Questionnaire')->send_questionnaires( { + site => 'fixmystreet' +} ); +my $email = $mech->get_email; +ok $email, "got an email"; +like $email->body, qr/fill in our short questionnaire/i, "got questionnaire email"; +my ($token) = $email->body =~ m{http://.*?/Q/(\S+)}; +ok $token, "extracted questionnaire token '$token'"; +$mech->clear_emails_ok; + +$report->discard_changes; +is $report->send_questionnaire, 0; + +$token = FixMyStreet::App->model("DB::Token")->find( { + scope => 'questionnaire', token => $token +} ); +ok $token, 'found token for questionnaire'; + +my $questionnaire = FixMyStreet::App->model('DB::Questionnaire')->find( { + id => $token->data +} ); +ok $questionnaire, 'found questionnaire'; + +foreach my $test ( + { + desc => 'User goes to questionnaire URL with a bad token', + token_extra => 'BAD', + content => "we couldn't validate that token", + }, + { + desc => 'User goes to questionnaire URL for a now-hidden problem', + state => 'hidden', + content => "we couldn't locate your problem", + }, + { + desc => 'User goes to questionnaire URL for an already answered questionnaire', + answered => \'ms_current_timestamp()', + content => 'already answered this questionnaire', + }, +) { + subtest $test->{desc} => sub { + $report->state( $test->{state} || 'confirmed' ); + $report->update; + $questionnaire->whenanswered( $test->{answered} ); + $questionnaire->update; + (my $token = $token->token); + $token .= $test->{token_extra} if $test->{token_extra}; + $mech->get_ok("/Q/$token"); + $mech->content_contains( $test->{content} ); + # Reset, no matter what test did + $report->state( 'confirmed' ); + $report->update; + $questionnaire->whenanswered( undef ); + $questionnaire->update; + }; +} + +$mech->get_ok("/Q/" . $token->token); +$mech->title_like( qr/Questionnaire/ ); +$mech->submit_form_ok( ); +my @errors = @{ $mech->page_errors }; +ok scalar @errors, 'displayed error messages'; +is $errors[0], "Please state whether or not the problem has been fixed", 'error message'; + +foreach my $test ( + { + desc => 'Open report, has been fixed, first time reporter, no update left', + problem_state => 'confirmed', + fields => { + been_fixed => 'Yes', + reported => 'No', + }, + comment => 'Questionnaire filled in by problem reporter', + }, + { + desc => 'Open report, has been fixed, reported before, leaves an update', + problem_state => 'confirmed', + fields => { + been_fixed => 'Yes', + reported => 'Yes', + update => 'The council fixed this really quickly, thanks!', + }, + }, + { + desc => 'Open report, has not been fixed, not reported before, no update, asks for another questionnaire', + problem_state => 'confirmed', + fields => { + been_fixed => 'No', + reported => 'No', + another => 'Yes', + }, + }, + { + desc => 'Open report, unknown fixed, reported before, update, no further questionnaire', + problem_state => 'confirmed', + fields => { + been_fixed => 'Unknown', + reported => 'Yes', + update => 'This is still going on.', + # another => 'No', Error for not setting this tested below + }, + }, + { + desc => 'Fixed report, confirmed fixed, not reported before, no update', + problem_state => 'fixed', + fields => { + been_fixed => 'Yes', + reported => 'No', + }, + lastupdate_static => 1, + }, + { + desc => 'Fixed report, unknown fixed, not reported before, no update, asks for another', + problem_state => 'fixed', + fields => { + been_fixed => 'Unknown', + reported => 'No', + another => 'Yes', + }, + }, + { + desc => 'Fixed report, reopened, reported before, no update, no further questionnaire', + problem_state => 'fixed', + fields => { + been_fixed => 'No', + reported => 'Yes', + another => 'No', + # update => 'Dummy', Error for not setting this tested below + }, + }, +) { + subtest $test->{desc} => sub { + $report->state ( $test->{problem_state} ); + $report->update; + + $mech->get_ok("/Q/" . $token->token); + $mech->title_like( qr/Questionnaire/ ); + $mech->submit_form_ok( { with_fields => $test->{fields} } ); + + # If reopening, we've just submitted without an update. Should cause an error. + if ($test->{problem_state} eq 'fixed' && $test->{fields}{been_fixed} eq 'No') { + my @errors = @{ $mech->page_errors }; + ok scalar @errors, 'displayed error messages'; + is $errors[0], "Please provide some explanation as to why you're reopening this report", 'error message'; + $test->{fields}{update} = 'This has not been fixed.'; + $mech->submit_form_ok( { with_fields => $test->{fields} } ); + } + + # We forgot to say we wanted another questionnaire or not with this test + if ($test->{problem_state} eq 'confirmed' && $test->{fields}{been_fixed} eq 'Unknown') { + my @errors = @{ $mech->page_errors }; + ok scalar @errors, 'displayed error messages'; + is $errors[0], "Please indicate whether you'd like to receive another questionnaire", 'error message'; + $test->{fields}{another} = 'No'; + $mech->submit_form_ok( { with_fields => $test->{fields} } ); + } + + my $result; + $result = 'fixed' if $test->{fields}{been_fixed} eq 'Yes'; + $result = 'confirmed' if $test->{fields}{been_fixed} eq 'No'; + $result = 'unknown' if $test->{fields}{been_fixed} eq 'Unknown'; + + my $another = 0; + $another = 1 if $test->{fields}{another} && $test->{fields}{another} eq 'Yes'; + + # Check the right HTML page has been returned + $mech->content_contains( 'glad to hear it’s been fixed' ) + if $result eq 'fixed'; + $mech->content_contains( 'get some more information about the status of your problem' ) + if $result eq 'unknown'; + $mech->content_contains( "sorry to hear that" ) + if $result eq 'confirmed'; + + # Check the database has the right information + $report->discard_changes; + $questionnaire->discard_changes; + is $report->state, $result eq 'unknown' ? $test->{problem_state} : $result; + is $report->send_questionnaire, $another; + ok DateTime::Format::Pg->format_datetime( $report->lastupdate) gt $report_time, 'lastupdate changed' + unless $test->{fields}{been_fixed} eq 'Unknown' || $test->{lastupdate_static}; + is $questionnaire->old_state, $test->{problem_state}; + is $questionnaire->new_state, $result; + is $questionnaire->ever_reported, $test->{fields}{reported} eq 'Yes' ? 1 : 0; + if ($test->{fields}{update} || $test->{comment}) { + my $c = FixMyStreet::App->model("DB::Comment")->find( + { problem_id => $report->id } + ); + is $c->text, $test->{fields}{update} || $test->{comment}; + } + + # Reset questionnaire for next test + $questionnaire->old_state( undef ); + $questionnaire->new_state( undef ); + $questionnaire->ever_reported( undef ); + $questionnaire->whenanswered( undef ); + $questionnaire->update; + $report->send_questionnaire( 0 ); + $report->lastupdate( $report_time ); + $report->comments->delete; + $report->update; + }; +} + +# EHA extra checking +ok $mech->host("reportemptyhomes.com"), 'change host to reportemptyhomes'; + +# Reset, and all the questionaire sending function - FIXME should it detect site itself somehow? +$report->send_questionnaire( 1 ); +$report->update; +$questionnaire->delete; +FixMyStreet::App->model('DB::Questionnaire')->send_questionnaires( { + site => 'emptyhomes' +} ); +$email = $mech->get_email; +ok $email, "got an email"; +like $email->body, qr/fill in this short questionnaire/i, "got questionnaire email"; +($token) = $email->body =~ m{http://.*?/Q/(\S+)}; +ok $token, "extracted questionnaire token '$token'"; + +$mech->get_ok("/Q/" . $token); +$mech->content_contains( 'should have reported what they have done' ); + +# Test already answered the ever reported question, so not shown again +my $questionnaire2 = FixMyStreet::App->model('DB::Questionnaire')->find_or_create( + { + problem_id => $report->id, + whensent => '2011-03-28 12:00:00', + ever_reported => 1, + } +); +ok $questionnaire, 'added another questionnaire'; +ok $mech->host("fixmystreet.com"), 'change host to fixmystreet'; +$mech->get_ok("/Q/" . $token); +$mech->title_like( qr/Questionnaire/ ); +$mech->content_contains( 'Has this problem been fixed?' ); +$mech->content_lacks( 'ever reported' ); + +# EHA extra checking +ok $mech->host("reportemptyhomes.com"), 'change host to reportemptyhomes'; +$mech->get_ok("/Q/" . $token); +$mech->content_contains( 'made a lot of progress' ); + +$mech->delete_user('test@example.com'); +done_testing(); diff --git a/t/app/controller/report_display.t b/t/app/controller/report_display.t new file mode 100644 index 000000000..1f857a387 --- /dev/null +++ b/t/app/controller/report_display.t @@ -0,0 +1,265 @@ +use strict; +use warnings; +use Test::More; + +use FixMyStreet::TestMech; +use Web::Scraper; +use Path::Class; +use DateTime; + +my $mech = FixMyStreet::TestMech->new; + +# create a test user and report +$mech->delete_user('test@example.com'); +my $user = + FixMyStreet::App->model('DB::User') + ->find_or_create( { email => 'test@example.com', name => 'Test User' } ); +ok $user, "created test user"; + +my $dt = DateTime->new( + year => 2011, + month => 04, + day => 16, + hour => 15, + minute => 47, + second => 23 +); + +my $report = FixMyStreet::App->model('DB::Problem')->find_or_create( + { + postcode => 'SW1A 1AA', + council => '2504', + areas => ',105255,11806,11828,2247,2504,', + category => 'Other', + title => 'Test 2', + detail => 'Test 2 Detail', + used_map => 't', + name => 'Test User', + anonymous => 'f', + state => 'confirmed', + confirmed => $dt->ymd . ' ' . $dt->hms, + lang => 'en-gb', + service => '', + cobrand => 'default', + cobrand_data => '', + send_questionnaire => 't', + latitude => '51.5016605453401', + longitude => '-0.142497580865087', + user_id => $user->id, + } +); +my $report_id = $report->id; +ok $report, "created test report - $report_id"; + +subtest "check that no id redirects to homepage" => sub { + $mech->get_ok('/report'); + is $mech->uri->path, '/', "at home page"; +}; + +subtest "test id=NNN redirects to /NNN" => sub { + $mech->get_ok("/report?id=$report_id"); + is $mech->uri->path, "/report/$report_id", "at /report/$report_id"; +}; + +subtest "test bad council email clients web links" => sub { + $mech->get_ok("/report/3D$report_id"); + is $mech->uri->path, "/report/$report_id", "at /report/$report_id"; +}; + +subtest "test tailing non-ints get stripped" => sub { + $mech->get_ok("/report/${report_id}xx "); + is $mech->uri->path, "/report/$report_id", "at /report/$report_id"; +}; + +subtest "test bad ids get dealt with (404)" => sub { + foreach my $id ( 'XXX', 99999999 ) { + ok $mech->get("/report/$id"), "get '/report/$id'"; + is $mech->res->code, 404, "page not found"; + is $mech->uri->path, "/report/$id", "at /report/$id"; + $mech->content_contains('Unknown problem ID'); + } +}; + +subtest "change report to unconfirmed and check for 404 status" => sub { + ok $report->update( { state => 'unconfirmed' } ), 'unconfirm report'; + ok $mech->get("/report/$report_id"), "get '/report/$report_id'"; + is $mech->res->code, 404, "page not found"; + is $mech->uri->path, "/report/$report_id", "at /report/$report_id"; + $mech->content_contains('Unknown problem ID'); + ok $report->update( { state => 'confirmed' } ), 'confirm report again'; +}; + +subtest "change report to hidden and check for 410 status" => sub { + ok $report->update( { state => 'hidden' } ), 'hide report'; + ok $mech->get("/report/$report_id"), "get '/report/$report_id'"; + is $mech->res->code, 410, "page gone"; + is $mech->uri->path, "/report/$report_id", "at /report/$report_id"; + $mech->content_contains('That report has been removed from FixMyStreet.'); + ok $report->update( { state => 'confirmed' } ), 'confirm report again'; +}; + +subtest "test a good report" => sub { + $mech->get_ok("/report/$report_id"); + is $mech->uri->path, "/report/$report_id", "at /report/$report_id"; + is $mech->extract_problem_title, 'Test 2', 'problem title'; + is $mech->extract_problem_meta, + 'Reported by Test User at 15:47, Saturday 16 April 2011', + 'correct problem meta information'; + $mech->content_contains('Test 2 Detail'); + + my $update_form = $mech->form_name('updateForm'); + + my %fields = ( + name => '', + rznvy => '', + update => '', + add_alert => 1, # defaults to true + fixed => undef + ); + is $update_form->value($_), $fields{$_}, "$_ value" for keys %fields; +}; + +foreach my $meta ( + { + anonymous => 'f', + category => 'Other', + service => '', + meta => 'Reported by Test User at 15:47, Saturday 16 April 2011' + }, + { + anonymous => 'f', + category => 'Roads', + service => '', + meta => +'Reported in the Roads category by Test User at 15:47, Saturday 16 April 2011' + }, + { + anonymous => 'f', + category => '', + service => 'Transport service', + meta => +'Reported by Transport service by Test User at 15:47, Saturday 16 April 2011' + }, + { + anonymous => 'f', + category => 'Roads', + service => 'Transport service', + meta => +'Reported by Transport service in the Roads category by Test User at 15:47, Saturday 16 April 2011' + }, + { + anonymous => 't', + category => 'Other', + service => '', + meta => 'Reported anonymously at 15:47, Saturday 16 April 2011' + }, + { + anonymous => 't', + category => 'Roads', + service => '', + meta => +'Reported in the Roads category anonymously at 15:47, Saturday 16 April 2011' + }, + { + anonymous => 't', + category => '', + service => 'Transport service', + meta => +'Reported by Transport service anonymously at 15:47, Saturday 16 April 2011' + }, + { + anonymous => 't', + category => 'Roads', + service => 'Transport service', + meta => +'Reported by Transport service in the Roads category anonymously at 15:47, Saturday 16 April 2011' + }, + ) +{ + $report->service( $meta->{service} ); + $report->category( $meta->{category} ); + $report->anonymous( $meta->{anonymous} ); + $report->update; + subtest "test correct problem meta information" => sub { + $mech->get_ok("/report/$report_id"); + + is $mech->extract_problem_meta, $meta->{meta}; + + }; +} + +for my $test ( + { + description => 'new report', + date => DateTime->now, + state => 'confirmed', + banner_id => '', + banner_text => '', + fixed => 0 + }, + { + description => 'old report', + date => DateTime->new( + year => 2009, + month => 6, + day => 12, + hour => 9, + minute => 43, + second => 12 + ), + state => 'confirmed', + banner_id => 'unknown', + banner_text => 'This problem is old and of unknown status.', + fixed => 0 + }, + { + description => 'old fixed report', + date => DateTime->new( + year => 2009, + month => 6, + day => 12, + hour => 9, + minute => 43, + second => 12 + ), + state => 'fixed', + banner_id => 'fixed', + banner_text => 'This problem has been fixed.', + fixed => 1 + }, + { + description => 'fixed report', + date => DateTime->now, + state => 'fixed', + banner_id => 'fixed', + banner_text => 'This problem has been fixed.', + fixed => 1 + }, +) { + subtest "banner for $test->{description}" => sub { + $report->confirmed( $test->{date}->ymd . ' ' . $test->{date}->hms ); + $report->lastupdate( $test->{date}->ymd . ' ' . $test->{date}->hms ); + $report->state( $test->{state} ); + $report->update; + + $mech->get_ok("/report/$report_id"); + is $mech->uri->path, "/report/$report_id", "at /report/$report_id"; + my $banner = $mech->extract_problem_banner; + $banner->{text} =~ s/^ //g; + $banner->{text} =~ s/ $//g; + + is $banner->{id}, $test->{banner_id}, 'banner id'; + is $banner->{text}, $test->{banner_text}, 'banner text'; + + my $update_form = $mech->form_name( 'updateForm' ); + if ( $test->{fixed} ) { + is $update_form->find_input( 'fixed' ), undef, 'problem is fixed'; + } else { + ok $update_form->find_input( 'fixed' ), 'problem is not fixed'; + } + }; +} + +# tidy up +$mech->delete_user('test@example.com'); +done_testing(); diff --git a/t/app/controller/report_import.t b/t/app/controller/report_import.t new file mode 100644 index 000000000..154de13d8 --- /dev/null +++ b/t/app/controller/report_import.t @@ -0,0 +1,242 @@ +use strict; +use warnings; +use Test::More; + +use FixMyStreet::TestMech; +use Web::Scraper; +use Path::Class; + +my $mech = FixMyStreet::TestMech->new; +$mech->get_ok('/import'); + +my $sample_file = file(__FILE__)->parent->file("sample.jpg")->stringify; +ok -e $sample_file, "sample file $sample_file exists"; + +# submit an empty report to import - check we get all errors +subtest "Test creating bad partial entries" => sub { + + foreach my $test ( + { + fields => { email => 'bob', }, + errors => [ + 'You must supply a service', + 'Please enter a subject', + 'Please enter your name', + 'Please enter a valid email', + 'Either a location or a photo must be provided.', + ], + }, + { + fields => { email => 'bob@example.com' }, + errors => [ + 'You must supply a service', + 'Please enter a subject', + 'Please enter your name', + 'Either a location or a photo must be provided.', + ], + }, + { + fields => { lat => 1, lon => 1, }, + errors => [ + 'You must supply a service', + 'Please enter a subject', + 'Please enter your name', + 'Please enter your email', +'We had a problem with the supplied co-ordinates - outside the UK?', + ], + }, + { + fields => { photo => $sample_file, }, + errors => [ + 'You must supply a service', + 'Please enter a subject', + 'Please enter your name', + 'Please enter your email', + ], + }, + ) + { + $mech->get_ok('/import'); + + $mech->submit_form_ok( # + { with_fields => $test->{fields} }, + "fill in form" + ); + + is_deeply( $mech->import_errors, $test->{errors}, "expected errors" ); + } + +}; + +# submit an empty report to import - check we get all errors +subtest "Submit a correct entry" => sub { + + $mech->get_ok('/import'); + + $mech->submit_form_ok( # + { + with_fields => { + service => 'test-script', + name => 'Test User', + email => 'test@example.com', + subject => 'Test report', + detail => 'This is a test report', + photo => $sample_file, + } + }, + "fill in form" + ); + + is_deeply( $mech->import_errors, [], "got no errors" ); + is $mech->content, 'SUCCESS', "Got success response"; + + # check that we have received the email + $mech->email_count_is(1); + my $email = $mech->get_email; + $mech->clear_emails_ok; + + my ($token_url) = $email->body =~ m{(http://\S+)}; + ok $token_url, "Found a token url $token_url"; + + # go to the token url + $mech->get_ok($token_url); + + # check that we are on '/around' + is $mech->uri->path, '/around', "sent to /around"; + + # check that we are not shown anything as we don't have a location yet + is_deeply $mech->visible_form_values, { pc => '' }, + "check only pc field is shown"; + + $mech->submit_form_ok( # + { with_fields => { pc => 'SW1A 1AA' } }, + "fill in postcode" + ); + + is $mech->uri->path, '/report/new', "sent to report page"; + + # check that fields are prefilled for us + is_deeply $mech->visible_form_values, + { + name => 'Test User', + email => 'test@example.com', + title => 'Test report', + detail => 'This is a test report', + photo => '', + phone => '', + may_show_name => '1', + category => '-- Pick a category --', + }, + "check imported fields are shown"; + + # change the details + $mech->submit_form_ok( # + { + with_fields => { + name => 'New Test User', + email => 'test@example.com', + title => 'New Test report', + detail => 'This is a test report', + phone => '01234 567 890', + may_show_name => '1', + category => 'Street lighting', + } + }, + "Update details and save" + ); + + # check that report has been created + my $user = + FixMyStreet::App->model('DB::User') + ->find( { email => 'test@example.com' } ); + ok $user, "Found a user"; + + my $report = $user->problems->first; + is $report->state, 'confirmed', 'is confirmed'; + is $report->title, 'New Test report', 'title is correct'; + + $mech->delete_user($user); +}; + +# submit an empty report to import - check we get all errors +subtest "Submit a correct entry (with location)" => sub { + + $mech->get_ok('/import'); + + $mech->submit_form_ok( # + { + with_fields => { + service => 'test-script', + lat => '51.5010096115539', # SW1A 1AA + lon => '-0.141587067110009', + name => 'Test User ll', + email => 'test-ll@example.com', + subject => 'Test report ll', + detail => 'This is a test report ll', + photo => $sample_file, + } + }, + "fill in form" + ); + + is_deeply( $mech->import_errors, [], "got no errors" ); + is $mech->content, 'SUCCESS', "Got success response"; + + # check that we have received the email + $mech->email_count_is(1); + my $email = $mech->get_email; + $mech->clear_emails_ok; + + my ($token_url) = $email->body =~ m{(http://\S+)}; + ok $token_url, "Found a token url $token_url"; + + # go to the token url + $mech->get_ok($token_url); + + # check that we are on '/around' + is $mech->uri->path, '/report/new', "sent to /around"; + + # check that fields are prefilled for us + is_deeply $mech->visible_form_values, + { + name => 'Test User ll', + email => 'test-ll@example.com', + title => 'Test report ll', + detail => 'This is a test report ll', + photo => '', + phone => '', + may_show_name => '1', + category => '-- Pick a category --', + }, + "check imported fields are shown"; + + # change the details + $mech->submit_form_ok( # + { + with_fields => { + name => 'New Test User ll', + email => 'test-ll@example.com', + title => 'New Test report ll', + detail => 'This is a test report ll', + phone => '01234 567 890', + may_show_name => '1', + category => 'Street lighting', + } + }, + "Update details and save" + ); + + # check that report has been created + my $user = + FixMyStreet::App->model('DB::User') + ->find( { email => 'test-ll@example.com' } ); + ok $user, "Found a user"; + + my $report = $user->problems->first; + is $report->state, 'confirmed', 'is confirmed'; + is $report->title, 'New Test report ll', 'title is correct'; + + $mech->delete_user($user); +}; + +done_testing(); diff --git a/t/app/controller/report_new.t b/t/app/controller/report_new.t new file mode 100644 index 000000000..01c29ecf4 --- /dev/null +++ b/t/app/controller/report_new.t @@ -0,0 +1,501 @@ +use strict; +use warnings; +use Test::More; + +use FixMyStreet::TestMech; +use Web::Scraper; + +my $mech = FixMyStreet::TestMech->new; +$mech->get_ok('/report/new'); + +subtest "test that bare requests to /report/new get redirected" => sub { + + $mech->get_ok('/report/new'); + is $mech->uri->path, '/around', "went to /around"; + is_deeply { $mech->uri->query_form }, {}, "query empty"; + + $mech->get_ok('/report/new?pc=SW1A%201AA'); + is $mech->uri->path, '/around', "went to /around"; + is_deeply { $mech->uri->query_form }, { pc => 'SW1A 1AA' }, + "pc correctly transferred"; +}; + +my %contact_params = ( + confirmed => 1, + deleted => 0, + editor => 'Test', + whenedited => \'current_timestamp', + note => 'Created for test', +); +# Let's make some contacts to send things to! +my $contact1 = FixMyStreet::App->model('DB::Contact')->find_or_create( { + %contact_params, + area_id => 2651, # Edinburgh + category => 'Street lighting', + email => 'highways@example.com', +} ); +my $contact2 = FixMyStreet::App->model('DB::Contact')->find_or_create( { + %contact_params, + area_id => 2226, # Gloucestershire + category => 'Potholes', + email => 'potholes@example.com', +} ); +my $contact3 = FixMyStreet::App->model('DB::Contact')->find_or_create( { + %contact_params, + area_id => 2326, # Cheltenham + category => 'Trees', + email => 'trees@example.com', +} ); +ok $contact1, "created test contact 1"; +ok $contact2, "created test contact 2"; +ok $contact3, "created test contact 3"; + +# test that the various bit of form get filled in and errors correctly +# generated. +foreach my $test ( + { + msg => 'all fields empty', + pc => 'SW1A 1AA', + fields => { + title => '', + detail => '', + photo => '', + name => '', + may_show_name => '1', + email => '', + phone => '', + category => 'Street lighting', + }, + changes => {}, + errors => [ + 'Please enter a subject', + 'Please enter some details', + 'Please enter your name', + 'Please enter your email', + ], + }, + { + msg => 'may_show_name defaults to true', + pc => 'SW1A 1AA', + fields => { + title => '', + detail => '', + photo => '', + name => '', + may_show_name => undef, + email => '', + phone => '', + category => 'Street lighting', + }, + changes => { may_show_name => '1' }, + errors => [ + 'Please enter a subject', + 'Please enter some details', + 'Please enter your name', + 'Please enter your email', + ], + }, + { + msg => 'may_show_name unchanged if name is present (stays false)', + pc => 'SW1A 1AA', + fields => { + title => '', + detail => '', + photo => '', + name => 'Bob Jones', + may_show_name => undef, + email => '', + phone => '', + category => 'Street lighting', + }, + changes => {}, + errors => [ + 'Please enter a subject', + 'Please enter some details', + 'Please enter your email', + ], + }, + { + msg => 'may_show_name unchanged if name is present (stays true)', + pc => 'SW1A 1AA', + fields => { + title => '', + detail => '', + photo => '', + name => 'Bob Jones', + may_show_name => '1', + email => '', + phone => '', + category => 'Street lighting', + }, + changes => {}, + errors => [ + 'Please enter a subject', + 'Please enter some details', + 'Please enter your email', + ], + }, + { + msg => 'title and details tidied up', + pc => 'SW1A 1AA', + fields => { + title => 'DOG SHIT ON WALLS', + detail => 'on this portakabin - more of a portaloo HEH!!', + photo => '', + name => 'Bob Jones', + may_show_name => '1', + email => '', + phone => '', + category => 'Street lighting', + }, + changes => { + title => 'Dog poo on walls', + detail => + 'On this [portable cabin] - more of a [portable loo] HEH!!', + }, + errors => [ 'Please enter your email', ], + }, + { + msg => 'name too short', + pc => 'SW1A 1AA', + fields => { + title => 'Test title', + detail => 'Test detail', + photo => '', + name => 'DUDE', + may_show_name => '1', + email => '', + phone => '', + category => 'Street lighting', + }, + changes => {}, + errors => [ +'Please enter your full name, councils need this information - if you do not wish your name to be shown on the site, untick the box', + 'Please enter your email', + ], + }, + { + msg => 'name is anonymous', + pc => 'SW1A 1AA', + fields => { + title => 'Test title', + detail => 'Test detail', + photo => '', + name => 'anonymous', + may_show_name => '1', + email => '', + phone => '', + category => 'Street lighting', + }, + changes => {}, + errors => [ +'Please enter your full name, councils need this information - if you do not wish your name to be shown on the site, untick the box', + 'Please enter your email', + ], + }, + { + msg => 'email invalid', + pc => 'SW1A 1AA', + fields => { + title => 'Test title', + detail => 'Test detail', + photo => '', + name => 'Joe Smith', + may_show_name => '1', + email => 'not an email', + phone => '', + category => 'Street lighting', + }, + changes => { email => 'notanemail', }, + errors => [ 'Please enter a valid email', ], + }, + { + msg => 'cleanup title and detail', + pc => 'SW1A 1AA', + fields => { + title => " Test title ", + detail => " first line \n\n second\nline\n\n ", + photo => '', + name => '', + may_show_name => '1', + email => '', + phone => '', + category => 'Street lighting', + }, + changes => { + title => 'Test title', + detail => "First line\n\nSecond line", + }, + errors => [ 'Please enter your name', 'Please enter your email', ], + }, + { + msg => 'clean up name and email', + pc => 'SW1A 1AA', + fields => { + title => '', + detail => '', + photo => '', + name => ' Bob Jones ', + may_show_name => '1', + email => ' BOB @ExAmplE.COM ', + phone => '', + category => 'Street lighting', + }, + changes => { + name => 'Bob Jones', + email => 'bob@example.com', + }, + errors => [ 'Please enter a subject', 'Please enter some details', ], + }, + ) +{ + subtest "check form errors where $test->{msg}" => sub { + $mech->get_ok('/around'); + + # submit initial pc form + $mech->submit_form_ok( { with_fields => { pc => $test->{pc} } }, + "submit location" ); + is_deeply $mech->form_errors, [], "no errors for pc '$test->{pc}'"; + + # click through to the report page + $mech->follow_link_ok( { text => 'skip this step', }, + "follow 'skip this step' link" ); + + # submit the main form + $mech->submit_form_ok( { with_fields => $test->{fields} }, + "submit form" ); + + # check that we got the errors expected + is_deeply $mech->form_errors, $test->{errors}, "check errors"; + + # check that fields have changed as expected + my $new_values = { + %{ $test->{fields} }, # values added to form + %{ $test->{changes} }, # changes we expect + }; + is_deeply $mech->visible_form_values, $new_values, + "values correctly changed"; + }; +} + +subtest "test report creation for a user who does not have an account" => sub { + $mech->log_out_ok; + $mech->clear_emails_ok; + + # check that the user does not exist + my $test_email = 'test-1@example.com'; + ok !FixMyStreet::App->model('DB::User')->find( { email => $test_email } ), + "test user does not exist"; + + # submit initial pc form + $mech->get_ok('/around'); + $mech->submit_form_ok( { with_fields => { pc => 'EH1 1BB', } }, + "submit location" ); + + # click through to the report page + $mech->follow_link_ok( { text => 'skip this step', }, + "follow 'skip this step' link" ); + + $mech->submit_form_ok( + { + with_fields => { + title => 'Test Report', + detail => 'Test report details.', + photo => '', + name => 'Joe Bloggs', + may_show_name => '1', + email => 'test-1@example.com', + phone => '07903 123 456', + category => 'Street lighting', + } + }, + "submit good details" + ); + + # check that we got the errors expected + is_deeply $mech->form_errors, [], "check there were no errors"; + + # check that the user has been created + my $user = + FixMyStreet::App->model('DB::User')->find( { email => $test_email } ); + ok $user, "created new user"; + + # find the report + my $report = $user->problems->first; + ok $report, "Found the report"; + + # check that the report is not available yet. + is $report->state, 'unconfirmed', "report not confirmed"; + is $mech->get( '/report/' . $report->id )->code, 404, "report not found"; + + # Check the report has been assigned appropriately + is $report->council, 2651; + + # receive token + my $email = $mech->get_email; + ok $email, "got an email"; + like $email->body, qr/confirm the problem/i, "confirm the problem"; + + my ($url) = $email->body =~ m{(http://\S+)}; + ok $url, "extracted confirm url '$url'"; + + # confirm token + $mech->get_ok($url); + $report->discard_changes; + is $report->state, 'confirmed', "Report is now confirmed"; + + $mech->get_ok( '/report/' . $report->id ); + + # check that the reporter has an alert + my $alert = FixMyStreet::App->model('DB::Alert')->find( { + user => $report->user, + alert_type => 'new_updates', + parameter => $report->id, + } ); + ok $alert, "created new alert"; + + # user is created and logged in + $mech->logged_in_ok; + + # cleanup + $mech->delete_user($user); +}; + +#### test report creation for a user who has account but is not logged in +# come to site +# fill in report +# receive token +# confirm token +# report is confirmed + +#### test report creation for user with account and logged in +foreach my $test ( + { category => 'Trees', council => 2326 }, + { category => 'Potholes', council => 2226 }, +) { + subtest "test report creation for a user who is logged in" => sub { + + # check that the user does not exist + my $test_email = 'test-2@example.com'; + + $mech->clear_emails_ok; + my $user = $mech->log_in_ok($test_email); + + # setup the user. + ok $user->update( + { + name => 'Test User', + phone => '01234 567 890', + } + ), + "set users details"; + + # submit initial pc form + $mech->get_ok('/around'); + $mech->submit_form_ok( { with_fields => { pc => 'GL50 2PR', } }, + "submit location" ); + + # click through to the report page + $mech->follow_link_ok( { text => 'skip this step', }, + "follow 'skip this step' link" ); + + # check that the fields are correctly prefilled + is_deeply( + $mech->visible_form_values, + { + title => '', + detail => '', + may_show_name => '1', + email => $test_email, + name => 'Test User', + phone => '01234 567 890', + photo => '', + category => '-- Pick a category --', + }, + "user's details prefilled" + ); + + $mech->submit_form_ok( + { + with_fields => { + title => 'Test Report', + detail => 'Test report details.', + photo => '', + name => 'Joe Bloggs', + may_show_name => '1', + phone => '07903 123 456', + category => $test->{category}, + } + }, + "submit good details" + ); + + # find the report + my $report = $user->problems->first; + ok $report, "Found the report"; + + # Check the report has been assigned appropriately + is $report->council, $test->{council}; + + # check that we got redirected to /report/ + is $mech->uri->path, "/report/" . $report->id, "redirected to report page"; + + # check that no emails have been sent + $mech->email_count_is(0); + + # check report is confirmed and available + is $report->state, 'confirmed', "report is now confirmed"; + $mech->get_ok( '/report/' . $report->id ); + + # check that the reporter has an alert + my $alert = FixMyStreet::App->model('DB::Alert')->find( { + user => $report->user, + alert_type => 'new_updates', + parameter => $report->id, + } ); + ok $alert, "created new alert"; + + # user is still logged in + $mech->logged_in_ok; + + # cleanup + $mech->delete_user($user); + }; + +} + +#### test uploading an image + +#### test completing a partial report (eq flickr upload) + +#### possibly manual testing +# create report without using map +# create report by clicking on may with javascript off +# create report with images off + +subtest "check that a lat/lon off coast leads to /around" => sub { + my $off_coast_latitude = 50.78301; + my $off_coast_longitude = -0.646929; + + $mech->get_ok( # + "/report/new" + . "?latitude=$off_coast_latitude" + . "&longitude=$off_coast_longitude" + ); + + is $mech->uri->path, '/around', "redirected to '/around'"; + + is_deeply # + $mech->page_errors, + [ 'That spot does not appear to be covered by a council. If you have' + . ' tried to report an issue past the shoreline, for example, please' + . ' specify the closest point on land.' ], # + "Found location error"; + +}; + +$contact1->delete; +$contact2->delete; +$contact3->delete; + +done_testing(); diff --git a/t/app/controller/report_updates.t b/t/app/controller/report_updates.t new file mode 100644 index 000000000..4dd1db737 --- /dev/null +++ b/t/app/controller/report_updates.t @@ -0,0 +1,885 @@ +use strict; +use warnings; +use Test::More; + +use FixMyStreet::TestMech; +use Web::Scraper; +use Path::Class; +use DateTime; + +my $mech = FixMyStreet::TestMech->new; + +# create a test user and report +$mech->delete_user('commenter@example.com'); +$mech->delete_user('test@example.com'); + +my $user = + FixMyStreet::App->model('DB::User') + ->find_or_create( { email => 'test@example.com', name => 'Test User' } ); +ok $user, "created test user"; + +my $user2 = + FixMyStreet::App->model('DB::User') + ->find_or_create( { email => 'commenter@example.com', name => 'Commenter' } ); +ok $user2, "created comment user"; + +my $dt = DateTime->new( + year => 2011, + month => 04, + day => 16, + hour => 15, + minute => 47, + second => 23 +); + +my $report = FixMyStreet::App->model('DB::Problem')->find_or_create( + { + postcode => 'SW1A 1AA', + council => '2504', + areas => ',105255,11806,11828,2247,2504,', + category => 'Other', + title => 'Test 2', + detail => 'Test 2 Detail', + used_map => 't', + name => 'Test User', + anonymous => 'f', + state => 'confirmed', + confirmed => $dt->ymd . ' ' . $dt->hms, + lang => 'en-gb', + service => '', + cobrand => 'default', + cobrand_data => '', + send_questionnaire => 't', + latitude => '51.5016605453401', + longitude => '-0.142497580865087', + user_id => $user->id, + } +); +my $report_id = $report->id; +ok $report, "created test report - $report_id"; + +my $comment = FixMyStreet::App->model('DB::Comment')->find_or_create( + { + problem_id => $report_id, + user_id => $user2->id, + name => 'Other User', + mark_fixed => 'false', + text => 'This is some update text', + state => 'confirmed', + confirmed => $dt->ymd . ' ' . $dt->hms, + anonymous => 'f', + } +); + +my $comment_id = $comment->id; +ok $comment, "created test update - $comment_id"; + +for my $test ( + { + description => 'named user, anon is false', + name => 'Other User', + anonymous => 'f', + mark_fixed => 'false', + mark_open => 'false', + meta => 'Posted by Other User at 15:47, Saturday 16 April 2011', + }, + { + description => 'blank user, anon is false', + name => '', + anonymous => 'f', + mark_fixed => 'false', + mark_open => 'false', + meta => 'Posted anonymously at 15:47, Saturday 16 April 2011', + }, + { + description => 'named user, anon is true', + name => 'Other User', + anonymous => 't', + mark_fixed => 'false', + mark_open => 'false', + meta => 'Posted anonymously at 15:47, Saturday 16 April 2011', + }, + { + description => 'named user, anon is true, fixed', + name => 'Other User', + anonymous => 't', + mark_fixed => 'true', + mark_open => 'false', + meta => +'Posted anonymously at 15:47, Saturday 16 April 2011, marked as fixed', + }, + { + description => 'named user, anon is true, reopened', + name => 'Other User', + anonymous => 't', + mark_fixed => 'false', + mark_open => 'true', + meta => 'Posted anonymously at 15:47, Saturday 16 April 2011, reopened', + } + ) +{ + subtest "test update displayed for $test->{description}" => sub { + $comment->name( $test->{name} ); + $comment->mark_fixed( $test->{mark_fixed} ); + $comment->mark_open( $test->{mark_open} ); + $comment->anonymous( $test->{anonymous} ); + $comment->update; + + $mech->get_ok("/report/$report_id"); + is $mech->uri->path, "/report/$report_id", "at /report/$report_id"; + $mech->content_contains('This is some update text'); + + my $meta = $mech->extract_update_metas; + is scalar @$meta, 1, 'number of updates'; + is $meta->[0], $test->{meta}; + }; +} + +subtest "unconfirmed updates not displayed" => sub { + $comment->state( 'unconfirmed' ); + $comment->update; + $mech->get_ok("/report/$report_id"); + + my $meta = $mech->extract_update_metas; + is scalar @$meta, 0, 'update not displayed'; +}; + +subtest "several updates shown in correct order" => sub { + for my $fields ( { + problem_id => $report_id, + user_id => $user2->id, + name => 'Other User', + mark_fixed => 'false', + text => 'First update', + state => 'confirmed', + confirmed => '2011-03-10 12:23:15', + anonymous => 'f', + }, + { + problem_id => $report_id, + user_id => $user->id, + name => 'Main User', + mark_fixed => 'false', + text => 'Second update', + state => 'confirmed', + confirmed => '2011-03-10 12:23:16', + anonymous => 'f', + }, + { + problem_id => $report_id, + user_id => $user->id, + name => 'Other User', + anonymous => 'true', + mark_fixed => 'true', + text => 'Third update', + state => 'confirmed', + confirmed => '2011-03-15 08:12:36', + } + ) { + my $comment = FixMyStreet::App->model('DB::Comment')->find_or_create( + $fields + ); + } + + $mech->get_ok("/report/$report_id"); + + my $meta = $mech->extract_update_metas; + is scalar @$meta, 3, 'number of updates'; + is $meta->[0], 'Posted by Other User at 12:23, Thursday 10 March 2011', 'first update'; + is $meta->[1], 'Posted by Main User at 12:23, Thursday 10 March 2011', 'second update'; + is $meta->[2], 'Posted anonymously at 08:12, Tuesday 15 March 2011, marked as fixed', 'third update'; +}; + +for my $test ( + { + desc => 'No email, no message', + fields => { + rznvy => '', + update => '', + name => '', + photo => '', + fixed => undef, + add_alert => 1, + may_show_name => undef, + }, + changes => {}, + field_errors => [ 'Please enter your email', 'Please enter a message' ] + }, + { + desc => 'Invalid email, no message', + fields => { + rznvy => 'test', + update => '', + name => '', + photo => '', + fixed => undef, + add_alert => 1, + may_show_name => undef, + }, + changes => {}, + field_errors => [ 'Please enter a valid email', 'Please enter a message' ] + }, + { + desc => 'email with spaces, no message', + fields => { + rznvy => 'test @ example. com', + update => '', + name => '', + photo => '', + fixed => undef, + add_alert => 1, + may_show_name => undef, + }, + changes => { + rznvy => 'test@example.com', + }, + field_errors => [ 'Please enter a message' ] + }, + { + desc => 'email with uppercase, no message', + fields => { + rznvy => 'test@EXAMPLE.COM', + update => '', + name => '', + photo => '', + fixed => undef, + add_alert => 1, + may_show_name => undef, + }, + changes => { + rznvy => 'test@example.com', + }, + field_errors => [ 'Please enter a message' ] + }, + ) +{ + subtest "submit an update - $test->{desc}" => sub { + $mech->get_ok("/report/$report_id"); + + $mech->submit_form_ok( { with_fields => $test->{fields} }, + 'submit update' ); + + is_deeply $mech->form_errors, $test->{field_errors}, 'field errors'; + + my $values = { + %{ $test->{fields} }, + %{ $test->{changes} }, + }; + + is_deeply $mech->visible_form_values('updateForm'), $values, 'form changes'; + }; +} + +for my $test ( + { + desc => 'submit an update for a non registered user', + initial_values => { + name => '', + rznvy => '', + may_show_name => undef, + add_alert => 1, + photo => '', + update => '', + fixed => undef, + }, + form_values => { + submit_update => 1, + rznvy => 'unregistered@example.com', + update => 'Update from an unregistered user', + add_alert => undef, + }, + changes => {}, + }, + { + desc => 'submit an update for a non registered user and sign up', + initial_values => { + name => '', + rznvy => '', + may_show_name => undef, + add_alert => 1, + photo => '', + update => '', + fixed => undef, + }, + form_values => { + submit_update => 1, + rznvy => 'unregistered@example.com', + update => 'update from an unregistered user', + add_alert => 1, + }, + changes => { + update => 'Update from an unregistered user', + }, + } +) { + subtest $test->{desc} => sub { + $mech->log_out_ok(); + $mech->clear_emails_ok(); + + $mech->get_ok("/report/$report_id"); + + my $values = $mech->visible_form_values('updateForm'); + + is_deeply $values, $test->{initial_values}, 'initial form values'; + + $mech->submit_form_ok( + { + with_fields => $test->{form_values} + }, + 'submit update' + ); + + $mech->content_contains('Nearly Done! Now check your email'); + + my $email = $mech->get_email; + ok $email, "got an email"; + like $email->body, qr/confirm the update you/i, "Correct email text"; + + my ( $url, $url_token ) = $email->body =~ m{(http://\S+/C/)(\S+)}; + ok $url, "extracted confirm url '$url'"; + + my $token = FixMyStreet::App->model('DB::Token')->find( + { + token => $url_token, + scope => 'comment' + } + ); + ok $token, 'Token found in database'; + + my $update_id = $token->data->{id}; + my $add_alerts = $token->data->{add_alert}; + my $update = + FixMyStreet::App->model('DB::Comment')->find( { id => $update_id } ); + + my $details = { + %{ $test->{form_values} }, + %{ $test->{changes} } + }; + + ok $update, 'found update in database'; + is $update->state, 'unconfirmed', 'update unconfirmed'; + is $update->user->email, $details->{rznvy}, 'update email'; + is $update->text, $details->{update}, 'update text'; + is $add_alerts, $details->{add_alert} ? 1 : 0, 'do not sign up for alerts'; + + $mech->get_ok( $url . $url_token ); + $mech->content_contains("/report/$report_id#update_$update_id"); + + my $unreg_user = FixMyStreet::App->model( 'DB::User' )->find( { email => $details->{rznvy} } ); + + ok $unreg_user, 'found user'; + + my $alert = FixMyStreet::App->model( 'DB::Alert' )->find( + { user => $unreg_user, alert_type => 'new_updates', confirmed => 1, } + ); + + ok $details->{add_alert} ? defined( $alert ) : !defined( $alert ), 'sign up for alerts'; + + $update->discard_changes; + + is $update->state, 'confirmed', 'update confirmed'; + $mech->delete_user( $unreg_user ); + }; +} + +for my $test ( + { + desc => 'submit update for register user', + initial_values => { + name => 'Test User', + rznvy => 'test@example.com', + may_show_name => 1, + add_alert => 1, + photo => '', + update => '', + fixed => undef, + }, + fields => { + submit_update => 1, + rznvy => 'test@example.com', + update => 'update from a registered user', + add_alert => undef, + fixed => undef, + }, + changed => { + update => 'Update from a registered user' + }, + initial_banner => '', + endstate_banner => '', + alert => 0, + anonymous => 0, + }, + { + desc => 'submit update for register user anonymously by unchecking', + initial_values => { + name => 'Test User', + rznvy => 'test@example.com', + may_show_name => 1, + add_alert => 1, + photo => '', + update => '', + fixed => undef, + }, + fields => { + submit_update => 1, + rznvy => 'test@example.com', + update => 'update from a registered user', + may_show_name => undef, + add_alert => undef, + fixed => undef, + }, + changed => { + update => 'Update from a registered user' + }, + initial_banner => '', + endstate_banner => '', + alert => 0, + anonymous => 1, + }, + { + desc => 'submit update for register user anonymously by deleting name', + initial_values => { + name => 'Test User', + rznvy => 'test@example.com', + may_show_name => 1, + add_alert => 1, + photo => '', + update => '', + fixed => undef, + }, + fields => { + submit_update => 1, + name => '', + rznvy => 'test@example.com', + update => 'update from a registered user', + may_show_name => 1, + add_alert => undef, + fixed => undef, + }, + changed => { + update => 'Update from a registered user' + }, + initial_banner => '', + endstate_banner => '', + alert => 0, + anonymous => 1, + }, + { + desc => 'submit update for register user and sign up', + initial_values => { + name => 'Test User', + rznvy => 'test@example.com', + may_show_name => 1, + add_alert => 1, + photo => '', + update => '', + fixed => undef, + }, + fields => { + submit_update => 1, + rznvy => 'test@example.com', + update => 'update from a registered user', + add_alert => 1, + fixed => undef, + }, + changed => { + update => 'Update from a registered user' + }, + initial_banner => '', + endstate_banner => '', + alert => 1, + anonymous => 0, + }, + { + desc => 'submit update for register user and mark fixed', + initial_values => { + name => 'Commenter', + rznvy => 'commenter@example.com', + may_show_name => 1, + add_alert => 1, + photo => '', + update => '', + fixed => undef, + }, + fields => { + submit_update => 1, + rznvy => 'commenter@example.com', + update => 'update from a registered user', + add_alert => undef, + fixed => 1, + }, + changed => { + update => 'Update from a registered user' + }, + initial_banner => '', + endstate_banner => ' This problem has been fixed. ', + alert => 1, # we signed up for alerts before, do not unsign us + anonymous => 0, + }, +) { + subtest $test->{desc} => sub { + $mech->log_out_ok(); + + # clear out comments for this problem to make + # checking details easier later + ok( $_->delete, 'deleted comment ' . $_->id ) + for $report->comments; + + $mech->clear_emails_ok(); + + $mech->log_in_ok( $test->{fields}->{rznvy} ); + $mech->get_ok("/report/$report_id"); + + my $values = $mech->visible_form_values( 'updateForm' ); + + is_deeply $values, $test->{initial_values}, 'initial form values'; + + is $mech->extract_problem_banner->{text}, $test->{initial_banner}, 'initial banner'; + + $mech->submit_form_ok( + { + with_fields => $test->{fields}, + }, + 'submit update' + ); + + is $mech->uri->path, "/report/" . $report_id, "redirected to report page"; + + is $mech->extract_problem_banner->{text}, $test->{endstate_banner}, 'submitted banner'; + + $mech->email_count_is(0); + + my $results = { + %{ $test->{fields} }, + %{ $test->{changed} }, + }; + + my $update = $report->comments->first; + ok $update, 'found update'; + is $update->text, $results->{update}, 'update text'; + is $update->user->email, $test->{fields}->{rznvy}, 'update user'; + is $update->state, 'confirmed', 'update confirmed'; + is $update->anonymous, $test->{anonymous}, 'user anonymous'; + + my $alert = + FixMyStreet::App->model('DB::Alert') + ->find( { user => $user, alert_type => 'new_updates', confirmed => 1 } ); + + ok $test->{alert} ? $alert : !$alert, 'not signed up for alerts'; + }; +} + +foreach my $test ( + { + desc => 'logged in reporter submits update and marks problem fixed', + initial_values => { + name => 'Test User', + rznvy => 'test@example.com', + may_show_name => 1, + add_alert => 1, + photo => '', + update => '', + fixed => undef, + }, + fields => { + submit_update => 1, + rznvy => 'test@example.com', + update => 'update from owner', + add_alert => undef, + fixed => 1, + }, + changed => { update => 'Update from owner' }, + initial_banner => '', + alert => 1, # we signed up for alerts before, do not unsign us + anonymous => 0, + answered => 0, + login => 1, + path => '/report/update', + content => +"Thanks, glad to hear it's been fixed! Could we just ask if you have ever reported a problem to a council before?", + }, + { + desc => +'logged in reporter submits update and marks problem fixed and has answered questionnaire', + initial_values => { + name => 'Test User', + rznvy => 'test@example.com', + may_show_name => 1, + add_alert => 1, + photo => '', + update => '', + fixed => undef, + }, + fields => { + submit_update => 1, + rznvy => 'test@example.com', + update => 'update from owner', + add_alert => undef, + fixed => 1, + }, + changed => { update => 'Update from owner' }, + initial_banner => '', + alert => 1, # we signed up for alerts before, do not unsign us + anonymous => 0, + answered => 1, + login => 1, + path => '/report/' . $report->id, + content => $report->title, + }, + ) +{ + subtest $test->{desc} => sub { + + # double check + $mech->log_out_ok(); + + # clear out comments for this problem to make + # checking details easier later + ok( $_->delete, 'deleted comment ' . $_->id ) for $report->comments; + + $report->discard_changes; + $report->state('confirmed'); + $report->update; + + my $questionnaire; + if ( $test->{answered} ) { + $questionnaire = + FixMyStreet::App->model('DB::Questionnaire')->create( + { + problem_id => $report_id, + ever_reported => 'y', + whensent => \'ms_current_timestamp()', + } + ); + + ok $questionnaire, 'added questionnaire'; + } + + $report->discard_changes; + + $mech->clear_emails_ok(); + + $mech->log_in_ok( $test->{fields}->{rznvy} ); + $mech->get_ok("/report/$report_id"); + + my $values = $mech->visible_form_values('updateForm'); + + is_deeply $values, $test->{initial_values}, 'initial form values'; + + is $mech->extract_problem_banner->{text}, $test->{initial_banner}, + 'initial banner'; + + $mech->submit_form_ok( { with_fields => $test->{fields}, }, + 'submit update' ); + + is $mech->uri->path, $test->{path}, "page after submission"; + + $mech->content_contains( $test->{content} ); + + $mech->email_count_is(0); + + my $results = { %{ $test->{fields} }, %{ $test->{changed} }, }; + + my $update = $report->comments->first; + ok $update, 'found update'; + is $update->text, $results->{update}, 'update text'; + is $update->user->email, $test->{fields}->{rznvy}, 'update user'; + is $update->state, 'confirmed', 'update confirmed'; + is $update->anonymous, $test->{anonymous}, 'user anonymous'; + + SKIP: { + skip( 'not answering questionnaire', 5 ) if $questionnaire; + + $mech->submit_form_ok( ); + + my @errors = @{ $mech->page_errors }; + ok scalar @errors, 'displayed error messages'; + is $errors[0], "Please say whether you've ever reported a problem to your council before", 'error message'; + + $mech->submit_form_ok( { with_fields => { reported => 'Yes' } } ); + + $mech->content_contains( 'Thank you — you can' ); + + $questionnaire = FixMyStreet::App->model( 'DB::Questionnaire' )->find( + { problem_id => $report_id } + ); + + ok $questionnaire, 'questionnaire exists'; + ok $questionnaire->ever_reported, 'ever reported is yes'; + }; + + if ($questionnaire) { + $questionnaire->delete; + ok !$questionnaire->in_storage, 'questionnaire deleted'; + } + }; +} + + +for my $test ( + { + desc => 'reporter submits update and marks problem fixed', + fields => { + submit_update => 1, + name => 'Test User', + rznvy => 'test@example.com', + may_show_name => 1, + update => 'update from owner', + add_alert => undef, + fixed => 1, + }, + changed => { update => 'Update from owner' }, + initial_banner => '', + alert => 1, # we signed up for alerts before, do not unsign us + anonymous => 0, + answered => 0, + path => '/report/update', + content => +"Thanks, glad to hear it's been fixed! Could we just ask if you have ever reported a problem to a council before?", + }, + { + desc => +'reporter submits update and marks problem fixed and has answered questionnaire', + fields => { + submit_update => 1, + name => 'Test User', + may_show_name => 1, + rznvy => 'test@example.com', + update => 'update from owner', + add_alert => undef, + fixed => 1, + }, + changed => { update => 'Update from owner' }, + initial_banner => '', + alert => 1, # we signed up for alerts before, do not unsign us + anonymous => 0, + answered => 1, + path => '/report/update', + content => "You have successfully confirmed your update", + }, + ) +{ + subtest $test->{desc} => sub { + + # double check + $mech->log_out_ok(); + + # clear out comments for this problem to make + # checking details easier later + ok( $_->delete, 'deleted comment ' . $_->id ) for $report->comments; + + $report->discard_changes; + $report->state('confirmed'); + $report->update; + + my $questionnaire; + if ( $test->{answered} ) { + $questionnaire = + FixMyStreet::App->model('DB::Questionnaire')->create( + { + problem_id => $report_id, + ever_reported => 'y', + whensent => \'ms_current_timestamp()', + } + ); + + ok $questionnaire, 'added questionnaire'; + } + + $report->discard_changes; + + $mech->clear_emails_ok(); + + $mech->get_ok("/report/$report_id"); + + my $values = $mech->visible_form_values('updateForm'); + + is $mech->extract_problem_banner->{text}, $test->{initial_banner}, + 'initial banner'; + + $mech->submit_form_ok( { with_fields => $test->{fields}, }, + 'submit update' ); + + is $mech->uri->path, $test->{path}, "page after submission"; + + $mech->content_contains( 'Now check your email' ); + + $mech->email_count_is(1); + + my $results = { %{ $test->{fields} }, %{ $test->{changed} }, }; + + my $update = $report->comments->first; + ok $update, 'found update'; + is $update->text, $results->{update}, 'update text'; + is $update->user->email, $test->{fields}->{rznvy}, 'update user'; + is $update->state, 'unconfirmed', 'update confirmed'; + is $update->anonymous, $test->{anonymous}, 'user anonymous'; + + my $email = $mech->get_email; + ok $email, "got an email"; + like $email->body, qr/confirm the update you/i, "Correct email text"; + + my ( $url, $url_token ) = $email->body =~ m{(http://\S+/C/)(\S+)}; + ok $url, "extracted confirm url '$url'"; + + my $token = FixMyStreet::App->model('DB::Token')->find( + { + token => $url_token, + scope => 'comment' + } + ); + ok $token, 'Token found in database'; + + $mech->get_ok( '/C/' . $url_token ); + + $mech->content_contains( $test->{content} ); + + SKIP: { + skip( 'not answering questionnaire', 5 ) if $questionnaire; + + $mech->submit_form_ok( ); + + my @errors = @{ $mech->page_errors }; + ok scalar @errors, 'displayed error messages'; + is $errors[0], "Please say whether you've ever reported a problem to your council before", 'error message'; + + $mech->submit_form_ok( { with_fields => { reported => 'Yes' } } ); + + $mech->content_contains( 'Thank you — you can' ); + + $questionnaire = FixMyStreet::App->model( 'DB::Questionnaire' )->find( + { problem_id => $report_id } + ); + + ok $questionnaire, 'questionnaire exists'; + ok $questionnaire->ever_reported, 'ever reported is yes'; + }; + + if ($questionnaire) { + $questionnaire->delete; + ok !$questionnaire->in_storage, 'questionnaire deleted'; + } + }; +} + +subtest 'check have to be logged in for creator fixed questionnaire' => sub { + $mech->log_out_ok(); + + $mech->get_ok( "/questionnaire/submit?problem=$report_id&reported=Yes" ); + + $mech->content_contains( "I'm afraid we couldn't locate your problem in the database." ) +}; + +subtest 'check cannot answer other user\'s creator fixed questionnaire' => sub { + $mech->log_out_ok(); + $mech->log_in_ok( $user2->email ); + + $mech->get_ok( "/questionnaire/submit?problem=$report_id&reported=Yes" ); + + $mech->content_contains( "I'm afraid we couldn't locate your problem in the database." ) +}; + +ok $comment->delete, 'deleted comment'; +$mech->delete_user('commenter@example.com'); +$mech->delete_user('test@example.com'); +done_testing(); diff --git a/t/app/controller/reports.t b/t/app/controller/reports.t new file mode 100644 index 000000000..6cb12e20f --- /dev/null +++ b/t/app/controller/reports.t @@ -0,0 +1,34 @@ +use strict; +use warnings; +use Test::More; +use Test::WWW::Mechanize::Catalyst 'FixMyStreet::App'; +use mySociety::MaPit; + +ok( my $mech = Test::WWW::Mechanize::Catalyst->new, 'Created mech object' ); + +# check that we can get the page +$mech->get_ok('/reports'); +$mech->title_like(qr{Summary reports}); +$mech->content_contains('Birmingham'); +$mech->follow_link_ok( { text_regex => qr/Birmingham/ } ); + +SKIP: { + skip( "Need 'emptyhomes' in ALLOWED_COBRANDS config", 8 ) + unless FixMyStreet::App->config->{ALLOWED_COBRANDS} =~ m{emptyhomes}; + ok $mech->host("reportemptyhomes.com"), 'change host to reportemptyhomes'; + $mech->get_ok('/reports'); + # EHA lacks one column the others have + $mech->content_lacks('state unknown'); + + skip( "Need 'fiksgatami' in ALLOWED_COBRANDS config", 8 ) + unless FixMyStreet::App->config->{ALLOWED_COBRANDS} =~ m{fiksgatami}; + mySociety::MaPit::configure('http://mapit.nuug.no/'); + ok $mech->host("fiksgatami.no"), 'change host to fiksgatami'; + $mech->get_ok('/reports'); + # There should only be one Oslo + $mech->content_contains('Oslo'); + $mech->content_unlike(qr{Oslo">Oslo.*Oslo}s); +} + +done_testing(); + diff --git a/t/app/controller/sample.jpg b/t/app/controller/sample.jpg Binary files differnew file mode 100644 index 000000000..23198cb83 --- /dev/null +++ b/t/app/controller/sample.jpg diff --git a/t/app/controller/tilma.t b/t/app/controller/tilma.t new file mode 100644 index 000000000..0eb0b251e --- /dev/null +++ b/t/app/controller/tilma.t @@ -0,0 +1,12 @@ +use strict; +use warnings; + +use Test::More; +use FixMyStreet::TestMech; + +my $mech = FixMyStreet::TestMech->new; + +$mech->get_ok('/tilma/tileserver/10k-full/3278-3283,1110-1115/JSON'); +is $mech->res->content_type, 'text/javascript', "got JS response"; + +done_testing();
\ No newline at end of file |