Files
Genarrative/apps/ai-game-creator-shell/tests/resourceBookModel.test.ts
T
suzmii 2f8753f597 AGC 资源画布切换为 6 类资产分类加项目版本栏目(阶段二:投影轴与栏目表落地)
- 契约层把 ProjectResourceCanvasPosition.section 加宽为 PersistedProjectResourceCanvasSection 并删除旧 ProjectResourceCanvasSection 联合
- 七个分区类型消费点改用 ProjectResourceCanvasCategory:投影、布局模型、布局 Hook、分区高度、依赖图层与画布历史
- RESOURCE_CANVAS_SECTION_ORDER 改为 PROJECT_RESOURCE_CANVAS_SECTIONS,删除 RESOURCE_CANVAS_VISIBLE_SECTION_ORDER
- reconcileResourceCanvasLayout 接入读时归一化:旧栏目值按资源当前分区改写 section,坐标与手动标记原样保留
- 归并后的布局与原布局逐项不同,由既有协调路径判定 changed 并写回一次新分区,不引入迁移脚本
- 投影层五个资源入表点统一走 projectResourceCanvasCategory:项目版本独立成栏、Agent 回执归文档、其余按资产分类
- 新增 projectResourceDisplayKind 收敛 manifest 资产 subtype 即 kind 的显示类型口径,projectResourceTypeLabel 不再依赖旧栏目
- 卡片预览、编辑分流、媒体工具条、预览文案与画布历史快照改用显示类型与新分区,历史快照入栈时收窄到现行分区
- index.tsx 删除可见栏目导入与 visibleCategoryOrder,栏目标签由资源筛选唯一中文口径派生并补齐 7 栏
- index.tsx 补齐 7 栏默认视口与 7 个栏目图标(新增 LayoutGrid、Users、PackageOpen,移除已无用的 Code2)
- index.tsx 删除 canvasResources 的 code 过滤:只登记游戏代码的项目现在落在待归类栏目并正常显示卡片
- 新增只登记游戏代码项目的 UI 回归用例,覆盖栏目大纲、默认落地栏目与代码卡片渲染
- 测试夹具按新分区轴迁移,新增旧栏目 sidecar 读时归并用例与栏目顺序用例
- 共享测试 harness 的资源卡查询正则允许栏目标签自带空格(UI 交互)
- 同步 PRD 与共享记忆决策记录的栏目口径描述
2026-09-10 20:41:19 +08:00

165 lines
4.8 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import {
initialResourceBookState,
resourceBookCategoryCardPresentation,
resourceBookReducer,
resourceBookSceneCategory,
resourceBookShowsExitingCards,
resourceBookShowsOverviewCards,
} from '../src/view/project-development/resourceBookModel';
describe('resource book state machine', () => {
it('keeps overview titles and preview cards visible on the steady main canvas', () => {
expect(resourceBookShowsOverviewCards(initialResourceBookState)).toBe(true);
});
it('commits the child target immediately and only keeps the motion phase transient', () => {
const entering = resourceBookReducer(initialResourceBookState, {
type: 'open-category',
category: 'document',
token: 1,
});
expect(entering).toMatchObject({
view: 'child',
category: 'document',
phase: 'entering',
token: 1,
});
expect(resourceBookSceneCategory(entering)).toBe('document');
});
it('retargets directly from one child canvas to another', () => {
const current = resourceBookReducer(initialResourceBookState, {
type: 'open-category',
category: 'document',
token: 1,
});
const switching = resourceBookReducer(current, {
type: 'open-category',
category: 'scene',
token: 2,
});
expect(switching).toMatchObject({
view: 'child',
category: 'scene',
phase: 'entering',
});
expect(resourceBookSceneCategory(switching)).toBe('scene');
});
it('marks a return to the main canvas separately from a child enter transition', () => {
const entering = resourceBookReducer(initialResourceBookState, {
type: 'open-category',
category: 'document',
token: 1,
});
const returning = resourceBookReducer(entering, {
type: 'return-to-main',
token: 2,
});
expect(returning).toMatchObject({
view: 'main',
category: null,
phase: 'returning-main',
});
});
it('lets an explicit collapse cancel an in-flight child switch', () => {
const entering = resourceBookReducer(initialResourceBookState, {
type: 'open-category',
category: 'document',
token: 1,
});
const switching = resourceBookReducer(entering, {
type: 'open-category',
category: 'scene',
token: 2,
});
const main = resourceBookReducer(switching, {
type: 'return-to-main',
token: 3,
});
expect(main).toMatchObject({
view: 'main',
category: null,
phase: 'returning-main',
token: 3,
});
});
it('ignores stale transition callbacks', () => {
const entering = resourceBookReducer(initialResourceBookState, {
type: 'open-category',
category: 'document',
token: 1,
});
const switched = resourceBookReducer(entering, {
type: 'open-category',
category: 'scene',
token: 2,
});
expect(
resourceBookReducer(switched, { type: 'finish-transition', token: 1 }),
).toEqual(switched);
});
});
describe('resource book card presentation', () => {
it('uses the overview stack on the steady main canvas', () => {
expect(
resourceBookCategoryCardPresentation(initialResourceBookState, 'scene'),
).toBe('overview');
});
it('keeps other categories mounted while entering so they can fade out', () => {
const entering = resourceBookReducer(initialResourceBookState, {
type: 'open-category',
category: 'scene',
token: 1,
});
expect(resourceBookCategoryCardPresentation(entering, 'scene')).toBe(
'child',
);
expect(resourceBookCategoryCardPresentation(entering, 'code')).toBe(
'overview',
);
});
it('drops other categories once the child canvas is steady', () => {
const steady = resourceBookReducer(
resourceBookReducer(initialResourceBookState, {
type: 'open-category',
category: 'scene',
token: 1,
}),
{ type: 'finish-transition', token: 1 },
);
expect(resourceBookCategoryCardPresentation(steady, 'scene')).toBe('child');
expect(resourceBookCategoryCardPresentation(steady, 'code')).toBeNull();
});
it('returns every category to the stack and exposes the exiting window', () => {
const returning = resourceBookReducer(
resourceBookReducer(initialResourceBookState, {
type: 'open-category',
category: 'scene',
token: 1,
}),
{ type: 'return-to-main', token: 2 },
);
expect(resourceBookCategoryCardPresentation(returning, 'scene')).toBe(
'overview',
);
expect(resourceBookCategoryCardPresentation(returning, 'code')).toBe(
'overview',
);
expect(resourceBookShowsExitingCards(returning)).toBe(true);
expect(resourceBookShowsExitingCards(initialResourceBookState)).toBe(false);
});
});