aboutsummaryrefslogtreecommitdiffstats
path: root/t/app/controller
diff options
context:
space:
mode:
Diffstat (limited to 't/app/controller')
-rw-r--r--t/app/controller/about.t31
-rw-r--r--t/app/controller/admin.t652
-rw-r--r--t/app/controller/alert.t66
-rw-r--r--t/app/controller/alert_new.t486
-rw-r--r--t/app/controller/around.t106
-rw-r--r--t/app/controller/auth.t227
-rw-r--r--t/app/controller/contact.t275
-rw-r--r--t/app/controller/council.t14
-rw-r--r--t/app/controller/index.t58
-rw-r--r--t/app/controller/json.t109
-rw-r--r--t/app/controller/my.t19
-rw-r--r--t/app/controller/page_not_found.t20
-rw-r--r--t/app/controller/questionnaire.t292
-rw-r--r--t/app/controller/report_display.t265
-rw-r--r--t/app/controller/report_import.t242
-rw-r--r--t/app/controller/report_new.t501
-rw-r--r--t/app/controller/report_updates.t885
-rw-r--r--t/app/controller/reports.t34
-rw-r--r--t/app/controller/sample.jpgbin0 -> 22588 bytes
-rw-r--r--t/app/controller/tilma.t12
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 &lsquo;EH99&nbsp;1SP&rsquo;');
+$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&rsquo;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 &mdash; 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 &mdash; 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
new file mode 100644
index 000000000..23198cb83
--- /dev/null
+++ b/t/app/controller/sample.jpg
Binary files differ
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