48 lines
2.8 KiB
TypeScript
48 lines
2.8 KiB
TypeScript
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)
|
|
})
|
|
})
|