use Test::MockTime ':all';
package FixMyStreet::Cobrand::Tester;
use parent 'FixMyStreet::Cobrand::Default';
# Allow access if CSV export for a body, otherwise deny
sub dashboard_permission {
my $self = shift;
my $c = $self->{c};
return 0 unless $c->get_param('export');
return $c->get_param('body') || 0;
}
package main;
use strict;
use warnings;
use FixMyStreet::TestMech;
use Web::Scraper;
set_absolute_time('2014-02-01T12:00:00');
my $mech = FixMyStreet::TestMech->new;
my $other_body = $mech->create_body_ok(1234, 'Some Other Council');
my $body = $mech->create_body_ok(2651, 'City of Edinburgh Council');
my @cats = ('Litter', 'Other', 'Potholes', 'Traffic lights');
for my $contact ( @cats ) {
$mech->create_contact_ok(body_id => $body->id, category => $contact, email => "$contact\@example.org");
}
my $superuser = $mech->create_user_ok('superuser@example.com', name => 'Super User', is_superuser => 1);
my $counciluser = $mech->create_user_ok('counciluser@example.com', name => 'Council User', from_body => $body);
my $normaluser = $mech->create_user_ok('normaluser@example.com', name => 'Normal User');
my $body_id = $body->id;
my $area_id = '60705';
my $alt_area_id = '62883';
my $last_month = DateTime->now->subtract(months => 2);
$mech->create_problems_for_body(2, $body->id, 'Title', { areas => ",$area_id,2651,", category => 'Potholes', cobrand => 'fixmystreet' });
$mech->create_problems_for_body(3, $body->id, 'Title', { areas => ",$area_id,2651,", category => 'Traffic lights', cobrand => 'fixmystreet', dt => $last_month });
$mech->create_problems_for_body(1, $body->id, 'Title', { areas => ",$alt_area_id,2651,", category => 'Litter', cobrand => 'fixmystreet' });
my @scheduled_problems = $mech->create_problems_for_body(7, $body->id, 'Title', { areas => ",$area_id,2651,", category => 'Traffic lights', cobrand => 'fixmystreet' });
my @fixed_problems = $mech->create_problems_for_body(4, $body->id, 'Title', { areas => ",$area_id,2651,", category => 'Potholes', cobrand => 'fixmystreet' });
my @closed_problems = $mech->create_problems_for_body(3, $body->id, 'Title', { areas => ",$area_id,2651,", category => 'Traffic lights', cobrand => 'fixmystreet' });
foreach my $problem (@scheduled_problems) {
$problem->update({ state => 'action scheduled' });
$mech->create_comment_for_problem($problem, $counciluser, 'Title', 'text', 0, 'confirmed', 'action scheduled');
}
foreach my $problem (@fixed_problems) {
$problem->update({ state => 'fixed - council' });
$mech->create_comment_for_problem($problem, $counciluser, 'Title', 'text', 0, 'confirmed', 'fixed');
}
my $first_problem_id;
my $first_update_id;
foreach my $problem (@closed_problems) {
$problem->update({ state => 'closed' });
my ($update) = $mech->create_comment_for_problem($problem, $counciluser, 'Title', 'text', 0, 'confirmed', 'closed', { confirmed => \'current_timestamp' });
$first_problem_id = $problem->id unless $first_problem_id;
$first_update_id = $update->id unless $first_update_id;
}
my $categories = scraper {
process "select[name=category] > option", 'cats[]' => 'TEXT',
process "table[id=overview] > tr", 'rows[]' => scraper {
process 'td', 'cols[]' => 'TEXT'
},
};
FixMyStreet::override_config {
ALLOWED_COBRANDS => [ { fixmystreet => '.' } ],
MAPIT_URL => 'http://mapit.uk/',
}, sub {
subtest 'not logged in, redirected to login' => sub {
$mech->not_logged_in_ok;
$mech->get_ok('/dashboard');
$mech->content_contains( 'sign in' );
};
subtest 'normal user, 404' => sub {
$mech->log_in_ok( $normaluser->email );
$mech->get('/dashboard');
is $mech->status, '404', 'If not council user get 404';
};
subtest 'superuser, body list' => sub {
$mech->log_in_ok( $superuser->email );
$mech->get_ok('/dashboard');
# Contains body name, in list of bodies
$mech->content_contains('Some Other Council');
$mech->content_contains('Edinburgh Council');
$mech->content_lacks('Category:');
$mech->get_ok('/dashboard?body=' . $body->id);
$mech->content_lacks('Some Other Council');
$mech->content_contains('Edinburgh Council');
$mech->content_contains('Trowbridge');
$mech->content_contains('Category:');
};
subtest 'council user, ward list' => sub {
$mech->log_in_ok( $counciluser->email );
$mech->get_ok('/dashboard');
$mech->content_lacks('Some Other Council');
$mech->content_contains('Edinburgh Council');
$mech->content_contains('Trowbridge');
$mech->content_contains('Category:');
};
subtest 'area user can only see their area' => sub {
$counciluser->update({area_id => $area_id});
$mech->get_ok("/dashboard");
$mech->content_contains('
Trowbridge
');
$mech->get_ok("/dashboard?body=" . $other_body->id);
$mech->content_contains('Trowbridge
');
$mech->get_ok("/dashboard?ward=$alt_area_id");
$mech->content_contains('Trowbridge
');
$counciluser->update({area_id => undef});
};
subtest 'The correct categories and totals shown by default' => sub {
$mech->get_ok("/dashboard");
my $expected_cats = [ 'All', @cats ];
my $res = $categories->scrape( $mech->content );
is_deeply( $res->{cats}, $expected_cats, 'correct list of categories' );
# Three missing as more than a month ago
test_table($mech->content, 1, 0, 0, 1, 0, 0, 0, 0, 2, 0, 4, 6, 7, 3, 0, 10, 10, 3, 4, 17);
};
subtest 'test filters' => sub {
$mech->get_ok("/dashboard");
$mech->submit_form_ok({ with_fields => { category => 'Litter' } });
test_table($mech->content, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1);
$mech->submit_form_ok({ with_fields => { category => '', state => 'fixed - council' } });
test_table($mech->content, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0, 4, 4);
$mech->submit_form_ok({ with_fields => { state => 'action scheduled' } });
test_table($mech->content, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 7, 7, 0, 0, 7);
my $start = DateTime->now->subtract(months => 3)->strftime('%Y-%m-%d');
my $end = DateTime->now->subtract(months => 1)->strftime('%Y-%m-%d');
$mech->submit_form_ok({ with_fields => { state => '', start_date => $start, end_date => $end } });
test_table($mech->content, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 3, 3, 0, 0, 3);
};
subtest 'test grouping' => sub {
$mech->get_ok("/dashboard?group_by=category");
test_table($mech->content, 1, 0, 6, 10, 17);
$mech->get_ok("/dashboard?group_by=state");
test_table($mech->content, 3, 7, 4, 3, 17);
$mech->get_ok("/dashboard?start_date=2000-01-01&group_by=month");
test_table($mech->content, 0, 17, 17, 3, 0, 3, 3, 17, 20);
};
subtest 'export as csv' => sub {
$mech->create_problems_for_body(1, $body->id, 'Title', {
detail => "this report\nis split across\nseveral lines",
areas => ",$alt_area_id,2651,",
});
$mech->get_ok('/dashboard?export=1');
open my $data_handle, '<', \$mech->content;
my $csv = Text::CSV->new( { binary => 1 } );
my @rows;
while ( my $row = $csv->getline( $data_handle ) ) {
push @rows, $row;
}
is scalar @rows, 19, '1 (header) + 18 (reports) = 19 lines';
is scalar @{$rows[0]}, 20, '20 columns present';
is_deeply $rows[0],
[
'Report ID',
'Title',
'Detail',
'User Name',
'Category',
'Created',
'Confirmed',
'Acknowledged',
'Fixed',
'Closed',
'Status',
'Latitude',
'Longitude',
'Query',
'Ward',
'Easting',
'Northing',
'Report URL',
'Site Used',
'Reported As',
],
'Column headers look correct';
is $rows[5]->[14], 'Trowbridge', 'Ward column is name not ID';
is $rows[5]->[15], '529025', 'Correct Easting conversion';
is $rows[5]->[16], '179716', 'Correct Northing conversion';
};
subtest 'export updates as csv' => sub {
$mech->get_ok('/dashboard?updates=1&export=1');
open my $data_handle, '<', \$mech->content;
my $csv = Text::CSV->new( { binary => 1 } );
my @rows;
while ( my $row = $csv->getline( $data_handle ) ) {
push @rows, $row;
}
is scalar @rows, 15, '1 (header) + 14 (updates) = 15 lines';
is scalar @{$rows[0]}, 8, '8 columns present';
is_deeply $rows[0],
[
'Report ID', 'Update ID', 'Date', 'Status', 'Problem state',
'Text', 'User Name', 'Reported As',
],
'Column headers look correct';
is $rows[1]->[0], $first_problem_id, 'Correct report ID';
is $rows[1]->[1], $first_update_id, 'Correct update ID';
is $rows[1]->[3], 'confirmed', 'Correct state';
is $rows[1]->[4], 'closed', 'Correct problem state';
is $rows[1]->[5], 'text', 'Correct text';
is $rows[1]->[6], 'Title', 'Correct name';
};
subtest 'export as csv using token' => sub {
$mech->log_out_ok;
$counciluser->set_extra_metadata('access_token', '1234567890abcdefgh');
$counciluser->update();
$mech->get_ok('/dashboard?export=1');
like $mech->res->header('Content-type'), qr'text/html';
$mech->content_lacks('Report ID');
$mech->add_header('Authorization', 'Bearer 1234567890abcdefgh');
$mech->get_ok('/dashboard?export=1');
like $mech->res->header('Content-type'), qr'text/csv';
$mech->content_contains('Report ID');
$mech->delete_header('Authorization');
};
};
FixMyStreet::override_config {
ALLOWED_COBRANDS => 'tester',
MAPIT_URL => 'http://mapit.uk/',
}, sub {
subtest 'no body or export, 404' => sub {
$mech->get('/dashboard');
is $mech->status, '404', 'No parameters, 404';
$mech->get('/dashboard?export=1');
is $mech->status, '404', 'If no body, 404';
$mech->get("/dashboard?body=$body_id");
is $mech->status, '404', 'If no export, 404';
};
subtest 'body and export, okay' => sub {
$mech->get_ok("/dashboard?body=$body_id&export=1");
};
};
sub test_table {
my ($content, @expected) = @_;
my $res = $categories->scrape( $mech->content );
my @actual;
foreach my $row ( @{ $res->{rows} }[1 .. 11] ) {
push @actual, @{$row->{cols}} if $row->{cols};
}
is_deeply \@actual, \@expected;
}
restore_time;
done_testing();