Repository navigation
test(plugin-chatbot): the pending-count pulse pin waits for the count render, not for the button - #26742
Conversation
… render, not for the button The draft card draws its 发布 button before the first fetchPendingDraftCount read answers; the count lands on a later render. Both tests read the count with a one-shot toHaveTextContent right after findByTestId, which resolves on the button alone, so under load the check could run before that render and read 发布 instead of 发布 (2) — the merge-queue ejections' signature. The pin now waits for the render that carries the count. Product code unchanged. Claude-Session: https://claude.ai/code/session_01J8VVAkq9LgnKiBeyJBZqSp Co-authored-by: Claude <noreply@anthropic.com>
维护者速读 · 席位定稿
席位核对
Pointer on the card: ACCEPT → this comment. Generated by Claude Code |
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 40561422008 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 分类: 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
Requested by Irene · project thread
Fixes #26647
Clause-②: no
Metadata-protocol: none
维护者速读
ui/packages/plugin-chatbot/src/__tests__/ChatbotEnhanced.pendingCountPulse-26471.test.tsx里新增的expectPublishButtonText和它替换掉的两处findByTestId一次性断言。pnpm --dir ui exec vitest run packages/plugin-chatbot/src/__tests__/ChatbotEnhanced.pendingCountPulse-26471.test.tsx,预期 2 passed。What changes
ChatbotEnhanced.pendingCountPulse-26471.test.tsxonly. Both tests read the draft card's count asand now read it through one helper,
expectPublishButtonText, which is awaitForaround the samegetByTestId('draft-publish')+toHaveTextContentassertion. Nothing else in the file moves: the call counts, the pulse leg, the unmount leg and every expected string are byte-identical.ChatbotEnhanced.tsxis untouched.Why
The draft card draws its publish button in the same render as the card. At that moment
fetchPendingDraftCounthas not answered,livePendingCountisundefined, and the button reads发布with no count. The count reaches the DOM on a second render, committed when the read resolves andsetPendingByPackagelands.findByTestIdresolves on its first check that finds the button, which is the first render, so the one-shottoHaveTextContentthat follows races the second render. On an idle box that render usually lands first; under load it sometimes does not, and the assertion reads发布.That is exactly what the queue saw. Both ejections (queue runs 40468287272 and 40493270857) failed
unmount unsubscribes: a later pulse reads nothingwithExpected element to have text content: 发布 (2) / Received: 发布, at that test's openingfindByTestId('draft-publish')assertion, before any pulse fires in it.The count is not wrong (triage asked to read the red as real until shown otherwise): the button shows no count while the count is unknown and
发布 (2)once it is known, which is the component's stated design ("Leave the package unknown — the card falls back to the in-memory snapshot rather than guessing"). The pin now waits for the render that carries the count instead of the render that carries the button. No sleep, retry, skip, timeout change or quarantine.Tests
All local, on this branch's head
b192892aunless markedorigin/main(f6ffd723); 4-core container, so absolute durations are shared-box figures.origin/mainunder load: 24 runs of the unchanged file with 6 CPU busy-loops: 23 passed, 1 failed inunmount unsubscribeswithReceived: 发布, the queue's signature byte for byte.fetchPendingDraftCountthat answers 30 ms later, the old pin fails every time (Received: 发布) and the new pin passes.ChatbotEnhanced.tsx(viascripts/ablation-replace.mjs), both tests go red withReceived: 发布; restored, blob equalsHEAD(2233fd2f),git diff HEADempty.pnpm --dir ui exec vitest run packages/plugin-chatbot/: 86 files, 816 tests passed.pnpm --filter @object-ui/plugin-chatbot run type-check: exit 0;tsc -p tsconfig.test.json --listFileslists this test file.Acceptance notes
await act(...), which flushes that update before the assertions after it, and was never the red line.ui/packages/plugin-chatbot/src, a one-shot text assertion straight after afindBy*occurs only at these two calls. The other suite that wiresfetchPendingDraftCount(ChatbotEnhanced.changeCardV2-12894) reads the count insideawait act(...).skip-changesetinstead. The diff is one test file.@object-ui/plugin-chatbotshipsdist,README.md,CHANGELOG.mdandLICENSE. After a build,distholds 0 hits forexpectPublishButtonTextorunmount unsubscribes, and 2 files for the positive controldraft-publish. So nothing publishes, and a patch changeset would put a test-only line in the released CHANGELOG.origin/maingained one commit after this branch's base (43731031,ui/packages/authonly), outside this package's dependency closure; not merged in.Verification
Queue failure log (job 122069386772, run 40468287272)
Loaded loops: origin/main vs this branch
Forced slow read: old pin vs new pin (scratch, not committed)
Count-suffix mutation against the new pin
Gates (derived by dispatch-gates --commands at b192892)
24 derived commands, all exit 0, reconciled by
dispatch-gates --ran: "24 derived famil(ies) accounted for — 24 run, 0 NOT-MEASURED (a DERIVED zero)". Among themnode scripts/check-sdui-manifest.mjs(and--self-test),pnpm check:nul-bytes,pnpm check:published-files,pnpm check:test-source-alias,pnpm check:cross-package-test-inputs,pnpm check:type-check-coverage,pnpm check:type-check-debt, andpnpm --dir ui exec vitest run scripts/(178 files passed, 2 skipped). Alsopnpm check:new-line-citations(0 new), and eslint on the changed file (clean). Repo-wide lint, the type-check lanes and the full UI farm are CI's.Human Minimum
packages/specholds no runtime logic. (not touched)pnpm lintpasses. (eslint clean on the changed file; repo-wide run is CI's)main, one pull request.skip-changeset)packages/spectouched: its generated artifacts are regenerated and committed. (not touched)content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.Generated by Claude Code