Make screenshot tests repeatable by providing own fonts

This commit is contained in:
Przemek Więch
2026-05-12 23:35:10 +02:00
parent 328008f8e9
commit 41d7ed8208
10 changed files with 52 additions and 40 deletions

View File

@@ -1,43 +1,68 @@
import {BrowserContext, Page} from '@playwright/test';
import {BrowserContext} from '@playwright/test';
import * as fs from 'fs';
/**
* Sets up a hermetic test environment by blocking external tracking services
* and intercepting Google Fonts to serve static embedded fonts locally.
* and intercepting index.html to serve static embedded fonts locally.
*/
export async function setupHermeticEnvironment(context: BrowserContext): Promise<void> {
export async function setupHermeticEnvironment(
context: BrowserContext,
): Promise<void> {
await context.route('**/*google-analytics.com/**', (route) => route.abort());
await context.route('**/*googletagmanager.com/**', (route) => route.abort());
// Intercept Google Fonts stylesheet requests to serve a deterministically embedded local font.
await context.route('**/fonts.googleapis.com/css2**', async (route) => {
const cssContent = `
// Intercept index.html to serve preloaded local fonts deterministically.
await context.route(
(url) => url.pathname === '/',
async (route) => {
const response = await route.fetch();
let body = await response.text();
body = body.replace(
/^.*Montserrat.*$/m,
` <link rel="preload" href="Montserrat-Regular.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="Montserrat-Bold.woff2" as="font" type="font/woff2" crossorigin>
<style>
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 100 900;
font-display: block;
src: url('http://localhost:3000/test-fonts/montserrat.woff2') format('woff2');
font-weight: 400;
src: url('Montserrat-Regular.woff2') format('woff2');
}
@font-face {
font-family: 'Montserrat';
font-style: italic;
font-weight: 100 900;
font-display: block;
src: url('http://localhost:3000/test-fonts/montserrat.woff2') format('woff2');
font-style: normal;
font-weight: 700;
src: url('Montserrat-Bold.woff2') format('woff2');
}
`;
text {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: geometricPrecision;
}
</style>`,
);
await route.fulfill({
response,
body,
});
},
);
// Intercept requests for the locally embedded test fonts and serve the static binaries.
await context.route('**/Montserrat-Regular.woff2', async (route) => {
const fontBuffer = fs.readFileSync(
'tests/fixtures/Montserrat-Regular.woff2',
);
await route.fulfill({
status: 200,
contentType: 'text/css',
contentType: 'font/woff2',
headers: {'Access-Control-Allow-Origin': '*'},
body: cssContent,
body: fontBuffer,
});
});
// Intercept requests for the locally embedded test font and serve the static binary.
await context.route('**/test-fonts/montserrat.woff2', async (route) => {
const fontBuffer = fs.readFileSync('tests/fixtures/montserrat.woff2');
await context.route('**/Montserrat-Bold.woff2', async (route) => {
const fontBuffer = fs.readFileSync('tests/fixtures/Montserrat-Bold.woff2');
await route.fulfill({
status: 200,
contentType: 'font/woff2',
@@ -75,12 +100,4 @@ export async function setupGedcomRoute(context: BrowserContext): Promise<void> {
);
await mockGedcomResponse(context, gedcomContent);
await setupHermeticEnvironment(context);
}
/**
* Ensures all custom web fonts are fully loaded and rendered.
*/
export async function waitForFonts(page: Page): Promise<void> {
await page.evaluate(() => document.fonts.ready);
}