Developer-Dashboard

 view release on metacpan or  search on metacpan

t/20-skill-web-routes.t  view on Meta::CPAN

}

{
    no warnings 'redefine';
    my $loaded_route_id = '';
    local *Developer::Dashboard::Web::App::_resolve_skill_route_spec = sub {
        return {
            skill_name     => 'route-skill',
            route_segments => [],
            skill_layers   => ['layer'],
        };
    };
    local *Developer::Dashboard::Web::App::_skill_dispatcher = sub { bless {}, 'Local::SkillDispatcherProbe' };
    local *Local::SkillDispatcherProbe::_load_skill_page = sub {
        my ( $self, %args ) = @_;
        $loaded_route_id = $args{route_id};
        return Developer::Dashboard::PageDocument->new(
            id    => 'route-skill',
            title => 'Skill Route Index',
            meta  => { source_kind => 'skill' },
        );
    };
    my $empty_route_page = $app->_load_skill_named_page('route-skill');
    is( $loaded_route_id, 'index', 'empty smart route specs load the skill index bookmark id' );
    isa_ok( $empty_route_page, 'Developer::Dashboard::PageDocument', 'empty smart route specs still return a page document' );
    is( $empty_route_page->{meta}{render_route}, '/app/route-skill', 'empty smart route specs keep the canonical smart-routed render alias' );
}

{
    no warnings 'redefine';
    my $loaded_route_id = '';
    local *Developer::Dashboard::Web::App::_resolve_skill_route_spec = sub {
        return {
            skill_name   => 'route-skill',
            skill_layers => ['layer'],
        };
    };
    local *Developer::Dashboard::Web::App::_skill_dispatcher = sub { bless {}, 'Local::SkillDispatcherProbeMissingSegments' };
    local *Local::SkillDispatcherProbeMissingSegments::_load_skill_page = sub {
        my ( $self, %args ) = @_;
        $loaded_route_id = $args{route_id};
        return Developer::Dashboard::PageDocument->new(
            id    => 'route-skill',
            title => 'Skill Route Index',
            meta  => { source_kind => 'skill' },
        );
    };
    my $missing_segments_page = $app->_load_skill_named_page('route-skill');
    is( $loaded_route_id, 'index', 'missing smart route segments default to the skill index bookmark id' );
    isa_ok( $missing_segments_page, 'Developer::Dashboard::PageDocument', 'missing smart route segments still return a page document' );
    is( $missing_segments_page->{meta}{render_route}, '/app/route-skill', 'missing smart route segments keep the canonical smart-routed render alias' );
}

my $ajax_page = $app->handle(
    path        => '/app/route-skill/ajax-demo',
    method      => 'GET',
    headers     => { host => '127.0.0.1' },
    remote_addr => '127.0.0.1',
);
is( $ajax_page->[0], 200, 'skill ajax demo page route returns success' );
like( $ajax_page->[2], qr{set_chain_value\(endpoints,'bar','/v1/route-skill/bar'\)}, 'skill page binds saved ajax helper to the canonical custom skill route' );

my $skill_alias_ajax = $app->handle(
    path        => '/v1/route-skill/bar',
    method      => 'GET',
    headers     => { host => '127.0.0.1' },
    remote_addr => '127.0.0.1',
);
is( $skill_alias_ajax->[0], 200, 'custom skill ajax alias route returns success' );
is( $skill_alias_ajax->[1], 'application/json; charset=utf-8', 'custom skill ajax alias route applies its default json content type' );
is( _drain_stream_body( $skill_alias_ajax->[2] ), qq|{"route":"bar"}\n|, 'custom skill ajax alias route streams the skill handler output' );

my $raw_mime_ajax = $app->handle(
    path        => '/v1/route-skill/raw',
    method      => 'GET',
    headers     => { host => '127.0.0.1' },
    remote_addr => '127.0.0.1',
);
is( $raw_mime_ajax->[0], 200, 'custom skill ajax route with a raw mime type returns success' );
is( $raw_mime_ajax->[1], 'application/vnd.route+json', 'custom skill ajax route keeps an arbitrary configured mime type' );
is( _drain_stream_body( $raw_mime_ajax->[2] ), qq|{"route":"raw"}\n|, 'custom skill ajax route with a raw mime type streams the skill handler output' );

my $skill_ajax = $app->handle(
    path        => '/ajax/route-skill/bar',
    method      => 'GET',
    headers     => { host => '127.0.0.1' },
    remote_addr => '127.0.0.1',
);
is( $skill_ajax->[0], 200, 'legacy smart skill ajax route still returns success' );
is( _drain_stream_body( $skill_ajax->[2] ), qq|{"route":"bar"}\n|, 'legacy smart skill ajax route still streams the skill handler output' );

my $custom_js = $app->handle(
    path        => '/assets/route-skill.js',
    method      => 'GET',
    headers     => { host => '127.0.0.1' },
    remote_addr => '127.0.0.1',
);
is( $custom_js->[0], 200, 'custom skill js route returns success' );
is( $custom_js->[2], qq{console.log("route-skill js");\n}, 'custom skill js route serves the skill asset' );

my $skill_js = $app->handle(
    path        => '/js/route-skill/skill.js',
    method      => 'GET',
    headers     => { host => '127.0.0.1' },
    remote_addr => '127.0.0.1',
);
is( $skill_js->[0], 200, 'skill-local js route returns success' );
is( $skill_js->[2], qq{console.log("route-skill js");\n}, 'skill-local js route serves the skill asset' );

my $skill_css = $app->handle(
    path        => '/css/route-skill/skill.css',
    method      => 'GET',
    headers     => { host => '127.0.0.1' },
    remote_addr => '127.0.0.1',
);
is( $skill_css->[0], 200, 'skill-local css route returns success' );
is( $skill_css->[2], qq{body { color: #123456; }\n}, 'skill-local css route serves the skill asset' );

my $custom_css = $app->handle(
    path        => '/assets/route-skill.css',
    method      => 'GET',

t/20-skill-web-routes.t  view on Meta::CPAN

is( $skill_other->[0], 200, 'skill-local others route returns success' );
is( $skill_other->[2], "route-skill info\n", 'skill-local others route serves the skill asset' );

my $custom_other = $app->handle(
    path        => '/downloads/route-skill.txt',
    method      => 'GET',
    headers     => { host => '127.0.0.1' },
    remote_addr => '127.0.0.1',
);
is( $custom_other->[0], 200, 'custom skill others route returns success' );
is( $custom_other->[1], 'text/plain; charset=utf-8', 'custom skill others route applies an explicit configured mime type' );
is( $custom_other->[2], "route-skill info\n", 'custom skill others route serves the skill asset' );

my $nested_index = $app->handle(
    path        => '/app/route-skill/def',
    method      => 'GET',
    headers     => { host => '127.0.0.1' },
    remote_addr => '127.0.0.1',
);
is( $nested_index->[0], 200, 'nested skill index route returns success' );
like( $nested_index->[2], qr/Nested Skill Index/, 'nested skill index route renders the nested skill bookmark' );
like( $nested_index->[2], qr/Nested Skill Nav/, 'nested skill index route renders nav fragments contributed by the nested skill' );
like( $nested_index->[2], qr{href="/app/route-skill/def/edit" id="view-source-url"}, 'nested skill index render exposes the smart-routed edit link' );

my $nested_index_edit = $app->handle(
    path        => '/app/route-skill/def/edit',
    method      => 'GET',
    headers     => { host => '127.0.0.1' },
    remote_addr => '127.0.0.1',
);
is( $nested_index_edit->[0], 200, 'nested skill index edit route returns success' );
like( $nested_index_edit->[2], qr{<form method="post" action="/app/route-skill/def/edit" id="instruction-form">}, 'nested skill index edit route posts back to the nested smart-routed edit alias' );
like( $nested_index_edit->[2], qr/Nested Skill Index/, 'nested skill index edit route loads the nested skill index bookmark source' );

my $nested_page = $app->handle(
    path        => '/app/route-skill/def/foo',
    method      => 'GET',
    headers     => { host => '127.0.0.1' },
    remote_addr => '127.0.0.1',
);
is( $nested_page->[0], 200, 'nested skill page route returns success' );
like( $nested_page->[2], qr/Nested Skill Foo/, 'nested skill page route renders the nested skill bookmark' );
like( $nested_page->[2], qr/Nested Skill Nav/, 'nested skill page route renders nav fragments contributed by the nested skill' );

my $nested_custom_page = $app->handle(
    path        => '/apps/route-skill/child/foo',
    method      => 'GET',
    headers     => { host => '127.0.0.1' },
    remote_addr => '127.0.0.1',
);
is( $nested_custom_page->[0], 200, 'nested custom skill app route returns success' );
like( $nested_custom_page->[2], qr/Nested Skill Foo/, 'nested custom skill app route renders the nested skill bookmark' );

my $nested_ajax_page = $app->handle(
    path        => '/app/route-skill/def/ajax-demo',
    method      => 'GET',
    headers     => { host => '127.0.0.1' },
    remote_addr => '127.0.0.1',
);
is( $nested_ajax_page->[0], 200, 'nested skill ajax demo page route returns success' );
like( $nested_ajax_page->[2], qr{set_chain_value\(endpoints,'nested','/v1/route-skill/nested'\)}, 'nested skill page binds saved ajax helper to the nested canonical custom route' );

my $nested_alias_ajax = $app->handle(
    path        => '/v1/route-skill/nested',
    method      => 'GET',
    headers     => { host => '127.0.0.1' },
    remote_addr => '127.0.0.1',
);
is( $nested_alias_ajax->[0], 200, 'nested custom ajax alias route returns success' );
is( $nested_alias_ajax->[1], 'text/html; charset=utf-8', 'nested custom ajax alias route applies its default html content type' );
is( _drain_stream_body( $nested_alias_ajax->[2] ), "<p>nested skill ajax route</p>\n", 'nested custom ajax alias route streams the nested skill handler output' );

my $nested_ajax = $app->handle(
    path        => '/ajax/route-skill/def/nested',
    method      => 'GET',
    headers     => { host => '127.0.0.1' },
    remote_addr => '127.0.0.1',
);
is( $nested_ajax->[0], 200, 'legacy nested skill-local ajax route still returns success' );
is( _drain_stream_body( $nested_ajax->[2] ), "<p>nested skill ajax route</p>\n", 'legacy nested skill-local ajax route still streams the nested skill handler output' );

my $nested_custom_js = $app->handle(
    path        => '/assets/route-skill-nested.js',
    method      => 'GET',
    headers     => { host => '127.0.0.1' },
    remote_addr => '127.0.0.1',
);
is( $nested_custom_js->[0], 200, 'nested custom skill js route returns success' );
is( $nested_custom_js->[2], qq{console.log("nested js");\n}, 'nested custom skill js route serves the nested skill asset' );

my $nested_js = $app->handle(
    path        => '/js/route-skill/def/ijk/lmn.js',
    method      => 'GET',
    headers     => { host => '127.0.0.1' },
    remote_addr => '127.0.0.1',
);
is( $nested_js->[0], 200, 'nested skill-local js route returns success' );
is( $nested_js->[2], qq{console.log("nested js");\n}, 'nested skill-local js route serves the nested skill asset' );

my $nested_css = $app->handle(
    path        => '/css/route-skill/def/ijk/lmn.css',
    method      => 'GET',
    headers     => { host => '127.0.0.1' },
    remote_addr => '127.0.0.1',
);
is( $nested_css->[0], 200, 'nested skill-local css route returns success' );
is( $nested_css->[2], qq{body { background: #abcdef; }\n}, 'nested skill-local css route serves the nested skill asset' );

my $nested_custom_css = $app->handle(
    path        => '/assets/route-skill-nested.css',
    method      => 'GET',
    headers     => { host => '127.0.0.1' },
    remote_addr => '127.0.0.1',
);
is( $nested_custom_css->[0], 200, 'nested custom skill css route returns success' );
is( $nested_custom_css->[2], qq{body { background: #abcdef; }\n}, 'nested custom skill css route serves the nested skill asset' );

my $nested_other = $app->handle(
    path        => '/others/route-skill/def/ijk/lmn.txt',
    method      => 'GET',
    headers     => { host => '127.0.0.1' },

t/20-skill-web-routes.t  view on Meta::CPAN

}

done_testing();

END {
    chdir $original_cwd if defined $original_cwd && length $original_cwd;
}

sub _create_skill_repo {
    my ( $name, %args ) = @_;
    my $repo = File::Spec->catdir( $test_repos, $name );
    make_path($repo);
    my $cwd = getcwd();
    chdir $repo or die "Unable to chdir to $repo: $!";
    _run_or_die(qw(git init --quiet));
    _run_or_die(qw(git config user.email test@example.com));
    _run_or_die(qw(git config user.name Test));
    make_path('cli');
    make_path('config');
    make_path('dashboards');
    make_path( File::Spec->catdir( 'dashboards', 'ajax' ) );
    make_path( File::Spec->catdir( 'dashboards', 'public', 'js' ) );
    make_path( File::Spec->catdir( 'dashboards', 'public', 'css' ) );
    make_path( File::Spec->catdir( 'dashboards', 'public', 'others' ) );
    _write_file( File::Spec->catfile( 'cli', 'noop' ), "#!/usr/bin/env perl\nprint qq{noop\\n};\n", 0755 );
    _write_file( File::Spec->catfile( 'config', 'config.json' ), qq|{"skill_name":"$name"}\n|, 0644 );
    _write_file(
        File::Spec->catfile( 'dashboards', 'index' ),
        <<'BOOKMARK',
TITLE: Skill Route Index
:--------------------------------------------------------------------------------:
BOOKMARK: index
:--------------------------------------------------------------------------------:
HTML:
Skill Route Index
BOOKMARK
        0644,
    );
    _write_file(
        File::Spec->catfile( 'dashboards', 'foo' ),
        <<'BOOKMARK',
TITLE: Skill Route Foo
:--------------------------------------------------------------------------------:
BOOKMARK: foo
:--------------------------------------------------------------------------------:
HTML:
Skill Route Foo
BOOKMARK
        0644,
    );
    _write_file(
        File::Spec->catfile( 'dashboards', 'ajax-demo' ),
        <<'BOOKMARK',
TITLE: Skill Ajax Demo
:--------------------------------------------------------------------------------:
BOOKMARK: ajax-demo
:--------------------------------------------------------------------------------:
HTML:
<div id="ajax-demo">Ajax Demo</div>
<script>
var endpoints = {};
</script>
:--------------------------------------------------------------------------------:
CODE1: Ajax jvar => 'endpoints.bar', file => 'bar', type => 'json', code => q{
print qq|{"route":"bar"}\n|;
};
BOOKMARK
        0644,
    );
    _write_file(
        File::Spec->catfile( 'config', 'routes.json' ),
        sprintf(
            <<'JSON',
{
   "/apps/%s/home" : "/app/index",
   "/apps/%s/foo" : "/app/foo",
   "/v1/%s/bar" : "/ajax/bar",
   "/v1/%s/raw" : {
      "to" : "/ajax/raw",
      "type" : "application/vnd.route+json"
   },
   "/assets/%s.css" : "/css/skill.css",
   "/assets/%s.js" : "/js/skill.js",
   "/downloads/%s.txt" : {
      "to" : "/others/info.txt",
      "type" : "text/plain; charset=utf-8"
   }
}

JSON
            ($name) x 7,
        ),
        0644,
    );
    _write_file( File::Spec->catfile( 'dashboards', 'ajax', 'bar' ), qq{print qq|{"route":"bar"}\\n|;\n}, 0700 );
    _write_file( File::Spec->catfile( 'dashboards', 'ajax', 'raw' ), qq{print qq|{"route":"raw"}\\n|;\n}, 0700 );
    _write_file( File::Spec->catfile( 'dashboards', 'public', 'js', 'skill.js' ), qq{console.log("$name js");\n}, 0644 );
    _write_file( File::Spec->catfile( 'dashboards', 'public', 'css', 'skill.css' ), qq{body { color: #123456; }\n}, 0644 );
    _write_file( File::Spec->catfile( 'dashboards', 'public', 'others', 'info.txt' ), "$name info\n", 0644 );
    make_path( File::Spec->catdir( 'skills', 'def', 'dashboards', 'ajax' ) );
    make_path( File::Spec->catdir( 'skills', 'def', 'dashboards', 'nav' ) );
    make_path( File::Spec->catdir( 'skills', 'def', 'dashboards', 'public', 'js', 'ijk' ) );
    make_path( File::Spec->catdir( 'skills', 'def', 'dashboards', 'public', 'css', 'ijk' ) );
    make_path( File::Spec->catdir( 'skills', 'def', 'dashboards', 'public', 'others', 'ijk' ) );
    make_path( File::Spec->catdir( 'skills', 'def', 'config' ) );
    _write_file(
        File::Spec->catfile( 'skills', 'def', 'dashboards', 'index' ),
        <<'BOOKMARK',
TITLE: Nested Skill Index
:--------------------------------------------------------------------------------:
BOOKMARK: index
:--------------------------------------------------------------------------------:
HTML:
Nested Skill Index
BOOKMARK
        0644,
    );
    _write_file(
        File::Spec->catfile( 'skills', 'def', 'dashboards', 'foo' ),
        <<'BOOKMARK',
TITLE: Nested Skill Foo
:--------------------------------------------------------------------------------:
BOOKMARK: foo
:--------------------------------------------------------------------------------:
HTML:
Nested Skill Foo
BOOKMARK
        0644,
    );
    _write_file(
        File::Spec->catfile( 'skills', 'def', 'dashboards', 'ajax-demo' ),
        <<'BOOKMARK',
TITLE: Nested Skill Ajax Demo
:--------------------------------------------------------------------------------:
BOOKMARK: ajax-demo
:--------------------------------------------------------------------------------:
HTML:
<div id="nested-ajax-demo">Nested Ajax Demo</div>
<script>
var endpoints = {};
</script>
:--------------------------------------------------------------------------------:
CODE1: Ajax jvar => 'endpoints.nested', file => 'nested', code => q{
print "<p>nested skill ajax route</p>\n";
};
BOOKMARK
        0644,
    );
    _write_file(
        File::Spec->catfile( 'skills', 'def', 'config', 'routes.json' ),
        sprintf(
            <<'JSON',
{
   "/apps/%s/child/foo" : "/app/foo",
   "/v1/%s/nested" : {
      "to" : "/ajax/nested",
      "type" : "html"
   },
   "/assets/%s-nested.css" : "/css/ijk/lmn.css",
   "/assets/%s-nested.js" : "/js/ijk/lmn.js",
   "/downloads/%s-nested.txt" : "/others/ijk/lmn.txt"
}
JSON
            ($name) x 5,
        ),
        0644,
    );
    _write_file( File::Spec->catfile( 'skills', 'def', 'dashboards', 'ajax', 'nested' ), qq{print "<p>nested skill ajax route</p>\\n";\n}, 0700 );
    _write_file( File::Spec->catfile( 'skills', 'def', 'dashboards', 'nav', 'index.tt' ), "<div>Nested Skill Nav</div>\n", 0644 );
    _write_file( File::Spec->catfile( 'skills', 'def', 'dashboards', 'public', 'js', 'ijk', 'lmn.js' ), qq{console.log("nested js");\n}, 0644 );
    _write_file( File::Spec->catfile( 'skills', 'def', 'dashboards', 'public', 'css', 'ijk', 'lmn.css' ), qq{body { background: #abcdef; }\n}, 0644 );
    _write_file( File::Spec->catfile( 'skills', 'def', 'dashboards', 'public', 'others', 'ijk', 'lmn.txt' ), "nested other asset\n", 0644 );
    make_path( File::Spec->catdir( 'dashboards', 'nav' ) );
    _write_file(
        File::Spec->catfile( 'dashboards', 'nav', 'skill.tt' ),
        '<div>' . ( $args{nav_label} || 'Skill Route Nav' ) . "</div>\n",
        0644,
    );
    _run_or_die(qw(git add .));
    _run_or_die( 'git', 'commit', '-m', 'Initial route skill' );
    chdir $cwd or die "Unable to chdir back to $cwd: $!";
    return $repo;
}

sub _write_file {
    my ( $path, $content, $mode ) = @_;
    open my $fh, '>', $path or die "Unable to write $path: $!";
    print {$fh} $content;
    close $fh;
    chmod $mode, $path or die "Unable to chmod $path: $!";
    return 1;
}

sub _run_or_die {
    my (@command) = @_;
    system(@command) == 0 or die "Command failed: @command";
    return 1;
}

sub _drain_stream_body {
    my ($body) = @_;
    return $body if ref($body) ne 'HASH' || ref( $body->{stream} ) ne 'CODE';
    my $output = '';



( run in 0.961 second using v1.01-cache-2.11-cpan-524268b4103 )