RSS Git Download  Clone
Raw Blame History
# initialises all tables used by previous_cml_monitoring query (requests,
# patient_case, request_initial_screen, screens, request_result_summaries,
# lab_sections)

use WWW::Mechanize::TreeBuilder; # look_down()
use HTML::TreeBuilder::XPath; # findnodes()
use Test::WWW::Mechanize;
use LWP::Protocol::PSGI;
use Test::More;
use Test::Deep;

use Data::Printer alias => 'ddp';

use RequestForm::Test;
use RequestForm;

my $psgi_app = RequestForm::runner()->psgi_app;
LWP::Protocol::PSGI->register($psgi_app);

my $mech = Test::WWW::Mechanize->new;
WWW::Mechanize::TreeBuilder->meta->apply($mech);

my $args = form_tokens(); # warn $args;
my $addr = 'http://localhost/bcr-abl';

my $config = YAML::Tiny->read( 'config.yml' ) or die $!; # ddp $config;
my $required_fields = $config->[0]->{validation}->{required}; # ddp $required_fields;

my $src = patient_data(); # ddp $src;
my $cml_patient = $src->[2]; # ddp $cml_patient;

my $today = DateTime->today();

my $dbix = get_dbix();
run_schema(); # exit;

# initialise session with form tokens:
$mech->get_ok($addr . '?' . $args);                       # print_output($mech);
$mech->text_contains(
    'request for RQ-PCR BCR-ABL estimation',
    'OK: BCR-ABL request form loaded'
);

$mech->field(nhs_number => $cml_patient->{nhs_number});
$mech->submit_form();                                     # print_output($mech);
{
    $mech->text_contains(
        'Matching patient details found',
        'OK: nhs number submitted, matching details found',
    );
    # check loaded fields:
    my %formatted = (
        nhs_number => $cml_patient->{nhs_number},
        last_name  => uc $cml_patient->{last_name},
        first_name => $cml_patient->{first_name},
        previous   => $cml_patient->{previous},
        gender     => $cml_patient->{gender},
        day        => $cml_patient->{day},
        month      => $cml_patient->{month},
        year       => $cml_patient->{year},
    );

    while ( my ($key, $val) = each %formatted ) {
        is( $mech->field($key), $val, "OK: $key field set" );
    }

    $mech->text_contains(
        'Previous BCR-ABL results ',
        'OK: previous BCR-ABL results retrieved',
    );

    $mech->text_contains(
        'Last result < 90 days ago',
        'OK: last result within minimum time required',
    );

    $mech->text_contains(
        'Reason for request',
        'OK: reason for request required',
    );
}
{ # submit cml form (without reason):
    my $reason = $cml_patient->{reason};
    delete $cml_patient->{reason};

    $mech->submit_form(fields => $cml_patient);           # print_output($mech);

    $mech->text_contains(
        'Form validation failed',
        'OK: form validation failed',
    ); # warn $mech->text;

    $mech->text_contains( # can't localise 'Missing' div tag to reason - use text_contains
        'Reason for request Missing',
        'OK: missing field identified',
    );

    # recreate reason for request:
    $cml_patient->{reason} = $reason;
    $mech->submit_form(fields => $cml_patient);           # print_output($mech);
    $mech->has_tag_like(
        p => qr/Form passed validation/,
        'OK: validation passed',
    );

    # put _skip_pds back in (not retained in form):
    $mech->field( _skip_pds => 1 );
    # submit form to generate pdf (or HTML for non-deployment env):
    $mech->submit_form();                                 # print_output($mech);

    $mech->has_tag_like(
        h3 => 'BCR-ABL Monitoring Request Form',
        'OK: request form title field',
    );

    ok( # barcode class table:
       $mech->look_down(_tag => 'table', class => 'hbc'), # table class="hbc"
       'OK: has barcode table element',
    );

    { # look for unique ref (eg 1428054818SILVERO):
        my $ref = uc( $cml_patient->{last_name}
            . substr($cml_patient->{first_name}, 0, 1) ); # ddp $ref;
        $mech->has_tag_like(
            td => qr/\d+$ref/,
            'OK: unique ref id found',
        );
    }
    # look for each required field (except special format fields):
    for my $field (@$required_fields) { # warn Dumper [$field, $cml_patient->{$field}]; # next;
        # defer testing fields with special formatting (tested below):
        next if grep $field eq $_, # location_id not present at pdf generation stage:
            qw(last_name nhs_number day month year location_id treatment);
        $mech->has_tag( span => $cml_patient->{$field}, "OK: $field field found" );
    }

    { # look for special format fields (dob, last_name, nhs_number) & cml_specific:
        my $nhs_number = join ' ', # amazingly, this works:
            ( $cml_patient->{nhs_number} =~ /(\d{3})(\d{3})(\d{4})/ ); # ddp $nhs_number;
        my $current_treament = sprintf '%s %s commenced %s',
            @{ $cml_patient }{ qw(line_number treatment first_line_date) };
        my $last_name = uc $cml_patient->{last_name};
        my $dob = sprintf '%02d-%02d-%s', @{$cml_patient}{ qw(day month year) };

        my %pre_formatted = (
            diagnosis_date  => $cml_patient->{diagnosis_date},
            nhs_number      => $nhs_number,
            last_name       => $last_name,
            treatment       => $current_treament,
            reason          => $cml_patient->{reason},
            phase           => $cml_patient->{phase},
            dob             => $dob,
        );
        while ( my ($key, $val) = each %pre_formatted ) {
            $mech->has_tag( span => $val, "OK: $key field found" );
        }
    }

    { # compare content of request_form table with cml_patient data:
        my $data = $dbix->select('request_form', '*')->hash; # ddp $data;
        # delete keys not expected in cmp_patient data:
        delete $data->{$_} for qw(id pds_code user_id created imported);
        # get cols from request_form table:
        my $cols = RequestForm::DB->new(dbname => 'test')
            ->get_cols('request_form'); # ddp $cols;

        my %ref; # create new ref data stucture from cml_patient data:
        $ref{$_} = $cml_patient->{$_} for grep $cml_patient->{$_}, @$cols;
        my %dob = map +($_ => $cml_patient->{$_}), qw(year month day);
        $ref{dob} = DateTime->new(%dob)->datetime;
        $ref{last_name} = uc $ref{last_name}; # ddp %ref;
        is_deeply( $data, \%ref, 'OK: request_form data matches patient data' );
    }
    { # compare content of patient_bcr_abl table with cml_patient data:
        my $tbl = $dbix->select('patient_bcr_abl', '*')->hash; # ddp $tbl;
        my $src = clone($cml_patient); # ddp $src;

        for ( qw/diagnosis_date first_line_date/ ) { # warn $src->{$date};
            my $dt = _to_datetime_using_datecalc($src->{$_}); # warn $dt;
            $src->{$_} = $dt->ymd('-');
        } # ddp $src;
        delete $tbl->{timestamp}; # not in $cml_patient
        cmp_deeply( $src, superhashof($tbl), 'OK: db data is superhashof patient');
    }
}
{ # change treatment details to 2nd line and phase to acute:
    my $data = clone($cml_patient);
    $data->{phase} = 'acute phase';
    $data->{line_number} = '2nd line';
    $data->{treatment_date} = '10/06/2012'; # for non-1st-line tx

    $mech->get_ok($addr);                                 # print_output($mech);
    $mech->field(nhs_number => $data->{nhs_number});
    $mech->submit_form();                                 # print_output($mech);

    # check first_line_date & diagnosis_date fields set (picked up from db table):
    is( $mech->field($_), $data->{$_}, "OK: $_ data retrieved" ) for
        qw(first_line_date diagnosis_date);

    # '** check this is correct **' - expect 4 instances of '*' for each date entry
    # is( $mech->text =~ y/*/*/, 8, "OK: 'check this' flags set" ); # y/// same as tr///
    { # same thing using HTML::TreeBuilder::XPath::findnodes():
        my @nodes = $mech->tree->findnodes( q!//div[@class='dfv-err']! ); # ddp @nodes;
        my $phrase = '** check this is correct **';
        # have 1 div with same classname (id=nhsno_result) but empty, so $_->content
        # undef so use empty arrayref, in scalar context will get array count:
        my $count = grep { ($_->content || [''])->[0] eq $phrase } @nodes; # ddp $count;
        is( $count, 2, "OK: 'check this' flags set" );
    }
    $mech->submit_form(fields => $data);                  # print_output($mech);
    $mech->has_tag_like(
        p => qr/Form passed validation/,
        'OK: validation passed',
    );

    # put _skip_pds back in (not retained in form):
    $mech->field( _skip_pds => 1 );
    # submit form to generate pdf (or HTML for non-deployment env):
    $mech->submit_form();                                 # print_output($mech);

    { # just check for fields changed from original 1st line treatment submission:
        my $current_treament = sprintf '%s %s commenced %s',
            @{ $data }{ qw(line_number treatment treatment_date) };

        my %fields = (
            diagnosis_date  => $data->{diagnosis_date},
            treatment       => $current_treament,
            phase           => $data->{phase},
        );
        while ( my ($key, $val) = each %fields ) {
            $mech->has_tag( span => $val, "OK: $key field found" );
        }
    }

    { # compare content of patient_bcr_abl table with cml_patient data:
        my $tbl = $dbix->select('patient_bcr_abl', '*')->hash; # ddp $tbl;
        my $src = clone($data); # ddp $src;

        for ( qw/diagnosis_date first_line_date/ ) { # warn $src->{$_};
            my $dt = _to_datetime_using_datecalc($src->{$_}); # warn $dt;
            $src->{$_} = $dt->ymd('-');
        } # ddp $src;
        delete $tbl->{timestamp}; # not in $cml_patient
        cmp_deeply( $src, superhashof($tbl), 'OK: db data is superhashof patient');
    }
}

done_testing(51);

#===============================================================================
sub run_schema {
    my @schema = _schema();
    do { $dbix->dbh->do($_) || die $dbix->error } foreach @schema; # $dbix->error doesn't work here
    { # initialise patients table with patient #3 from patients.conf:
        my $info = $dbix->query("PRAGMA table_info(patients)")->hashes; # warn Dumper $info;
        my @cols = grep { $_ ne 'id' } map $_->{name}, @$info; # warn Dumper \@cols;

        my %h;
        $h{$_} = $cml_patient->{$_} for @cols; # warn Dumper \%data;
        # dob from components:
        $h{dob} = join '-', @{$cml_patient}{qw(year month day)}; # warn Dumper \%h;
        $dbix->insert('patients', \%h);
    }
    { # requests, request_initial_screen, request_result_summaries:
        my %h = (
            2 => 0.004,
            4 => 0.014,
            6 => 0.018,
            8 => 0.023,
        );

        for my $i ( reverse sort keys %h ) { # warn $i;
            $dbix->dbh->do( qq!
                INSERT INTO requests(patient_case_id, created_at)
                SELECT 1, date('now', "-$i months")! ) || die $dbix->error;

            my $ratio = $h{$i}; # eg 0.004%
            $dbix->dbh->do(
                qq!INSERT INTO request_result_summaries(lab_section_id,
                    results_summary, time)
                SELECT 1, "BCR-ABL : ABL ratio = ${ratio}%",
                    date('now', "-$i months")! ) || die $dbix->error;

            $dbix->dbh->do( q!INSERT INTO request_initial_screen(screen_id)
                VALUES(1)! ) || die $dbix->error; # doesn't need auto-increment
        }
        # my $t1 = $dbix->select('requests','*')->hashes; ddp $t1;
        # my $t2 = $dbix->select('request_initial_screen','*')->hashes; ddp $t2;
        # my $t3 = $dbix->select('request_result_summaries','*')->hashes; ddp $t3;
        # _previous_cml_monitoring() # complex query
    }


sub _schema {
    return (
        # don't need full table schemas, just enough for previous_cml_monitoring query:
        q{
            CREATE TABLE requests (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                patient_case_id INTEGER,
                created_at INTEGER
            )
        },
        q{
            CREATE TABLE patient_case (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                patient_id INTEGER
            )
        },
        q{
            INSERT INTO patient_case(patient_id) VALUES(1)
        },
        # request_initial_screen.request_id AUTOINCREMENT for sync with requests
        q{
            CREATE TABLE request_initial_screen (
                request_id INTEGER PRIMARY KEY AUTOINCREMENT,
                screen_id INTEGER
            )
        },
        q{
            CREATE TABLE screens (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                description TEXT
            )
        },
        q{
            INSERT INTO screens(description) VALUES('Follow-up CML (PB)')
        },
        # request_result_summaries.request_id AUTOINCREMENT for sync with requests
        q{
            CREATE TABLE request_result_summaries (
                request_id INTEGER PRIMARY KEY AUTOINCREMENT,
                lab_section_id INTEGER,
                results_summary TEXT,
                time TEXT
            )
        },
        q{
            CREATE TABLE lab_sections (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                section_name TEXT
            )
        },
        q{
            INSERT INTO lab_sections(section_name) VALUES('Molecular')
        },
        q{
            CREATE TABLE patient_bcr_abl (
                nhs_number INTEGER PRIMARY KEY,
                diagnosis_date TEXT,
                first_line_date TEXT,
                treatment TEXT,
                line_number TEXT,
                phase TEXT,
                timestamp TEXT
            )
        },
    );
}

sub _to_datetime_using_datecalc {
    LIMS::Local::Utils::to_datetime_using_datecalc(@_);
}

sub _previous_cml_monitoring { # check data:
    my $nhs_number = $cml_patient->{nhs_number};
    my $sql = qq!
        select date(r.created_at) as 'registered', rrs.results_summary as 'result'
        from requests r
            join ( patient_case pc join patients p on pc.patient_id = p.id )
                on r.patient_case_id = pc.id
            join ( request_initial_screen ris join screens s
                on ris.screen_id = s.id ) on ris.request_id = r.id
            join ( request_result_summaries rrs join lab_sections ls
                on rrs.lab_section_id = ls.id ) on rrs.request_id = r.id
        where s.description = 'Follow-up CML (PB)'
            and ls.section_name = 'Molecular'
            and p.nhs_number = ?
        order by r.created_at desc!;

        my $data = $dbix->query($sql, $nhs_number)->hashes; ddp $data;
    }
}