diff options
Diffstat (limited to 't/app/controller/dashboard.t')
| -rw-r--r-- | t/app/controller/dashboard.t | 1036 | 
1 files changed, 548 insertions, 488 deletions
| diff --git a/t/app/controller/dashboard.t b/t/app/controller/dashboard.t index 47d10ff5c..4e62028b5 100644 --- a/t/app/controller/dashboard.t +++ b/t/app/controller/dashboard.t @@ -1,6 +1,7 @@  use strict;  use warnings;  use Test::More; +use Test::MockTime ':all';  use FixMyStreet::TestMech;  use Web::Scraper; @@ -12,6 +13,8 @@ my $test_pass = 'password';  my $test_council = 2651;  my $test_ward = 20723; +$mech->create_body_ok($test_council, 'City of Edinburgh Council'); +  $mech->delete_user( $test_user );  my $user = FixMyStreet::App->model('DB::User')->create( {      email => $test_user, @@ -22,549 +25,606 @@ my $p_user = FixMyStreet::App->model('DB::User')->find_or_create( {      email => 'p_user@example.com'  } ); -$mech->not_logged_in_ok; -$mech->get_ok('/dashboard'); - -$mech->content_contains( 'sign in' ); +# Dashboard tests assume we are not too early in year, to allow reporting +# within same year, as a convenience. +set_absolute_time('2014-03-01T12:00:00'); +FixMyStreet::override_config { +    ALLOWED_COBRANDS => [ { fixmystreet => '.' } ], +    MAPIT_URL => 'http://mapit.mysociety.org/', +}, sub { -$mech->submit_form( -    with_fields => { email => $test_user, password_sign_in => $test_pass } -); +    $mech->not_logged_in_ok; +    $mech->get_ok('/dashboard'); -is $mech->status, '404', 'If not council user get 404'; +    $mech->content_contains( 'sign in' ); -$user->from_council( $test_council ); -$user->update; - -$mech->log_out_ok; -$mech->get_ok('/dashboard'); -$mech->submit_form_ok( { -    with_fields => { email => $test_user, password_sign_in => $test_pass } -} ); +    $mech->submit_form( +        with_fields => { email => $test_user, password_sign_in => $test_pass } +    ); -$mech->content_contains( 'City of Edinburgh' ); +    is $mech->status, '404', 'If not council user get 404'; -FixMyStreet::App->model('DB::Contact')->search( { area_id => $test_council } ) -  ->delete; +    $user->from_body( $test_council ); +    $user->update; -delete_problems(); +    $mech->log_out_ok; +    $mech->get_ok('/dashboard'); +    $mech->submit_form_ok( { +        with_fields => { email => $test_user, password_sign_in => $test_pass } +    } ); -my @cats = qw( Grafitti Litter Potholes Other ); -for my $contact ( @cats ) { -    FixMyStreet::App->model('DB::Contact')->create( -        { -            area_id    => $test_council, -            category   => $contact, -            email      => "$contact\@example.org", -            confirmed  => 1, -            whenedited => DateTime->now, -            deleted    => 0, -            editor     => 'test', -            note       => 'test', -        } -    ); -} +    $mech->content_contains( 'City of Edinburgh' ); -$mech->get_ok('/dashboard'); - -my $categories = scraper { -    process "select[name=category] > option", 'cats[]' => 'TEXT', -    process "select[name=ward] > option", 'wards[]' => 'TEXT', -    process "table[id=overview] > tr", 'rows[]' => scraper { -        process 'td', 'cols[]' => 'TEXT' -    }, -    process "tr[id=total] > td", 'totals[]' => 'TEXT', -    process "tr[id=fixed_council] > td", 'council[]' => 'TEXT', -    process "tr[id=fixed_user] > td", 'user[]' => 'TEXT', -    process "tr[id=total_fixed] > td", 'total_fixed[]' => 'TEXT', -    process "tr[id=in_progress] > td", 'in_progress[]' => 'TEXT', -    process "tr[id=planned] > td", 'planned[]' => 'TEXT', -    process "tr[id=investigating] > td", 'investigating[]' => 'TEXT', -    process "tr[id=marked] > td", 'marked[]' => 'TEXT', -    process "tr[id=avg_marked] > td", 'avg_marked[]' => 'TEXT', -    process "tr[id=avg_fixed] > td", 'avg_fixed[]' => 'TEXT', -    process "tr[id=not_marked] > td", 'not_marked[]' => 'TEXT', -    process "tr[id=closed] > td", 'closed[]' => 'TEXT', -    process "table[id=reports] > tr > td", 'report_lists[]' => scraper { -        process 'ul > li', 'reports[]' => 'TEXT' -    }, -}; +    FixMyStreet::App->model('DB::Contact')->search( { body_id => $test_council } ) +      ->delete; -my $expected_cats = [ 'All', '-- Pick a category --', @cats ]; -my $res = $categories->scrape( $mech->content ); -is_deeply( $res->{cats}, $expected_cats, 'correct list of categories' ); +    delete_problems(); -foreach my $row ( @{ $res->{rows} }[1 .. 11] ) { -    foreach my $col ( @{ $row->{cols} } ) { -        is $col, 0; +    my @cats = qw( Grafitti Litter Potholes Other ); +    for my $contact ( @cats ) { +        FixMyStreet::App->model('DB::Contact')->create( +            { +                body_id    => $test_council, +                category   => $contact, +                email      => "$contact\@example.org", +                confirmed  => 1, +                whenedited => DateTime->now, +                deleted    => 0, +                editor     => 'test', +                note       => 'test', +            } +        );      } -} -for my $reports ( @{ $res->{report_lists} } ) { -    is_deeply $reports, {}, 'No reports'; -} +    $mech->get_ok('/dashboard'); -foreach my $test ( -    { -        desc => 'confirmed today with no state', -        dt   => DateTime->now, -        counts => [1,1,1,1], -        report_counts => [1, 0, 0], -    }, -    { -        desc => 'confirmed last 7 days with no state', -        dt   => DateTime->now->subtract( days => 6, hours => 23 ), -        counts => [1,2,2,2], -        report_counts => [2, 0, 0], -    }, -    { -        desc => 'confirmed last 8 days with no state', -        dt   => DateTime->now->subtract( days => 8 ), -        counts => [1,2,3,3], -        report_counts => [2, 1, 0], -    }, -    { -        desc => 'confirmed last 4 weeks with no state', -        dt   => DateTime->now->subtract( weeks => 2 ), -        counts => [1,2,4,4], -        report_counts => [2, 1, 1], -    }, -    { -        desc => 'confirmed this year with no state', -        dt   => DateTime->now->subtract( weeks => 7 ), -        counts => [1,2,4,5], -        report_counts => [2, 1, 1], -    }, -) { -    subtest $test->{desc} => sub { -        make_problem( { state => 'confirmed', conf_dt => $test->{dt} } ); - -        $mech->get_ok('/dashboard'); -        $res = $categories->scrape( $mech->content ); - -        check_row( $res, 'totals', $test->{counts} ); -        check_row( $res, 'not_marked', $test->{counts} ); - -        check_report_counts( $res, $test->{report_counts} ); +    my $categories = scraper { +        process "select[name=category] > option", 'cats[]' => 'TEXT', +        process "select[name=ward] > option", 'wards[]' => 'TEXT', +        process "table[id=overview] > tr", 'rows[]' => scraper { +            process 'td', 'cols[]' => 'TEXT' +        }, +        process "tr[id=total] > td", 'totals[]' => 'TEXT', +        process "tr[id=fixed_council] > td", 'council[]' => 'TEXT', +        process "tr[id=fixed_user] > td", 'user[]' => 'TEXT', +        process "tr[id=total_fixed] > td", 'total_fixed[]' => 'TEXT', +        process "tr[id=in_progress] > td", 'in_progress[]' => 'TEXT', +        process "tr[id=action_scheduled] > td", 'action_scheduled[]' => 'TEXT', +        process "tr[id=investigating] > td", 'investigating[]' => 'TEXT', +        process "tr[id=marked] > td", 'marked[]' => 'TEXT', +        process "tr[id=avg_marked] > td", 'avg_marked[]' => 'TEXT', +        process "tr[id=avg_fixed] > td", 'avg_fixed[]' => 'TEXT', +        process "tr[id=not_marked] > td", 'not_marked[]' => 'TEXT', +        process "tr[id=closed] > td", 'closed[]' => 'TEXT', +        process "table[id=reports] > tr > td", 'report_lists[]' => scraper { +            process 'ul > li', 'reports[]' => 'TEXT' +        },      }; -} -delete_problems(); - -my $is_monday = DateTime->now->day_of_week == 1 ? 1 : 0; - -foreach my $test ( -    { -        desc => 'user fixed today', -        confirm_dt   => DateTime->now->subtract( days => 1 ), -        mark_dt      => DateTime->now, -        state => 'fixed - user', -        counts => { -            totals => $is_monday ? [0,1,1,1] : [1,1,1,1], -            user => [1,1,1,1], -            council => [0,0,0,0], -            avg_fixed => [0,0,0,0], -            total_fixed => [1,1,1,1], -        } -    }, -    { -        desc => 'council fixed today', -        confirm_dt   => DateTime->now->subtract( days => 1 ), -        mark_dt      => DateTime->now, -        state => 'fixed - council', -        counts => { -            totals => $is_monday ? [0,2,2,2] : [2,2,2,2], -            user => [1,1,1,1], -            council => [1,1,1,1], -            avg_fixed => [1,1,1,1], -            total_fixed => [2,2,2,2], -        } -    }, -    { -        desc => 'marked investigating today', -        confirm_dt   => DateTime->now->subtract( days => 1 ), -        mark_dt      => DateTime->now, -        state => 'investigating', -        counts => { -            totals => $is_monday ? [0,3,3,3] : [3,3,3,3], -            user => [1,1,1,1], -            council => [1,1,1,1], -            total_fixed => [2,2,2,2], -            avg_marked => [1,1,1,1], -            investigating => [1,1,1,1], -            marked => [1,1,1,1] -        } -    }, -    { -        desc => 'marked in progress today', -        confirm_dt   => DateTime->now->subtract( days => 1 ), -        mark_dt      => DateTime->now, -        state => 'in progress', -        counts => { -            totals => $is_monday ? [0,4,4,4] : [4,4,4,4], -            user => [1,1,1,1], -            council => [1,1,1,1], -            total_fixed => [2,2,2,2], -            avg_marked => [1,1,1,1], -            investigating => [1,1,1,1], -            in_progress => [1,1,1,1], -            marked => [2,2,2,2] -        } -    }, -    { -        desc => 'marked as planned today', -        confirm_dt   => DateTime->now->subtract( days => 1 ), -        mark_dt      => DateTime->now, -        state => 'planned', -        counts => { -            totals => $is_monday ? [ 0,5,5,5] : [5,5,5,5], -            user => [1,1,1,1], -            council => [1,1,1,1], -            total_fixed => [2,2,2,2], -            avg_marked => [1,1,1,1], -            investigating => [1,1,1,1], -            in_progress => [1,1,1,1], -            planned => [1,1,1,1], -            marked => [3,3,3,3] -        } -    }, -    { -        desc => 'marked as planned today, confirmed a week ago', -        confirm_dt   => DateTime->now->subtract( days => 8 ), -        mark_dt      => DateTime->now, -        state => 'planned', -        counts => { -            totals => $is_monday ? [0,5,6,6] : [5,5,6,6], -            user => [1,1,1,1], -            council => [1,1,1,1], -            total_fixed => [2,2,2,2], -            avg_marked => [3,3,3,3], -            investigating => [1,1,1,1], -            in_progress => [1,1,1,1], -            planned => [2,2,2,2], -            marked => [4,4,4,4] -        } -    }, -    { -        desc => 'marked as council fixed today, confirmed a week ago', -        confirm_dt   => DateTime->now->subtract( days => 8 ), -        mark_dt      => DateTime->now, -        state => 'fixed - council', -        counts => { -            totals => $is_monday ? [0,5,7,7] : [5,5,7,7], -            user => [1,1,1,1], -            council => [2,2,2,2], -            total_fixed => [3,3,3,3], -            avg_fixed => [5,5,5,5], -            avg_marked => [3,3,3,3], -            investigating => [1,1,1,1], -            in_progress => [1,1,1,1], -            planned => [2,2,2,2], -            marked => [4,4,4,4] -        } -    }, -    { -        desc => 'marked as council fixed a week ago, confirmed 3 weeks ago', -        confirm_dt   => DateTime->now->subtract( days => 21), -        mark_dt      => DateTime->now->subtract( days => 8 ), -        state => 'fixed - council', -        counts => { -            totals => $is_monday ? [0,5,8,8] : [5,5,8,8], -            user => [1,1,1,1], -            council => [2,2,3,3], -            total_fixed => [3,3,4,4], -            avg_fixed => [5,5,7,7], -            avg_marked => [3,3,3,3], -            investigating => [1,1,1,1], -            in_progress => [1,1,1,1], -            planned => [2,2,2,2], -            marked => [4,4,4,4] -        } -    }, -    { -        desc => 'marked as user fixed 6 weeks ago, confirmed 7 weeks ago', -        confirm_dt   => DateTime->now->subtract( weeks => 6 ), -        mark_dt      => DateTime->now->subtract( weeks => 7 ), -        state => 'fixed - user', -        counts => { -            totals => $is_monday ? [0,5,8,9] : [5,5,8,9], -            user => [1,1,1,2], -            council => [2,2,3,3], -            total_fixed => [3,3,4,5], -            avg_fixed => [5,5,7,7], -            avg_marked => [3,3,3,3], -            investigating => [1,1,1,1], -            in_progress => [1,1,1,1], -            planned => [2,2,2,2], -            marked => [4,4,4,4] -        } -    }, -    { -        desc => 'marked as closed', -        confirm_dt   => DateTime->now->subtract( days => 1 ), -        mark_dt      => DateTime->now, -        state => 'closed', -        counts => { -            totals => $is_monday ? [0,6,9,10] : [6,6,9,10], -            user => [1,1,1,2], -            council => [2,2,3,3], -            total_fixed => [3,3,4,5], -            avg_fixed => [5,5,7,7], -            avg_marked => [2,2,2,2], -            investigating => [1,1,1,1], -            in_progress => [1,1,1,1], -            planned => [2,2,2,2], -            closed => [1,1,1,1], -            marked => [5,5,5,5] -        } -    }, -) { -    subtest $test->{desc} => sub { -        make_problem( -            { -                state   => $test->{state}, -                conf_dt => $test->{confirm_dt}, -                mark_dt => $test->{mark_dt}, -            } -        ); - -        $mech->get_ok('/dashboard'); -        $res = $categories->scrape( $mech->content ); +    my $expected_cats = [ 'All', '-- Pick a category --', @cats ]; +    my $res = $categories->scrape( $mech->content ); +    is_deeply( $res->{cats}, $expected_cats, 'correct list of categories' ); -        foreach my $row ( keys %{ $test->{counts} } ) { -            check_row( $res, $row, $test->{counts}->{$row} ); +    foreach my $row ( @{ $res->{rows} }[1 .. 11] ) { +        foreach my $col ( @{ $row->{cols} } ) { +            is $col, 0;          } -    }; -} +    } -delete_problems(); +    for my $reports ( @{ $res->{report_lists} } ) { +        is_deeply $reports, {}, 'No reports'; +    } -for my $test ( -    { -        desc => 'Selecting no category does nothing', -        p1 => { -                state   => 'confirmed', -                conf_dt => DateTime->now(), -                category => 'Potholes', +    my $now = DateTime->now(time_zone => 'local'); +    foreach my $test ( +        { +            desc => 'confirmed today with no state', +            dt   => $now, +            counts => [1,1,1,1], +            report_counts => [1, 0, 0],          }, -        p2 => { -                state   => 'confirmed', -                conf_dt => DateTime->now(), -                category => 'Litter', +        { +            desc => 'confirmed last 7 days with no state', +            dt   => $now->clone->subtract( days => 6, hours => 23 ), +            counts => [1,2,2,2], +            report_counts => [2, 0, 0],          }, -        category => '', -        counts => { -            totals => [2,2,2,2], +        { +            desc => 'confirmed last 8 days with no state', +            dt   => $now->clone->subtract( days => 8 ), +            counts => [1,2,3,3], +            report_counts => [2, 1, 0],          }, -        counts_after => { -            totals => [2,2,2,2], +        { +            desc => 'confirmed last 2 weeks with no state', +            dt   => $now->clone->subtract( weeks => 2 ), +            counts => [1,2,4,4], +            report_counts => [2, 1, 1],          }, -        report_counts => [2,0,0], -        report_counts_after => [2,0,0], -    }, -    { -        desc => 'Limit display by category', -        category => 'Potholes', -        counts => { -            totals => [2,2,2,2], +        { +            desc => 'confirmed this year with no state', +            dt   => $now->clone->subtract( weeks => 7 ), +            counts => [1,2,4,5], +            report_counts => [2, 1, 1],          }, -        counts_after => { -            totals => [1,1,1,1], +    ) { +        subtest $test->{desc} => sub { +            make_problem( { state => 'confirmed', conf_dt => $test->{dt} } ); + +            $mech->get_ok('/dashboard'); +            $res = $categories->scrape( $mech->content ); + +            check_row( $res, 'totals', $test->{counts} ); +            check_row( $res, 'not_marked', $test->{counts} ); + +            check_report_counts( $res, $test->{report_counts} ); +        }; +    } + +    delete_problems(); + +    my $is_monday = DateTime->now->day_of_week == 1 ? 1 : 0; + +    foreach my $test ( +        { +            desc => 'user fixed today', +            confirm_dt   => DateTime->now->subtract( days => 1 ), +            mark_dt      => DateTime->now, +            state => 'fixed - user', +            counts => { +                totals => $is_monday ? [0,1,1,1] : [1,1,1,1], +                user => [1,1,1,1], +                council => [0,0,0,0], +                avg_fixed => [0,0,0,0], +                total_fixed => [1,1,1,1], +            }          }, -        report_counts => [2,0,0], -        report_counts_after => [1,0,0], -    }, -    { -        desc => 'Limit display for category with no entries', -        category => 'Grafitti', -        counts => { -            totals => [2,2,2,2], +        { +            desc => 'council fixed today', +            confirm_dt   => DateTime->now->subtract( days => 1 ), +            mark_dt      => DateTime->now, +            state => 'fixed - council', +            counts => { +                totals => $is_monday ? [0,2,2,2] : [2,2,2,2], +                user => [1,1,1,1], +                council => [1,1,1,1], +                avg_fixed => [1,1,1,1], +                total_fixed => [2,2,2,2], +            }          }, -        counts_after => { -            totals => [0,0,0,0], +        { +            desc => 'marked investigating today', +            confirm_dt   => DateTime->now->subtract( days => 1 ), +            mark_dt      => DateTime->now, +            state => 'investigating', +            counts => { +                totals => $is_monday ? [0,3,3,3] : [3,3,3,3], +                user => [1,1,1,1], +                council => [1,1,1,1], +                total_fixed => [2,2,2,2], +                avg_marked => [1,1,1,1], +                investigating => [1,1,1,1], +                marked => [1,1,1,1] +            }          }, -        report_counts => [2,0,0], -        report_counts_after => [0,0,0], -    }, -    { -        desc => 'Limit display by category for council fixed', -        p1 => { -                state   => 'fixed - council', -                conf_dt => DateTime->now()->subtract( weeks => 1 ), -                mark_dt => DateTime->now()->subtract( weeks => 1 ), -                category => 'Potholes', +        { +            desc => 'marked in progress today', +            confirm_dt   => DateTime->now->subtract( days => 1 ), +            mark_dt      => DateTime->now, +            state => 'in progress', +            counts => { +                totals => $is_monday ? [0,4,4,4] : [4,4,4,4], +                user => [1,1,1,1], +                council => [1,1,1,1], +                total_fixed => [2,2,2,2], +                avg_marked => [1,1,1,1], +                investigating => [1,1,1,1], +                in_progress => [1,1,1,1], +                marked => [2,2,2,2] +            }          }, -        p2 => { -                state   => 'fixed - council', -                conf_dt => DateTime->now()->subtract( weeks => 1 ), -                mark_dt => DateTime->now()->subtract( weeks => 1 ), -                category => 'Litter', +        { +            desc => 'marked as action scheduled today', +            confirm_dt   => DateTime->now->subtract( days => 1 ), +            mark_dt      => DateTime->now, +            state => 'action scheduled', +            counts => { +                totals => $is_monday ? [ 0,5,5,5] : [5,5,5,5], +                user => [1,1,1,1], +                council => [1,1,1,1], +                total_fixed => [2,2,2,2], +                avg_marked => [1,1,1,1], +                investigating => [1,1,1,1], +                in_progress => [1,1,1,1], +                action_scheduled => [1,1,1,1], +                marked => [3,3,3,3] +            } +        }, +        { +            desc => 'marked as action scheduled today, confirmed a week ago', +            confirm_dt   => DateTime->now->subtract( days => 8 ), +            mark_dt      => DateTime->now, +            state => 'action scheduled', +            counts => { +                totals => $is_monday ? [0,5,6,6] : [5,5,6,6], +                user => [1,1,1,1], +                council => [1,1,1,1], +                total_fixed => [2,2,2,2], +                avg_marked => [3,3,3,3], +                investigating => [1,1,1,1], +                in_progress => [1,1,1,1], +                action_scheduled => [2,2,2,2], +                marked => [4,4,4,4] +            } +        }, +        { +            desc => 'marked as council fixed today, confirmed a week ago', +            confirm_dt   => DateTime->now->subtract( days => 8 ), +            mark_dt      => DateTime->now, +            state => 'fixed - council', +            counts => { +                totals => $is_monday ? [0,5,7,7] : [5,5,7,7], +                user => [1,1,1,1], +                council => [2,2,2,2], +                total_fixed => [3,3,3,3], +                avg_fixed => [5,5,5,5], +                avg_marked => [3,3,3,3], +                investigating => [1,1,1,1], +                in_progress => [1,1,1,1], +                action_scheduled => [2,2,2,2], +                marked => [4,4,4,4] +            }          }, -        category => 'Potholes', -        counts => { -            council => [0,0,2,2], -            totals => [2,2,4,4], +        { +            desc => 'marked as council fixed a week ago, confirmed 3 weeks ago', +            confirm_dt   => DateTime->now->subtract( days => 21), +            mark_dt      => DateTime->now->subtract( days => 8 ), +            state => 'fixed - council', +            counts => { +                totals => $is_monday ? [0,5,8,8] : [5,5,8,8], +                user => [1,1,1,1], +                council => [2,2,3,3], +                total_fixed => [3,3,4,4], +                avg_fixed => [5,5,7,7], +                avg_marked => [3,3,3,3], +                investigating => [1,1,1,1], +                in_progress => [1,1,1,1], +                action_scheduled => [2,2,2,2], +                marked => [4,4,4,4] +            }          }, -        counts_after => { -            council => [0,0,1,1], -            totals => [1,1,2,2], +        { +            desc => 'marked as user fixed 6 weeks ago, confirmed 7 weeks ago', +            confirm_dt   => DateTime->now->subtract( weeks => 6 ), +            mark_dt      => DateTime->now->subtract( weeks => 7 ), +            state => 'fixed - user', +            counts => { +                totals => $is_monday ? [0,5,8,9] : [5,5,8,9], +                user => [1,1,1,2], +                council => [2,2,3,3], +                total_fixed => [3,3,4,5], +                avg_fixed => [5,5,7,7], +                avg_marked => [3,3,3,3], +                investigating => [1,1,1,1], +                in_progress => [1,1,1,1], +                action_scheduled => [2,2,2,2], +                marked => [4,4,4,4] +            }          }, -        report_counts => [2,2,0], -        report_counts_after => [1,1,0], -    }, -    { -        desc => 'Limit display by category for user fixed', -        p1 => { -                state   => 'fixed - user', -                conf_dt => DateTime->now()->subtract( weeks => 1 ), -                mark_dt => DateTime->now()->subtract( weeks => 1 ), -                category => 'Potholes', +        { +            desc => 'marked as closed', +            confirm_dt   => DateTime->now->subtract( days => 1 ), +            mark_dt      => DateTime->now, +            state => 'closed', +            counts => { +                totals => $is_monday ? [0,6,9,10] : [6,6,9,10], +                user => [1,1,1,2], +                council => [2,2,3,3], +                total_fixed => [3,3,4,5], +                avg_fixed => [5,5,7,7], +                avg_marked => [2,2,2,2], +                investigating => [1,1,1,1], +                in_progress => [1,1,1,1], +                action_scheduled => [2,2,2,2], +                closed => [1,1,1,1], +                marked => [5,5,5,5] +            }          }, -        p2 => { -                state   => 'fixed - user', -                conf_dt => DateTime->now()->subtract( weeks => 1 ), -                mark_dt => DateTime->now()->subtract( weeks => 1 ), -                category => 'Litter', +        { +            desc => 'marked as planned', +            confirm_dt   => DateTime->now->subtract( days => 1 ), +            mark_dt      => DateTime->now, +            state => 'planned', +            counts => { +                totals => $is_monday ? [0,7,10,11] : [7,7,10,11], +                user => [1,1,1,2], +                council => [2,2,3,3], +                total_fixed => [3,3,4,5], +                avg_fixed => [5,5,7,7], +                avg_marked => [2,2,2,2], +                investigating => [1,1,1,1], +                in_progress => [1,1,1,1], +                action_scheduled => [3,3,3,3], +                closed => [1,1,1,1], +                marked => [6,6,6,6] +            }          }, -        category => 'Potholes', -        counts => { -            user => [0,0,2,2], -            council => [0,0,2,2], -            totals => [2,2,6,6], +    ) { +        subtest $test->{desc} => sub { +            make_problem( +                { +                    state   => $test->{state}, +                    conf_dt => $test->{confirm_dt}, +                    mark_dt => $test->{mark_dt}, +                } +            ); + +            $mech->get_ok('/dashboard'); +            $res = $categories->scrape( $mech->content ); + +            foreach my $row ( keys %{ $test->{counts} } ) { +                check_row( $res, $row, $test->{counts}->{$row} ); +            } +        }; +    } + +    delete_problems(); + +    for my $test ( +        { +            desc => 'Selecting no category does nothing', +            p1 => { +                    state   => 'confirmed', +                    conf_dt => DateTime->now(), +                    category => 'Potholes', +            }, +            p2 => { +                    state   => 'confirmed', +                    conf_dt => DateTime->now(), +                    category => 'Litter', +            }, +            category => '', +            counts => { +                totals => [2,2,2,2], +            }, +            counts_after => { +                totals => [2,2,2,2], +            }, +            report_counts => [2,0,0], +            report_counts_after => [2,0,0],          }, -        counts_after => { -            user => [0,0,1,1], -            council => [0,0,1,1], -            totals => [1,1,3,3], +        { +            desc => 'Limit display by category', +            category => 'Potholes', +            counts => { +                totals => [2,2,2,2], +            }, +            counts_after => { +                totals => [1,1,1,1], +            }, +            report_counts => [2,0,0], +            report_counts_after => [1,0,0],          }, -        report_counts => [2,4,0], -        report_counts_after => [1,2,0], -    }, -    { -        desc => 'Limit display by ward', -        p1 => { -                state   => 'confirmed', -                conf_dt => DateTime->now()->subtract( weeks => 1 ), -                category => 'Potholes', -                # in real life it has commas around it and the search -                # uses them -                areas => ',20720,', +        { +            desc => 'Limit display for category with no entries', +            category => 'Grafitti', +            counts => { +                totals => [2,2,2,2], +            }, +            counts_after => { +                totals => [0,0,0,0], +            }, +            report_counts => [2,0,0], +            report_counts_after => [0,0,0],          }, -        p2 => { -                state   => 'fixed - council', -                conf_dt => DateTime->now()->subtract( weeks => 1 ), -                mark_dt => DateTime->now()->subtract( weeks => 1 ), -                category => 'Litter', -                areas => ',20720,', +        { +            desc => 'Limit display by category for council fixed', +            p1 => { +                    state   => 'fixed - council', +                    conf_dt => DateTime->now()->subtract( weeks => 1 ), +                    mark_dt => DateTime->now()->subtract( weeks => 1 ), +                    category => 'Potholes', +            }, +            p2 => { +                    state   => 'fixed - council', +                    conf_dt => DateTime->now()->subtract( weeks => 1 ), +                    mark_dt => DateTime->now()->subtract( weeks => 1 ), +                    category => 'Litter', +            }, +            category => 'Potholes', +            counts => { +                council => [0,0,2,2], +                totals => [2,2,4,4], +            }, +            counts_after => { +                council => [0,0,1,1], +                totals => [1,1,2,2], +            }, +            report_counts => [2,2,0], +            report_counts_after => [1,1,0],          }, -        ward => 20720, -        counts => { -            user => [0,0,2,2], -            council => [0,0,3,3], -            totals => [2,2,8,8], +        { +            desc => 'Limit display by category for user fixed', +            p1 => { +                    state   => 'fixed - user', +                    conf_dt => DateTime->now()->subtract( weeks => 1 ), +                    mark_dt => DateTime->now()->subtract( weeks => 1 ), +                    category => 'Potholes', +            }, +            p2 => { +                    state   => 'fixed - user', +                    conf_dt => DateTime->now()->subtract( weeks => 1 ), +                    mark_dt => DateTime->now()->subtract( weeks => 1 ), +                    category => 'Litter', +            }, +            category => 'Potholes', +            counts => { +                user => [0,0,2,2], +                council => [0,0,2,2], +                totals => [2,2,6,6], +            }, +            counts_after => { +                user => [0,0,1,1], +                council => [0,0,1,1], +                totals => [1,1,3,3], +            }, +            report_counts => [2,4,0], +            report_counts_after => [1,2,0],          }, -        counts_after => { -            user => [0,0,0,0], -            council => [0,0,1,1], -            totals => [0,0,2,2], +        { +            desc => 'Limit display by ward', +            p1 => { +                    state   => 'confirmed', +                    conf_dt => DateTime->now()->subtract( weeks => 1 ), +                    category => 'Potholes', +                    # in real life it has commas around it and the search +                    # uses them +                    areas => ',20720,', +            }, +            p2 => { +                    state   => 'fixed - council', +                    conf_dt => DateTime->now()->subtract( weeks => 1 ), +                    mark_dt => DateTime->now()->subtract( weeks => 1 ), +                    category => 'Litter', +                    areas => ',20720,', +            }, +            ward => 20720, +            counts => { +                user => [0,0,2,2], +                council => [0,0,3,3], +                totals => [2,2,8,8], +            }, +            counts_after => { +                user => [0,0,0,0], +                council => [0,0,1,1], +                totals => [0,0,2,2], +            }, +            report_counts => [2,6,0], +            report_counts_after => [0,2,0],          }, -        report_counts => [2,6,0], -        report_counts_after => [0,2,0], -    }, -) { -    subtest $test->{desc} => sub { -        make_problem( $test->{p1} ) if $test->{p1}; -        make_problem( $test->{p2} ) if $test->{p2}; +    ) { +        subtest $test->{desc} => sub { +            make_problem( $test->{p1} ) if $test->{p1}; +            make_problem( $test->{p2} ) if $test->{p2}; -        $mech->get_ok('/dashboard'); +            $mech->get_ok('/dashboard'); -        $res = $categories->scrape( $mech->content ); +            $res = $categories->scrape( $mech->content ); -        foreach my $row ( keys %{ $test->{counts} } ) { -            check_row( $res, $row, $test->{counts}->{$row} ); -        } +            foreach my $row ( keys %{ $test->{counts} } ) { +                check_row( $res, $row, $test->{counts}->{$row} ); +            } -        check_report_counts( $res, $test->{report_counts} ); +            check_report_counts( $res, $test->{report_counts} ); -        $mech->submit_form_ok( { -            with_fields => { -                category => $test->{category}, -                ward     => $test->{ward}, -            } -        } ); +            $mech->submit_form_ok( { +                with_fields => { +                    category => $test->{category}, +                    ward     => $test->{ward}, +                } +            } ); -        $res = $categories->scrape( $mech->content ); +            $res = $categories->scrape( $mech->content ); -        foreach my $row ( keys %{ $test->{counts_after} } ) { -            check_row( $res, $row, $test->{counts_after}->{$row} ); -        } -        check_report_counts( $res, $test->{report_counts_after} ); -    }; -} +            foreach my $row ( keys %{ $test->{counts_after} } ) { +                check_row( $res, $row, $test->{counts_after}->{$row} ); +            } +            check_report_counts( $res, $test->{report_counts_after} ); +        }; +    } -delete_problems(); +    delete_problems(); -for my $test ( -    { -        desc => 'Selecting no state does nothing', -        p1 => { -                state   => 'fixed - user', -                conf_dt => DateTime->now(), -                category => 'Potholes', +    for my $test ( +        { +            desc => 'Selecting no state does nothing', +            p1 => { +                    state   => 'fixed - user', +                    conf_dt => DateTime->now(), +                    category => 'Potholes', +            }, +            p2 => { +                    state   => 'confirmed', +                    conf_dt => DateTime->now(), +                    category => 'Litter', +            }, +            state => '', +            report_counts => [2,0,0], +            report_counts_after => [2,0,0],          }, -        p2 => { -                state   => 'confirmed', -                conf_dt => DateTime->now(), -                category => 'Litter', +        { +            desc => 'limit by state works', +            state => 'fixed', +            report_counts => [2,0,0], +            report_counts_after => [1,0,0],          }, -        state => '', -        report_counts => [2,0,0], -        report_counts_after => [2,0,0], -    }, -    { -        desc => 'limit by state works', -        state => 'fixed', -        report_counts => [2,0,0], -        report_counts_after => [1,0,0], -    }, -    { -        desc => 'All fixed states count as fixed', -        p1 => { -                state   => 'fixed - council', -                conf_dt => DateTime->now(), -                category => 'Potholes', +        { +            desc => 'planned counted as action scheduled', +            p1 => { +                    state   => 'planned', +                    conf_dt => DateTime->now(), +                    category => 'Potholes', +            }, +            state => 'action scheduled', +            report_counts => [3,0,0], +            report_counts_after => [1,0,0],          }, -        p2 => { -                state   => 'fixed', -                conf_dt => DateTime->now(), -                category => 'Potholes', +        { +            desc => 'All fixed states count as fixed', +            p1 => { +                    state   => 'fixed - council', +                    conf_dt => DateTime->now(), +                    category => 'Potholes', +            }, +            p2 => { +                    state   => 'fixed', +                    conf_dt => DateTime->now(), +                    category => 'Potholes', +            }, +            state => 'fixed', +            report_counts => [5,0,0], +            report_counts_after => [3,0,0],          }, -        state => 'fixed', -        report_counts => [4,0,0], -        report_counts_after => [3,0,0], -    }, -) { -    subtest $test->{desc} => sub { -        make_problem( $test->{p1} ) if $test->{p1}; -        make_problem( $test->{p2} ) if $test->{p2}; +    ) { +        subtest $test->{desc} => sub { +            make_problem( $test->{p1} ) if $test->{p1}; +            make_problem( $test->{p2} ) if $test->{p2}; -        $mech->get_ok('/dashboard'); +            $mech->get_ok('/dashboard'); -        $res = $categories->scrape( $mech->content ); +            $res = $categories->scrape( $mech->content ); -        check_report_counts( $res, $test->{report_counts} ); +            check_report_counts( $res, $test->{report_counts} ); -        $mech->submit_form_ok( { -            with_fields => { -                state => $test->{state}, -            } -        } ); +            $mech->submit_form_ok( { +                with_fields => { +                    state => $test->{state}, +                } +            } ); -        $res = $categories->scrape( $mech->content ); +            $res = $categories->scrape( $mech->content ); -        check_report_counts( $res, $test->{report_counts_after} ); +            check_report_counts( $res, $test->{report_counts_after} ); +        }; +    } + +    subtest 'export as csv' => sub { +        make_problem( { +            detail => "this report\nis split across\nseveral lines", +            state => "confirmed", +            conf_dt => DateTime->now(), +        } ); +        $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, 7, '1 (header) + 6 (reports) = 7 lines';      }; -} +}; +restore_time;  sub make_problem {      my $args = shift; @@ -573,12 +633,12 @@ sub make_problem {          title => 'a problem',          name => 'a user',          anonymous => 1, -        detail => 'some detail', +        detail => $args->{detail} || 'some detail',          state => $args->{state},          confirmed => $args->{conf_dt},          whensent => $args->{conf_dt},          lastupdate => $args->{mark_dt} || $args->{conf_dt}, -        council => $test_council, +        bodies_str => $test_council,          postcode => 'EH99 1SP',          latitude => '51',          longitude => '1', @@ -632,10 +692,10 @@ sub check_report_counts {  sub delete_problems {      FixMyStreet::App->model('DB::Comment') -      ->search( { 'problem.council' => $test_council }, { join => 'problem' } ) +      ->search( { 'problem.bodies_str' => $test_council }, { join => 'problem' } )        ->delete;      FixMyStreet::App->model('DB::Problem') -      ->search( { council => $test_council } )->delete(); +      ->search( { bodies_str => $test_council } )->delete();  }  done_testing; | 
