Trog-Bundle.t 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. #!/usr/bin/env perl
  2. use 5.040;
  3. use re '/aasx';
  4. use warnings FATAL => 'all';
  5. use Test::More;
  6. use Test::MockModule qw{strict};
  7. use Test::Fatal qw{exception};
  8. use Cwd();
  9. use File::Path();
  10. use File::Temp();
  11. use Path::Tiny();
  12. use FindBin::libs;
  13. # Every path in tCMS is relative to the instance root, so this stands in one.
  14. my $root = File::Temp::tempdir( 'tcms-bundle-XXXXXX', TMPDIR => 1, CLEANUP => 0 );
  15. my $oldcwd = Cwd::getcwd();
  16. chdir($root) or die "could not chdir to the sandbox: $!";
  17. END {
  18. chdir($oldcwd) if $oldcwd;
  19. File::Path::remove_tree($root) if $root && -d $root;
  20. }
  21. require_ok('Trog::Bundle') or BAIL_OUT("Can't find SUT");
  22. my $stock = Path::Tiny->new('www/scripts');
  23. my $theme = Path::Tiny->new('www/themes/spec/scripts');
  24. $_->mkpath foreach ( $stock, $theme );
  25. $stock->child('one.js')->spew_raw("function one () {\n return 1;\n}\n");
  26. $stock->child('two.js')->spew_raw("// two\nvar two = 2;\n");
  27. $stock->child('vendor.min.js')->spew_raw("var vendor = 'kept as it is'; // a trailing comment");
  28. $stock->child('themed.js')->spew_raw("var themed = 'stock';\n");
  29. $theme->child('themed.js')->spew_raw("var themed = 'theme';\n");
  30. my $themedir = '';
  31. my $mock = Test::MockModule->new('Trog::Themes');
  32. $mock->redefine( 'get_dir', sub { $themedir } );
  33. subtest 'the scripts, in the order named' => sub {
  34. my $bundle = Trog::Bundle::scripts(qw{two.js vendor.min.js one.js two.js});
  35. is( $bundle->{body}, "var two=2;\n;\nvar vendor = 'kept as it is'; // a trailing comment\n;\nfunction one(){return 1;}", 'minified, except the one that already is, and a name given twice is used once' );
  36. like( $bundle->{version}, qr/\A[[:xdigit:]]{16}\z/, 'the version is a digest' );
  37. is( $bundle->{href}, "/bundle/$bundle->{version}/two+vendor.min+one.js", 'and the href carries it, and the names' );
  38. };
  39. subtest 'a name that is not a script' => sub {
  40. my @not = ( qw{nothere.js ../one.js .hidden.js sub/one.js one.css}, 'one.js+two' );
  41. foreach my $name (@not) {
  42. like( exception { Trog::Bundle::scripts( 'one.js', $name ) }, qr/no[ ]script[ ]to[ ]bundle[ ]named[ ]\Q$name\E/, "$name is fatal, and named" );
  43. }
  44. is( Trog::Bundle::scripts(), undef, 'an empty list is no bundle' );
  45. };
  46. subtest "the theme's copy" => sub {
  47. is( Trog::Bundle::scripts(qw{themed.js})->{body}, "var themed='stock';", 'is not used without the theme' );
  48. $themedir = 'www/themes/spec';
  49. is( Trog::Bundle::scripts(qw{themed.js})->{body}, "var themed='theme';", 'and is used in place of the stock one with it' );
  50. is( Trog::Bundle::scripts(qw{one.js})->{body}, 'function one(){return 1;}', 'while a script the theme lacks is the stock one' );
  51. $themedir = '';
  52. };
  53. subtest 'a script that changes' => sub {
  54. my $before = Trog::Bundle::scripts(qw{one.js});
  55. is( Trog::Bundle::scripts(qw{one.js}), $before, 'the bundle is built once' );
  56. $stock->child('one.js')->spew_raw("function one () {\n return 'one';\n}\n");
  57. utime( time + 10, time + 10, $stock->child('one.js') ) or die "could not touch one.js: $!";
  58. my $after = Trog::Bundle::scripts(qw{one.js});
  59. is( $after->{body}, "function one(){return'one';}", 'and built again when a file in it changes' );
  60. isnt( $after->{href}, $before->{href}, 'at a new href' );
  61. };
  62. subtest 'a list that a route did not declare' => sub {
  63. is( Trog::Bundle::served(qw{one.js themed.js}), undef, 'is not served' );
  64. is( Trog::Bundle::served(), undef, 'nor is an empty one' );
  65. Trog::Bundle::declare( [qw{one.js themed.js}], [] );
  66. is( Trog::Bundle::served(qw{one.js themed.js}), Trog::Bundle::scripts(qw{one.js themed.js}), 'until a route declares it' );
  67. my $linked = Trog::Bundle::scripts(qw{vendor.min.js});
  68. is( Trog::Bundle::served(qw{vendor.min.js}), $linked, 'or a page links it' );
  69. Trog::Bundle::declare( [qw{one.js nothere.js}] );
  70. like( exception { Trog::Bundle::served(qw{one.js nothere.js}) }, qr/nothere[.]js/, 'and a declared list with a missing script is fatal' );
  71. };
  72. done_testing();