Use standard form buttons and resume entrance effects in 1.10.1
This commit is contained in:
1 parent
f182f9e125
commit
cff468167b
12 files changed
+161
-12
No files matched your search
@@ -10,6 +10,7 @@ const hash = async () => createHash('sha256').update(await readFile('var/kantit.
|
||||
const before = await hash();
|
||||
const fixture = JSON.parse(execFileSync(php, ['tests/pilot-fixture.php'], { encoding: 'utf8', windowsHide: true }));
|
||||
const env = { ...process.env, APP_ENV: 'prod', APP_DEBUG: '0', APP_SECRET: randomBytes(32).toString('hex'), DATABASE_URL: fixture.databaseUrl, MEDIA_DIRECTORY: fixture.mediaDirectory };
|
||||
execFileSync(php, ['bin/console', 'cache:clear', '--env=prod', '--no-debug'], { env, windowsHide: true, stdio: 'ignore' });
|
||||
const probe = net.createServer(); await new Promise(resolve => probe.listen(0, '127.0.0.1', resolve));
|
||||
const port = probe.address().port; await new Promise(resolve => probe.close(resolve));
|
||||
const origin = `http://127.0.0.1:${port}`;
|
||||
@@ -23,7 +24,13 @@ try {
|
||||
if (attempt === 59) throw new Error('Pilot server did not start');
|
||||
await new Promise(resolve => setTimeout(resolve, 200));
|
||||
}
|
||||
browser = await chromium.launch();
|
||||
browser = await chromium.launch(process.env.MOTION_BROWSER_CHANNEL ? { channel: process.env.MOTION_BROWSER_CHANNEL } : {});
|
||||
const systemContext = await browser.newContext({ reducedMotion: null });
|
||||
const systemPage = await systemContext.newPage();
|
||||
await systemPage.goto(origin);
|
||||
const systemMotion = await systemPage.evaluate(() => ({ reduced: matchMedia('(prefers-reduced-motion: reduce)').matches, userAgent: navigator.userAgent }));
|
||||
console.log('Default browser motion preference:', JSON.stringify(systemMotion));
|
||||
await systemContext.close();
|
||||
for (const width of [1600, 390]) {
|
||||
const context = await browser.newContext({ viewport: { width, height: 900 }, reducedMotion: 'no-preference' });
|
||||
await context.addInitScript(() => {
|
||||
@@ -40,6 +47,12 @@ try {
|
||||
const inventory = await page.locator('[class*="fx-entrance-"]').evaluateAll(nodes => nodes.map(node => ({ id: node.id, classes: node.className })));
|
||||
assert.ok(inventory.length > 0, 'Pilot has entrance effects');
|
||||
assert.equal(await page.locator('script[src*="motion.js"]').count(), 1);
|
||||
const hoverTarget = page.locator('#leistung-app');
|
||||
await hoverTarget.scrollIntoViewIfNeeded(); await page.waitForTimeout(800);
|
||||
await hoverTarget.hover(); await page.waitForTimeout(350);
|
||||
const hovered = await hoverTarget.evaluate(node => ({ transform: getComputedStyle(node).transform, matches: node.matches(':hover'), classes: node.className }));
|
||||
console.log('Pilot hover:', width, JSON.stringify(hovered));
|
||||
assert.equal(hovered.transform, 'matrix(1, 0, 0, 1, 0, -4)', 'Saved lift effect changes the rendered transform');
|
||||
const target = page.locator('#kontakt');
|
||||
assert.equal(await page.evaluate(() => motionCalls.some(call => call.id === 'kontakt')), false, 'Below-fold section must wait for scrolling');
|
||||
await target.scrollIntoViewIfNeeded();
|
||||
@@ -76,7 +89,26 @@ try {
|
||||
await page.reload(); await target.scrollIntoViewIfNeeded(); await page.waitForTimeout(800);
|
||||
assert.equal(await page.evaluate(() => motionCalls.length), 0, 'Reduced motion suppresses animations');
|
||||
assert.equal(await target.evaluate(node => getComputedStyle(node).opacity), '1');
|
||||
results.push({ width, inventory, calls, checks: ['scroll trigger', 'once only', 'left/right computed movement', 'reduced motion'] });
|
||||
await hoverTarget.hover(); await page.waitForTimeout(350);
|
||||
assert.equal(await hoverTarget.evaluate(node => getComputedStyle(node).transform), 'none', 'Reduced motion suppresses hover movement');
|
||||
await target.scrollIntoViewIfNeeded();
|
||||
await page.emulateMedia({ reducedMotion: 'no-preference' });
|
||||
await page.waitForFunction(() => motionCalls.some(call => call.id === 'kontakt'), null, { timeout: 3000 });
|
||||
await page.waitForTimeout(800);
|
||||
await page.emulateMedia({ reducedMotion: 'reduce' });
|
||||
await page.emulateMedia({ reducedMotion: 'no-preference' });
|
||||
await page.waitForTimeout(100);
|
||||
assert.equal(await page.evaluate(() => motionCalls.filter(call => call.id === 'kontakt').length), 1, 'Preference changes do not replay an already seen element');
|
||||
await hoverTarget.hover(); await page.waitForTimeout(350);
|
||||
assert.equal(await hoverTarget.evaluate(node => getComputedStyle(node).transform), 'matrix(1, 0, 0, 1, 0, -4)', 'Hover resumes after allowing motion');
|
||||
// Also cover a page that starts normally, then suppresses motion before reaching its content.
|
||||
await page.reload(); await page.waitForTimeout(800);
|
||||
await page.emulateMedia({ reducedMotion: 'reduce' });
|
||||
await target.scrollIntoViewIfNeeded(); await page.waitForTimeout(100);
|
||||
assert.equal(await page.evaluate(() => motionCalls.filter(call => call.id === 'kontakt').length), 0);
|
||||
await page.emulateMedia({ reducedMotion: 'no-preference' });
|
||||
await page.waitForFunction(() => motionCalls.some(call => call.id === 'kontakt'), null, { timeout: 3000 });
|
||||
results.push({ width, inventory, calls, checks: ['scroll trigger', 'once only', 'left/right computed movement', 'saved hover lift', 'reduced motion', 'resume without reloading after initial and subsequent reduced motion', 'hover resumes after preference change'] });
|
||||
await context.close();
|
||||
}
|
||||
const noJs = await browser.newContext({ javaScriptEnabled: false });
|
||||
@@ -84,9 +116,25 @@ try {
|
||||
assert.ok(await page.locator('main').innerText());
|
||||
assert.equal(await page.locator('#kontakt').evaluate(node => getComputedStyle(node).opacity), '1');
|
||||
await noJs.close();
|
||||
const editorContext = await browser.newContext({ reducedMotion: 'reduce', viewport: { width: 1600, height: 1000 } });
|
||||
const editor = await editorContext.newPage(); editor.on('pageerror', error => errors.push(error.message));
|
||||
await editor.goto(origin + '/admin/login');
|
||||
await editor.getByLabel('Benutzername').fill(fixture.username);
|
||||
await editor.getByLabel('Passwort', { exact: true }).fill(fixture.password);
|
||||
await editor.getByRole('button', { name: 'Anmelden', exact: true }).click();
|
||||
await editor.waitForURL(origin + '/admin');
|
||||
await editor.goto(`${origin}/admin/pages/${fixture.homeId}`);
|
||||
await editor.locator('#motion-status').waitFor({ state: 'visible' });
|
||||
await editor.locator('#preview-status').filter({ hasText: 'Entwurf ·' }).waitFor();
|
||||
await editor.screenshot({ path: `${report}/editor-motion-status.png` });
|
||||
await editor.emulateMedia({ reducedMotion: 'no-preference' });
|
||||
await editor.locator('#motion-status').waitFor({ state: 'hidden' });
|
||||
await editor.emulateMedia({ reducedMotion: 'reduce' });
|
||||
await editor.locator('#motion-status').waitFor({ state: 'visible' });
|
||||
await editorContext.close();
|
||||
assert.deepEqual(errors, []);
|
||||
assert.equal(await hash(), before, 'Original database unchanged');
|
||||
await writeFile(`${report}/result.json`, JSON.stringify({ results, errors, noJavaScript: true, originalUnchanged: true }, null, 2));
|
||||
await writeFile(`${report}/result.json`, JSON.stringify({ systemMotion, results, errors, editorMotionStatus: true, noJavaScript: true, originalUnchanged: true }, null, 2));
|
||||
console.log(JSON.stringify({ passed: true, devices: results.map(result => result.width), effects: results[0].inventory, report }));
|
||||
} finally {
|
||||
await browser?.close(); server.kill();
|
||||
|
||||
Reference in new issue
Block a user