refactor: 收口创作恢复URL模型

This commit is contained in:
2026-06-03 20:46:39 +08:00
parent fe2f8a66e6
commit 30ead590e2
9 changed files with 569 additions and 218 deletions

View File

@@ -0,0 +1,224 @@
import { describe, expect, test } from 'vitest';
import type { BarkBattleDraftConfig } from '../../../packages/shared/src/contracts/barkBattle';
import type { BigFishSessionSnapshotResponse } from '../../../packages/shared/src/contracts/bigFish';
import type { BabyObjectMatchDraft } from '../../../packages/shared/src/contracts/edutainmentBabyObject';
import type { Match3DAgentSessionSnapshot } from '../../../packages/shared/src/contracts/match3dAgent';
import type { PuzzleAgentSessionSnapshot } from '../../../packages/shared/src/contracts/puzzleAgentSession';
import type { PuzzleWorkSummary } from '../../../packages/shared/src/contracts/puzzleWorkSummary';
import type { SquareHoleSessionSnapshot } from '../../../packages/shared/src/contracts/squareHoleAgent';
import type { VisualNovelAgentSessionSnapshot } from '../../../packages/shared/src/contracts/visualNovel';
import type {
JumpHopSessionSnapshotResponse,
JumpHopWorkProfileResponse,
} from '../../services/jump-hop/jumpHopClient';
import type {
WoodenFishSessionSnapshotResponse,
WoodenFishWorkProfileResponse,
} from '../../services/wooden-fish/woodenFishClient';
import {
buildBabyObjectMatchCreationUrlState,
buildBarkBattleCreationUrlState,
buildBigFishCreationUrlState,
buildJumpHopCreationUrlState,
buildMatch3DCreationUrlState,
buildPuzzleCreationUrlState,
buildPuzzleDraftRuntimeUrlState,
buildPuzzlePublishedRuntimeUrlState,
buildPuzzleRuntimeUrlStateKey,
buildSquareHoleCreationUrlState,
buildVisualNovelCreationUrlState,
buildWoodenFishCreationUrlState,
hasCreationUrlStateValue,
hasPuzzleRuntimeUrlStateValue,
normalizeCreationUrlValue,
} from './platformCreationUrlStateModel';
describe('platformCreationUrlStateModel', () => {
test('normalizes private creation url state values', () => {
expect(normalizeCreationUrlValue(' session-1 ')).toBe('session-1');
expect(normalizeCreationUrlValue(' ')).toBeNull();
expect(
hasCreationUrlStateValue({
sessionId: ' ',
profileId: null,
draftId: undefined,
workId: 'work-1',
}),
).toBe(true);
expect(hasCreationUrlStateValue({})).toBe(false);
});
test('builds creation restore state for core session based plays', () => {
expect(
buildBigFishCreationUrlState({
sessionId: ' big-fish-session-1 ',
} as BigFishSessionSnapshotResponse),
).toEqual({
sessionId: 'big-fish-session-1',
workId: 'big-fish-work-big-fish-session-1',
});
expect(
buildMatch3DCreationUrlState({
sessionId: 'match3d-session-1',
draft: { profileId: 'match3d-profile-draft' },
} as Match3DAgentSessionSnapshot),
).toEqual({
sessionId: 'match3d-session-1',
profileId: 'match3d-profile-draft',
workId: 'match3d-profile-draft',
});
expect(
buildSquareHoleCreationUrlState({
sessionId: 'square-session-1',
publishedProfileId: 'square-profile-published',
} as SquareHoleSessionSnapshot),
).toEqual({
sessionId: 'square-session-1',
profileId: 'square-profile-published',
workId: 'square-profile-published',
});
expect(
buildVisualNovelCreationUrlState({
sessionId: 'visual-session-1',
draft: { profileId: 'visual-profile-1' },
} as VisualNovelAgentSessionSnapshot),
).toEqual({
sessionId: 'visual-session-1',
profileId: 'visual-profile-1',
workId: 'visual-profile-1',
});
});
test('builds puzzle creation and runtime query state', () => {
expect(
buildPuzzleCreationUrlState({
sessionId: 'puzzle-session-ocean',
} as PuzzleAgentSessionSnapshot),
).toEqual({
sessionId: 'puzzle-session-ocean',
profileId: 'puzzle-profile-ocean',
workId: 'puzzle-work-ocean',
});
const draftRuntime = buildPuzzleDraftRuntimeUrlState(
buildPuzzleWork({
profileId: 'puzzle-profile-ocean',
sourceSessionId: null,
}),
'level-2',
);
expect(draftRuntime).toEqual({
mode: 'draft',
runtimeSessionId: 'puzzle-session-ocean',
runtimeProfileId: 'puzzle-profile-ocean',
runtimeLevelId: 'level-2',
});
expect(hasPuzzleRuntimeUrlStateValue(draftRuntime)).toBe(true);
expect(buildPuzzleRuntimeUrlStateKey(draftRuntime)).toBe(
'draft|puzzle-session-ocean|puzzle-profile-ocean|level-2|',
);
const publishedRuntime = buildPuzzlePublishedRuntimeUrlState(
buildPuzzleWork({ profileId: 'puzzle-profile-ocean' }),
);
expect(publishedRuntime.mode).toBe('published');
expect(publishedRuntime.runtimeProfileId).toBe('puzzle-profile-ocean');
expect(publishedRuntime.publicWorkCode).toMatch(/^PZ-/u);
});
test('builds creation state for work backed plays with work id priority', () => {
expect(
buildJumpHopCreationUrlState({
session: {
sessionId: 'jump-session-1',
draft: { profileId: 'jump-profile-draft' },
} as JumpHopSessionSnapshotResponse,
work: {
summary: {
profileId: 'jump-profile-work',
workId: 'jump-work-1',
},
} as JumpHopWorkProfileResponse,
}),
).toEqual({
sessionId: 'jump-session-1',
profileId: 'jump-profile-work',
workId: 'jump-work-1',
});
expect(
buildWoodenFishCreationUrlState({
session: {
sessionId: 'wood-session-1',
draft: { profileId: 'wood-profile-draft' },
} as WoodenFishSessionSnapshotResponse,
work: {
summary: {
profileId: 'wood-profile-work',
workId: 'wood-work-1',
},
} as WoodenFishWorkProfileResponse,
}),
).toEqual({
sessionId: 'wood-session-1',
profileId: 'wood-profile-work',
draftId: 'wood-profile-work',
workId: 'wood-work-1',
});
});
test('builds creation state for draft backed local plays', () => {
expect(
buildBarkBattleCreationUrlState({
draftId: 'bark-draft-1',
workId: 'bark-work-1',
} as BarkBattleDraftConfig),
).toEqual({
draftId: 'bark-draft-1',
workId: 'bark-work-1',
});
expect(
buildBabyObjectMatchCreationUrlState({
draftId: 'baby-draft-1',
profileId: 'baby-profile-1',
} as BabyObjectMatchDraft),
).toEqual({
profileId: 'baby-profile-1',
draftId: 'baby-draft-1',
workId: 'baby-profile-1',
});
});
});
function buildPuzzleWork(
overrides: Partial<PuzzleWorkSummary> = {},
): PuzzleWorkSummary {
return {
workId: 'puzzle-work-base',
profileId: 'puzzle-profile-base',
ownerUserId: 'user-1',
sourceSessionId: 'puzzle-session-base',
authorDisplayName: '测试作者',
workTitle: '潮雾拼图',
workDescription: '潮雾港口拼图。',
levelName: '潮雾拼图',
summary: '潮雾港口拼图。',
themeTags: [],
coverImageSrc: null,
coverAssetId: null,
publicationStatus: 'draft',
updatedAt: '2026-06-03T08:00:00.000Z',
publishedAt: null,
playCount: 0,
remixCount: 0,
likeCount: 0,
publishReady: false,
levels: [],
...overrides,
};
}