1
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
2026-04-28 10:57:40 +08:00
parent bb4100fca4
commit a9febe7678
28 changed files with 1342 additions and 89 deletions

View File

@@ -1,16 +1,18 @@
// @vitest-environment jsdom
import {
act,
fireEvent,
render,
screen,
waitFor,
within,
} from '@testing-library/react';
import { describe, expect, test, vi } from 'vitest';
import { afterEach, describe, expect, test, vi } from 'vitest';
import type { PuzzleAgentSessionSnapshot } from '../../../packages/shared/src/contracts/puzzleAgentSession';
import { puzzleAssetClient } from '../../services/puzzle-works/puzzleAssetClient';
import * as puzzleWorksService from '../../services/puzzle-works';
import { PuzzleResultView } from './PuzzleResultView';
vi.mock('../ResolvedAssetImage', () => ({
@@ -31,6 +33,15 @@ vi.mock('../../services/puzzle-works/puzzleAssetClient', () => ({
},
}));
vi.mock('../../services/puzzle-works', () => ({
updatePuzzleWork: vi.fn(),
}));
afterEach(() => {
vi.useRealTimers();
vi.clearAllMocks();
});
function createSession(
overrides: Partial<PuzzleAgentSessionSnapshot> = {},
): PuzzleAgentSessionSnapshot {
@@ -149,6 +160,39 @@ function createSession(
}
describe('PuzzleResultView', () => {
test('auto saves renamed title to the puzzle work profile', async () => {
vi.useFakeTimers();
vi.mocked(puzzleWorksService.updatePuzzleWork).mockResolvedValue({
item: {} as never,
});
render(
<PuzzleResultView
session={createSession()}
profileId="puzzle-profile-session-1"
onBack={() => {}}
onExecuteAction={() => {}}
/>,
);
fireEvent.change(screen.getByDisplayValue('雨夜猫街'), {
target: { value: '暖灯猫街' },
});
await act(async () => {
await vi.runAllTimersAsync();
});
expect(puzzleWorksService.updatePuzzleWork).toHaveBeenCalledWith(
'puzzle-profile-session-1',
expect.objectContaining({
levelName: '暖灯猫街',
summary: '屋檐下的猫与暖灯街角。',
themeTags: ['猫咪', '雨夜'],
}),
);
});
test('uses two tabs without author preview or persistent publish validation', () => {
render(
<PuzzleResultView
@@ -168,9 +212,13 @@ describe('PuzzleResultView', () => {
});
test('edits theme tags with chips instead of a persistent tag input', () => {
vi.mocked(puzzleWorksService.updatePuzzleWork).mockResolvedValue({
item: {} as never,
});
render(
<PuzzleResultView
session={createSession()}
profileId="puzzle-profile-session-1"
onBack={() => {}}
onExecuteAction={() => {}}
/>,
@@ -256,6 +304,78 @@ describe('PuzzleResultView', () => {
);
});
test('requires at least three theme tags before publish can pass', () => {
const onExecuteAction = vi.fn();
render(
<PuzzleResultView
session={createSession()}
onBack={() => {}}
onExecuteAction={onExecuteAction}
/>,
);
fireEvent.click(screen.getByLabelText('删除标签 猫咪'));
fireEvent.click(screen.getByRole('button', { name: //u }));
const dialog = screen.getByRole('dialog', { name: '发布拼图作品' });
expect(
within(dialog).getByText('正式标签数量必须在 3 到 6 之间。'),
).toBeTruthy();
expect(
(
within(dialog).getByRole('button', {
name: '发布到广场',
}) as HTMLButtonElement
).disabled,
).toBe(true);
});
test('auto saves added and removed theme tags', async () => {
vi.useFakeTimers();
vi.mocked(puzzleWorksService.updatePuzzleWork).mockResolvedValue({
item: {} as never,
});
render(
<PuzzleResultView
session={createSession()}
profileId="puzzle-profile-session-1"
onBack={() => {}}
onExecuteAction={() => {}}
/>,
);
fireEvent.click(screen.getByLabelText('新增题材标签'));
fireEvent.change(screen.getByLabelText('新题材标签'), {
target: { value: '暖灯' },
});
fireEvent.click(screen.getByRole('button', { name: '添加' }));
await act(async () => {
await vi.runAllTimersAsync();
});
expect(puzzleWorksService.updatePuzzleWork).toHaveBeenLastCalledWith(
'puzzle-profile-session-1',
expect.objectContaining({
themeTags: ['猫咪', '雨夜', '暖灯'],
}),
);
fireEvent.click(screen.getByLabelText('删除标签 猫咪'));
await act(async () => {
await vi.runAllTimersAsync();
});
expect(puzzleWorksService.updatePuzzleWork).toHaveBeenLastCalledWith(
'puzzle-profile-session-1',
expect.objectContaining({
themeTags: ['雨夜', '暖灯'],
}),
);
});
test('generates one image from the picture description and replaces current image', () => {
const onExecuteAction = vi.fn();