206 lines
5.5 KiB
TypeScript
206 lines
5.5 KiB
TypeScript
import { describe, expect, test } from 'vitest';
|
|
|
|
import type { ProfilePlayedWorkSummary } from '../../../packages/shared/src/contracts/runtime';
|
|
import { resolvePlatformPlayedWorkOpenIntent } from './platformPlayedWorkOpenModel';
|
|
|
|
function buildPlayedWork(
|
|
overrides: Partial<ProfilePlayedWorkSummary> = {},
|
|
): ProfilePlayedWorkSummary {
|
|
return {
|
|
worldKey: 'custom:world-1',
|
|
ownerUserId: 'user-1',
|
|
profileId: 'world-1',
|
|
worldType: 'CUSTOM',
|
|
worldTitle: '潮雾列岛',
|
|
worldSubtitle: '旧灯塔与失控航路',
|
|
firstPlayedAt: '2026-04-18T12:00:00.000Z',
|
|
lastPlayedAt: '2026-04-19T12:00:00.000Z',
|
|
lastObservedPlayTimeMs: 12_000,
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
describe('platformPlayedWorkOpenModel', () => {
|
|
test('opens puzzle played works with profile tab context', () => {
|
|
expect(
|
|
resolvePlatformPlayedWorkOpenIntent(
|
|
buildPlayedWork({
|
|
worldType: 'PUZZLE',
|
|
profileId: 'puzzle-profile-1',
|
|
}),
|
|
),
|
|
).toEqual({
|
|
type: 'open-puzzle',
|
|
profileId: 'puzzle-profile-1',
|
|
tab: 'profile',
|
|
});
|
|
});
|
|
|
|
test('falls back to worldKey prefixes when profile id is absent', () => {
|
|
const cases = [
|
|
['puzzle:profile-1', 'open-puzzle', 'profile-1'],
|
|
['match3d:profile-2', 'open-match3d', 'profile-2'],
|
|
['square-hole:profile-3', 'open-square-hole', 'profile-3'],
|
|
['jump-hop:profile-4', 'open-jump-hop', 'profile-4'],
|
|
['wooden-fish:profile-5', 'open-wooden-fish', 'profile-5'],
|
|
] as const;
|
|
|
|
for (const [worldKey, type, profileId] of cases) {
|
|
expect(
|
|
resolvePlatformPlayedWorkOpenIntent(
|
|
buildPlayedWork({
|
|
worldKey,
|
|
profileId: null,
|
|
worldType: null,
|
|
}),
|
|
),
|
|
).toMatchObject({ type, profileId });
|
|
}
|
|
});
|
|
|
|
test('keeps explicit profile id ahead of worldKey fallback', () => {
|
|
expect(
|
|
resolvePlatformPlayedWorkOpenIntent(
|
|
buildPlayedWork({
|
|
worldKey: 'jump-hop:key-profile',
|
|
profileId: 'explicit-profile',
|
|
worldType: null,
|
|
}),
|
|
),
|
|
).toMatchObject({
|
|
type: 'open-jump-hop',
|
|
profileId: 'explicit-profile',
|
|
});
|
|
});
|
|
|
|
test('supports played work type aliases for mini-games', () => {
|
|
const cases = [
|
|
['match_3d', 'open-match3d'],
|
|
['square_hole', 'open-square-hole'],
|
|
['jump_hop', 'open-jump-hop'],
|
|
['wooden_fish', 'open-wooden-fish'],
|
|
] as const;
|
|
|
|
for (const [worldType, type] of cases) {
|
|
expect(
|
|
resolvePlatformPlayedWorkOpenIntent(
|
|
buildPlayedWork({
|
|
worldType,
|
|
profileId: `${worldType}-profile`,
|
|
}),
|
|
),
|
|
).toMatchObject({
|
|
type,
|
|
profileId: `${worldType}-profile`,
|
|
});
|
|
}
|
|
});
|
|
|
|
test('returns noop when a mini-game target is empty', () => {
|
|
expect(
|
|
resolvePlatformPlayedWorkOpenIntent(
|
|
buildPlayedWork({
|
|
worldKey: 'puzzle:key-profile',
|
|
profileId: '',
|
|
worldType: 'puzzle',
|
|
}),
|
|
),
|
|
).toEqual({
|
|
type: 'noop',
|
|
reason: 'missing-target',
|
|
});
|
|
});
|
|
|
|
test('builds big fish intent and fallback work for gallery misses', () => {
|
|
expect(
|
|
resolvePlatformPlayedWorkOpenIntent(
|
|
buildPlayedWork({
|
|
worldKey: 'big-fish:big-fish-session-1',
|
|
ownerUserId: null,
|
|
profileId: null,
|
|
worldType: 'big_fish',
|
|
worldTitle: '机械深海',
|
|
worldSubtitle: '',
|
|
}),
|
|
),
|
|
).toEqual({
|
|
type: 'open-big-fish',
|
|
sessionId: 'big-fish-session-1',
|
|
fallbackWork: {
|
|
workId: 'big-fish:big-fish-session-1',
|
|
sourceSessionId: 'big-fish-session-1',
|
|
ownerUserId: '',
|
|
authorDisplayName: '玩家',
|
|
title: '机械深海',
|
|
subtitle: '',
|
|
summary: '',
|
|
coverImageSrc: null,
|
|
status: 'published',
|
|
updatedAt: '2026-04-19T12:00:00.000Z',
|
|
publishReady: true,
|
|
levelCount: 0,
|
|
levelMainImageReadyCount: 0,
|
|
levelMotionReadyCount: 0,
|
|
backgroundReady: false,
|
|
},
|
|
});
|
|
});
|
|
|
|
test('opens unknown played work types as RPG detail when identity is complete', () => {
|
|
expect(
|
|
resolvePlatformPlayedWorkOpenIntent(
|
|
buildPlayedWork({
|
|
worldType: 'CUSTOM',
|
|
profileId: null,
|
|
}),
|
|
),
|
|
).toEqual({
|
|
type: 'open-rpg',
|
|
detail: {
|
|
ownerUserId: 'user-1',
|
|
profileId: 'custom:world-1',
|
|
publicWorkCode: null,
|
|
authorPublicUserCode: null,
|
|
visibility: 'published',
|
|
publishedAt: '2026-04-18T12:00:00.000Z',
|
|
updatedAt: '2026-04-19T12:00:00.000Z',
|
|
authorDisplayName: '旧灯塔与失控航路',
|
|
worldName: '潮雾列岛',
|
|
subtitle: '旧灯塔与失控航路',
|
|
summaryText: '',
|
|
coverImageSrc: null,
|
|
themeMode: 'martial',
|
|
playableNpcCount: 0,
|
|
landmarkCount: 0,
|
|
playCount: 0,
|
|
remixCount: 0,
|
|
likeCount: 0,
|
|
},
|
|
});
|
|
});
|
|
|
|
test('returns noop for RPG fallback when owner or profile is missing', () => {
|
|
expect(
|
|
resolvePlatformPlayedWorkOpenIntent(
|
|
buildPlayedWork({
|
|
ownerUserId: null,
|
|
}),
|
|
),
|
|
).toEqual({
|
|
type: 'noop',
|
|
reason: 'missing-target',
|
|
});
|
|
expect(
|
|
resolvePlatformPlayedWorkOpenIntent(
|
|
buildPlayedWork({
|
|
worldKey: '',
|
|
profileId: null,
|
|
}),
|
|
),
|
|
).toEqual({
|
|
type: 'noop',
|
|
reason: 'missing-target',
|
|
});
|
|
});
|
|
});
|