test: restore production release gate
This commit is contained in:
@@ -441,3 +441,19 @@
|
||||
- 相关记录:BUG-007、BUG-020、BUG-021
|
||||
- 复发自:BUG-007
|
||||
- 修复版本:待提交(测试 Supabase smoke 通过)
|
||||
|
||||
## BUG-026 | 首页与会话改版后旧测试阻断生产发布门禁
|
||||
|
||||
- 状态:resolved
|
||||
- 首次发现:2026-07-22
|
||||
- 最近更新:2026-07-22
|
||||
- 影响面:production 发布门禁、首页主题入口、会话输入区、生时校正组件服务端渲染测试
|
||||
- 用户现象:production 应用构建成功,但完整前端测试有 7 项失败,导致最新 `main` 无法通过发布前验证。
|
||||
- 触发条件:运行完整前端测试;旧断言仍查找已移除的首页证据预览、固定 180px 模型菜单、无条件输入区类名和旧 `profile` 文案来源,组件测试还会在 Node ESM 下加载 GSAP 默认导出。
|
||||
- 根因:首页与普通 session 的布局和文案已经更新,测试契约没有随产品行为同步;`chat-message-row` 使用 GSAP 默认导入,在 Next 构建中可用,但 Node ESM 测试运行器解析到的模块形态不同。
|
||||
- 修复:测试改为锁定当前首页主题选择、内容自适应模型菜单、带首页修饰类的停靠输入区和 `profileDraft` 文案来源;GSAP 改用其正式命名导出,保持浏览器行为不变并恢复 Node ESM 组件测试。
|
||||
- 验证:6 个相关测试文件、完整前端测试、ESLint、production build 与 patch check 全部通过后方可发布。
|
||||
- 防复发:产品 UI 结构调整时必须在同一提交同步源码契约测试;跨 Next 与 Node 运行的依赖优先使用包声明的稳定命名导出。
|
||||
- 相关记录:BUG-022、BUG-024、BUG-025
|
||||
- 复发自:无
|
||||
- 修复版本:待提交(production gate)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useGSAP } from "@gsap/react";
|
||||
import gsap from "gsap";
|
||||
import { gsap } from "gsap";
|
||||
import { useRef } from "react";
|
||||
|
||||
import { AgentActivityStatus } from "@/components/agent-activity-status";
|
||||
|
||||
@@ -239,7 +239,7 @@ test("homepage and profile result copy use the source-aware consultation options
|
||||
const intake = readFileSync(new URL("../src/components/birth-time-intake.tsx", import.meta.url), "utf8");
|
||||
|
||||
assert.match(page, /birthTimeConsultationOptionsCopy\(profileDraft\)/);
|
||||
assert.match(page, /birthTimeConsultationOptionsCopy\(profile\)/);
|
||||
assert.doesNotMatch(page, /birthTimeConsultationOptionsCopy\(profile\)/);
|
||||
assert.match(intake, /birthTimeConsultationOptionsCopy\(value\)/);
|
||||
});
|
||||
|
||||
|
||||
@@ -150,7 +150,7 @@ test("terminal CJK copy stays intact while homepage candidates remain unconfirme
|
||||
const pageSource = readFileSync(new URL("../src/app/page.tsx", import.meta.url), "utf8");
|
||||
|
||||
assert.match(candidateResultSource, /候选范围已保留,但当前证据不足以将具体分钟写入当前排盘时间。补充经历后可重新评估。/);
|
||||
assert.match(pageSource, /未确认;\$\{birthTimeConsultationOptionsCopy\(profile\)\}/);
|
||||
assert.match(pageSource, /`出生资料已保存。\$\{birthTimeConsultationOptionsCopy\(profileDraft\)\}`/);
|
||||
assert.match(pageSource, /<ConversationalBirthTimeRectification/);
|
||||
assert.doesNotMatch(pageSource, /当前使用候选时间排盘/);
|
||||
});
|
||||
|
||||
@@ -65,7 +65,7 @@ test("keeps the suggestion row height stable while an answer streams", () => {
|
||||
});
|
||||
|
||||
test("docks the composer inside the chat panel instead of floating over content", () => {
|
||||
assert.match(pageSource, /<div className="composer-wrap">/);
|
||||
assert.match(pageSource, /<div className=\{`composer-wrap \$\{starterHomeVisible \? "composer-wrap-starter" : ""\}`\}>/);
|
||||
assert.match(globalStyles, /\.chat-panel[^}]*grid-template-rows:\s*68px minmax\(0,\s*1fr\) auto/);
|
||||
assert.match(globalStyles, /\.conversation[^}]*padding-bottom:\s*var\(--composer-reserve\)/);
|
||||
assert.match(globalStyles, /\.composer-wrap[^}]*position:\s*sticky/);
|
||||
|
||||
@@ -70,7 +70,7 @@ function controllerFor(turn: ConversationalRectificationTurn): ConversationalRec
|
||||
};
|
||||
}
|
||||
|
||||
test("confirmed surface requires an explicit click before continuing the original question", () => {
|
||||
test("confirmed surface requires an explicit click before returning to the original question", () => {
|
||||
let continuationCalls = 0;
|
||||
const markup = renderToStaticMarkup(React.createElement(
|
||||
ConversationalRectificationSurface,
|
||||
@@ -80,8 +80,8 @@ test("confirmed surface requires an explicit click before continuing the origina
|
||||
},
|
||||
));
|
||||
|
||||
assert.match(markup, /原问题:未来半年是否适合换工作?/);
|
||||
assert.match(markup, />使用新确认时间继续回答原问题</);
|
||||
assert.doesNotMatch(markup, /原问题:未来半年是否适合换工作?/);
|
||||
assert.match(markup, />返回原问题</);
|
||||
assert.equal(continuationCalls, 0);
|
||||
});
|
||||
|
||||
@@ -95,7 +95,7 @@ test("continuation action is visibly locked while ordinary consultation is pendi
|
||||
},
|
||||
));
|
||||
|
||||
assert.match(markup, /<button[^>]+disabled=""[^>]*>正在继续回答原问题…<\/button>/);
|
||||
assert.match(markup, /<button[^>]+disabled=""[^>]*>正在继续回答…<\/button>/);
|
||||
});
|
||||
|
||||
test("choosing rectify-first captures the visible question and passes it only to v3 start", async () => {
|
||||
|
||||
@@ -36,8 +36,9 @@ test("completed account initialization switches directly to the home cards", ()
|
||||
|
||||
test("default starter questions are guided Jyotish topics with evidence and claim boundaries", () => {
|
||||
assert.match(pageSource, /defaultGuidedJyotishTopics/);
|
||||
assert.match(pageSource, /theme\.evidencePreview\.join/);
|
||||
assert.match(pageSource, /theme\.claimBoundary/);
|
||||
assert.match(pageSource, /starterSuggestions\.map/);
|
||||
assert.match(pageSource, /themes\.find\(\(candidate\) => candidate\.id === item\.theme\)/);
|
||||
assert.match(pageSource, /chooseSuggestedQuestion\(item\.text, item\.theme\)/);
|
||||
assert.match(guidedTopicsSource, /strictWorkflowRoute/);
|
||||
assert.match(guidedTopicsSource, /evidencePreview/);
|
||||
assert.match(guidedTopicsSource, /confidenceCap/);
|
||||
@@ -73,13 +74,15 @@ test("keeps session history clickable while another session is answering", () =>
|
||||
assert.doesNotMatch(appSidebarSource, /pendingSession|isLoading|cancellationPending|requestPending/);
|
||||
});
|
||||
|
||||
test("uses the compact model popup width", () => {
|
||||
test("sizes the model popup to its content with responsive bounds", () => {
|
||||
// Given: the model selector popup styles.
|
||||
const popupStyles = sourceBetween(globalStyles, ".model-selector-popup {", "}\n.model-selector-popup[data-starting-style]");
|
||||
|
||||
// When: its responsive width is inspected.
|
||||
// Then: the desktop cap is half of the former 360px width.
|
||||
assert.match(popupStyles, /width:\s*min\(180px,/);
|
||||
// Then: short labels stay compact while long content remains viewport-safe.
|
||||
assert.match(popupStyles, /width:\s*max-content/);
|
||||
assert.match(popupStyles, /min-width:\s*180px/);
|
||||
assert.match(popupStyles, /max-width:\s*min\(420px,/);
|
||||
});
|
||||
|
||||
test("centers the credit value with its icon", () => {
|
||||
|
||||
Reference in New Issue
Block a user