V2 Phase 5+6: connectivity, presence, navigation & friction
Phase 5 — live-session & multi-device hardening: - connectivityStore + SyncStatusIndicator in the shell: shows "Offline" when the browser is offline and the cloud autosave state (saving / saved / failed) when signed in; useCloudAutosave now reports its status. Owns online/offline events. - server presence heartbeat: protocol-level ping/pong per socket terminates a vanished connection (~30s), so a player who closes their laptop drops out of the GM's roster instead of lingering. No client changes needed. Phase 6 — onboarding & friction: - navigation: surfaced the previously orphaned routes in the rail — a new "World" group (Notes, NPCs, Quests, Calendar) and Homebrew + Assistant under Reference. (Empty-state hints and map rename already existed.) - combat keyboard control: n/→ next turn, p/← previous turn, guarded so it never fires while typing; button tooltips document it. Test hygiene: scoped now-ambiguous nav links in e2e to the Primary landmark, and fixed pre-existing stale emoji selectors in the realtime suite (📡 Host → Host, 📨 Just for you → Just for you) left over from the Living Codex emoji purge. Gate green: tsc + 277 unit + 34 e2e + 2 realtime. App + server build clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -33,7 +33,8 @@ test('level-up advisor offers routes and expands a chosen one (deterministic)',
|
||||
test('assistant page renders the campaign insights section', async ({ page }) => {
|
||||
await page.getByLabel('Settings').click();
|
||||
await page.getByRole('button', { name: 'Load sample campaign' }).click();
|
||||
await page.getByRole('link', { name: 'Assistant' }).click();
|
||||
await expect(page.getByRole('heading', { name: 'Sample: Lost Mine' })).toBeVisible();
|
||||
await page.getByLabel('Primary').getByRole('link', { name: 'Assistant' }).click();
|
||||
await expect(page.getByRole('heading', { name: 'Campaign insights' })).toBeVisible();
|
||||
// Sample has a single encounter → not enough for a trend yet.
|
||||
await expect(page.getByText(/No trends detected yet/)).toBeVisible();
|
||||
|
||||
@@ -23,7 +23,7 @@ test('assistant flags a bloodied PC and builds an encounter', async ({ page }) =
|
||||
|
||||
// Assistant shows a resource suggestion
|
||||
await page.getByLabel('Primary').getByRole('link', { name: 'Dashboard' }).click();
|
||||
await page.getByRole('link', { name: 'Assistant' }).click();
|
||||
await page.getByLabel('Primary').getByRole('link', { name: 'Assistant' }).click();
|
||||
await expect(page.getByRole('heading', { name: 'Assistant' })).toBeVisible();
|
||||
await expect(page.getByText(/Lia the Brave is bloodied/)).toBeVisible();
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ test('homebrew: create a custom monster and find it in the compendium', async ({
|
||||
await page.locator('input[data-autofocus]').fill('Brew');
|
||||
await page.getByRole('button', { name: 'Create' }).click();
|
||||
await page.getByRole('link', { name: 'Dashboard' }).click();
|
||||
await page.getByRole('link', { name: 'Homebrew' }).click();
|
||||
await page.getByLabel('Primary').getByRole('link', { name: 'Homebrew' }).click();
|
||||
|
||||
// Create a homebrew monster and name it
|
||||
await page.getByRole('button', { name: /New monster/ }).click();
|
||||
|
||||
@@ -30,13 +30,13 @@ test('worldbuilding: dashboard, note with wiki link, npc, quest, calendar', asyn
|
||||
|
||||
// NPC
|
||||
await page.getByRole('link', { name: 'Dashboard' }).click();
|
||||
await page.getByRole('link', { name: 'NPCs' }).click();
|
||||
await page.getByLabel('Primary').getByRole('link', { name: 'NPCs' }).click();
|
||||
await page.getByRole('button', { name: '+ New NPC' }).first().click();
|
||||
await expect(page.getByLabel('NPC name')).toBeVisible();
|
||||
|
||||
// Quest with an objective
|
||||
await page.getByRole('link', { name: 'Dashboard' }).click();
|
||||
await page.getByRole('link', { name: 'Quests' }).click();
|
||||
await page.getByLabel('Primary').getByRole('link', { name: 'Quests' }).click();
|
||||
await page.getByRole('button', { name: '+ New quest' }).first().click();
|
||||
await page.getByPlaceholder('Add objective…').fill('Find the Tome');
|
||||
await page.getByRole('button', { name: 'Add', exact: true }).click();
|
||||
@@ -44,7 +44,7 @@ test('worldbuilding: dashboard, note with wiki link, npc, quest, calendar', asyn
|
||||
|
||||
// Calendar advances days
|
||||
await page.getByRole('link', { name: 'Dashboard' }).click();
|
||||
await page.getByRole('link', { name: 'Calendar' }).click();
|
||||
await page.getByLabel('Primary').getByRole('link', { name: 'Calendar' }).click();
|
||||
await page.getByRole('button', { name: '+1 week' }).click();
|
||||
await expect(page.getByText('7', { exact: true })).toBeVisible();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user