Repository navigation
test(app-shell): fold six more RecordDetailView pins over the shared chrome mocks onto the harness - #31057
Merged
Conversation
…chrome mocks onto the harness Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibzBe9FF3NSNMyRNF4E
Contributor
Author
|
domain:ui#2 · os-tesla · session_01L9qibw7DekEe3wx5f3zphf 席位核对 · ACCEPT · 2026-11-06T23:11Z · head
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by Tesla · project thread
Fixes #29469
Clause-②: no
Metadata-protocol: none
维护者速读
RecordDetailView(app-shell包)的 6 个单卡测试文件并入 test(app-shell): fold seven RecordDetailView pins over the shared chrome mocks onto one harness #31051 建的共享测试文件RecordDetailView.harness.test.tsx,每个原文件变成一个顶层describe,断言和标题一字未改;复原帮手restoreAfterBlock()多复原一样东西:地址栏(其中一个原文件把记录地址写进真实history后不放回)。restoreAfterBlock()里新加的两行(href的记录与history.replaceState),再随便挑一块对照原文件;下面「留下的 pin」表是卡的收尾清单。ui/下跑pnpm exec vitest run packages/app-shell/src/views/RecordDetailView.harness.test.tsx,应见 1 个文件、49 个测试全过。bed3e2b3的 diff 复核:7 个文件、+1229 / −1467,纯测试改动,无受治理路径。RecordDetailView 家族再并入 6 个用例文件(含 4 个vi.spyOn用例,各自在 afterEach 里vi.restoreAllMocks(),RelatedCountStore._reset()按块执行);it 20 = 20、expect 99 = 99、标题一致,乱序种子下通过;restoreAfterBlock另外复原地址栏(recordTabRowUrl 会把记录地址写进 history)。并入的文件 CPU 约 48 s → 9 s。正文列出其余 90 个未并入用例及原因。CI 全绿,Clause-② no,不欠契约复审。这是本卡最后一个 PR,同意落地。What changes
Slice 4b, the second and last
RecordDetailView*PR of the shared-setup rollout (ruling 6583487846 on #29469; seat amendment 2, 6672694520: at most two PRs per family), and the card's last PR. Slice 4a (#31051, merged as81deb548) createdui/packages/app-shell/src/views/RecordDetailView.harness.test.tsxwith 7 blocks; this PR adds 6 more from the same cluster, the pins that share the harness's eight mocks verbatim (@object-ui/auth,@object-ui/collaboration,sonner,./ActionConfirmDialog,./ActionParamDialog,./ActionResultDialog,./FlowRunner,./MetadataInspector).relatedListTitlePlural-11733andfeedRefusal-11195, and the four smallest of thevi.spyOnrow,relatedListsOrder-27241,bodyTablePredicate-27478,relatedCountsFirst-27056andrecordTabRowUrl-27524. Each of those four spies onHTMLElement.prototype.getBoundingClientRectin its ownbeforeEachand undoes it withvi.restoreAllMocks()in its ownafterEach, so the spy never outlives a test of its block.describenamed after its stem (RecordDetailView.STEM), docblock above it,restoreAfterBlock()first, the rest of the file after its imports and mocks moved verbatim and re-indented two spaces (template-literal lines keep their bytes). The six files are deleted. The harness's imports gainscreen,actandfireEventfrom@testing-library/react,BrowserRouterfromreact-router-dom,RelatedCountStorefrom@object-ui/componentsandcreateI18nfrom@object-ui/i18n; no two files bound one local name to different modules. Those 4 import lines and the helper are the only harness lines from 4a that change.vi.mockcalls, and the one-line comments directly above those mocks. A line-multiset check of the six former files against the harness finds nothing else missing.restoreAfterBlock()also puts back the address bar.recordTabRowUrl-27524writes the record's path into the realwindow.history(replaceStatein its render helper, then the view's own pushes) and leaves it there; its former file got a fresh window, and a block after it in the harness would now start at/app/demo/showcase_project/p-1. The helper readswindow.location.hrefin itsbeforeAlland callswindow.history.replaceState(null, '', href)in itsafterAll. The probe found this under three shuffle seeds, whererecordTabRowUrl-27524is not the last block (see Verification).No other file names any of the six (
git grepof each stem over the whole tree finds only the harness), so no comment elsewhere changes. Test files only: no source file, no changeset (skip-changeset).Tests
Former file → describe (no title or assertion dropped)
TypeScript AST walk of each former file at
origin/main(81deb548) against thedescribeof the same name in the harness at this PR's head. Anitis a call toit/test; anexpect(is a call toexpect; titles are thedescribe > itpaths under the block, compared as sorted lists.RecordDetailView.relatedListTitlePlural-11733.test.tsxRecordDetailView.feedRefusal-11195.test.tsxRecordDetailView.relatedListsOrder-27241.test.tsxRecordDetailView.bodyTablePredicate-27478.test.tsxRecordDetailView.relatedCountsFirst-27056.test.tsxRecordDetailView.recordTabRowUrl-27524.test.tsxThe whole harness holds 49
itand 153expect(calls: 4a's 29 and 54, which this PR does not change, plus the 20 and 99 above. No statement outside the blocks holds either.CPU before and after (local A/B, one machine)
CI after: NOT MEASURED: the per-file timings reporter (#29517) uploads on
main's full-battery runs only. Its first after-reading is the first full-batterymainrun after this merges.Local A/B on one 4-vCPU container, under
os-verify-lock(shared-box seconds), same command both legs, fromui/:pnpm exec vitest run packages/app-shell/src/views/RecordDetailView. --maxWorkers=2(everyRecordDetailView.*file), with a throwaway reporter summing each module'sdiagnostic(). Fixed = environment + prepare + setup + collect (import). The "before" leg writes the six files and the harness fromorigin/main(81deb548, 4a's harness of 7 blocks) into the branch's tree, so both legs run the same 90 other files; the tree is reset toHEADafter each before leg and checked clean. Run order: before 1, after 1, before 2, after 2.The six files took 31.5 s of CPU on average, and the harness that now holds them and 4a's seven takes 9.4 s. 4a's harness read 7.1 / 7.6 s in 4a's A/B and 17.4 / 14.9 s in this one's before legs: its import time depends on which worker picks it up, so the honest per-file comparison is the six files plus 4a's harness, 48.1 / 47.1 s, against this harness, 9.1 / 9.6 s (−80 %). The family read 559.8 s before and 527.0 s after on average (−5.9 %), wall 293.3 s to 274.6 s; the two before runs differ by 18.7 s, so this is a reading of two runs per leg on a shared box, not a measured saving.
Acceptance notes
phoneOwnerLine-28909(204 lines), would add about 410 changed lines and take it past 3,000. So the family ends with 13 of its 103 pins in the harness, and with it the card's fourth and last family.RecordDetailViewpins are inui/packages/app-shell/src/views/.headerRefreshis named by path inui/scripts/__tests__/check-vi-mock-override-shape.test.ts, so it stays a file of its own. Names of pins in source-file comments stay as they are (claim 6694271643: source files are ⛔).pnpm check:new-line-citations: 0 new).ui/scripts/test-shard-timings.jsonis keyed by a hash of each file's path, so the six deleted files leave six stale keys until the timings refresh, as 4a's did.RecordDetailView pins left unfolded: 90 files, 29,399 lines, by shared setup
Names drop the
RecordDetailView.prefix and.test.tsx. "Named by" lists the other files whose text names the pin.feedRecordScope(461; named bydefaults-maps-mirror-en-pack.test.tsx),relatedBadgeArity-8882(453; named byrelated-count-store.ts),discussionFallbackPipeline-8983(439; named byrecord-chatter.tsx),relatedListFilter-4664(420; named byderiveRelatedLists.relatedListFilter-4664.test.ts,RecordDetailView.childWriteRefreshesParent-12244.test.tsx,RecordDetailView.relatedBadgeArity-8882.test.tsx,related-count-store.declaredScope-4664.test.ts,related-count-store.ts,buildDefaultPageSchema.relatedListFilter-4664.test.ts),feedLoading(394; named byRecordDetailView.discussionFallbackPipeline-8983.test.tsx,RecordDetailView.harness.test.tsx,RecordDetailView.headerRefresh.test.tsx),authoredChildWriteRefreshesParent-26890(351; named byRecordDetailView.unregisteredObjectLists-26988.test.tsx,recordPageChildObjects.test.ts),discussionExplicitComposition-7298(327; named byRecordDetailView.discussionFallbackPipeline-8983.test.tsx),sectionHeadingsRenderPath-6190(320; named byCHANGELOG.md,CHANGELOG.md,DetailView.expandFls-7230.test.tsx),managedByBadgeAuthoring-12194(213; named byObjectView.managedByBadgeAuthoring-12194.test.tsx,RecordFormPage.managedByBadgeAuthoring-12194.test.tsx),printAction-11958(162; named byRecordDetailView.harness.test.tsx,RecordDetailView.printPageHeaderActions-12906.test.tsx)vi.spyOn(each restored in itsafterEach)recordPageTiers-26678(431),phoneFace-27058(425),panelToggles-27052(381),activityMapIdentity-5878(346),topBar-27524(312),relatedListInheritedSort-5795(296),phoneOwnerLine-28909(204)vi.spyOnblocks this PR folds. The family's two PRs are spent; the smallest of these (phoneOwnerLine-28909) would take this PR past 3,000 lines.userActionPredicates(513),headerActionLookupPredicate(352),builtinActionSessionUserPredicate(346),reactionWriteFailure-10899(346),authoredActivityThreading-12249(335),replyCountOnRead-12144(302),commentWriteFailure-10899(259),accessibleNames-12625(199)describe.eachat collection timehiddenAffordanceVerdicts-13045(250),oneProvenanceFooter-12307(208),appendInset-27520(183)vi.hoisted/globalThisslot or a global installer of its ownunregisteredObjectLists-26988(312),namedRecordPage-12715(293)headerRefresh(251; named bycheck-vi-mock-override-shape.test.ts)@object-ui/authfactory answers a different user or organizationreactionRecords-12078(567),childWriteRefreshesParent-12244(433),feedGrant-12082(428),withheldMentions-28218(310),printPageHeaderActions-12906(287),reactionKeepIds-11019(271),reactionsCommentRowsOnly-11035(265),activityActorId-12067(176)vi.mockfactory applies to the whole file, and its@object-ui/authanswers a different user or organization from the harness'sAda. It needs a harness of its own.../hooks/useActionModal+../utils/consoleServerAction+./ActionConfirmDialog+./ActionParamDialog+./ActionResultDialog+./FlowRunner+./MetadataInspector+@object-ui/auth+@object-ui/collaboration+@object-ui/react+sonner, not the harness setparamRuntimeParity-6431(610),approvalDeclaredActions(543),confirmRuntimeParity-5835(458),headerRecordIdLoadWindow(404),approvalRecallGate(355),approvalLock-25934(348),recordIdParamSeed(339),accessEndedAfterDecision-26589(330),undoLookupId-11122(309),paramDialogTitle(302),headerApiInterpolation(296),undoCapture-11082(291),apiActionDoor-27611(280),modalDispatch(278),approvalLock-12220(273),paramCancelText-28879(263),paramSubmitText-28158(263),undoneToast-11056(231),banCompanion-30205(227),ctxOrg-10918(222),apiFlowRefusal-27487(212)vi.mockapplies to the whole file, so it cannot join a harness whose mocks it does not share. A harness for its set would be new work.@object-ui/auth+@object-ui/collaboration+sonner, not the harness setrecordOpenWaves-13010(811),feedLoadFailure-29188(462),recordPagePayload-27627(389),timelineCount-28737(368),recordOpenRequests-12701(350),afterActionExplain-13341(315),recordReadFailure-11902(303),recordOpenOneRequest-28470(290),approvalRequestPage-28546(180),phoneGuardBar-28483(161)vi.mockapplies to the whole file, so it cannot join a harness whose mocks it does not share. A harness for its set would be new work../ActionParamDialog+./ActionResultDialog+./FlowRunner+./MetadataInspector+@object-ui/auth+@object-ui/collaboration+sonner, not the harness setfeedCommentEditDelete-12268(518),updateActionRefresh-29935(329),deleteConfirmDialog-11001(310),favoritesEntry-12427(293),paneOpenAsPage-27545(292),placedHeaderActions-29951(262),apiNewTabUrl-26747(257),headerMenuIcons-12529(239),deleteCascade-28472(188)vi.mockapplies to the whole file, so it cannot join a harness whose mocks it does not share. A harness for its set would be new work../MetadataInspector+@object-ui/auth+@object-ui/collaboration+@object-ui/react+sonner, not the harness setflowActionDoor-12037(277),flowDoneSuccessMessage-12274(240),refusedLaunch-9973(236),flowActionSuccessMessage-12234(219)vi.mockapplies to the whole file, so it cannot join a harness whose mocks it does not share. A harness for its set would be new work../ActionConfirmDialog+./ActionParamDialog+./ActionResultDialog+./FlowRunner+./MetadataInspector+@object-ui/auth+@object-ui/collaboration+@object-ui/fields+sonner, not the harness setlookupDependsOn-7190(619)vi.mockapplies to the whole file, so it cannot join a harness whose mocks it does not share. A harness for its set would be new work.@object-ui/auth+@object-ui/collaboration+@object-ui/permissions+react+sonner, not the harness setrecordOpenRequests-11699(505)vi.mockapplies to the whole file, so it cannot join a harness whose mocks it does not share. A harness for its set would be new work.../context/NavigationContext+../hooks/useActionModal+../utils/consoleServerAction+./ActionConfirmDialog+./ActionParamDialog+./ActionResultDialog+./FlowRunner+./MetadataInspector+@object-ui/auth+@object-ui/collaboration+@object-ui/react+react-router-dom+sonner, not the harness setonSuccessNavigateHost-13396(399)vi.mockapplies to the whole file, so it cannot join a harness whose mocks it does not share. A harness for its set would be new work../ActionConfirmDialog+./ActionParamDialog+./ActionResultDialog+./FlowRunner+./MetadataInspector+@object-ui/auth+@object-ui/collaboration+@object-ui/plugin-detail+sonner, not the harness setactivityUnmappedType-5896(380)vi.mockapplies to the whole file, so it cannot join a harness whose mocks it does not share. A harness for its set would be new work../ActionConfirmDialog+./ActionParamDialog+./ActionResultDialog+./FlowRunner+./MetadataInspector+@object-ui/auth+@object-ui/collaboration+@object-ui/permissions+sonner, not the harness setexpandFls-7230(281)vi.mockapplies to the whole file, so it cannot join a harness whose mocks it does not share. A harness for its set would be new work.vi.mockheaderActionGates(182),actionUser(89)Verification
At head
bed3e2b3, onorigin/main81deb548(4a's merge), every run underos-verify-lock:--sequence.shuffle.testswith--sequence.seed11, 222 and 3333 (each VERDICT command-exit 0). The seed runs and the probe read the tree one commit earlier, before a comment-only rewrap of the helper's docblock; both A/B after legs ran this head's harness, 49 / 49 passed.restoreAfterBlock()writes the state at each block's first test (the same fields as 4a's probe: registry entries,localStoragedescriptor and both storages,lang/dir,innerWidth/innerHeight, react-i18next'sgetI18n(),document.title,body, added window keys, thefetchstub,toastcall counts,location.href). With this head's helper, all 13 blocks start from the same state in all four orders. With 4a's helper, the three shuffled orders showlocation.hrefat/app/demo/showcase_project/p-1for every block afterrecordTabRowUrl-27524, which is why the helper now puts the address back. With the helper'safterAllbody removed,lang/dir,innerWidthandlocalStoragealso leak, as in 4a. The probe copies were deleted.pnpm run type-checkinui/packages/app-shell(tsc --noEmit && tsc -p tsconfig.test.json): VERDICT command-exit 0, 0error TS.eslinton the harness fromui/packages/app-shell: 0 errors, 24 warnings (allno-explicit-any), the same as 4a's harness (12) plus the six former files atorigin/main(12).node scripts/pm/dispatch-gates.mjs --commands, change set 7 paths against merge base81deb548): 26 derived, 26 run with stdin from/dev/null, each exit 0 captured before any pipe, among thempnpm --dir ui exec vitest run scripts/,node scripts/check-sdui-manifest.mjsand its--self-test, andpnpm check:test-source-alias.--ranreconciliation: 26 derived, 26 run, 0 NOT-MEASURED, 0 UNRUN, every family with a recorded exit code.pnpm check:new-line-citationsfromui/: 0 new citations.@object-ui/app-shell's suite was not run locally; no file outside the family changed, and CI's Test UI runs it.git diff --shortstat origin/main HEADis 7 files, +1,229 / −1,467, 2,696 changed lines.mainhas moved 2 commits past81deb548; neither touchesui/packages/app-shell/src/views/,ui/vitest.config.mtsor theui/vitest.setup.*files, so the branch is not re-merged and the readings above stand for this head.ui/or a package (fix(app-shell): name the language menu's built-in locales from the platform locale table #31053, feat(app-shell): Connect an AI Assistant opens with what a connected assistant can do, in plain words #31052, feat(plugin-auth, service-settings)!: the access policy is set per organization, with three MFA levels #31013, feat(mcp): read_file and create_upload_link read and attach a record's files #31009, feat(objectql)!: an API, an object-less action and an engine function hold one name per package (bare-name phase 1, 2/4) #31006, feat(audit): every data export writes one run-levelsys_audit_logrow, and theexportaction comes back with its writer #31000, feat(spec,i18n): register the delete_package platform tool and label it in every pack (cloud#3656) #31037, feat(lint): warn when a permission set reads a roll-up summary over child data it cannot read #31046, feat(spec): the published JSON Schema states the marketplace taxonomy facets' no-duplicates rule as uniqueItems #31047) changes aRecordDetailViewfile (read from each PR head's diff against its merge base before the push; feat(app-shell): Connect an AI Assistant opens with what a connected assistant can do, in plain words #31052 and feat(spec): the published JSON Schema states the marketplace taxonomy facets' no-duplicates rule as uniqueItems #31047 have merged since, neither touchingui/packages/app-shell/src/views/).Human Minimum
packages/specholds no runtime logic. (packages/specnot touched.)pnpm lintpasses. (ui/is linted by its own config; the lint readings are above.)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/.