Punk-Queue
view release on metacpan or search on metacpan
t/77-admin-templates.t view on Meta::CPAN
my $ldir = write_dir(
'layout.tmpl' => qq{<html><head><title>{% title %}</title>\n}
. qq{{% for href in styles %}<link href="{% href %}">{% end %}\n}
. qq{</head><body data-page="{% page %}" data-live="{% live %}">\n}
. qq{<nav>{% for i in nav %}<a href="{% i.href %}">{% i.label %}</a>{% end %}</nav>\n}
. qq{{% raw content %}\n}
. qq{{% for src in scripts %}<script src="{% src %}"></script>{% end %}\n}
. qq{</body></html>\n},
);
{
package LayoutApp;
use Punk;
plugin 'Queue' => {
dsn => 'dbi:SQLite:dbname=' . PQTest::queue_file(),
admin => { prefix => '/admin/q', guard => sub { return },
templates => $ldir },
};
}
my $lapp = LayoutApp->to_app;
{
my $html = get($lapp, '/admin/q/locks')->[2][0];
like($html, qr/^<html><head><title>Locks<\/title>/,
'a custom layout replaces ours');
like($html, qr/pqLocksTable/, '...and still wraps the shipped page');
like($html, qr{<link href="/admin/q/assets/funky\.css">},
'styles carries the stylesheet URLs, so a layout needs no paths');
like($html, qr{<script src="/admin/q/assets/funky\.js"></script>\s*<script src="/admin/q/assets/app\.js"></script>},
'scripts carries them in load order');
like($html, qr{<a href="/admin/q">Overview</a>}, 'nav is data');
like($html, qr/data-live="false"/, 'live is a JS literal');
unlike($html, qr/\{%/, 'nothing is left untemplated');
}
# ---- css and js overrides ----------------------------------------------------
my $adir = write_dir(
'brand.css' => ".pq-brand { color: rebeccapurple }\n",
'extra.js' => "window.__MINE = 1;\n",
'more.js' => "window.__ALSO = 2;\n",
);
{
package AssetApp2;
use Punk;
plugin 'Queue' => {
dsn => 'dbi:SQLite:dbname=' . PQTest::queue_file(),
admin => { prefix => '/q', guard => sub { return },
css => File::Spec->catfile($adir, 'brand.css'),
js => [ File::Spec->catfile($adir, 'extra.js'),
File::Spec->catfile($adir, 'more.js') ] },
};
}
my $aapp = AssetApp2->to_app;
{
my $css = get($aapp, '/q/assets/funky.css')->[2][0];
like($css, qr/rebeccapurple/, 'a css override is served');
ok(index($css, 'rebeccapurple') > index($css, '--pq-'),
'...at the end, after our own sheet, so the cascade favours it');
my $js = get($aapp, '/q/assets/app.js')->[2][0];
like($js, qr/window\.__MINE = 1/, 'a js override is served');
ok(index($js, 'window.__MINE') < index($js, 'window.__ALSO'),
'...in the order given');
ok(index($js, 'window.__MINE') > index($js, 'Funky'),
'...after app.js, which it can therefore build on');
}
# ---- the ETag follows the bytes ----------------------------------------------
{
my $plain = get($app, '/q/assets/funky.css');
my $mine = get($aapp, '/q/assets/funky.css');
my ($e1, $e2) = (header_of($plain, 'ETag'), header_of($mine, 'ETag'));
ok($e1 && $e2, 'both bundles are ETagged');
isnt($e1, $e2, 'an override changes the ETag - no stale shared cache');
my $again = get($aapp, '/q/assets/funky.css',
HTTP_IF_NONE_MATCH => $e2);
is($again->[0], 304, 'and the ETag still answers a conditional GET');
}
# ---- boot-time failures ------------------------------------------------------
{
my $err = '';
eval {
package BadTmplApp;
use Punk;
plugin 'Queue' => {
dsn => 'dbi:SQLite:dbname=' . PQTest::queue_file(),
admin => { guard => sub { return },
templates => '/no/such/template/dir' },
};
1;
} or $err = $@;
like($err, qr/templates => '\/no\/such\/template\/dir' is not a directory/,
'a missing template directory croaks at boot');
}
{
my $err = '';
eval {
package BadCssApp;
use Punk;
plugin 'Queue' => {
dsn => 'dbi:SQLite:dbname=' . PQTest::queue_file(),
admin => { guard => sub { return },
css => '/no/such/sheet.css' },
};
1;
} or $err = $@;
like($err, qr/css override '\/no\/such\/sheet\.css' is not a readable file/,
'a missing override sheet croaks at boot, naming it');
}
done_testing();
( run in 0.872 second using v1.01-cache-2.11-cpan-e7c6538aa59 )