Files
Genarrative/apps/ai-game-creator-shell/tests/resourcePromptPolishSlot.test.tsx
suzmii 1e17d2c852
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 7m44s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 7m57s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 5m44s
Project CI / Backend tests (pull_request) Failing after 16s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 5m53s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m21s
Project CI / Repository checks (pull_request) Failing after 12s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m27s
Project CI / Frontend tests (pull_request) Successful in 7m4s
Project CI / AI game creator shell web tests (pull_request) Successful in 6m22s
Project CI / Native shell tests (pull_request) Successful in 10m13s
补齐画布验收第一批:润色回包提示、未提交草稿恢复与派生名预检
AI 润色回包与原文相同时给出明确提示,不再落下点了等于没点的「恢复原文」假入口
润色「与原文相同」的判据改为规范化之后要写回宿主的文本,回包被长度上限截回原文同样算没变化
共享聊天输入区显示润色提示,并让提示随用户手改提示词失效
快速编辑未提交草稿改按资源路径归属,收起面板或被旁路重投影后都不再静默丢掉
恢复入口按路径与本会话草稿对号,并区分「本会话未提交」与原生账本条目
账本读取失败时入口仍报出本会话草稿条数,「继续编辑」重开面板回填提示词与 @ 引用
派生资源名预检接入快速编辑与角色动画两条提交路径,早于正规化写盘
名称预检自身抛错时回写面板失败态,不再留下「点了没反应」的提交按钮
浮层关闭判定改在捕获阶段冻结,避免浮层内按钮卸载自己时整块面板被自己人收掉
恢复入口动作按钮收进统一容器,补移动端纵向排布与禁用态样式
空草稿表改工厂函数,跨语言对表用例按模块路径解析 Rust 源码
补回归用例:旁路重投影后的草稿、原样回包提示、提交前名称拦截、草稿表读写与跨卡隔离
同步 decision-log 与画布验收待办的进展说明
2026-09-20 17:36:02 +08:00

131 lines
5.0 KiB
TypeScript
Raw Permalink 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.
// @vitest-environment jsdom
import {
cleanup,
fireEvent,
render,
screen,
waitFor,
} from '@testing-library/react';
import { useState } from 'react';
import { afterEach, describe, expect, test, vi } from 'vitest';
import { ResourcePromptPolishSlot } from '../src/features/resource-canvas/ResourcePromptPolishSlot';
type TauriInvoke = (
command: string,
args?: Record<string, unknown>,
) => Promise<unknown>;
/**
* 平台侧润色的桩:`ResourcePromptPolishSlot` 走 `usePromptPolish` 的默认实现
* (`polish_local_project_prompt`),所以这里和生成素材面板的既有用例一样,
* 用 `window.__TAURI__` 打桩,不碰真实 Provider。
*/
function installPolishInvoke(result: string) {
const invoke = vi.fn(async (command: string) => {
if (command !== 'polish_local_project_prompt') {
throw new Error(`unexpected invoke ${command}`);
}
return result;
});
(
window as unknown as { __TAURI__?: { core?: { invoke: TauriInvoke } } }
).__TAURI__ = { core: { invoke } };
return invoke;
}
afterEach(() => {
cleanup();
delete (window as unknown as { __TAURI__?: unknown }).__TAURI__;
});
/**
* 宿主侧的最小接线:slot 本身是受控的,提示词文本存在宿主里
* (与 AGC 快速编辑面板 / 生成素材弹窗同一形状),`output` 只是把宿主状态显示出来。
*/
function PolishSlotHarness({ prompt }: { prompt: string }) {
const [text, setText] = useState(prompt);
return (
<>
<ResourcePromptPolishSlot
subject="图片素材的快速编辑提示词"
editKind="image-reference"
prompt={text}
applyPrompt={setText}
/>
{/* 刻意用 span:`<output>` 自带 status 角色,会和 slot 的状态行撞名。 */}
<span aria-label="宿主提示词">{text}</span>
{/* 宿主输入框里的手改:与 AGC 面板里改提示词同一条路径(改的是宿主状态)。 */}
<button type="button" onClick={() => setText('把角色头发改成蓝色')}>
模拟用户手改
</button>
</>
);
}
describe('ResourcePromptPolishSlot', () => {
test('回包与原文相同:状态行说清「未做修改」,也不给「恢复原文」假入口', async () => {
const invoke = installPolishInvoke('把角色头发改成红色');
render(<PolishSlotHarness prompt="把角色头发改成红色" />);
fireEvent.click(screen.getByRole('button', { name: 'AI 润色' }));
// 验收项 AGC-004 的用户可见面:必须有一条说得清的反馈,而不是静默什么都不发生。
await waitFor(() =>
expect(screen.getByRole('status').textContent).toBe(
'AI 润色结果与原文相同,未做修改',
),
);
expect(invoke).toHaveBeenCalledWith('polish_local_project_prompt', {
prompt: '把角色头发改成红色',
context: expect.stringContaining('图片素材的快速编辑提示词'),
});
// 文本没变,也就没有可回退的变化:不渲染「恢复原文」。
expect(screen.getByLabelText('宿主提示词').textContent).toBe(
'把角色头发改成红色',
);
expect(screen.queryByRole('button', { name: '恢复原文' })).toBeNull();
});
test('用户接着手改提示词:上一轮的提示收起,宿主文本就是用户写的那份', async () => {
installPolishInvoke('把角色头发改成红色');
render(<PolishSlotHarness prompt="把角色头发改成红色" />);
fireEvent.click(screen.getByRole('button', { name: 'AI 润色' }));
await waitFor(() =>
expect(screen.getByRole('status').textContent).toBe(
'AI 润色结果与原文相同,未做修改',
),
);
// 宿主文本被用户改写:上一轮「与原文相同」的结论不再描述当前这段话,提示收起,
// 免得用户把上一轮的结论当成对现在这段文本的判断。
fireEvent.click(screen.getByRole('button', { name: '模拟用户手改' }));
await waitFor(() => expect(screen.queryByRole('status')).toBeNull());
expect(screen.getByLabelText('宿主提示词').textContent).toBe(
'把角色头发改成蓝色',
);
});
test('回包不同:「恢复原文」把原输入回填给宿主,并收起自己与提示', async () => {
installPolishInvoke('把角色头发设定改为亮红色');
render(<PolishSlotHarness prompt="把角色头发改成红色" />);
fireEvent.click(screen.getByRole('button', { name: 'AI 润色' }));
const restore = await screen.findByRole('button', { name: '恢复原文' });
expect(screen.getByLabelText('宿主提示词').textContent).toBe(
'把角色头发设定改为亮红色',
);
fireEvent.click(restore);
// 验收项 AGC-005 的动作面:恢复原文 = 回填最初原文,快照被消费掉,按钮与提示一起收干净。
expect(screen.getByLabelText('宿主提示词').textContent).toBe(
'把角色头发改成红色',
);
expect(screen.queryByRole('button', { name: '恢复原文' })).toBeNull();
expect(screen.queryByRole('status')).toBeNull();
});
});