Files
Jyotisha/frontend/tests/onboarding-motion-gate.test.tsx
T
Jesse_ChenandClaude Opus 5.5 de9d4826c1 #111 第 3 轮:建档不退回加载、右栏能拖宽、清单不迟到、月亮问句与别人的上升句(BUG-1455~1459)
- 建档重读人物名单时保留旧名单,失败也不卡在加载画面(BUG-1455)
- 对话右栏改用自己的拖宽把手,侧栏与右栏都能用方向键(BUG-1456/1457)
- 启程清单胶囊和首页一起出来,读状态时用上次的样子占位(BUG-1458)
- 起步第一问与别人的天空过场读一次已算好的星盘取星座,上升只在不会换座时用(BUG-1459,产品 10-27 同意)
- 补回删减的断言与三栏说明;登录代码改回原样,替身放进测试;删旧校正画面的无用样式
- 首屏 +7.54% 产品已接受,写进 DESIGN

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LutgzyJqNhPpZy1nFsJtN3
2026-10-27 10:24:57 +08:00

93 lines
3.6 KiB
TypeScript

import "./install-test-document";
import assert from "node:assert/strict";
import test from "node:test";
import { OnboardingMotionHost } from "../src/components/onboarding-motion-host.tsx";
import { onboardingMotionEnabled } from "../src/lib/onboarding-hints.ts";
import { OnboardingJourneyContext, type OnboardingJourney } from "../src/lib/onboarding-journey.tsx";
import { claimOnboardingPlay, resetOnboardingPlays } from "../src/lib/motion/onboarding-play.ts";
import { playOnboardingEnter, setOnboardingMotionLoader } from "../src/lib/motion/onboarding-run.ts";
import { createClientLifecycleHarness } from "./react-client-lifecycle-test-support.ts";
function closedJourney(): OnboardingJourney {
return {
showChecklist: false,
checklistPending: false,
userId: "",
items: [],
label: "",
celebration: false,
activeHint: null,
hintText: "",
showChartDot: false,
tabHasDot: () => false,
dismissChecklist: () => {},
dismissHint: async () => true,
go: () => {},
setChartTab: () => {},
markChartVisited: () => {},
setChecklistOpen: () => {},
setLive: () => {},
registerHome: () => {},
hintWatch: false,
motionEnabled: onboardingMotionEnabled({
checklistDismissed: true,
checklistOpen: false,
unfinishedItem: true,
beforeFirstQuestion: true,
}),
};
}
test("a closed checklist plays none of the four onboarding beats", async () => {
const journey = closedJourney();
assert.equal(journey.motionEnabled, false);
resetOnboardingPlays();
const harness = createClientLifecycleHarness();
try {
await harness.render(
<OnboardingJourneyContext.Provider value={journey}>
<OnboardingMotionHost />
<button type="button" data-onboarding-enter="follow-up">追问</button>
<article data-onboarding-enter="archive">档案</article>
<svg data-onboarding-draw="vedic" data-onboarding-draw-key="vedic" />
<article data-onboarding-synastry="00000000-0000-4000-8000-000000001447">合盘</article>
</OnboardingJourneyContext.Provider>,
);
await harness.idle();
assert.equal(claimOnboardingPlay("enter:follow-up"), true);
assert.equal(claimOnboardingPlay("enter:archive"), true);
assert.equal(claimOnboardingPlay("draw:vedic"), true);
assert.equal(claimOnboardingPlay("syn:00000000-0000-4000-8000-000000001447"), true);
assert.equal(harness.errors.length, 0, harness.errors.map(String).join("\n"));
} finally {
await harness.close();
}
});
test("a failed or slow Motion load leaves the element visible", async () => {
const harness = createClientLifecycleHarness();
try {
resetOnboardingPlays();
setOnboardingMotionLoader(() => Promise.reject(new Error("motion failed")));
const failed = harness.document.createElement("div");
failed.setAttribute("data-onboarding-enter", "follow-up");
(failed.style as { opacity?: string }).opacity = "1";
await playOnboardingEnter(failed as unknown as HTMLElement);
assert.notEqual((failed.style as { opacity?: string }).opacity, "0");
resetOnboardingPlays();
setOnboardingMotionLoader(() => new Promise(() => {}));
const slow = harness.document.createElement("div");
slow.setAttribute("data-onboarding-enter", "archive");
(slow.style as { opacity?: string }).opacity = "1";
const started = Date.now();
await playOnboardingEnter(slow as unknown as HTMLElement);
assert.ok(Date.now() - started >= 250);
assert.notEqual((slow.style as { opacity?: string }).opacity, "0");
} finally {
setOnboardingMotionLoader(null);
await harness.close();
}
});