Developer-Dashboard
view release on metacpan or search on metacpan
t/14-coverage-closure-extra.t view on Meta::CPAN
is(
$app->_highlight_section_text( '<plain>', { section => 'TITLE', html_mode => '' } ),
'<plain>',
'web app section highlighter falls back to escaped plain text for non-code non-HTML sections',
);
like(
$app->_highlight_html_text( q{body { color: red; }</style><div>next</div>}, { html_mode => 'style' } ),
qr/tok-attr|tok-value.*tok-tag/s,
'web app HTML highlighter closes style mode and resumes markup highlighting',
);
like(
$app->_highlight_html_text( q{before<style>body { color: red; }</style>after}, { html_mode => '' } ),
qr/tok-tag.*tok-css/s,
'web app HTML highlighter enters style mode when a style tag opens on the current line',
);
no warnings 'redefine';
local *Developer::Dashboard::Web::App::command_in_path = sub {
my ($name) = @_;
return $name eq 'ifconfig' ? '/tmp/fake-ifconfig' : undef;
};
local *Developer::Dashboard::Web::App::capture = sub (&) {
my ($code) = @_;
my $stdout = "wg0: flags\n inet 10.8.0.2\neth0: flags\n inet 192.168.1.9\n";
my $exit = 0;
return ( $stdout, '', $exit );
};
my @ifconfig_pairs = $app->_ip_pairs_from_ifconfig;
is_deeply(
\@ifconfig_pairs,
[
{ iface => 'wg0', ip => '10.8.0.2' },
{ iface => 'eth0', ip => '192.168.1.9' },
],
'web app parses ifconfig fallback output',
);
{
no warnings 'redefine';
local *Developer::Dashboard::Web::App::_ip_interface_pairs = sub {
return (
{ iface => 'wg0', ip => '10.8.0.2' },
{ iface => 'eth0', ip => '192.168.1.9' },
{ iface => 'lo', ip => '127.0.0.1' },
{ iface => 'eth0', ip => '192.168.1.9' },
);
};
is_deeply(
[ $app->_ip_candidates ],
[ '10.8.0.2', '192.168.1.9', '127.0.0.1' ],
'web app orders VPN, preferred, and other IPv4 candidates while removing duplicates',
);
}
my $transient_action_page = Developer::Dashboard::PageDocument->new(
title => 'Transient Action',
state => { value => 'hello' },
actions => [ { id => 'page-state', kind => 'builtin', builtin => 'page.state' } ],
permissions => { allow_untrusted_actions => 1 },
);
my $token = $store->encode_page($transient_action_page);
my ( $blocked_status, $blocked_type, $blocked_body ) = @{ $app->handle(
path => '/action',
method => 'POST',
query => '',
body => 'token=' . uri_escape($token) . '&id=page-state',
remote_addr => '127.0.0.1',
headers => { host => '127.0.0.1' },
) };
is( $blocked_status, 403, 'transient action fallback route is denied by default' );
like( $blocked_type, qr/text\/plain/, 'transient action fallback denial returns plain-text content type' );
like( $blocked_body, qr/Transient token URLs are disabled/, 'transient action fallback denial explains the policy' );
local $ENV{DEVELOPER_DASHBOARD_ALLOW_TRANSIENT_URLS} = 1;
my ( $status, $type, $body ) = @{ $app->handle(
path => '/action',
method => 'POST',
query => '',
body => 'token=' . uri_escape($token) . '&id=page-state',
remote_addr => '127.0.0.1',
headers => { host => '127.0.0.1' },
) };
is( $status, 404, 'transient action fallback route executes and rejects missing serialized actions cleanly' );
like( $type, qr/text\/plain/, 'transient action fallback returns plain-text error content type when the action is absent' );
like( $body, qr/Action not found/, 'transient action fallback reports missing transient action ids cleanly' );
my $body_app = Developer::Dashboard::Web::App->new(
actions => bless( {}, 'Local::BodyActionRunner' ),
auth => $auth,
pages => $store,
prompt => $prompt,
runtime => $runtime,
sessions => $sessions,
);
my $saved_action_page = Developer::Dashboard::PageDocument->new(
id => 'body-action',
title => 'Body Action',
actions => [ { id => 'download', kind => 'builtin', builtin => 'page.state' } ],
);
my $response = $body_app->_action_response(
id => 'download',
page => $saved_action_page,
source => 'saved',
params => {},
);
is( $response->[0], 200, 'web app action response returns success for explicit body payloads' );
is( $response->[1], 'text/plain; charset=utf-8', 'web app action response uses explicit body content type defaults' );
is( $response->[2], 'body-payload', 'web app action response returns raw body payloads' );
{
my $render_page = Developer::Dashboard::PageDocument->new(
id => 'render-cover',
title => 'Render Cover',
layout => { body => '<div>render body</div>' },
actions => [ undef, { builtin => 'missing-id' }, { id => 'download', builtin => 'page.state' } ],
);
$render_page->{meta}{source_kind} = 'saved';
my $html = $body_app->_render_page_html( $render_page, 'render' );
like( $html, qr/render body/, 'web app render helper still renders page bodies when invalid actions are skipped' );
like( $html, qr/view-source-url/, 'web app render helper still renders the shared chrome after skipping invalid action rows' );
}
$indicator_store->set_indicator(
'docker',
label => 'Docker',
alias => '🐳',
status => 'ok',
prompt_visible => 1,
);
is( $app->_prompt_summary, '✅🐳', 'web app top status summary renders indicator status and alias pairs' );
like(
$app->_top_chrome_html(
( run in 1.164 second using v1.01-cache-2.11-cpan-39bf76dae61 )