Uncommitted sx-tools changes: WASM bundles, Playwright specs, engine fixes
WASM browser bundles rebuilt with latest kernel. Playwright test specs updated (helpers, navigation, handler-responses, hypermedia-handlers, isomorphic, SPA navigation). Engine/boot/orchestration SX files updated. Handler examples and not-found page refreshed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -51,29 +51,63 @@ test.describe('Page Navigation', () => {
|
||||
// afterEach handles assertion
|
||||
});
|
||||
|
||||
test('copyright shows current route after SX navigation', async ({ page }) => {
|
||||
await loadPage(page, '');
|
||||
test('copyright updates path after SX navigation', async ({ page }) => {
|
||||
await loadPage(page, '(geography)');
|
||||
|
||||
// Mark the page to verify SX navigation (not full reload)
|
||||
await page.evaluate(() => window.__sx_nav_marker = true);
|
||||
|
||||
// Before: copyright shows the current path
|
||||
// Before: copyright shows geography path
|
||||
const before = await page.evaluate(() =>
|
||||
document.querySelector('[data-sx-lake="copyright"]')?.textContent);
|
||||
expect(before).toContain('/sx/');
|
||||
expect(before).toContain('/sx/(geography)');
|
||||
|
||||
// Navigate via SX (sx-get link)
|
||||
await page.click('a[sx-get*="(geography)"]');
|
||||
await expect(page).toHaveURL(/geography/, { timeout: 5000 });
|
||||
// Navigate via SX to Reactive Islands
|
||||
await page.click('a[sx-get*="(geography.(reactive))"]:not([href*="runtime"])');
|
||||
await expect(page).toHaveURL(/reactive/, { timeout: 5000 });
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// Verify SX navigation (marker survives SX nav, lost on reload)
|
||||
const marker = await page.evaluate(() => window.__sx_nav_marker);
|
||||
expect(marker).toBe(true);
|
||||
|
||||
// After: copyright lake still visible (lakes persist across SPA nav)
|
||||
// After: copyright must show the NEW path, not the old one
|
||||
const after = await page.evaluate(() =>
|
||||
document.querySelector('[data-sx-lake="copyright"]')?.textContent);
|
||||
expect(after).toContain('Giles Bradshaw');
|
||||
expect(after).toContain('(reactive)');
|
||||
});
|
||||
|
||||
test('back button reverses nav and copyright to previous page', async ({ page }) => {
|
||||
await loadPage(page, '');
|
||||
|
||||
// Home page: nav shows top-level sections, copyright shows /sx/
|
||||
await expect(page.locator('#sx-nav')).toContainText('Geography');
|
||||
await expect(page.locator('#sx-nav')).toContainText('Language');
|
||||
const homeCopyright = await page.evaluate(() =>
|
||||
document.querySelector('[data-sx-lake="copyright"]')?.textContent);
|
||||
expect(homeCopyright).toContain('/sx/');
|
||||
expect(homeCopyright).not.toContain('(language)');
|
||||
|
||||
// Navigate to Language
|
||||
await page.click('a[sx-get*="(language)"]');
|
||||
await expect(page).toHaveURL(/language/, { timeout: 5000 });
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// Nav should show Language sub-pages
|
||||
await expect(page.locator('#sx-nav')).toContainText('Docs');
|
||||
const langCopyright = await page.evaluate(() =>
|
||||
document.querySelector('[data-sx-lake="copyright"]')?.textContent);
|
||||
expect(langCopyright).toContain('(language)');
|
||||
|
||||
// Go back
|
||||
await page.goBack();
|
||||
await expect(page).toHaveURL(/\/sx\/?$/, { timeout: 5000 });
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// Nav must revert to home top-level sections
|
||||
await expect(page.locator('#sx-nav')).toContainText('Geography');
|
||||
await expect(page.locator('#sx-nav')).toContainText('Language');
|
||||
// Must NOT still show Language sub-pages
|
||||
await expect(page.locator('#sx-nav')).not.toContainText('Docs');
|
||||
|
||||
// Copyright must revert to /sx/
|
||||
const backCopyright = await page.evaluate(() =>
|
||||
document.querySelector('[data-sx-lake="copyright"]')?.textContent);
|
||||
expect(backCopyright).toContain('/sx/');
|
||||
expect(backCopyright).not.toContain('(language)');
|
||||
});
|
||||
|
||||
test('stepper persists index across navigation', async ({ page }) => {
|
||||
@@ -89,15 +123,25 @@ test.describe('Page Navigation', () => {
|
||||
const initial = await getIndex();
|
||||
expect(initial).not.toBeNull();
|
||||
|
||||
// Advance the stepper
|
||||
// Step back first (initial may be at max), then forward
|
||||
await page.evaluate(() => {
|
||||
const btns = document.querySelectorAll('[data-sx-island="home/stepper"] button');
|
||||
if (btns.length >= 2) btns[0].click(); // back button
|
||||
});
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
const backed = await getIndex();
|
||||
expect(backed).toBe(initial - 1);
|
||||
|
||||
// Now advance
|
||||
await page.evaluate(() => {
|
||||
const btns = document.querySelectorAll('[data-sx-island="home/stepper"] button');
|
||||
if (btns.length >= 2) btns[1].click(); // next button
|
||||
});
|
||||
await page.waitForTimeout(300);
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
const advanced = await getIndex();
|
||||
expect(advanced).toBe(initial + 1);
|
||||
expect(advanced).toBe(backed + 1);
|
||||
|
||||
// Navigate away
|
||||
await page.click('a[sx-get*="(geography)"]');
|
||||
@@ -188,7 +232,10 @@ test.describe('Page Navigation', () => {
|
||||
function snap(el) {
|
||||
if (el.nodeType === 3) { const t = el.textContent.trim(); return t ? { t } : null; }
|
||||
if (el.nodeType !== 1) return null;
|
||||
const n = { tag: el.tagName.toLowerCase() };
|
||||
const tag = el.tagName.toLowerCase();
|
||||
// Skip style/script elements — they differ between SSR and SPA (hoisting)
|
||||
if (tag === 'style' || tag === 'script') return null;
|
||||
const n = { tag };
|
||||
if (el.id) n.id = el.id;
|
||||
const cls = Array.from(el.classList).sort().join(' ');
|
||||
if (cls) n.cls = cls;
|
||||
|
||||
Reference in New Issue
Block a user