// @ts-check /** * Geography demos — comprehensive page load + interaction tests. */ const { test, expect } = require('playwright/test'); const { loadPage, trackErrors } = 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', () => { let t; test.beforeEach(({ page }) => { t = trackErrors(page); }); test.afterEach(() => { expect(t.errors()).toEqual([]); }); 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', () => { let t; test.beforeEach(({ page }) => { t = trackErrors(page); }); test.afterEach(() => { expect(t.errors()).toEqual([]); }); 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', () => { let t; test.beforeEach(({ page }) => { t = trackErrors(page); }); test.afterEach(() => { expect(t.errors()).toEqual([]); }); 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 }) => { const t = trackErrors(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); } expect(t.errors()).toEqual([]); }); // =========================================================================== // Other geography pages // =========================================================================== test.describe('Other geography pages', () => { let t; test.beforeEach(({ page }) => { t = trackErrors(page); }); test.afterEach(() => { expect(t.errors()).toEqual([]); }); 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', () => { let t; test.beforeEach(({ page }) => { t = trackErrors(page); }); test.afterEach(() => { expect(t.errors()).toEqual([]); }); for (const sub of ['attributes', 'events', 'headers', 'js-api']) { test(`${sub} loads`, async ({ page }) => { await loadPage(page, `(geography.(hypermedia.(reference.${sub})))`); }); } });