Homepage no longer waits on /api/onboarding for six starter questions. Natal answers show the spoken layer first; the Level 2 skeleton sits in a collapsed 完整分析 block. Wide tables scroll sideways on a phone. Form inputs are 16px so iOS does not zoom on focus.
63 lines
3.1 KiB
TypeScript
63 lines
3.1 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
import { readFileSync } from "node:fs";
|
|
import {
|
|
createOnboardingFallbackGreeting,
|
|
createStartGreeting,
|
|
createStartGreetingParts,
|
|
} from "../src/lib/starter-greeting.ts";
|
|
import { homeSurface } from "./home-surface.ts";
|
|
|
|
test("terminal and fallback greetings follow the current profile name", () => {
|
|
// 原值: 同时锁 onboardingRequestIdentity / isCurrentOnboardingRequest,避免建议问题串号。
|
|
// 新值: 只保留问候语随当前称呼变化。
|
|
// 原因: 建议问题请求已删除,身份去重不再有消费点。
|
|
const terminalGreeting = createStartGreeting("周宁", new Date(2026, 6, 19, 8), 0);
|
|
const fallbackGreeting = createOnboardingFallbackGreeting("周宁");
|
|
for (const greeting of [terminalGreeting, fallbackGreeting]) {
|
|
assert.match(greeting, /周宁/);
|
|
assert.doesNotMatch(greeting, /林遥/);
|
|
}
|
|
assert.equal(fallbackGreeting, "周宁,从你此刻最关心的问题开始吧。");
|
|
});
|
|
|
|
test("the starter hero splits one time-aware greeting instead of drawing from a separate pool", () => {
|
|
// Given: the same daypart variant, asked for as parts and as one line.
|
|
const noon = new Date(2026, 6, 19, 12);
|
|
const parts = createStartGreetingParts("周宁", noon, 0);
|
|
const whole = createStartGreeting("周宁", noon, 0);
|
|
|
|
// Then: the salutation carries the name and the question carries no name, and they recompose exactly.
|
|
assert.equal(parts.salutation, "中午好,周宁。");
|
|
assert.equal(parts.question, "现在最想理清哪件事?");
|
|
assert.equal(`${parts.salutation}${parts.question}`, whole);
|
|
assert.doesNotMatch(parts.question, /周宁/);
|
|
|
|
// And: the extremes stay inside the variant list rather than falling off the end.
|
|
assert.equal(createStartGreetingParts("周宁", noon, 1).question, "事业、关系或选择,想先聊哪个?");
|
|
assert.equal(createStartGreetingParts("周宁", noon, 0.999999).question, "事业、关系或选择,想先聊哪个?");
|
|
|
|
// And: every daypart is reachable, so the heading is not one fixed line in disguise.
|
|
const questions = new Set([0, 8, 12, 16, 20, 23].flatMap((hour) =>
|
|
[0, 1 / 3, 2 / 3].map((selection) =>
|
|
createStartGreetingParts("周宁", new Date(2026, 6, 19, hour), selection).question)));
|
|
assert.ok(questions.size >= 12);
|
|
});
|
|
|
|
test("the starter hero stays at a salutation and a question", () => {
|
|
const source = homeSurface;
|
|
|
|
// Given: the hero heading is the question half of the time-aware greeting.
|
|
assert.match(source, /<p className="starter-greeting">\{starterGreeting\.salutation\}<\/p>/);
|
|
assert.match(source, /<h1 id="starter-heading">\{starterGreeting\.question\}<\/h1>/);
|
|
|
|
// Then: no third line repeats the welcome the two lines above already carry.
|
|
assert.doesNotMatch(source, /starter-hero-note/);
|
|
const styles = readFileSync(new URL("../src/app/globals.css", import.meta.url), "utf8");
|
|
assert.doesNotMatch(styles, /starter-hero-note/);
|
|
|
|
// And: the separate static heading pool is gone for good.
|
|
assert.doesNotMatch(source, /starterPrompt|createStarterPrompt|greetingForHour/);
|
|
assert.doesNotMatch(source, /greeting: createStartGreeting\(/);
|
|
});
|