Files
gmtool/tests/components/gm-shell-hub.test.js
T
slaguru666andClaude Opus 4.8 b57880d630 feat: Slice 5 — convention hub (live now / up next, deep-links)
Add the convention hub landing screen: a pure schedule engine
(analyzeSchedule) classifies each slot as live/next/done/upcoming from an
injected now; <con-hub> renders the slate + summary and emits open-scenario;
a scenario registry resolves a slot's scenarioId to its module; gm-shell
routes hub<->session (hiding/restoring the Rail) with a home rail chip.

Ships continuum-2026.js with the real slate (only AFTERIMAGE ported;
others scenarioId:null, start-times TBC) and a fully-timed example-con.js
template/fixture. 122 tests pass; build clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 21:35:47 +01:00

49 lines
2.0 KiB
JavaScript

import { describe, it, expect, beforeEach } from 'vitest';
import '../../src/components/gm-shell.js';
import continuum from '../../src/con/continuum-2026.js';
describe('<gm-shell> convention hub', () => {
let el;
beforeEach(() => {
localStorage.clear();
document.body.innerHTML = '';
el = document.createElement('gm-shell');
el.now = () => 0;
document.body.appendChild(el);
el.loadCon(continuum);
});
it('boots into the hub with the rail and stage hidden', () => {
expect(el.querySelector('con-hub').hidden).toBe(false);
expect(el.querySelector('director-rail').hidden).toBe(true);
expect(el.querySelector('.stage').hidden).toBe(true);
expect(el.querySelector('con-hub').con).toBe(continuum);
});
it('deep-links a ported slot into a session and hides the hub', () => {
el.dispatchEvent(new CustomEvent('open-scenario', { detail: { scenarioId: 'afterimage' }, bubbles: true }));
expect(el.scenario.meta.id).toBe('afterimage');
expect(el.querySelector('con-hub').hidden).toBe(true);
expect(el.querySelector('director-rail').hidden).toBe(false);
expect(el.querySelector('.stage').hidden).toBe(false);
expect(el.querySelector('director-rail [data-role=here]').textContent).toContain('The pier');
});
it('ignores open-scenario for an unknown / unported slot', () => {
el.dispatchEvent(new CustomEvent('open-scenario', { detail: { scenarioId: 'not-ported' }, bubbles: true }));
expect(el.scenario).toBe(null);
expect(el.querySelector('con-hub').hidden).toBe(false);
});
it('the rail hub chip emits open-hub, returning to the hub', () => {
el.dispatchEvent(new CustomEvent('open-scenario', { detail: { scenarioId: 'afterimage' }, bubbles: true }));
const rail = el.querySelector('director-rail');
let fired = 0;
el.addEventListener('open-hub', () => fired++);
rail.querySelector('[data-role=open-hub]').click();
expect(fired).toBe(1);
expect(el.querySelector('con-hub').hidden).toBe(false);
expect(rail.hidden).toBe(true);
});
});