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 => '' } ),
        '&lt;plain&gt;',
        '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          => '&#x1F433;',
        status         => 'ok',
        prompt_visible => 1,
    );
    is( $app->_prompt_summary, '&#x2705;&#x1F433;', '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 )