Files
homepage/tests/e2e/01-page.spec.js
T
ducoterra 3898dc3c5e Add Playwright E2E suite against the built dist/
Pin @playwright/test 1.62.0 (matches the cached chromium
revision) and serve dist/ via python3 http.server, so the
deployed artifact is what gets tested. Covers page load,
terminal commands, vim mode, achievements, and the nav menu.
Ignore node_modules, test-results, playwright-report, and the
phased-execution runtime scratch (.agents/phase-sessions,
pipeline.log).
2026-09-18 17:23:30 -04:00

78 lines
3.5 KiB
JavaScript

// @ts-check
const { test, expect } = require('@playwright/test');
test.describe('Page structure', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/');
});
test('loads with correct title and lang', async ({ page }) => {
await expect(page).toHaveTitle(/Reese Wells/);
await expect(page.locator('html')).toHaveAttribute('lang', 'en');
});
test('nav has all seven section links pointing at existing targets', async ({ page }) => {
const links = page.locator('#navLinks a');
await expect(links).toHaveCount(7);
const hrefs = await links.evaluateAll(as => as.map(a => a.getAttribute('href')));
expect(hrefs).toEqual(['#hero', '#about', '#experience', '#skills', '#projects', '#contact', '#gpg']);
for (const href of hrefs) {
await expect(page.locator(href)).toBeAttached();
}
});
test('all major sections exist and are in the DOM', async ({ page }) => {
for (const id of ['hero', 'about', 'experience', 'skills', 'projects', 'contact', 'gpg']) {
await expect(page.locator(`#${id}`)).toBeAttached();
}
});
test('profile image loads', async ({ page }) => {
const img = page.locator('#about img');
await expect(img).toBeVisible();
await expect.poll(async () =>
page.evaluate(() => document.querySelector('#about img').naturalWidth)
).toBeGreaterThan(0);
});
test('server rack background is generated with a terminal unit', async ({ page }) => {
const rack = page.locator('.server-rack-bg .rack-container');
await expect(rack).toBeAttached();
await expect(rack.locator('.rack-unit')).not.toHaveCount(0);
await expect(page.locator('.terminal-display')).toBeAttached();
});
test('GPG section shows both fingerprints and key blocks', async ({ page }) => {
await expect(page.locator('#gpg .gpg-key-card')).toHaveCount(2);
await expect(page.locator('#gpg .gpg-key-fingerprint code').first()).toHaveText(
'7FC1 B297 0011 4F4F C589 E706 5FDD CFA5 44D7 7B8C');
await expect(page.locator('#gpg .gpg-key-fingerprint code').last()).toHaveText(
'2FF3 619F A6CA 2A4C FA2D 3532 816E 5FE7 8271 602B');
const blocks = page.locator('#gpg .gpg-key-block');
await expect(blocks).toHaveCount(2);
for (const block of [blocks.first(), blocks.last()]) {
await expect(block).toContainText('BEGIN PGP PUBLIC KEY BLOCK');
await expect(block).toContainText('END PGP PUBLIC KEY BLOCK');
}
});
test('external links all carry rel="noopener"', async ({ page }) => {
const links = page.locator('a[target="_blank"]');
const count = await links.count();
expect(count).toBeGreaterThan(0);
for (let i = 0; i < count; i++) {
await expect(links.nth(i)).toHaveAttribute('rel', /noopener/);
}
});
test('hashed assets are referenced and served', async ({ page }) => {
const html = await page.content();
expect(html).toMatch(/<link rel="stylesheet" href="style\.[0-9a-f]{32}\.css"/);
expect(html).toMatch(/<script src="terminal\.[0-9a-f]{32}\.js" defer="?">/);
expect(html).toMatch(/<script src="script\.[0-9a-f]{32}\.js" defer="?">/);
const resp = await page.request.get(page.url().replace(/\/$/, '') + '/' +
(await page.locator('link[rel="stylesheet"]').getAttribute('href')));
expect(resp.ok()).toBeTruthy();
});
});