fix: refine chart evidence layouts
This commit is contained in:
@@ -77,49 +77,70 @@ test('failed project images leave titles, captions, chart explanations, and alt
|
||||
await expect(page.locator('[data-project-id="currency-converter"] img')).toHaveAttribute('alt', /conversion interface/iu);
|
||||
});
|
||||
|
||||
test('desktop chart descriptions and exact values occupy sequential full-width rows', async ({ page, distUrl }, testInfo) => {
|
||||
test('desktop chart descriptions keep readable value columns and exact values in sequential full-width rows', async ({ page, distUrl }, testInfo) => {
|
||||
test.skip(testInfo.project.name !== 'desktop-chromium', 'Desktop chart grid geometry is verified once.');
|
||||
await page.setViewportSize({ width: 1440, height: 900 });
|
||||
await page.addInitScript(() => localStorage.setItem('portfolio.motion.maximum-quality', 'static'));
|
||||
await page.goto(distUrl, { waitUntil: 'networkidle' });
|
||||
|
||||
const chart = page.locator('[data-project-id="opinion-dynamics-simulation"] .project-media--chart').first();
|
||||
const geometry = await chart.evaluate((figure) => {
|
||||
const charts = page.locator('[data-project-id="opinion-dynamics-simulation"] .project-media--chart');
|
||||
const geometry = await charts.evaluateAll((figures) => figures.map((figure) => {
|
||||
const description = figure.querySelector<HTMLElement>('.chart-description')!;
|
||||
const table = figure.querySelector<HTMLElement>('.chart-values')!;
|
||||
const table = figure.querySelector<HTMLElement>('.chart-values');
|
||||
const values = [...description.querySelectorAll<HTMLElement>('dd')];
|
||||
const figureRect = figure.getBoundingClientRect();
|
||||
const descriptionStyle = getComputedStyle(description);
|
||||
const tableStyle = getComputedStyle(table);
|
||||
const tableStyle = table === null ? null : getComputedStyle(table);
|
||||
return {
|
||||
descriptionColumn: descriptionStyle.gridColumnStart,
|
||||
descriptionRow: descriptionStyle.gridRowStart,
|
||||
tableColumn: tableStyle.gridColumnStart,
|
||||
tableRow: tableStyle.gridRowStart,
|
||||
tableColumn: tableStyle?.gridColumnStart ?? null,
|
||||
tableRow: tableStyle?.gridRowStart ?? null,
|
||||
descriptionWidthRatio: description.getBoundingClientRect().width / figureRect.width,
|
||||
tableWidthRatio: table.getBoundingClientRect().width / figureRect.width,
|
||||
tableWidthRatio: table === null ? null : table.getBoundingClientRect().width / figureRect.width,
|
||||
minimumValueWidth: Math.min(...values.map((value) => value.getBoundingClientRect().width)),
|
||||
descriptionHeight: description.getBoundingClientRect().height,
|
||||
};
|
||||
});
|
||||
}));
|
||||
const opinionHeight = await page.locator('[data-project-id="opinion-dynamics-simulation"]')
|
||||
.evaluate((article) => article.getBoundingClientRect().height);
|
||||
|
||||
expect(geometry).toEqual({
|
||||
expect(geometry[0]).toEqual({
|
||||
descriptionColumn: '1',
|
||||
descriptionRow: '3',
|
||||
tableColumn: '1',
|
||||
tableRow: '4',
|
||||
descriptionWidthRatio: expect.any(Number),
|
||||
tableWidthRatio: expect.any(Number),
|
||||
minimumValueWidth: expect.any(Number),
|
||||
descriptionHeight: expect.any(Number),
|
||||
});
|
||||
expect(geometry.descriptionWidthRatio).toBeGreaterThanOrEqual(0.8);
|
||||
expect(geometry.tableWidthRatio).toBeGreaterThanOrEqual(0.8);
|
||||
expect(geometry[1]).toMatchObject({
|
||||
descriptionColumn: '1',
|
||||
descriptionRow: '3',
|
||||
tableColumn: null,
|
||||
tableRow: null,
|
||||
});
|
||||
expect(geometry.every(({ descriptionWidthRatio }) => descriptionWidthRatio >= 0.8)).toBe(true);
|
||||
expect(geometry[0]!.tableWidthRatio).toBeGreaterThanOrEqual(0.8);
|
||||
expect.soft(
|
||||
Math.min(...geometry.map(({ minimumValueWidth }) => minimumValueWidth)),
|
||||
JSON.stringify(geometry),
|
||||
).toBeGreaterThanOrEqual(160);
|
||||
expect.soft(Math.max(...geometry.map(({ descriptionHeight }) => descriptionHeight))).toBeLessThan(600);
|
||||
expect(opinionHeight).toBeLessThan(3_000);
|
||||
});
|
||||
|
||||
test('print project captions and evidence text retain readable contrast', async ({ page, distUrl }, testInfo) => {
|
||||
test.skip(testInfo.project.name !== 'desktop-chromium', 'Print contrast is verified once.');
|
||||
await page.setViewportSize({ width: 1440, height: 900 });
|
||||
await page.emulateMedia({ media: 'print' });
|
||||
await page.goto(distUrl, { waitUntil: 'networkidle' });
|
||||
const opinionCharts = page.locator('[data-project-id="opinion-dynamics-simulation"] .project-media--chart img');
|
||||
await opinionCharts.first().scrollIntoViewIfNeeded();
|
||||
await expect.poll(() => opinionCharts.evaluateAll((images) => images.every((image) => (
|
||||
(image as HTMLImageElement).complete && (image as HTMLImageElement).naturalWidth > 0
|
||||
)))).toBe(true);
|
||||
await page.emulateMedia({ media: 'print' });
|
||||
|
||||
const result = await page.locator('.project-media').evaluateAll((figures) => {
|
||||
const channel = (value: number): number => {
|
||||
@@ -139,12 +160,34 @@ test('print project captions and evidence text retain readable contrast', async
|
||||
return [...figure.querySelectorAll<HTMLElement>('figcaption, .media-description, .chart-description, .chart-values')]
|
||||
.map((element) => contrast(getComputedStyle(element).color, background));
|
||||
});
|
||||
const chartImages = figures
|
||||
.filter((figure) => figure.matches('.project-media--chart'))
|
||||
.map((figure) => figure.querySelector<HTMLImageElement>('img')!);
|
||||
return {
|
||||
backgrounds: [...new Set(figures.map((figure) => getComputedStyle(figure).backgroundColor))],
|
||||
minimumContrast: Math.min(...samples),
|
||||
chartImages: chartImages.map((image) => {
|
||||
const rendered = image.getBoundingClientRect();
|
||||
const renderedAspect = rendered.width / rendered.height;
|
||||
const intrinsicAspect = Number(image.getAttribute('width')) / Number(image.getAttribute('height'));
|
||||
return {
|
||||
background: getComputedStyle(image).backgroundColor,
|
||||
renderedWidth: rendered.width,
|
||||
renderedHeight: rendered.height,
|
||||
renderedAspect,
|
||||
intrinsicAspect,
|
||||
aspectError: Math.abs(renderedAspect - intrinsicAspect) / intrinsicAspect,
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
expect(result.backgrounds).toEqual(['rgb(255, 255, 255)']);
|
||||
expect(result.minimumContrast).toBeGreaterThanOrEqual(4.5);
|
||||
expect(result.chartImages).toHaveLength(2);
|
||||
expect.soft(result.chartImages.every(({ background }) => background === 'rgb(255, 255, 255)')).toBe(true);
|
||||
expect.soft(
|
||||
Math.max(...result.chartImages.map(({ aspectError }) => aspectError)),
|
||||
JSON.stringify(result.chartImages),
|
||||
).toBeLessThanOrEqual(0.02);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user