feat: add BaseLayout with SEO head tags and theme init script

Canonical/hreflang/OG tags derived from the locale dictionary, plus a
pre-paint script applying data-theme from localStorage or system
preference.
This commit is contained in:
2026-08-02 15:54:42 +02:00
parent 2606508713
commit 1d65bb7aa8
6 changed files with 238 additions and 21 deletions
+40
View File
@@ -0,0 +1,40 @@
import { describe, it, expect, beforeAll } from 'vitest';
import { execSync } from 'node:child_process';
import { readFileSync } from 'node:fs';
describe('BaseLayout SEO tags and theming', () => {
beforeAll(() => {
execSync('npm run build', { stdio: 'inherit' });
});
it('sets canonical and hreflang alternates pointing at each other', () => {
const en = readFileSync('dist/en/index.html', 'utf-8');
const fr = readFileSync('dist/fr/index.html', 'utf-8');
expect(en).toContain('rel="canonical" href="https://www.ombrora.com/en/"');
expect(en).toContain('hreflang="fr" href="https://www.ombrora.com/fr/"');
expect(fr).toContain('rel="canonical" href="https://www.ombrora.com/fr/"');
expect(fr).toContain('hreflang="en" href="https://www.ombrora.com/en/"');
});
it('uses the locale-specific meta title and description', () => {
const en = readFileSync('dist/en/index.html', 'utf-8');
const fr = readFileSync('dist/fr/index.html', 'utf-8');
expect(en).toContain('<title>Ombrora — Security tracking and file tools</title>');
expect(fr).toContain('<title>Ombrora — Veille sécurité et outils de fichiers</title>');
});
it('includes a pre-paint theme script keyed on ombrora-theme', () => {
const en = readFileSync('dist/en/index.html', 'utf-8');
expect(en).toContain("localStorage.getItem('ombrora-theme')");
expect(en).toContain('prefers-color-scheme: light');
});
it('applies the global stylesheet (inlined or linked)', () => {
const en = readFileSync('dist/en/index.html', 'utf-8');
const hasInlineStyle = /<style>[\s\S]*--accent[\s\S]*<\/style>/.test(en);
const hasStylesheetLink = /<link rel="stylesheet"[^>]*href="[^"]+\.css"/.test(en);
expect(hasInlineStyle || hasStylesheetLink).toBe(true);
});
});