This commit is contained in:
@@ -34,13 +34,68 @@ for (const trigger of ['click', 'wheel', 'key']) {
|
||||
});
|
||||
}
|
||||
|
||||
test('hover streams are masked at the actual slash edges throughout the loop', async ({ page }, testInfo) => {
|
||||
await armed(page);
|
||||
const root = page.locator('.root-mark');
|
||||
const box = (await root.boundingBox())!;
|
||||
const shape = (await root.locator('.root-shape').boundingBox())!;
|
||||
const clip = { x: Math.floor(box.x) - 8, y: Math.floor(box.y) - 8, width: Math.ceil(box.width) + 16, height: Math.ceil(box.height) + 16 };
|
||||
const before = (await page.screenshot({ clip })).toString('base64');
|
||||
await root.hover();
|
||||
await expect(page.locator('.tap-mask')).toHaveAttribute('mask', 'url(#tap-edge-mask)');
|
||||
const mask = await page.locator('#tap-edge-mask rect').evaluate((rect) => {
|
||||
const svg = rect.closest('svg')!;
|
||||
const matrix = svg.getScreenCTM()!;
|
||||
return { top: new DOMPoint(0, 4).matrixTransform(matrix).y, bottom: new DOMPoint(0, 60).matrixTransform(matrix).y };
|
||||
});
|
||||
expect(mask.top).toBeCloseTo(shape.y, 1);
|
||||
expect(mask.bottom).toBeCloseTo(shape.y + shape.height, 1);
|
||||
for (const time of [0, 700, 1399]) {
|
||||
await page.locator('.tap-stream text').evaluateAll((texts, time) => {
|
||||
texts.forEach((text) => text.getAnimations().forEach((animation) => {
|
||||
animation.pause();
|
||||
animation.currentTime = time;
|
||||
}));
|
||||
}, time);
|
||||
const after = (await page.screenshot({ clip, path: testInfo.outputPath(`hover-mask-${time}.png`) })).toString('base64');
|
||||
const ink = await page.evaluate(async ({ before, after }) => {
|
||||
const pixels = async (base64: string) => {
|
||||
const image = new Image();
|
||||
image.src = 'data:image/png;base64,' + base64;
|
||||
await image.decode();
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = image.width; canvas.height = image.height;
|
||||
const ctx = canvas.getContext('2d')!;
|
||||
ctx.drawImage(image, 0, 0);
|
||||
return { data: ctx.getImageData(0, 0, image.width, image.height).data, width: image.width };
|
||||
};
|
||||
const a = await pixels(before), b = await pixels(after);
|
||||
let minY = Infinity, maxY = -Infinity, count = 0;
|
||||
for (let i = 0; i < a.data.length; i += 4) {
|
||||
if (Math.abs(a.data[i] - b.data[i]) + Math.abs(a.data[i + 1] - b.data[i + 1]) + Math.abs(a.data[i + 2] - b.data[i + 2]) > 30) {
|
||||
const y = Math.floor(i / 4 / a.width);
|
||||
minY = Math.min(minY, y); maxY = Math.max(maxY, y); count++;
|
||||
}
|
||||
}
|
||||
return { minY, maxY, count };
|
||||
}, { before, after });
|
||||
expect(ink.count).toBeGreaterThan(50);
|
||||
expect(ink.minY + clip.y).toBeGreaterThanOrEqual(Math.floor(shape.y));
|
||||
expect(ink.maxY + clip.y).toBeLessThanOrEqual(Math.ceil(shape.y + shape.height));
|
||||
}
|
||||
await expect(page.locator(stage)).toHaveAttribute('data-phase', 'armed');
|
||||
await page.mouse.move(0, 0);
|
||||
await expect(page.locator('.tap-stream-a')).toHaveCSS('opacity', '0');
|
||||
await expect(page.locator('.tap-stream-b')).toHaveCSS('opacity', '0');
|
||||
});
|
||||
|
||||
test('continuous motion overlaps growth, travel and reveal without intermediate stops', async ({ page }, testInfo) => {
|
||||
await page.clock.install({ time: new Date('2026-01-01T00:00:00Z') });
|
||||
await page.clock.pauseAt(new Date('2026-01-01T00:00:01Z'));
|
||||
await armed(page);
|
||||
const root = page.locator('.root-mark');
|
||||
await expect(root.locator('svg .root-shape')).toHaveCount(1);
|
||||
await expect(root).toHaveText(''); // Geometry, never a font glyph.
|
||||
await expect(root.locator('.root-shape')).toHaveAttribute('d', 'M31 4H41L17 60H7Z'); // The slash is geometry, not a font glyph.
|
||||
await expect(page.locator('.call-panel')).toHaveAttribute('inert', '');
|
||||
const initial = await root.boundingBox();
|
||||
expect(initial).not.toBeNull();
|
||||
|
||||
Reference in New Issue
Block a user