1
This commit is contained in:
@@ -74,6 +74,10 @@ import {
|
||||
listPuzzleGallery,
|
||||
remixPuzzleGalleryWork,
|
||||
} from '../../services/puzzle-gallery';
|
||||
import {
|
||||
generatePuzzleOnboardingWork,
|
||||
savePuzzleOnboardingWork,
|
||||
} from '../../services/puzzle-onboarding';
|
||||
import {
|
||||
advancePuzzleNextLevel,
|
||||
dragPuzzlePieceOrGroup,
|
||||
@@ -161,7 +165,7 @@ async function clickFirstAsyncButtonByName(
|
||||
async function openCreateTemplateHub(user: ReturnType<typeof userEvent.setup>) {
|
||||
await clickFirstButtonByName(user, '创作');
|
||||
expect(
|
||||
await screen.findByText('10分钟创作一个精品互动玩法'),
|
||||
await screen.findByRole('tablist', { name: '选择模板' }),
|
||||
).toBeTruthy();
|
||||
expect(screen.getByRole('tab', { name: '拼图' })).toBeTruthy();
|
||||
expect(screen.getByText('拼图工作区:missing-session')).toBeTruthy();
|
||||
@@ -390,6 +394,11 @@ vi.mock('../../services/puzzle-runtime/puzzleLocalRuntime', async () => {
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('../../services/puzzle-onboarding', () => ({
|
||||
generatePuzzleOnboardingWork: vi.fn(),
|
||||
savePuzzleOnboardingWork: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('../../services/puzzle-agent', () => ({
|
||||
createPuzzleAgentSession: vi.fn(),
|
||||
executePuzzleAgentAction: vi.fn(),
|
||||
@@ -2080,6 +2089,107 @@ beforeEach(() => {
|
||||
vi.mocked(listPuzzleGallery).mockResolvedValue({
|
||||
items: [],
|
||||
});
|
||||
vi.mocked(generatePuzzleOnboardingWork).mockResolvedValue({
|
||||
item: {
|
||||
workId: 'onboarding-work-1',
|
||||
profileId: 'onboarding-profile-1',
|
||||
ownerUserId: 'onboarding-guest',
|
||||
sourceSessionId: null,
|
||||
authorDisplayName: '百梦主',
|
||||
workTitle: '梦境拼图',
|
||||
workDescription: '我想飞上天',
|
||||
levelName: '云上飞行',
|
||||
summary: '我想飞上天',
|
||||
themeTags: ['新手引导', '拼图'],
|
||||
coverImageSrc: 'data:image/svg+xml;utf8,onboarding',
|
||||
coverAssetId: 'onboarding-asset-1',
|
||||
publicationStatus: 'draft',
|
||||
updatedAt: '2026-05-05T12:00:00.000Z',
|
||||
publishedAt: null,
|
||||
playCount: 0,
|
||||
remixCount: 0,
|
||||
likeCount: 0,
|
||||
publishReady: true,
|
||||
levels: [],
|
||||
},
|
||||
level: {
|
||||
levelId: 'onboarding-level-1',
|
||||
levelName: '云上飞行',
|
||||
pictureDescription: '我想飞上天',
|
||||
pictureReference: null,
|
||||
candidates: [
|
||||
{
|
||||
candidateId: 'onboarding-candidate-1',
|
||||
imageSrc: 'data:image/svg+xml;utf8,onboarding',
|
||||
assetId: 'onboarding-asset-1',
|
||||
prompt: '我想飞上天',
|
||||
actualPrompt: '我想飞上天',
|
||||
sourceType: 'generated',
|
||||
selected: true,
|
||||
},
|
||||
],
|
||||
selectedCandidateId: 'onboarding-candidate-1',
|
||||
coverImageSrc: 'data:image/svg+xml;utf8,onboarding',
|
||||
coverAssetId: 'onboarding-asset-1',
|
||||
generationStatus: 'ready',
|
||||
},
|
||||
});
|
||||
vi.mocked(savePuzzleOnboardingWork).mockResolvedValue({
|
||||
item: {
|
||||
workId: 'onboarding-work-saved',
|
||||
profileId: 'onboarding-profile-saved',
|
||||
ownerUserId: mockAuthUser.id,
|
||||
sourceSessionId: 'puzzle-session-onboarding',
|
||||
authorDisplayName: mockAuthUser.displayName,
|
||||
workTitle: '梦境拼图',
|
||||
workDescription: '我想飞上天',
|
||||
levelName: '云上飞行',
|
||||
summary: '我想飞上天',
|
||||
themeTags: ['新手引导', '拼图'],
|
||||
coverImageSrc: 'data:image/svg+xml;utf8,onboarding',
|
||||
coverAssetId: 'onboarding-asset-1',
|
||||
publicationStatus: 'draft',
|
||||
updatedAt: '2026-05-05T12:00:00.000Z',
|
||||
publishedAt: null,
|
||||
playCount: 0,
|
||||
remixCount: 0,
|
||||
likeCount: 0,
|
||||
publishReady: true,
|
||||
levels: [],
|
||||
anchorPack: {
|
||||
themePromise: {
|
||||
key: 'theme_promise',
|
||||
label: '主题承诺',
|
||||
value: '新手引导',
|
||||
status: 'confirmed',
|
||||
},
|
||||
visualSubject: {
|
||||
key: 'visual_subject',
|
||||
label: '视觉主体',
|
||||
value: '云上飞行',
|
||||
status: 'confirmed',
|
||||
},
|
||||
visualMood: {
|
||||
key: 'visual_mood',
|
||||
label: '视觉气质',
|
||||
value: '明亮',
|
||||
status: 'confirmed',
|
||||
},
|
||||
compositionHooks: {
|
||||
key: 'composition_hooks',
|
||||
label: '构图钩子',
|
||||
value: '天空',
|
||||
status: 'confirmed',
|
||||
},
|
||||
tagsAndForbidden: {
|
||||
key: 'tags_and_forbidden',
|
||||
label: '标签与禁区',
|
||||
value: '拼图',
|
||||
status: 'confirmed',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
vi.mocked(remixPuzzleGalleryWork).mockRejectedValue(
|
||||
new Error('未启用拼图 remix'),
|
||||
);
|
||||
@@ -3262,7 +3372,7 @@ test('puzzle draft result back button returns to creation hub', async () => {
|
||||
await user.click(screen.getByRole('button', { name: '返回' }));
|
||||
|
||||
expect(
|
||||
await screen.findByText('10分钟创作一个精品互动玩法'),
|
||||
await screen.findByRole('tablist', { name: '选择模板' }),
|
||||
).toBeTruthy();
|
||||
expect(screen.getByText('雨夜里有一只会发光的猫站在遗迹台阶上。')).toBeTruthy();
|
||||
expect(screen.queryByText('拼图结果页')).toBeNull();
|
||||
@@ -3312,6 +3422,82 @@ test('published puzzle work card restores its source session for editing', async
|
||||
expect(screen.getByDisplayValue('雨夜猫塔')).toBeTruthy();
|
||||
});
|
||||
|
||||
test('first launch puzzle onboarding can be skipped from top right', async () => {
|
||||
const user = userEvent.setup();
|
||||
window.localStorage.removeItem(
|
||||
'genarrative.puzzle-onboarding.first-visit.v1',
|
||||
);
|
||||
|
||||
render(
|
||||
<TestWrapper
|
||||
authValue={createAuthValue({
|
||||
user: null,
|
||||
canAccessProtectedData: false,
|
||||
openLoginModal: () => {},
|
||||
requireAuth: () => {},
|
||||
})}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(await screen.findByText('待定待定待定')).toBeTruthy();
|
||||
await user.click(screen.getByRole('button', { name: '跳过' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText('待定待定待定')).toBeNull();
|
||||
});
|
||||
expect(
|
||||
window.localStorage.getItem(
|
||||
'genarrative.puzzle-onboarding.first-visit.v1',
|
||||
),
|
||||
).toBe('1');
|
||||
expect(generatePuzzleOnboardingWork).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('first launch puzzle onboarding falls back to local run when generate route is missing', async () => {
|
||||
const user = userEvent.setup();
|
||||
window.localStorage.removeItem(
|
||||
'genarrative.puzzle-onboarding.first-visit.v1',
|
||||
);
|
||||
vi.mocked(generatePuzzleOnboardingWork).mockRejectedValueOnce(
|
||||
new ApiClientError({
|
||||
message: '资源不存在',
|
||||
status: 404,
|
||||
code: 'NOT_FOUND',
|
||||
}),
|
||||
);
|
||||
|
||||
render(
|
||||
<TestWrapper
|
||||
authValue={createAuthValue({
|
||||
user: null,
|
||||
canAccessProtectedData: false,
|
||||
openLoginModal: () => {},
|
||||
requireAuth: () => {},
|
||||
})}
|
||||
/>,
|
||||
);
|
||||
|
||||
await user.type(
|
||||
await screen.findByPlaceholderText('把你的梦讲给我听吧'),
|
||||
'我想飞上天',
|
||||
);
|
||||
await user.click(screen.getByRole('button', { name: '生成' }));
|
||||
|
||||
expect(
|
||||
await screen.findByTestId('puzzle-board', undefined, { timeout: 3000 }),
|
||||
).toBeTruthy();
|
||||
expect(generatePuzzleOnboardingWork).toHaveBeenCalledWith({
|
||||
promptText: '我想飞上天',
|
||||
});
|
||||
expect(screen.queryByText('资源不存在')).toBeNull();
|
||||
expect(startPuzzleRun).not.toHaveBeenCalled();
|
||||
expect(
|
||||
window.localStorage.getItem(
|
||||
'genarrative.puzzle-onboarding.first-visit.v1',
|
||||
),
|
||||
).toBe('1');
|
||||
});
|
||||
|
||||
test('formal puzzle runtime uses frontend move merge logic and backend leaderboard next level', async () => {
|
||||
const user = userEvent.setup();
|
||||
const clearedFirstLevel = buildClearedPuzzleRun({
|
||||
@@ -4717,7 +4903,7 @@ test('agent draft result back button returns to creation hub without syncing res
|
||||
await user.click(screen.getByRole('button', { name: /返回创作/u }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('10分钟创作一个精品互动玩法')).toBeTruthy();
|
||||
expect(screen.getByRole('tablist', { name: '选择模板' })).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(
|
||||
@@ -5041,16 +5227,16 @@ test('manual tab switch is preserved after platform bootstrap requests finish',
|
||||
|
||||
await clickFirstButtonByName(user, '创作');
|
||||
expect(
|
||||
await screen.findByText('10分钟创作一个精品互动玩法'),
|
||||
await screen.findByRole('tablist', { name: '选择模板' }),
|
||||
).toBeTruthy();
|
||||
|
||||
resolveGalleryRequest([]);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
within(getPlatformTabPanel('create')).getByText(
|
||||
'10分钟创作一个精品互动玩法',
|
||||
),
|
||||
within(getPlatformTabPanel('create')).getByRole('tablist', {
|
||||
name: '选择模板',
|
||||
}),
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user