# https://metacpan.org/dist/Dancer2/view/lib/Dancer2/Manual/Testing.pod
use strict;
use warnings;
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,'household'), { 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/(.*)!;
my %entry = (
description => 'Anti-freeze / coolat', # deliberate spelling error, corrected later
filename => $test_file,
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 $req = POST $url . '/create', \%entry, %hx_request_headers;
my $res = process_request($req);
# successful input gets redirect
ok( $res->is_redirect, '[POST /create] redirect' );
# have to retrieve update manually due to redirect:
my $next = get_next_location($res);
like( $next->as_string, qr/Input success/, 'has input success' );
like( $next->as_string, qr/Anti-freeze/, 'have expected content' );
};
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' );
};
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/coolant/, 'has updated content' );
# original text not found:
unlike( $next->as_string, qr/coolat/, 'lacks original content' );
};
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 expected content' );
};
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);