diff --git a/app/gateway-frontend/e2e/legacy-log-html.spec.ts b/app/gateway-frontend/e2e/legacy-log-html.spec.ts index 3773e1df..e525ec94 100644 --- a/app/gateway-frontend/e2e/legacy-log-html.spec.ts +++ b/app/gateway-frontend/e2e/legacy-log-html.spec.ts @@ -115,6 +115,13 @@ for (const viewport of [ await expect(lines.nth(1)).toContainText(' getComputedStyle(element).fontFamily); + const historyFontFamily = await page + .locator('.status-history') + .evaluate((element) => getComputedStyle(element).fontFamily); + expect(historyFontFamily).toBe(pageFontFamily); + expect(historyFontFamily).toContain('Pretendard'); + const geometry = await lines.evaluateAll((elements) => elements.map((element) => { const rect = element.getBoundingClientRect(); @@ -144,7 +151,7 @@ for (const viewport of [ const name = `legacy-log-gateway-${viewport.name}`; await writeFile( resolve(artifactRoot, `${name}.json`), - `${JSON.stringify({ viewport, geometry }, null, 2)}\n`, + `${JSON.stringify({ viewport, pageFontFamily, historyFontFamily, geometry }, null, 2)}\n`, 'utf8' ); await page.screenshot({ path: resolve(artifactRoot, `${name}.png`), fullPage: true }); diff --git a/app/gateway-frontend/src/views/HomeView.vue b/app/gateway-frontend/src/views/HomeView.vue index 03361fd6..932f5ddf 100644 --- a/app/gateway-frontend/src/views/HomeView.vue +++ b/app/gateway-frontend/src/views/HomeView.vue @@ -362,7 +362,7 @@ const handlePasswordReset = async (): Promise => { border-top: 1px solid #444; padding: 8px 12px; color: #ddd; - font-family: 'Times New Roman', serif; + font-family: inherit; font-size: 14px; line-height: 1.35; } diff --git a/app/gateway-frontend/test/fontContract.test.mjs b/app/gateway-frontend/test/fontContract.test.mjs new file mode 100644 index 00000000..d8ca7d12 --- /dev/null +++ b/app/gateway-frontend/test/fontContract.test.mjs @@ -0,0 +1,43 @@ +import assert from 'node:assert/strict'; +import { readFile, readdir } from 'node:fs/promises'; +import path from 'node:path'; +import { describe, it } from 'node:test'; + +const sourceRoot = path.resolve(import.meta.dirname, '../src'); +const fontFamilyDeclaration = /font-family\s*:\s*([^;]+);/g; +const fontShorthandDeclaration = /(?:^|[\s{])font\s*:\s*([^;]+);/gm; +const forcedSerifFamily = /Times New Roman|(? { + const entries = await readdir(sourceRoot, { recursive: true, withFileTypes: true }); + + return entries + .filter((entry) => entry.isFile() && (entry.name.endsWith('.css') || entry.name.endsWith('.vue'))) + .map((entry) => path.join(entry.parentPath, entry.name)) + .sort(); +}; + +describe('gateway content font contract', () => { + it('does not force Times New Roman or a generic serif family', async () => { + const violations = []; + + for (const file of await listStyleSources()) { + const source = await readFile(file, 'utf8'); + for (const match of source.matchAll(fontFamilyDeclaration)) { + const value = match[1]?.trim() ?? ''; + if (forcedSerifFamily.test(value)) { + violations.push(`${path.relative(sourceRoot, file)}: font-family: ${value}`); + } + } + + for (const match of source.matchAll(fontShorthandDeclaration)) { + const value = match[1]?.trim() ?? ''; + if (forcedSerifFamily.test(value)) { + violations.push(`${path.relative(sourceRoot, file)}: font: ${value}`); + } + } + } + + assert.deepEqual(violations, []); + }); +});