1d051f8bf9
- Keep game/campaign audio assets referenced (no prune) - Flush pending project save on quit/switch/export to avoid losing campaignAudios - Control: prevent game music restarts on scene changes; allow always-on controls; handle autoplay-after-scene-audio - Editor: reduce ReactFlow churn with stable scene card map; lazy/async image decode - Add contract/unit tests and update test script Made-with: Cursor
102 lines
2.9 KiB
TypeScript
102 lines
2.9 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
|
|
import type { Project } from '../../../shared/types';
|
|
import type { AssetId, SceneId } from '../../../shared/types/ids';
|
|
|
|
import { buildNextSceneCardById } from './sceneCardById';
|
|
|
|
function minimalProject(overrides: Partial<Project>): Project {
|
|
return {
|
|
id: 'p1' as unknown as Project['id'],
|
|
meta: {
|
|
name: 'n',
|
|
fileBaseName: 'f',
|
|
createdAt: '',
|
|
updatedAt: '',
|
|
createdWithAppVersion: '1',
|
|
appVersion: '1',
|
|
schemaVersion: 1 as unknown as Project['meta']['schemaVersion'],
|
|
},
|
|
scenes: {},
|
|
assets: {},
|
|
campaignAudios: [],
|
|
currentSceneId: null,
|
|
currentGraphNodeId: null,
|
|
sceneGraphNodes: [],
|
|
sceneGraphEdges: [],
|
|
...overrides,
|
|
} as unknown as Project;
|
|
}
|
|
|
|
void test('buildNextSceneCardById: does not change refs when irrelevant fields change', () => {
|
|
const sid = 's1' as SceneId;
|
|
const base = minimalProject({
|
|
scenes: {
|
|
[sid]: {
|
|
id: sid,
|
|
title: 'T',
|
|
description: 'A',
|
|
media: { videos: [], audios: [{ assetId: 'a1' as AssetId, autoplay: false, loop: true }] },
|
|
settings: { autoplayVideo: false, autoplayAudio: false, loopVideo: false, loopAudio: false },
|
|
connections: [],
|
|
layout: { x: 0, y: 0 },
|
|
previewAssetId: null,
|
|
previewAssetType: null,
|
|
previewVideoAutostart: false,
|
|
previewRotationDeg: 0,
|
|
},
|
|
} as unknown as Project['scenes'],
|
|
});
|
|
|
|
const first = buildNextSceneCardById({}, base);
|
|
const card1 = first[sid];
|
|
assert.ok(card1);
|
|
|
|
const changedOnlyDescription = minimalProject({
|
|
...base,
|
|
scenes: {
|
|
...base.scenes,
|
|
[sid]: { ...base.scenes[sid], description: 'B' },
|
|
},
|
|
});
|
|
const second = buildNextSceneCardById(first, changedOnlyDescription);
|
|
|
|
assert.equal(second, first, 'record identity should be reused');
|
|
assert.equal(second[sid], card1, 'card identity should be reused');
|
|
});
|
|
|
|
void test('buildNextSceneCardById: changes card when title changes', () => {
|
|
const sid = 's1' as SceneId;
|
|
const base = minimalProject({
|
|
scenes: {
|
|
[sid]: {
|
|
id: sid,
|
|
title: 'T',
|
|
description: '',
|
|
media: { videos: [], audios: [] },
|
|
settings: { autoplayVideo: false, autoplayAudio: false, loopVideo: false, loopAudio: false },
|
|
connections: [],
|
|
layout: { x: 0, y: 0 },
|
|
previewAssetId: null,
|
|
previewAssetType: null,
|
|
previewVideoAutostart: false,
|
|
previewRotationDeg: 0,
|
|
},
|
|
} as unknown as Project['scenes'],
|
|
});
|
|
const first = buildNextSceneCardById({}, base);
|
|
const card1 = first[sid];
|
|
|
|
const changedTitle = minimalProject({
|
|
...base,
|
|
scenes: {
|
|
...base.scenes,
|
|
[sid]: { ...base.scenes[sid], title: 'T2' },
|
|
},
|
|
});
|
|
const second = buildNextSceneCardById(first, changedTitle);
|
|
|
|
assert.notEqual(second[sid], card1);
|
|
});
|