Files
rose-ash/tests/playwright/geography-demos.spec.js
giles e14947cedc Add sx:ready hydration signal, eliminate test sleeps
boot-init now sets data-sx-ready on <html> and dispatches an sx:ready
CustomEvent after all islands are hydrated. Playwright tests use this
instead of networkidle + hard-coded sleeps (50+ seconds eliminated).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 12:47:52 +00:00

198 lines
6.8 KiB
JavaScript

// @ts-check
/**
* Geography demos — comprehensive page load + interaction tests.
*/
const { test, expect } = require('playwright/test');
const { loadPage } = require('./helpers');
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
async function expectIsland(page, pattern) {
const island = page.locator(`[data-sx-island*="${pattern}"]`);
await expect(island).toBeVisible({ timeout: 8000 });
return island;
}
// ===========================================================================
// Geography section index pages
// ===========================================================================
test.describe('Geography sections', () => {
const sections = [
['(geography)', 'Geography'],
['(geography.(reactive))', 'Reactive'],
['(geography.(hypermedia))', 'Hypermedia'],
['(geography.(marshes))', 'Marshes'],
['(geography.(scopes))', 'Scopes'],
['(geography.(cek))', 'CEK'],
['(geography.(isomorphism))', 'Isomorphism'],
['(geography.(spreads))', 'Spreads'],
['(geography.(provide))', 'Provide'],
];
for (const [path, text] of sections) {
test(`${path} loads`, async ({ page }) => {
await loadPage(page, path);
const root = page.locator('#sx-root');
expect(await root.textContent()).toContain(text);
});
}
});
// ===========================================================================
// Reactive demos — each test is isolated but fast (cached)
// ===========================================================================
test.describe('Reactive demos', () => {
const demos = [
['counter', 'counter'],
['temperature', 'temperature'],
['stopwatch', 'stopwatch'],
['input-binding', 'input-binding'],
['dynamic-class', 'dynamic-class'],
['reactive-list', 'reactive-list'],
['stores', 'store-writer'],
['refs', 'refs'],
['portal', 'portal'],
['resource', null],
['imperative', null],
['transition', null],
['error-boundary', null],
['event-bridge-demo', null],
['defisland', null],
['coverage', null],
];
for (const [slug, islandPattern] of demos) {
test(`${slug} loads`, async ({ page }) => {
await loadPage(page, `(geography.(reactive.(examples.${slug})))`);
if (islandPattern) await expectIsland(page, islandPattern);
});
}
test('counter: buttons change count', async ({ page }) => {
await loadPage(page, '(geography.(reactive.(examples.counter)))');
const el = await expectIsland(page, 'counter');
const buttons = el.locator('button');
await expect(buttons).toHaveCount(2);
const textBefore = await el.textContent();
await buttons.last().click();
await page.waitForTimeout(300);
expect(await el.textContent()).not.toBe(textBefore);
});
test('temperature: buttons change conversion', async ({ page }) => {
await loadPage(page, '(geography.(reactive.(examples.temperature)))');
const el = await expectIsland(page, 'temperature');
const buttons = el.locator('button');
if (await buttons.count() >= 2) {
const textBefore = await el.textContent();
await buttons.last().click();
await page.waitForTimeout(300);
expect(await el.textContent()).not.toBe(textBefore);
}
});
test('stores: shared state across islands', async ({ page }) => {
await loadPage(page, '(geography.(reactive.(examples.stores)))');
await expect(page.locator('[data-sx-island*="store-reader"]')).toBeVisible({ timeout: 8000 });
await expect(page.locator('[data-sx-island*="store-writer"]')).toBeVisible({ timeout: 8000 });
});
});
// ===========================================================================
// Hypermedia demos
// ===========================================================================
test.describe('Hypermedia demos', () => {
const demos = [
'click-to-load', 'form-submission', 'polling', 'delete-row', 'edit-row',
'tabs', 'active-search', 'inline-validation', 'lazy-loading',
'infinite-scroll', 'select-filter', 'loading-states', 'dialogs',
'oob-swaps', 'bulk-update', 'animations', 'inline-edit', 'progress-bar',
'swap-positions', 'sync-replace', 'keyboard-shortcuts', 'json-encoding',
'put-patch', 'retry', 'reset-on-submit', 'value-select', 'vals-and-headers',
];
for (const slug of demos) {
test(`${slug} loads`, async ({ page }) => {
await loadPage(page, `(geography.(hypermedia.(example.${slug})))`);
});
}
});
// ===========================================================================
// Cross-navigation reactivity
// ===========================================================================
test('counter → temperature → counter: all stay reactive', async ({ page }) => {
await loadPage(page, '(geography.(reactive.(examples.counter)))');
let el = await expectIsland(page, 'counter');
let buttons = el.locator('button');
let before = await el.textContent();
await buttons.last().click();
await page.waitForTimeout(300);
expect(await el.textContent()).not.toBe(before);
// SPA navigate to temperature
const tempLink = page.locator('a[href*="temperature"]').first();
if (await tempLink.count() > 0) {
await tempLink.click();
el = await expectIsland(page, 'temperature');
buttons = el.locator('button');
if (await buttons.count() >= 2) {
before = await el.textContent();
await buttons.last().click();
await page.waitForTimeout(300);
expect(await el.textContent()).not.toBe(before);
}
}
// SPA navigate back to counter
const counterLink = page.locator('a[href*="counter"]').first();
if (await counterLink.count() > 0) {
await counterLink.click();
el = await expectIsland(page, 'counter');
buttons = el.locator('button');
before = await el.textContent();
await buttons.last().click();
await page.waitForTimeout(300);
expect(await el.textContent()).not.toBe(before);
}
});
// ===========================================================================
// Other geography pages
// ===========================================================================
test.describe('Other geography pages', () => {
const pages = [
'(geography.(cek.demo))', '(geography.(cek.content))', '(geography.(cek.freeze))',
'(geography.(marshes.hypermedia-feeds))', '(geography.(marshes.on-settle))',
'(geography.(marshes.server-signals))', '(geography.(marshes.signal-triggers))',
'(geography.(marshes.view-transform))',
'(geography.(isomorphism))',
];
for (const path of pages) {
test(`${path} loads`, async ({ page }) => {
await loadPage(page, path);
});
}
});
test.describe('Reference pages', () => {
for (const sub of ['attributes', 'events', 'headers', 'js-api']) {
test(`${sub} loads`, async ({ page }) => {
await loadPage(page, `(geography.(hypermedia.(reference.${sub})))`);
});
}
});