import { chromium } from '@playwright/test'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import path from 'node:path'; import { pathToFileURL } from 'node:url'; const root=path.resolve(import.meta.dirname,'..'); const browser=await chromium.launch({headless:true,...(process.env.CHROMIUM_EXECUTABLE?{executablePath:process.env.CHROMIUM_EXECUTABLE}:{})}); try { const context=await browser.newContext({offline:true}); const page=await context.newPage();const errors=[],requests=[]; page.on('pageerror',e=>errors.push(String(e))); page.on('request',r=>{if(/^https?:/.test(r.url()))requests.push(r.url());}); await page.goto(pathToFileURL(path.join(root,'dist/presentation-html-demo-0.3.0.html')).href); await page.waitForFunction(()=>window.deckReady); assert.equal(await page.evaluate(()=>typeof presentationQA.seek),'function'); await page.evaluate(()=>Reveal.slide(3)); const sample=()=>page.evaluate(()=>[...document.querySelectorAll('#sequence [data-motion]')].map(e=>({opacity:e.style.opacity,transform:e.style.transform}))); await page.evaluate(()=>presentationQA.seek(240)); const first=await sample(); await page.evaluate(()=>presentationQA.seek(600));await page.evaluate(()=>presentationQA.seek(240)); assert.deepEqual(await sample(),first,'backward seek is deterministic'); assert.equal(await page.evaluate(()=>presentationQA.active()),0,'seek pauses the clock'); await page.evaluate(()=>presentationQA.seek(Infinity)).then(()=>assert.fail('nonfinite seek accepted'),()=>{}); await page.evaluate(()=>presentationQA.replay()); assert.equal(await page.evaluate(()=>presentationQA.active()),1); await page.evaluate(()=>Reveal.slide(4)); assert.equal(await page.evaluate(()=>[...document.querySelectorAll('#sequence [data-motion]')].every(e=>+getComputedStyle(e).opacity===1)),true,'departure settles previous slide'); await page.evaluate(()=>Reveal.slide(3));assert.equal(await page.evaluate(()=>presentationQA.active()),0,'revisit is complete'); await page.evaluate(()=>presentationQA.replay());await page.keyboard.press('Escape'); assert.equal(await page.evaluate(()=>presentationQA.active()),0,'overview settles');await page.keyboard.press('Escape'); await page.evaluate(()=>presentationQA.replay());await page.emulateMedia({reducedMotion:'reduce'}); await page.waitForFunction(()=>presentationQA.active()===0 && document.querySelector('#motion').getAttribute('aria-pressed')==='false'); assert.equal(await page.evaluate(()=>presentationQA.active()),0); assert.equal(await page.evaluate(()=>presentationQA.replay()),false,'reduced motion forbids replay'); await page.evaluate(()=>presentationQA.seek(0)); assert.equal(await page.evaluate(()=>[...document.querySelectorAll('#sequence [data-motion]')].every(e=>+getComputedStyle(e).opacity===1)),true,'seek respects reduced motion'); await page.emulateMedia({reducedMotion:'no-preference'}); await page.evaluate(()=>presentationQA.replay());await page.evaluate(()=>dispatchEvent(new Event('beforeprint'))); assert.equal(await page.evaluate(()=>presentationQA.active()),0); await page.setContent('