# https://metacpan.org/dist/Dancer2/view/lib/Dancer2/Manual/Testing.pod # run: carmel exec prove -lv t/moongate.t use 5.34.0; # say BEGIN { # set test env otherwise get development config settings - unless explicitly # set at command-line: "DANCER_ENVIRONMENT=development prove -lv t/" $ENV{DANCER_ENVIRONMENT} ||= $ENV{PLACK_ENV} ||= 'test'; } use File::Path 'remove_tree'; # say "$_: $INC{$_}" for sort keys %INC; use File::Spec::Functions; # catfile use HTTP::Request::Common; use Data::Printer; use HTTP::Cookies; use Plack::Test; use Test::More; use App::Test; # get_next_location, process_request & initialise use_ok('DocsLib'); my $test = Plack::Test->create( DocsLib->to_app ); # p $test->app; exit; my $jar = HTTP::Cookies->new(); my $cfg = DocsLib->dancer_app->settings; # p $cfg; exit; my $url = 'http://localhost/moongate'; my $userid = $cfg->{user}->{name}; my $passwd = $cfg->{user}->{plain_text_pwd} || die qq!require 'plain_text_pwd' setting in test_local.yml file!; my %hx_request_headers = ( HX_Target => 'content-div', # ← optional: element id to swap HX_Trigger => 'save-button', # ← optional: id/name of the triggering element HX_Request => 'true', # ← required by htmx HX_Current_URL => '/', # necessary for correct url in record.tt using hx-current-url header ); App::Test::initialise( $jar, $test ); # check we have test env config, or die: die "####### incorrect config loaded ########" unless $cfg->{environment} eq 'test'; { # clear test-files dir 1st: my $docs_path = $cfg->{documents_path}; # say $docs_path; die '####### '.$docs_path.' upload path does not exist' unless -e $docs_path; die "####### incorrect docs-path ########" unless $docs_path =~ m!t/file-tree!; remove_tree( catfile($docs_path,'moongate'), { keep_root => 1, error => \my $err } ); die Dumper $err if @$err; } my $test_file = $cfg->{appdir} . 't/src/Uniden_Bearcat_scanner.jpg'; # appdir has trailing '/' my ($filename) = $test_file =~ m!/src/(.*)!; # use 'our' to allow temporary dynamic block substitution our %entry = ( description => 'Anti-freeze / coolat', # deliberate spelling error, corrected later filename => $filename, comment => 'Napa 5ltr', date => '2025-09-23', ); subtest 'Landing page' => sub { my $res = $test->request( GET '/moongate/' ); ok( $res->is_redirect, '[GET /] redirect' ); }; subtest 'Login' => sub { my @fields = ( username => $userid, password => $passwd, ); my $request = POST '/login', \@fields ; my $response = $test->request( $request ); ok( $response->is_redirect, '[POST /login] redirect' ); # handle cookies for next request: $jar->extract_cookies($response); }; subtest 'Home page' => sub { # create HTTP::Request object and add cookies to it: my $req = GET $url . '/', %hx_request_headers; $jar->add_cookie_header( $req ); # p $req->dump; # resubmit GET '/', should get 'new_document' link: my $res = $test->request( $req ); # p $res; like( $res->as_string, qr{/moongate/new_document}, 'have link for new document' ); }; subtest 'Create document' => sub { my $res; { # need to temporarily substitute $entry{filename} with array including content-type: local $entry{filename} = [ $test_file, $filename, 'image/jpeg' ]; my $req = POST $url . '/create', Content_Type => 'form-data', Content => \%entry, %hx_request_headers; $res = process_request($req); # p $res; # successful input gets redirect ok( $res->is_redirect, '[POST /create] redirect' ); } # p %entry; # have to retrieve update manually due to redirect: my $next = get_next_location($res); # p $next; like( $next->as_string, qr/Input success/, 'has input success' ); like( $next->as_string, qr/$entry{$_}/, "have expected content [$_ => $entry{$_}]" ) for keys %entry; my $txt = App::Test::html2txt($next); like( $txt, qr/Total records 1/, 'expected number of records' ); my $path = catfile($cfg->{documents_path},'moongate', $filename); # say $path; ok( -e $path, 'OK: expected path to uploaded file'); }; subtest 'Edit document' => sub { my $req = POST $url . '/edit/1', # full url to match cookie expectation %hx_request_headers; # p $req; $jar->add_cookie_header( $req ); my $res = $test->request( $req ); # p $res; like( $res->as_string, qr{/update/1}, 'contains update link' ); like( $res->as_string, qr/coolat/, 'has expected content [coolat]' ); }; subtest 'Update document' => sub { $entry{description} = 'Anti-freeze / coolant'; local $entry{filename} = $filename; # needs filename not file my $req = POST $url . '/update/1', \%entry, %hx_request_headers; # p %entry; my $res = process_request($req); # successful input gets redirect ok( $res->is_redirect, '[POST /update] redirect' ); # have to retrieve update manually due to redirect: my $next = get_next_location($res); like( $next->as_string, qr/Update success/, 'has update success' ); like( $next->as_string, qr/$entry{$_}/, "have expected content [$_ => $entry{$_}]" ) for keys %entry; # original text not found: unlike( $next->as_string, qr/coolat/, 'lacks original content [coolat]' ); }; subtest 'Search' => sub { my $req = POST $url . '/search' , [ search => 'freeze' ], %hx_request_headers; # don't need to add cookies here as route isn't protected by login my $res = $test->request( $req ); # p $res; like( $res->as_string, qr/Anti-freeze/, 'search by free-text returned search term' ); }; subtest 'Test error' => sub { my %data = (title => 'title', content => 'content', test_err => 'test error'); my $req = POST $url . '/create', \%data, %hx_request_headers; $jar->add_cookie_header( $req ); my $res = $test->request( $req ); # p $res; like( $res->as_string, qr/test error/, 'has error string' ); }; done_testing (9);