import { test, expect } from '@playwright/test'; async function open(page) { const problems = []; page.on('console', m => { if (m.type() === 'error') problems.push(m.text()); }); page.on('pageerror', e => problems.push(String(e))); await page.goto('./'); await expect(page.getByRole('heading', { name: 'Orgchain' })).toBeVisible(); return problems; } const say = page => page.locator('#say'); const row = (page, name) => page.locator('#tree-rows .sel').filter({ has: page.locator('.l', { hasText: new RegExp(`^${name}$`) }) }); const verb = (page, name) => page.locator(`[data-verb="${name}"]`).click(); const submit = (page, form) => page.locator(`#f-${form} [type="submit"]`).click(); async function found(page, name) { await page.locator('#found-name').fill(name); await submit(page, 'found'); } async function birth(page, name, kind = 'org') { await verb(page, 'birth'); await page.locator('#birth-name').fill(name); await page.locator(`#f-birth input[value="${kind}"]`).check(); await submit(page, 'birth'); } const slide = (page, beat) => page.locator('#beat').evaluate((el, v) => { el.value = v; el.dispatchEvent(new Event('input', { bubbles: true })); }, String(beat)); test('found a holding, then birth, award, decide, graduate and close at the default tempo', async ({ page }) => { const problems = await open(page); await found(page, 'Acme Holdings'); await expect(say(page)).toHaveText('acme-holdings is founded, at beat 2.'); await birth(page, 'studio'); await expect(say(page)).toHaveText('studio is born to acme-holdings, at beat 3.'); await row(page, 'studio').click(); await birth(page, 'bot', 'agent'); await expect(say(page)).toHaveText('bot is born to studio, at beat 4.'); await verb(page, 'award'); await page.locator('#award-to').selectOption({ label: 'acme-holdings / studio / bot (agent)' }); await page.locator('#award-skill').fill('launch'); await page.locator('#award-belt').selectOption('green'); await submit(page, 'award'); await expect(say(page)).toHaveText('bot holds a green belt in launch, at beat 5.'); await verb(page, 'decide'); await page.locator('#decide-title').fill('Ship weekly'); await submit(page, 'decide'); await expect(say(page)).toHaveText('studio decided “Ship weekly”, at beat 6.'); await verb(page, 'graduate'); await page.locator('#graduate-go').click(); await expect(say(page)).toHaveText('studio graduates from acme-holdings, at beat 7. Its edge is adopted now.'); await expect(row(page, 'studio')).toContainText('graduated'); await row(page, 'acme-holdings').click(); await verb(page, 'close'); await page.locator('#close-go').click(); await expect(page.locator('#close-go')).toHaveText('Yes, close acme-holdings'); await page.locator('#close-go').click(); await expect(say(page)).toHaveText('acme-holdings is closed, at beat 8.'); await expect(row(page, 'acme-holdings')).toContainText('closed'); await expect(row(page, 'studio')).not.toContainText('closed'); // graduated: it holds its own root await row(page, 'bot').click(); await verb(page, 'birth'); await expect(page.locator('#act-why')).toHaveText('Agents do not give birth.'); await page.locator('#timeline-list .ev', { hasText: 'Ship weekly' }).click(); await expect(page.locator('#inspect-body')).toContainText('"op": "decide"'); await expect(page.locator('#inspect-body')).toContainText('applied'); expect(problems).toEqual([]); }); test('a timed tempo cues acts; Beat now and the clock land them', async ({ page }) => { const problems = await open(page); await found(page, 'acme'); await page.locator('[data-tempo="10"]').click(); await birth(page, 'a'); await expect(say(page)).toHaveText('a is born to acme, cued for the next beat.'); await birth(page, 'b'); await expect(page.locator('#clock-cued')).toContainText('2 cued · next beat in'); await expect(row(page, 'b')).toContainText('cued'); await page.locator('#beat-now').click(); await expect(say(page)).toHaveText('Beat 3: 2 cued acts landed.'); await birth(page, 'c'); await expect(say(page)).toHaveText('Beat 4: 1 cued act landed.', { timeout: 15_000 }); await page.locator('[data-tempo="manual"]').click(); await birth(page, 'd'); await expect(page.locator('#clock-cued')).toHaveText('1 cued · waiting for Beat now'); await page.locator('[data-tempo="each"]').click(); await expect(page.locator('#clock-cued')).toHaveText('nothing cued'); await expect(page.locator('#clock-beat')).toHaveText('5'); expect(problems).toEqual([]); }); test('the sample replays, any beat can be inspected, and the lab survives a reload', async ({ page }) => { const problems = await open(page); await page.locator('#sample').click(); await expect(say(page)).toContainText('Loaded the yolopreneur sample', { timeout: 20_000 }); await expect(page.locator('#tree-rows .sel')).toHaveCount(12); await expect(page.locator('#beat-label')).toHaveText('Now · beat 7'); await expect(row(page, 'lineage')).toContainText('graduated'); await expect(page.locator('#sample')).toBeDisabled(); await slide(page, 3); await expect(page.locator('#beat-label')).toHaveText('Beat 3 of 7'); await expect(page.locator('#tree-rows .sel')).toHaveCount(3); await expect(page.locator('#act-past')).toBeVisible(); await page.locator('#replay').click(); await expect(page.locator('#beat-label')).toHaveText('Now · beat 7', { timeout: 15_000 }); await page.locator('#timeline-list .ev', { hasText: 'graduate lineage from well-known' }).click(); await expect(page.locator('#inspect-body')).toContainText('"op": "graduate"'); await expect(page.locator('#inspect-body')).toContainText("well-known's key"); await row(page, 'lineage').click(); await expect(page.locator('#inspect-body')).toContainText("lineage root · m/86'/1'/0'/0/0"); await expect(page.locator('#inspect-body')).toContainText('its own key'); await row(page, 'time').click(); await expect(page.locator('#act-key')).toHaveText("Signs as time: yolopreneur root › 1' · m/86'/1'/0'/0/0"); expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true); await page.reload(); await expect(page.locator('#tree-rows .sel')).toHaveCount(12); await page.locator('#theme').click(); await expect(page.locator('html')).toHaveAttribute('data-theme', 'light'); await page.locator('#theme').click(); await page.reload(); await expect(page.locator('html')).toHaveAttribute('data-theme', 'dark'); await expect(page.locator('#theme')).toHaveText('Theme: dark'); await page.locator('#reset').click(); await page.locator('#confirm button', { hasText: 'Erase' }).click(); await expect(say(page)).toHaveText('Erased. This is a fresh lab.'); await expect(page.locator('#holdings-list li')).toHaveCount(0); expect(problems).toEqual([]); });