scavold 0.2.0-rc.9 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -154,7 +154,7 @@ expect( manifest.adapter?.version === version, "reports this package's version a
154
154
  expect( manifest.sections?.video?.props?.src?.type === "media-file", "declares video.src as a media file" );
155
155
  expect( manifest.sections?.pagelist?.props?.sort?.values?.join() === "order,date,date-asc,title",
156
156
  "declares the page list's ordering options" );
157
- expect( manifest.sections?.video?.props?.overlay?.type === "boolean", "declares video.overlay as a boolean" );
157
+ expect( manifest.sections?.video?.props?.overlay === undefined, "offers no background mode for a video; that is a cover's" );
158
158
  expect( manifest.sections?.teaser?.props?.background?.type === "media-file",
159
159
  "carries the site's own container with its typed props" );
160
160
  expect( manifest.sections?.teaser?.props?.variant?.values?.join() === "plain,boxed",
@@ -271,18 +271,67 @@ expect( built( "index.html" ).includes( 'href="/containers.html"' ), "leaves a l
271
271
  console.log( "\nvideo" );
272
272
 
273
273
  const videos = tags( media, "video" );
274
- const overlays = media.match( /<div class="scavold-video scavold-video--overlay"/g ) ?? [];
275
274
 
276
275
  expect( videos.every( t => /src="\/media\/clip\.mp4"/.test( t ) ), "rewrites the video source to its published URL" );
277
276
  expect( videos.some( t => /poster="\/media\/wide--\d+w-[0-9a-f]+\.jpg"/.test( t ) ),
278
277
  "resolves a poster to a single generated variant rather than a srcset" );
279
- expect( overlays.length === 2, "renders background mode for both spellings of its arguments",
280
- `found ${overlays.length} overlay blocks, expected 2` );
281
278
 
282
- const backgrounds = videos.filter( t => !t.includes( "controls" ) );
283
-
284
- expect( backgrounds.length === 2 && backgrounds.every( t => /autoplay/.test( t ) && /loop/.test( t ) && /muted/.test( t ) ),
285
- "gives both spellings the same autoplay, loop and muted attributes" );
279
+ // Autoplay implies muted, which is how it shows in the markup: the playing itself is
280
+ // started by script, once reduced motion has been ruled out.
281
+ const looping = videos.filter( t => /\bloop\b/.test( t ) );
282
+
283
+ expect( looping.length === 2 && looping.every( t => /\bmuted\b/.test( t ) ),
284
+ "gives both spellings of autoplay and loop the same attributes",
285
+ `found ${looping.length} looping video(s), expected 2` );
286
+ expect( videos.every( t => !/\bautoplay\b/.test( t ) ), "leaves starting an autoplay video to the script" );
287
+ expect( videos.every( t => /\bcontrols\b/.test( t ) ), "gives every video its playback controls" );
288
+
289
+ // ── cover ────────────────────────────────────────────────────────────────────
290
+
291
+ console.log( "\ncover" );
292
+
293
+ expect( manifest.sections?.cover?.props?.src?.type === "media-file", "declares cover.src as a media file" );
294
+
295
+ const cover = built( "cover.html" );
296
+ const covers = cover.split( /<div class="scavold-cover[ "]/ ).slice( 1 );
297
+ const [ coverImage = "", coverVideo = "" ] = covers;
298
+
299
+ expect( covers.length === 2, "renders both covers of the page", `found ${covers.length}` );
300
+ expect( /<div class="scavold-cover[ "][^>]*\sdata-leading[\s=>]/.test( cover ) && cover.match( /\sdata-leading[\s=>]/g )?.length === 1,
301
+ "marks the cover opening the page, and only that one" );
302
+ expect( cover.includes( '<main data-leading-container="cover">' ),
303
+ "tells the layout before the content renders that the page opens with a cover" );
304
+ expect( !/<main[^>]*data-leading-container/.test( built( "media.html" ) ),
305
+ "tells it nothing on a page that opens with anything else" );
306
+ // The variants, not just the widest one: a cover is the largest image of a page and
307
+ // must not cost a phone the full 1920px file.
308
+ expect( /<source type="image\/webp" srcset="[^"]*wide--320w-[0-9a-f]+\.webp 320w[^"]*wide--1920w-[0-9a-f]+\.webp 1920w"/.test( coverImage ),
309
+ "renders a cover image from all its variants" );
310
+ // A 16:9 source cropped to an upright window is drawn wider than the window.
311
+ expect( coverImage.includes( 'sizes="(min-aspect-ratio: 2400/1350) 100vw, 177.78vh"' ),
312
+ "tells the browser how wide a cropped cover image is drawn" );
313
+ expect( /<img[^>]*loading="eager"/.test( coverImage ) && /<img[^>]*fetchpriority="high"/.test( coverImage ),
314
+ "loads a cover image at once rather than lazily" );
315
+ expect( /<img[^>]*alt="A wide blue field"/.test( coverImage ), "uses the label as the image's alternative text" );
316
+ expect( coverImage.includes( "--scavold-cover-focus:center top" ) || coverImage.includes( "--scavold-cover-focus: center top" ),
317
+ "passes the focal point on to the stylesheet" );
318
+ expect( /class="scavold-cover__overlay"[^>]*>\s*(?:<!--\[-->)?\s*<h1[^>]*>Over the cover image/.test( coverImage ),
319
+ "lays the section's content on top of the image" );
320
+
321
+ const coverVideoTag = tags( coverVideo, "video" )[0] ?? "";
322
+
323
+ expect( coverVideo.startsWith( "scavold-cover--video" ), "tells a video cover by its file type" );
324
+ // A mark for the theme to style, nothing more.
325
+ expect( /^scavold-cover--light"/.test( coverImage ), "marks the tone asked for the content on top" );
326
+ expect( !/scavold-cover--(light|dark)/.test( coverVideo ), "marks no tone where none is asked for" );
327
+ expect( !cover.includes( "data-poster-srcset" ), "keeps the variants of a still image out of the markup" );
328
+ expect( /src="\/media\/clip\.mp4"/.test( coverVideoTag ) && /poster="\/media\/wide--\d+w-[0-9a-f]+\.jpg"/.test( coverVideoTag ),
329
+ "resolves a cover video and its still image to their published URLs" );
330
+ // Started by script once reduced motion has been ruled out, never by the markup.
331
+ expect( /muted/.test( coverVideoTag ) && /loop/.test( coverVideoTag ) && !/autoplay/.test( coverVideoTag ),
332
+ "renders a cover video muted and looping, without autoplay in the markup" );
333
+ expect( /<button type="button" class="scavold-cover__toggle" aria-label="[^"]+"/.test( coverVideo ),
334
+ "offers a labelled button to pause a cover video" );
286
335
 
287
336
  // ── page list ────────────────────────────────────────────────────────────────
288
337
 
@@ -303,6 +352,36 @@ expect( menu.includes( '<a href="/containers.html">' ),
303
352
  expect( crumbs.includes( '<a href="/blog/index.html"' ) && crumbs.includes( 'aria-current="page"' ),
304
353
  "marks the page the breadcrumb ends on" );
305
354
 
355
+ console.log( "\nnamed menus" );
356
+
357
+ const footer = ( blogPage.match( /<nav aria-label="Footer"[\s\S]*?<\/nav>/ ) ?? [""] )[0];
358
+ const footerTree = ( blogPage.match( /<nav aria-label="Footer tree"[\s\S]*?<\/nav>/ ) ?? [""] )[0];
359
+
360
+ /**
361
+ * @param {string} nav one rendered menu
362
+ * @param {string} label link text of one entry
363
+ * @returns {number} how often the menu links that entry
364
+ */
365
+ function linked( nav, label ) {
366
+ return nav.split( `>${label}</a>` ).length - 1;
367
+ }
368
+
369
+ expect( linked( footer, "Imprint" ) === 1 && linked( footer, "Contact" ) === 1,
370
+ "lists in a named menu the pages choosing it" );
371
+ expect( linked( menu, "Imprint" ) === 0 && linked( menu, "About" ) === 0,
372
+ "leaves a page choosing only a named menu out of the page tree's menus" );
373
+ expect( linked( menu, "Contact" ) === 1,
374
+ "keeps a page in the page tree's menus when it chooses them along with a named one" );
375
+ expect( linked( footer, "Team" ) === 1 && footer.split( "<ul" ).length === 2,
376
+ "keeps a menu without sub-pages flat, listing a page chosen along with its parent beside it" );
377
+ expect( linked( footerTree, "Team" ) === 1 &&
378
+ />About<\/a><ul>(?:<!--\[-->)?<li[^>]*><a [^>]*>Team<\/a>/.test( footerTree ),
379
+ "lists a page chosen along with its parent below that parent where the menu shows sub-pages, not twice" );
380
+ expect( linked( footer, "Secret" ) === 0 && linked( menu, "Secret" ) === 0,
381
+ "lets hiding from menus rule over choosing one" );
382
+ expect( /chooses menu 'sidebar', which \.cratly\.config\.yaml does not declare/.test( log ),
383
+ "warns about a menu name the site does not declare" );
384
+
306
385
  const sitemap = built( "sitemap.xml" );
307
386
 
308
387
  expect( sitemap.includes( "<loc>https://fixture.example.com/index.html</loc>" ) &&