收口前端平台组件库能力
新增 PlatformUiKit 通用弹窗、按钮、状态、空态、媒体、表单和标签等公共组件 迁移结果页、创作工作台、认证入口、RPG 暗色面板和运行态弹窗的重复 UI chrome 补充组件测试、页面回归测试、技术文档和 Hermes 共享决策记录
This commit is contained in:
@@ -253,7 +253,9 @@ async function openCreateTemplateHub(user: ReturnType<typeof userEvent.setup>) {
|
||||
).toBeTruthy();
|
||||
// 中文注释:真实最近创作存在时会成为默认页签,模板入口用例需显式切回模板分类。
|
||||
if (!within(panel).queryByRole('button', { name: /拼图/u })) {
|
||||
await user.click(await within(panel).findByRole('tab', { name: '热门推荐' }));
|
||||
await user.click(
|
||||
await within(panel).findByRole('tab', { name: '热门推荐' }),
|
||||
);
|
||||
}
|
||||
expect(
|
||||
await within(panel).findByRole('button', { name: /拼图/u }),
|
||||
@@ -3815,9 +3817,7 @@ test('create tab shows recent template cards when backend returns failed drafts'
|
||||
expect(
|
||||
await within(panel).findByRole('button', { name: /文字冒险/u }),
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
within(panel).getByText('仅显示最近7天内使用过的模板'),
|
||||
).toBeTruthy();
|
||||
expect(within(panel).getByText('仅显示最近7天内使用过的模板')).toBeTruthy();
|
||||
expect(within(panel).getByText('经典 RPG 体验')).toBeTruthy();
|
||||
expect(within(panel).queryByText('入口可见的失败草稿')).toBeNull();
|
||||
expect(
|
||||
@@ -3842,7 +3842,9 @@ test('create tab refreshes recent works after opening from an empty draft shelf'
|
||||
render(<TestWrapper withAuth />);
|
||||
|
||||
await openDraftHub(user);
|
||||
expect(within(getPlatformTabPanel('saves')).getByText('还没有作品')).toBeTruthy();
|
||||
expect(
|
||||
within(getPlatformTabPanel('saves')).getByText('还没有作品'),
|
||||
).toBeTruthy();
|
||||
|
||||
await clickFirstButtonByName(user, '创作');
|
||||
const panel = getPlatformTabPanel('create');
|
||||
@@ -3850,9 +3852,7 @@ test('create tab refreshes recent works after opening from an empty draft shelf'
|
||||
expect(
|
||||
await within(panel).findByRole('button', { name: /文字冒险/u }),
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
within(panel).getByText('仅显示最近7天内使用过的模板'),
|
||||
).toBeTruthy();
|
||||
expect(within(panel).getByText('仅显示最近7天内使用过的模板')).toBeTruthy();
|
||||
expect(within(panel).getByText('经典 RPG 体验')).toBeTruthy();
|
||||
expect(within(panel).queryByText('点击创作后出现的失败草稿')).toBeNull();
|
||||
expect(
|
||||
@@ -4015,9 +4015,9 @@ test('bark battle form checks mud points before creating image assets', async ()
|
||||
).toBeTruthy();
|
||||
expect(screen.getByText('汪汪声浪配置表单')).toBeTruthy();
|
||||
expect(screen.queryByRole('tablist', { name: '创作入口页签' })).toBeNull();
|
||||
expect((screen.getByLabelText('汪汪作品标题') as HTMLInputElement).value).toBe(
|
||||
'自定义声浪杯',
|
||||
);
|
||||
expect(
|
||||
(screen.getByLabelText('汪汪作品标题') as HTMLInputElement).value,
|
||||
).toBe('自定义声浪杯');
|
||||
expect(createBarkBattleDraft).not.toHaveBeenCalled();
|
||||
expect(generateAllBarkBattleImageAssets).not.toHaveBeenCalled();
|
||||
});
|
||||
@@ -5063,8 +5063,9 @@ test('failed parallel puzzle generations stay as separate non-generating drafts'
|
||||
const failureDialog = await screen.findByRole('dialog', {
|
||||
name: '发生错误',
|
||||
});
|
||||
expect(within(failureDialog).getByText(/拼图 VectorEngine 图片编辑失败/u))
|
||||
.toBeTruthy();
|
||||
expect(
|
||||
within(failureDialog).getByText(/拼图 VectorEngine 图片编辑失败/u),
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
||||
test('failed puzzle draft retry reuses current session instead of creating another draft', async () => {
|
||||
@@ -7502,8 +7503,9 @@ test('home recommendation share opens publish share modal', async () => {
|
||||
await screen.findByRole('dialog', { name: '分享给朋友' }),
|
||||
).toBeTruthy();
|
||||
expect(screen.getByText(/作品号:PZ-SHARE001/u)).toBeTruthy();
|
||||
expect(screen.getByText(/\/gallery\/puzzle\/detail\?work=PZ-SHARE001/u))
|
||||
.toBeTruthy();
|
||||
expect(
|
||||
screen.getByText(/\/gallery\/puzzle\/detail\?work=PZ-SHARE001/u),
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
||||
test('home recommendation wooden fish like does not call RPG gallery like', async () => {
|
||||
@@ -7780,9 +7782,7 @@ test('home recommendation keeps cover while switching during a pending puzzle st
|
||||
|
||||
await user.click(await screen.findByRole('button', { name: '下一个' }));
|
||||
|
||||
expect(
|
||||
screen.queryByText('作品暂时无法进入,请稍后再试。'),
|
||||
).toBeNull();
|
||||
expect(screen.queryByText('作品暂时无法进入,请稍后再试。')).toBeNull();
|
||||
expect(
|
||||
await screen.findByLabelText('贝壳潮汐 作品信息', undefined, {
|
||||
timeout: 3000,
|
||||
@@ -7807,9 +7807,7 @@ test('home recommendation keeps cover while switching during a pending puzzle st
|
||||
}),
|
||||
);
|
||||
});
|
||||
expect(
|
||||
screen.queryByText('作品暂时无法进入,请稍后再试。'),
|
||||
).toBeNull();
|
||||
expect(screen.queryByText('作品暂时无法进入,请稍后再试。')).toBeNull();
|
||||
});
|
||||
|
||||
test('home recommendation puzzle next level uses unified recommend switching', async () => {
|
||||
@@ -7902,7 +7900,8 @@ test('home recommendation puzzle next level uses unified recommend switching', a
|
||||
items: [entryWork, nextRecommendWork],
|
||||
});
|
||||
vi.mocked(getPuzzleGalleryDetail).mockImplementation(async (profileId) => ({
|
||||
item: profileId === nextRecommendWork.profileId ? nextRecommendWork : entryWork,
|
||||
item:
|
||||
profileId === nextRecommendWork.profileId ? nextRecommendWork : entryWork,
|
||||
}));
|
||||
vi.mocked(startPuzzleRun).mockImplementation(async (payload) => {
|
||||
const run =
|
||||
@@ -8727,7 +8726,8 @@ test('embedded puzzle form maps raw bearer token errors to user-facing auth copy
|
||||
expect(createPuzzleAgentSession).toHaveBeenCalledTimes(1);
|
||||
expect(createCreativeAgentSession).not.toHaveBeenCalled();
|
||||
expect(
|
||||
(await screen.findAllByText('当前登录状态已失效,请重新登录后继续。')).length,
|
||||
(await screen.findAllByText('当前登录状态已失效,请重新登录后继续。'))
|
||||
.length,
|
||||
).toBeTruthy();
|
||||
expect(screen.queryByText('缺少 Authorization Bearer Token')).toBeNull();
|
||||
});
|
||||
@@ -9720,7 +9720,8 @@ test('missing puzzle public detail returns to platform home', async () => {
|
||||
expect(screen.queryByText('资源不存在')).toBeNull();
|
||||
});
|
||||
|
||||
test('direct missing public work detail alert returns to platform home', async () => {
|
||||
test('direct missing public work detail shows unified dialog before returning home', async () => {
|
||||
const user = userEvent.setup();
|
||||
const alertSpy = vi.spyOn(window, 'alert').mockImplementation(() => {});
|
||||
|
||||
window.history.replaceState(null, '', '/works/detail?work=PZ-7A7B18D9');
|
||||
@@ -9732,9 +9733,12 @@ test('direct missing public work detail alert returns to platform home', async (
|
||||
|
||||
expect(await screen.findByText('正在读取作品详情...')).toBeTruthy();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(alertSpy).toHaveBeenCalledWith('作品不存在或已下架,将返回首页。');
|
||||
});
|
||||
const dialog = await screen.findByRole('dialog', { name: '作品不可用' });
|
||||
expect(within(dialog).getByText('作品不存在或已下架,将返回首页。')).toBeTruthy();
|
||||
expect(alertSpy).not.toHaveBeenCalled();
|
||||
|
||||
await user.click(within(dialog).getByRole('button', { name: '知道了' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(window.location.pathname).toBe('/');
|
||||
});
|
||||
@@ -9747,6 +9751,8 @@ test('direct missing public work detail alert returns to platform home', async (
|
||||
expect(screen.queryByText('详情')).toBeNull();
|
||||
expect(screen.queryByText('未找到拼图作品。')).toBeNull();
|
||||
expect(startPuzzleRun).toHaveBeenCalledTimes(0);
|
||||
|
||||
alertSpy.mockRestore();
|
||||
});
|
||||
|
||||
test('public code search opens a published big fish work by BF code', async () => {
|
||||
@@ -12326,7 +12332,9 @@ test('creation hub gives jump hop wooden fish and bark battle cards the shared d
|
||||
if (!shell) {
|
||||
throw new Error('作品卡应位于统一操作壳内');
|
||||
}
|
||||
await user.click(within(shell as HTMLElement).getByRole('button', { name: '删除' }));
|
||||
await user.click(
|
||||
within(shell as HTMLElement).getByRole('button', { name: '删除' }),
|
||||
);
|
||||
|
||||
const dialog = await screen.findByRole('dialog', { name: '删除作品' });
|
||||
expect(within(dialog).getByText(`确认删除《${title}》吗?`)).toBeTruthy();
|
||||
|
||||
Reference in New Issue
Block a user