Files
Genarrative/apps/ai-game-creator-shell/tests/resourceCanvasVersionBindingModel.test.ts
T
suzmii b8849b8c01 优化 AGC 工作台顶栏布局:一行到底、版本入口钉右分级、播放并入运行页签
- 顶栏去掉两侧 flex-wrap、工具条改 overflow: hidden,空间不足按 data-layout 三档降级而不是换行
- 新增 workbenchToolbarModel(档位顺序与 1px 判据)与 useWorkbenchToolbarLayout(ResizeObserver 管宽度、MutationObserver 管内容,实测内容宽度写档位)
- 版本入口 margin-left: auto 钉在动作区最右,标识改「版本 N(原因 · 时间)」,窄档只留「版本 N」(序号复用资源画布版本卡编号口径)
- 新增 WorkbenchMoreActionsMenu:「打开项目目录 / 资源面板 / 整理画布」在 collapsed-actions 档收进「更多」下拉
- 删除独立「播放」按钮,运行页签前加 ▶ 图标,点页签即切视图并载入游戏资源
- 运行画面右下角新增「刷新运行画面」,LocalGamePreviewFrame 新增 reloadNonce 换 iframe 元素身份重新载入页面
- 用例:新增 workbenchToolbarLayout / runPreviewRefresh;改写 appSurface 顶栏与播放/刷新断言、版本标识断言与顶栏样式断言
2026-10-04 14:04:02 +08:00

129 lines
4.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, test } from 'vitest';
import {
currentVersionResourceBindingIds,
formatIterationVersionDetail,
formatIterationVersionLabel,
formatIterationVersionTitle,
isResourceUsedByCurrentVersion,
} from '../src/features/resource-canvas/resourceCanvasVersionBindingModel';
/**
* 夹具必须与落盘口径一致:`versions[].createdAt` 是 **Unix 秒**。
*
* 写入侧见 `project/manifest.rs` 的 `created_at: unix_timestamp()`(`as_secs()`)。
* `1788075047` 取自真机项目 `What do u wanna do kitten` 的 `versions[0].createdAt`,
* 它被当成毫秒渲染时正好是 `1970/1/22 00:41:15`,即真机截图里的 1970 年。
*/
const versions = [
{
versionId: 'version-root',
parentVersionId: null,
projectRevision: 3,
resourceBindings: [
{ slotId: 'asset:asset-player', resourceId: 'asset-player' },
],
createdReason: 'initial' as const,
createdAt: 1_788_075_047,
},
{
versionId: 'version-child',
parentVersionId: 'version-root',
projectRevision: 4,
resourceBindings: [
{ slotId: 'asset:asset-town', resourceId: 'asset-town' },
// 悬空绑定的 slotId 不是恒等映射,不参与「当前使用」判定。
{ slotId: 'player', resourceId: 'asset-player' },
],
createdReason: 'agent-revision' as const,
createdAt: 1_788_075_104,
},
];
describe('运行模块版本绑定判定', () => {
test('falls back to the newest manifest version when no version is selected', () => {
expect(Array.from(currentVersionResourceBindingIds({ versions }))).toEqual([
'asset-town',
]);
});
test('resolves the binding ids of the explicitly selected version', () => {
expect(
Array.from(
currentVersionResourceBindingIds({ versions }, 'version-root'),
),
).toEqual(['asset-player']);
});
test('returns no bindings for a missing version or a manifest without versions', () => {
expect(
currentVersionResourceBindingIds({ versions }, 'version-missing').size,
).toBe(0);
expect(currentVersionResourceBindingIds({}).size).toBe(0);
expect(currentVersionResourceBindingIds({ versions: [] }).size).toBe(0);
});
test('marks only registered assets bound by the current version as in use', () => {
const bindingIds = currentVersionResourceBindingIds(
{ versions },
'version-root',
);
expect(
isResourceUsedByCurrentVersion(
{ manifestAssetId: 'asset-player' },
bindingIds,
),
).toBe(true);
expect(
isResourceUsedByCurrentVersion(
{ manifestAssetId: 'asset-town' },
bindingIds,
),
).toBe(false);
// 未登记为 manifest 素材的资源永远不算「当前使用」。
expect(
isResourceUsedByCurrentVersion({ manifestAssetId: null }, bindingIds),
).toBe(false);
});
test('labels a version with its Chinese created reason and creation time', () => {
// 完整标识=`版本 N(原因 · 时间)`;`N` 取 manifest 里的落盘顺序(与资源画布
// 「项目卡片」上的 `版本 N` 同一编号)。
expect(formatIterationVersionLabel(versions[0]!, 0)).toBe(
`版本 1(初始版本 · ${new Date(1_788_075_047 * 1000).toLocaleString('zh-CN')})`,
);
expect(formatIterationVersionLabel(versions[1]!, 1)).toBe(
`版本 2(智能体修订 · ${new Date(1_788_075_104 * 1000).toLocaleString('zh-CN')})`,
);
// 顶栏窄到只放得下序号时显示的就是 `formatIterationVersionTitle`,括号里那一截整段收起
// (样式按 `data-layout` 隐藏 `.game-run-version-trigger-detail`)。两半各自是独立口径。
expect(formatIterationVersionTitle(1)).toBe('版本 2');
expect(formatIterationVersionDetail(versions[1]!)).toBe(
`智能体修订 · ${new Date(1_788_075_104 * 1000).toLocaleString('zh-CN')}`,
);
});
test('把版本 createdAt 的 Unix 秒换算成毫秒,不再渲染成 1970 年', () => {
// 期望值按同一个本地时区口径算出,用例结果不随运行机器时区漂移。
// 1788075047 秒 = 2026-08-30T07:30:47Z。
const createdAtLocal = new Date(1_788_075_047 * 1000).toLocaleString(
'zh-CN',
);
const label = formatIterationVersionLabel(versions[0]!, 0);
expect(label).toBe(`版本 1(初始版本 · ${createdAtLocal})`);
// 年 / 月 / 日必须来自真实时刻,而不是 1970。这里用显式数值选项断言,
// 不依赖 `toLocaleString` 的具体排版(不同 ICU 版本会给出不同分隔符)。
expect(
new Intl.DateTimeFormat('zh-CN', {
year: 'numeric',
month: 'numeric',
day: 'numeric',
}).format(new Date(1_788_075_047 * 1000)),
).toBe('2026/8/30');
// 回归守卫:按毫秒解释同一个值会落到 1970/1/22,这正是真机截图里的错误显示。
expect(label).not.toContain('1970');
});
});