import { describe, expect, it } from 'vitest' import type { CaseState, DocumentExhibit, NoteExhibit } from '../src/types.js' import { filterLevelVisibility, mergePlayerStateForPersistence } from './levelVisibility.js' const placed = { x: 10, y: 20, width: 174, height: 145, rotation: 0, zIndex: 1, hidden: false } const open: DocumentExhibit = { id: 'open', type: 'document', title: 'Open', body: [], regions: [], fileType: 'image', metadata: {}, ...placed } const gated: DocumentExhibit = { id: 'gated', type: 'document', title: 'Gated', body: [], regions: [], fileType: 'image', metadata: {}, requiredFlags: ['tip.received'], ...placed } const note: NoteExhibit = { id: 'note', type: 'note', title: 'Note', content: '', ...placed } const state: CaseState = { id: 'demo', title: 'Demo', subtitle: '', exhibits: [open, gated, note], viewport: { x: 0, y: 0, zoom: 1 }, relations: [{ id: 'source', type: 'source', fromExhibitId: note.id, toExhibitId: gated.id, sortOrder: 0 }], connections: [{ id: 'thread', fromExhibitId: open.id, toExhibitId: gated.id }], views: [], brief: { body: '', concepts: [] }, goals: [], revision: 0, } describe('level flag visibility', () => { it('hides gated documents and every edge touching them', () => { const visible = filterLevelVisibility(state, [], [], false) expect(visible.exhibits.map(item => item.id)).toEqual(['open', 'note']) expect(visible.relations).toEqual([]) expect(visible.connections).toEqual([]) expect(visible.newlyVisibleDocumentIds).toEqual(['open']) }) it('reveals earned documents once without leaking their gate definition', () => { const visible = filterLevelVisibility(state, ['tip.received'], ['open'], false) expect(visible.exhibits.map(item => item.id)).toEqual(['open', 'gated', 'note']) expect((visible.exhibits[1] as DocumentExhibit).requiredFlags).toBeUndefined() expect(visible.newlyVisibleDocumentIds).toEqual(['gated']) }) it('returns all documents and requirements to author mode', () => { const authored = filterLevelVisibility(state, [], [], true) expect((authored.exhibits[1] as DocumentExhibit).requiredFlags).toEqual(['tip.received']) expect(authored.newlyVisibleDocumentIds).toEqual([]) }) it('preserves unrevealed documents and their edges during a play-mode save', () => { const visible = filterLevelVisibility(state, [], ['open'], false) const submitted = { ...visible, exhibits: visible.exhibits.map(item => item.id === 'open' ? { ...item, x: 99 } : item) } const merged = mergePlayerStateForPersistence(state, visible, submitted) expect(merged.exhibits.find(item => item.id === 'open')?.x).toBe(99) expect(merged.exhibits.find(item => item.id === 'gated')).toMatchObject({ requiredFlags: ['tip.received'] }) expect(merged.relations).toHaveLength(1) expect(merged.connections).toHaveLength(1) }) })