fix: unify landing glyph animation with pinned site fonts
Reference site / build (push) Canceled after 0s
Reference site / build (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
test.use({ javaScriptEnabled: true });
|
||||
|
||||
test('self-hosted Lyth Mono and EB Garamond load with the configured base', async ({ page }, testInfo) => {
|
||||
const external: string[] = [];
|
||||
page.on('request', (request) => {
|
||||
if (request.resourceType() === 'font' && !request.url().startsWith(testInfo.project.use.baseURL!)) external.push(request.url());
|
||||
});
|
||||
await page.goto('./');
|
||||
const fonts = await page.evaluate(async () => {
|
||||
await document.fonts.ready;
|
||||
const mono = await document.fonts.load('14px "Lyth Mono"', '0W│├└─');
|
||||
const bold = await document.fonts.load('700 14px "Lyth Mono"', 'WIP');
|
||||
const serif = await document.fonts.load('16px "EB Garamond"', 'Worldspace');
|
||||
const italic = await document.fonts.load('italic 16px "EB Garamond"', 'Worldspace');
|
||||
return {
|
||||
mono: mono.map((font) => font.status), bold: bold.map((font) => font.status),
|
||||
serif: serif.map((font) => font.status), italic: italic.map((font) => font.status),
|
||||
stack: getComputedStyle(document.body).fontFamily,
|
||||
prefix: document.querySelector('.branch-prefix')!.textContent!.trim(),
|
||||
};
|
||||
});
|
||||
expect(fonts.mono).toEqual(['loaded']);
|
||||
expect(fonts.bold).toEqual(['loaded']);
|
||||
expect(fonts.serif).toEqual(['loaded']);
|
||||
expect(fonts.italic).toEqual(['loaded']);
|
||||
expect(fonts.stack).toContain('Lyth Mono');
|
||||
expect(fonts.prefix).toBe(''); // SSR uses the same glyph paths, not HTML wires.
|
||||
expect(external).toEqual([]);
|
||||
await page.goto('./book/1-concept/');
|
||||
expect(await page.locator('.prose').evaluate((element) => getComputedStyle(element).fontFamily)).toContain('EB Garamond');
|
||||
await page.screenshot({ path: testInfo.outputPath('eb-garamond-book.png') });
|
||||
});
|
||||
|
||||
test.describe('static font and tree rendering', () => {
|
||||
test.use({ javaScriptEnabled: false, deviceScaleFactor: 4 });
|
||||
test('glyph joins paint continuously across SVG cell boundaries', async ({ page }) => {
|
||||
await page.goto('./');
|
||||
await page.evaluate(() => document.fonts.ready);
|
||||
const joins = await page.locator('.demo-node[aria-level="2"]').evaluateAll((nodes) => nodes.map((node) => {
|
||||
const svg = node.parentElement!.querySelector<SVGSVGElement>('.branch-vector')!;
|
||||
const p = new DOMPoint(Number(svg.dataset.cellWidth) / 2, 12).matrixTransform(svg.getScreenCTM()!);
|
||||
return { x: p.x, y: p.y };
|
||||
}));
|
||||
for (const join of joins) {
|
||||
const clip = { x: Math.floor(join.x), y: Math.floor(join.y) - 1, width: 14, height: 3 };
|
||||
const png = (await page.screenshot({ clip })).toString('base64');
|
||||
const columns = await page.evaluate(async (png) => {
|
||||
const image = new Image(); image.src = 'data:image/png;base64,' + png;
|
||||
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);
|
||||
const data = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
|
||||
return Array.from({ length: canvas.width }, (_, x) => {
|
||||
let darkest = 765;
|
||||
for (let y = 0; y < canvas.height; y++) {
|
||||
const i = (y * canvas.width + x) * 4;
|
||||
darkest = Math.min(darkest, data[i] + data[i + 1] + data[i + 2]);
|
||||
}
|
||||
return darkest;
|
||||
});
|
||||
}, png);
|
||||
// Ignore only the outer antialiasing fringe at the trunk's left edge.
|
||||
const start = Math.ceil((join.x - clip.x + .25) * 4);
|
||||
expect(columns.slice(start).every((ink) => ink < 710), JSON.stringify(columns)).toBe(true);
|
||||
}
|
||||
});
|
||||
test('the same SVG trunk and Lyth Mono joins are visible without JavaScript', async ({ page }, testInfo) => {
|
||||
await page.goto('./');
|
||||
await expect(page.locator('html')).not.toHaveAttribute('data-landing');
|
||||
await expect(page.locator('.trunk-line')).toBeVisible();
|
||||
await expect(page.locator('.trunk-line')).toHaveCSS('stroke', 'none');
|
||||
await expect(page.locator('.branch-prefix').first()).toHaveAttribute('data-prefix', '├── ');
|
||||
await expect(page.locator('.branch-prefix').first().locator('path')).toHaveCount(2);
|
||||
await expect(page.getByRole('link', { name: 'Book', exact: true })).toBeVisible();
|
||||
expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true);
|
||||
await page.screenshot({ path: testInfo.outputPath('lyth-mono-static.png') });
|
||||
});
|
||||
});
|
||||
|
||||
test('failed font downloads do not strand the animation or interactive demo', async ({ page }) => {
|
||||
await page.route('**/*.woff2', (route) => route.abort());
|
||||
await page.goto('./');
|
||||
await expect(page.locator('[data-landing-stage]')).toHaveAttribute('data-phase', 'armed');
|
||||
await page.keyboard.press('Escape');
|
||||
await expect(page.locator('[data-landing-stage]')).toHaveAttribute('data-phase', 'complete');
|
||||
await page.getByRole('button', { name: 'Call', exact: false }).click();
|
||||
await expect(page.locator('[data-result]')).toContainText('Give every capability a place.');
|
||||
});
|
||||
Reference in New Issue
Block a user