fix(pdf): preserve accented names in revised CV and letter headings

This commit is contained in:
cesnimda
2026-10-29 23:38:43 +01:00
parent 38d7133d20
commit 154a9e89f5
13 changed files with 235 additions and 13 deletions
@@ -3,6 +3,7 @@ import fs from 'node:fs/promises';
import path from 'node:path';
import { createHash } from 'node:crypto';
import { previewDocumentHtml } from '../src/cvPreview';
import { minimumNameInkClearance } from './helpers/nameInkClearance';
const api = 'http://localhost:5302/api';
const output = path.resolve(process.env.LETTER_LIBRARY_OUTPUT || '../.artifacts/pre-phase10-ux/matching-letters-01');
@@ -26,7 +27,8 @@ test('[PRE-P10 B] nine matching letter designs retain short EN and long NB physi
const company = await companyResponse.json();
await fs.mkdir(output, { recursive: true });
const fixtures = [];
for (const language of ['en', 'nb'] as const) {
const europeanControls = [];
for (const { language, european } of [{ language: 'en', european: false }, { language: 'nb', european: false }, { language: 'en', european: true }] as const) {
const nb = language === 'nb';
const paragraphs = Array.from({ length: nb ? 20 : 3 }, (_, index) => {
const sentence = nb ? 'Jeg dokumenterte pålitelige arbeidsflyter, tilgjengelige grensesnitt og tydelig ansvar i et oppdiktet prosjekt. '
@@ -37,11 +39,11 @@ test('[PRE-P10 B] nine matching letter designs retain short EN and long NB physi
: 'R99 Kind regards, Åse Ødegård-Sørensen. These are synthetic examples only.');
const text = paragraphs.join('\n\n');
for (const theme of themes) {
const fixture = `${nb ? 'long-nb' : 'short-en'}-${theme.id}`;
const fixture = `${european ? 'european-en' : nb ? 'long-nb' : 'short-en'}-${theme.id}`;
const directory = path.join(output, fixture);
await fs.mkdir(directory, { recursive: true });
const documentSettings = { schemaVersion: 1, designVersion: 2, language: nb ? 'nb-NO' : 'en', themeId: theme.id,
senderName: 'R01 Åse Ødegård-Sørensen', senderTitle: nb ? 'P01 Plattformingeniør' : 'P01 Platform engineer',
senderName: european ? 'R01 Åse Émilie Müller Žák Łódź Sørensen' : 'R01 Åse Ødegård-Sørensen', senderTitle: nb ? 'P01 Plattformingeniør' : 'P01 Platform engineer',
senderEmail: 'fictional.ase@example.test', senderLocation: 'Tromsø, Norge',
recipient: 'R03 Fictional hiring team\nFictional Fjord Systems AS\nTromsø, Norge',
subject: nb ? 'R02 Søknad om plattformingeniør' : 'R02 Application for platform engineer', date: '2026-10-27', pageSize: 'a4' };
@@ -66,6 +68,8 @@ test('[PRE-P10 B] nine matching letter designs retain short EN and long NB physi
await page.setViewportSize({ width: 794, height: 1123 });
await page.setContent(previewDocumentHtml(rendered.html, 297 * 96 / 25.4));
await expect.poll(() => page.evaluate(() => document.documentElement.dataset.cvPreviewReady), { message: fixture }).toBe('true');
const nameInkClearancePx = await page.evaluate(minimumNameInkClearance, 'h1');
expect(nameInkClearancePx, `${fixture} full sender name ink stays inside print fragment`).toBeGreaterThanOrEqual(0);
const measured = await page.evaluate(() => {
const data = document.documentElement.dataset;
const width = Number(data.cvPreviewWidth), height = Number(data.cvPreviewHeight);
@@ -112,13 +116,14 @@ test('[PRE-P10 B] nine matching letter designs retain short EN and long NB physi
await page.screenshot({ path: path.join(directory, `preview-${index + 1}.png`) });
}
expect(await (await page.request.get(letterUrl)).json()).toEqual(saved);
fixtures.push({ fixture, settings: saved.documentSettings, expectedMarkers, expectedParagraphs: paragraphs,
(european ? europeanControls : fixtures).push({ fixture, settings: saved.documentSettings, expectedMarkers, expectedParagraphs: paragraphs, nameInkClearancePx,
expectedRecipient: documentSettings.recipient, expectedSender: documentSettings.senderName, expectedSubject: documentSettings.subject,
previewPages: measured.pages, measured, savedRevision: saved.revision, htmlSha256: sha256(rendered.html), pdfSha256: sha256(bytes) });
await fs.writeFile(path.join(output, 'measurements.json'), JSON.stringify({ browserVersion: browser.version(), fixtures }, null, 2));
await fs.writeFile(path.join(output, 'measurements.json'), JSON.stringify({ browserVersion: browser.version(), fixtures, europeanControls }, null, 2));
}
}
expect(fixtures).toHaveLength(18);
expect(europeanControls).toHaveLength(9);
expect(await (await page.request.get(`${api}/career/profile`)).json()).toEqual(sourceBefore);
await info.attach('matching-letter-library-measurements', { path: path.join(output, 'measurements.json'), contentType: 'application/json' });
});