Developer-Dashboard

 view release on metacpan or  search on metacpan

t/08-web-update-coverage.t  view on Meta::CPAN

    my (@pairs) = @_;
    my @encoded;
    while (@pairs) {
        my ( $name, $value ) = splice @pairs, 0, 2;
        push @encoded, uri_escape($name) . '=' . uri_escape( defined $value ? $value : '' );
    }
    return join '&', @encoded;
}

my $home = tempdir(CLEANUP => 1);
local $ENV{HOME} = $home;
local $ENV{DEVELOPER_DASHBOARD_BOOKMARKS};
local $ENV{DEVELOPER_DASHBOARD_CONFIGS};
local $ENV{DEVELOPER_DASHBOARD_CHECKERS};
chdir $home or die "Unable to chdir to $home: $!";
my $paths = Developer::Dashboard::PathRegistry->new( home => $home );
my $files = Developer::Dashboard::FileRegistry->new( paths => $paths );
my $store = Developer::Dashboard::PageStore->new( paths => $paths );
my $runtime = Developer::Dashboard::PageRuntime->new( paths => $paths );
my $auth = Developer::Dashboard::Auth->new( files => $files, paths => $paths );
my $sessions = Developer::Dashboard::SessionStore->new( paths => $paths );

my $page = Developer::Dashboard::PageDocument->new(
    id     => 'sample',
    title  => 'Sample',
    layout => { body => 'body text [% stash.name %]' },
);
$store->save_page($page);

my $app = Developer::Dashboard::Web::App->new(
    auth     => $auth,
    pages    => $store,
    runtime  => $runtime,
    sessions => $sessions,
);
dies_like( sub { Developer::Dashboard::Web::App->new( pages => $store, sessions => $sessions ) }, qr/Missing auth store/, 'web app requires auth store' );
dies_like( sub { Developer::Dashboard::Web::App->new }, qr/Missing auth store/, 'web app requires auth before other dependencies' );
dies_like( sub { Developer::Dashboard::Web::App->new( auth => $auth, sessions => $sessions ) }, qr/Missing page store/, 'web app requires page store' );
dies_like( sub { Developer::Dashboard::Web::App->new( auth => $auth, pages => $store ) }, qr/Missing session store/, 'web app requires session store' );

my ( $root_code, $root_type, $root_body ) = @{ $app->handle( path => '/', query => '', remote_addr => '127.0.0.1', headers => { host => '127.0.0.1' } ) };
is( $root_code, 200, 'root route responds with success' );
like( $root_body, qr/<textarea[^>]*name="instruction"/, 'root route renders free-form instruction editor' );

my $index_page = Developer::Dashboard::PageDocument->new(
    id     => 'index',
    title  => 'Index',
    layout => { body => 'index body' },
);
$store->save_page($index_page);
my ( $root_index_code, undef, undef, $root_index_headers ) = @{ $app->handle( path => '/', query => '', remote_addr => '127.0.0.1', headers => { host => '127.0.0.1' } ) };
is( $root_index_code, 302, 'root route redirects to the saved index page when it exists' );
is( $root_index_headers->{Location}, '/app/index', 'root route redirects to the canonical saved index bookmark path' );
unlink $store->page_file('index') or die "Unable to remove temporary index bookmark: $!";

my ( $apps_code, undef, undef, $apps_headers ) = @{ $app->handle( path => '/apps', query => '', remote_addr => '127.0.0.1', headers => { host => '127.0.0.1' } ) };
is( $apps_code, 302, '/apps redirects to default index bookmark' );
is( $apps_headers->{Location}, '/app/index', '/apps uses index bookmark as default target' );

my $token = uri_escape( $store->encode_page($page) );
my ( $blocked_code, $blocked_type, $blocked_body ) = @{ $app->handle( path => '/', query => "token=$token", remote_addr => '127.0.0.1', headers => { host => '127.0.0.1' } ) };
is( $blocked_code, 403, 'transient edit route is denied by default' );
like( $blocked_type, qr/text\/plain/, 'denied transient edit route returns plain text' );
like( $blocked_body, qr/Transient token URLs are disabled/, 'denied transient edit route explains the policy' );

local $ENV{DEVELOPER_DASHBOARD_ALLOW_TRANSIENT_URLS} = 1;

my ( $edit_code, $edit_type, $edit_body ) = @{ $app->handle( path => '/', query => "token=$token", remote_addr => '127.0.0.1', headers => { host => '127.0.0.1' } ) };
is( $edit_code, 200, 'transient edit route responds with success' );
like( $edit_body, qr/<textarea[^>]*name="instruction"/, 'edit route renders editable source textarea' );
unlike( $edit_body, qr/request_host|request_path|request_remote_addr/, 'edit route does not persist synthetic request metadata into source' );

my ( $render_code, undef, $render_body ) = @{ $app->handle( path => '/', query => "mode=render&token=$token", remote_addr => '127.0.0.1', headers => { host => '127.0.0.1' } ) };
is( $render_code, 200, 'transient render route responds with success' );
like( $render_body, qr/body text/, 'render route includes body text' );

my ( $source_code, $source_type, $source_body ) = @{ $app->handle( path => '/', query => "mode=source&token=$token", remote_addr => '127.0.0.1', headers => { host => '127.0.0.1' } ) };
is( $source_code, 200, 'transient source route responds with success' );
like( $source_type, qr/text\/plain/, 'source route emits instruction text' );
like( $source_body, qr/^TITLE:\s+Sample/m, 'source route returns canonical instruction text' );

my ( $saved_edit_code, undef, $saved_edit_body ) = @{ $app->handle( path => '/app/sample/edit', query => '', remote_addr => '127.0.0.1', headers => { host => '127.0.0.1' } ) };
is( $saved_edit_code, 200, 'saved edit route responds with success' );
like( $saved_edit_body, qr/Right Click Copy &amp; Share or Bookmark This Page/, 'saved edit route includes top chrome links' );
like( $saved_edit_body, qr{<form method="post" action="/app/sample/edit" id="instruction-form">}, 'saved edit route posts back to the named bookmark edit path' );
like( $saved_edit_body, qr{<a href="/app/sample" id="play-url">Play</a>}, 'saved edit route exposes a saved-page play link instead of a transient token url' );
my ( $saved_edit_post_without_instruction_code, undef, $saved_edit_post_without_instruction_body ) = @{ $app->handle(
    path        => '/app/sample/edit',
    method      => 'POST',
    body        => '',
    remote_addr => '127.0.0.1',
    headers     => { host => '127.0.0.1' },
) };
is( $saved_edit_post_without_instruction_code, 200, 'saved edit POST without instruction falls back to the saved editor view' );
like( $saved_edit_post_without_instruction_body, qr{<form method="post" action="/app/sample/edit" id="instruction-form">}, 'saved edit POST fallback keeps the named bookmark edit form action' );

my $updated_instruction = join "\n",
    'TITLE: Sample',
    ':--------------------------------------------------------------------------------:',
    'BOOKMARK: sample',
    ':--------------------------------------------------------------------------------:',
    'HTML: updated saved bookmark body',
    '';
my ( $saved_update_code, undef, $saved_update_body ) = @{ $app->handle(
    path        => '/app/sample/edit',
    method      => 'POST',
    body        => 'instruction=' . uri_escape($updated_instruction),
    remote_addr => '127.0.0.1',
    headers     => { host => '127.0.0.1' },
) };
is( $saved_update_code, 200, 'saved edit post route responds with success while transient urls remain disabled' );
like( $saved_update_body, qr/updated saved bookmark body/, 'saved edit post route returns the updated bookmark editor content' );
my ( $saved_updated_source_code, undef, $saved_updated_source_body ) = @{ $app->handle( path => '/app/sample/source', query => '', remote_addr => '127.0.0.1', headers => { host => '127.0.0.1' } ) };
is( $saved_updated_source_code, 200, 'saved source route still responds after a saved edit post' );
like( $saved_updated_source_body, qr/^HTML:\s+updated saved bookmark body$/m, 'saved edit post route persists the updated bookmark source text' );

my ( $saved_source_code, undef, $saved_source_body ) = @{ $app->handle( path => '/app/sample/source', query => '', remote_addr => '127.0.0.1', headers => { host => '127.0.0.1' } ) };
is( $saved_source_code, 200, 'saved source route responds with success' );
like( $saved_source_body, qr/^BOOKMARK:\s+sample/m, 'saved source route returns canonical page instruction source' );
unlike( $saved_source_body, qr/request_host|request_path|request_remote_addr/, 'saved source route does not inject request metadata into source' );

my ( $saved_render_code, undef, $saved_render_body ) = @{ $app->handle( path => '/app/sample', query => '', remote_addr => '127.0.0.1', headers => { host => '127.0.0.1' } ) };
is( $saved_render_code, 200, 'saved render route responds with success' );
like( $saved_render_body, qr/updated saved bookmark body/, 'saved page route renders the latest saved bookmark body content' );



( run in 1.931 second using v1.01-cache-2.11-cpan-39bf76dae61 )