Repository navigation
Commit 2436b2f
test(plugin-gantt): fold four more ObjectGantt pins onto the shared harness (#30745)
<!-- claude-projects-attribution: {"github_login":"os-sales"} -->
_Requested by **Sales** · [project
thread](https://claude.ai/code/project/chan_01D5bWFY3rFzgJcytD5gD4Uu?thread=cmsg_01D5bWFY3rFzgJcytD5gD4UuDYk72QQ4SmR4iyCBay2TWJ)_
Part of #29469
Clause-②: no
Metadata-protocol: none
## 维护者速读
- **改了什么**:甘特图组件再把 4 个用同一套 mock 的单卡测试文件合进 #30725 建的共享测试文件
`ObjectGantt.harness.test.tsx`,每个原文件变成一个顶层 `describe`,断言一字未改;另把 12
个测试文件注释里还写着已合并文件名的地方,改成指向共享文件里对应的块。
- **为什么改**:#29469 的推广,甘特图族的第二片也是最后一片(席位修订 2:每族最多两个 PR)。本地同机实测,这 4
个文件并入后,共享文件加这 4 个的 CPU 从约 20.3 秒降到约 8.9 秒,整个甘特图测试族再快约 8%。
- **风险与回滚**:只动测试文件(含注释),不改源码、门禁、CI,不发布任何东西;块之间串状态的风险已用全包测试排除。回滚 = revert
本 PR。
- **先看**:`ObjectGantt.harness.test.tsx` 开头 75 行(`sonner` mock
改成并集、槽位类型改成 `(props: never)`);再看 `ObjectGantt.invalidationRefetch-10035`
块的 `beforeEach`(带 hook 的替身改成具名组件)。
- **两分钟验证**:在 `ui/` 下跑 `pnpm exec vitest run
packages/plugin-gantt/src/ObjectGantt.harness.test.tsx`,应见 1 个文件、52
个测试全过。
- **需要你做的**:无,席位落地。
## What changes
Slice 1b, the second and last `ObjectGantt*` PR of the shared-setup
rollout (ruling 6583487846 on #29469; seat amendment 2, 6672694520: at
most two PRs per family). Four more pins render the real `ObjectGantt`
over the same three mocks as the seven blocks #30725 folded (`sonner`'s
toast, a `./GanttView` stand-in, `@object-ui/plugin-detail` with
`RecordDetailDrawer` and `deriveRecordPageHref` stubbed out), so they
join `ui/packages/plugin-gantt/src/ObjectGantt.harness.test.tsx` the
same way:
- `ObjectGantt.colorFieldLadder-7243`,
`ObjectGantt.invalidationRefetch-10035`,
`ObjectGantt.propertiesBag-10859` and
`ObjectGantt.retiredApiProvider-12325` are each a top-level `describe`
named after the former file, docblock above it, stand-in installed in a
`beforeEach` through the `standIns` slot, everything else moved verbatim
and re-indented by two spaces.
- Three changes to the harness's shared part, each needed by one of the
four:
- The `sonner` mock is now the union of the blocks' mocks, `{ error,
success }`: `invalidationRefetch-10035` mocked `success` too. No block
asserts on a toast, and `ObjectGantt.tsx` calls only `toast.error`.
- The slot is typed `(props: never) => unknown` and called with `props
as never`, so a stand-in keeps its own props annotation
(`propertiesBag-10859` types its `tasks`).
- The `invalidationRefetch-10035` stand-in calls `React.useState`, so
its `beforeEach` declares it as `const GanttView = …` and assigns that
to the slot; an arrow assigned straight to `standIns.ganttView` fails
`react-hooks/rules-of-hooks`. The body is unchanged, and it still runs
inside the mocked `GanttView`.
- The comment above `import './index'` is `propertiesBag-10859`'s, which
said why the import is at module scope.
- `ObjectGantt.test.tsx` names the `retiredApiProvider-12325` block
instead of the deleted file.
**Comments that named a folded file (amendment 2).** Twelve test files
in eight workspace packages named one of the eleven files #30725 and
this PR fold. Each now names the block and the harness file (comment
text only): `plugin-gantt` `ObjectGantt.hostRowClick-27057`,
`plugin-list` `ListView.ganttPagingChrome-7210`,
`ListView.ganttToolbarFilter-10037`,
`ListView.selfQueryingViewsToolbarState-10250`, `ListView.test.tsx`,
`ObjectGallery.hostOwnsRows-7390`, `plugin-view`
`ObjectView.fetchAllowList-10982`, `react`
`useSettledSchema.equalPayload-10106`, `app-shell`
`ObjectView.refreshInPlace-10035`, `core` `record-color`, `types`
`object-gantt-properties-bag-10859-b6`, and one `pins` description
string in
`ui/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts` (the
`object-gantt.gantt` row). That ledger checks a pin's `file` (exists, is
collected, names the block and the key), never its `pins` text. The five
source files that name a folded file (`ObjectGantt.tsx`, `index.tsx`,
`ObjectTimeline.tsx`, `ListView.tsx`, `ObjectView.tsx`) are unchanged,
as amendment 2 says; each stem still `git grep`s to its `describe`.
Test files only: no source file, no changeset (`skip-changeset`). No
package entry imports a test file: the plugins and the console bundle
from their entries with `vite build`, the built `core`, `types` and
`react` `dist` hold no module that imports `vitest`, and `app-shell` is
private.
## Tests
### Former file → describe (no title or assertion dropped)
TypeScript AST walk of each former file at `f18fd963` (the #30725 head,
where they still exist) against the `describe` of the same name in the
harness at this PR's head.
| former file | `it` before | `it` after | `expect(` before | `expect(`
after | titles identical |
|---|--:|--:|--:|--:|:-:|
| `ObjectGantt.colorFieldLadder-7243.test.tsx` | 6 | 6 | 9 | 9 | yes |
| `ObjectGantt.invalidationRefetch-10035.test.tsx` | 3 | 3 | 10 | 10 |
yes |
| `ObjectGantt.propertiesBag-10859.test.tsx` | 6 | 6 | 21 | 21 | yes |
| `ObjectGantt.retiredApiProvider-12325.test.tsx` | 2 | 2 | 7 | 7 | yes
|
| **total** | 17 | 17 | 47 | 47 | yes |
The harness now holds 11 top-level `describe` blocks and 52 tests (35
from #30725, 17 from here), all passing.
### CPU before and after (local A/B, one machine)
**CI after: NOT MEASURED**, for the reason #30725 gives: the per-file
timings reporter (#29517) uploads on `main`'s full-battery runs only.
Its first after-reading is the first full-battery `main` run after this
merges.
Local A/B on one 4-vCPU container, under `os-verify-lock` (shared-box
seconds), same command both legs, two runs each, from `ui/`: `pnpm exec
vitest run <every ObjectGantt*.test.ts(x) in plugin-gantt>
--maxWorkers=2`, with a throwaway reporter reading each module's
`diagnostic()`. Fixed = environment + prepare + setup + import. The
"before" leg restores the four files and the #30725 harness from
`f18fd963` into this branch's tree, so both legs run the same 45 other
files.
| | files | tests passed | fixed CPU | test CPU | total CPU | wall |
|---|--:|--:|--:|--:|--:|--:|
| ObjectGantt family, before (run 1 / run 2) | 50 | 327 | 143.4 / 144.6
s | 10.5 / 10.6 s | 153.9 / 155.2 s | 82.3 / 83.1 s |
| ObjectGantt family, after (run 1 / run 2) | 46 | 327 | 131.8 / 131.6 s
| 10.3 / 10.8 s | 142.1 / 142.4 s | 75.8 / 77.1 s |
| harness + the four, before → harness, after (run 1) | 5 → 1 | 52 → 52
| 18.6 → 7.2 s | 1.8 → 1.6 s | 20.4 → 8.8 s | |
| harness + the four, before → harness, after (run 2) | 5 → 1 | 52 → 52
| 18.5 → 7.4 s | 1.7 → 1.6 s | 20.2 → 8.9 s | |
The four files cost 12.4 / 12.3 s on their own; folded, they add about
0.8 s to the harness. The family went from 154.6 s to 142.3 s of CPU
(−8.0 %), wall −8 %. The A/B ran on `e673f7c6`, the pre-merge commit of
this fold; its `plugin-gantt` tree is byte-identical to this branch's
`7cbfc512`, and the head adds one comment-only commit (`6a0388d8`).
## Acceptance notes
- **Why this cluster and not the biggest one left.** The largest cluster
still unfolded is 18 pins that mock `./GanttView` only, 3,722 lines;
moving them into a harness changes about twice that, over 7,000 lines,
which no single PR under the 3,000-line bar can carry. Amendment 2 has a
family's second PR fold the next cluster that fits, and these four are
the pins left on the harness's own mock set.
- **`ObjectGantt.elementDataSource` stays its own file.** It shares the
harness's three mocks, but
`ui/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts`
names its path as the `object-gantt.dataSource` pin, and that ledger
fails when the file is gone. The ledger is outside the claim's file
surface.
- **Unfolded `ObjectGantt*` pins (amendment 2: listed in the family's
last PR).** 39 files in `ui/packages/plugin-gantt/src/`, by the setup
they share; `ObjectGantt.test.tsx` is the component's main suite, not a
per-issue pin, and is not counted. Lines at this PR's head.
| setup the files share | files (lines) | lines |
|---|---|--:|
| `./GanttView` stand-in only (real `sonner`, real
`@object-ui/plugin-detail`) | `contractEnvelope-6839` (328),
`currencyDep` (296), `currencyMode-10422` (136), `dateLocale` (132),
`discardedConfigMemo` (124), `invalidBlockRefusal-13459` (102),
`numberLocale` (333), `numberResolvedWidth-11254` (195),
`percentResolvedWidth-11254` (158), `persistfilters` (113),
`quickfilter.i18n.fallback` (84), `quickfilter.i18n` (149),
`quickfilter` (377), `readback` (152), `referenceArms-6837` (316),
`staleReloadFinally-7231` (359), `unconfiguredRefusal-7070` (187),
`writeGrant-12082` (181) | 3722 |
| `./GanttView` stand-in and a `sonner` mock (`error` + `success`;
`writeerror` mocks `error` only), real `@object-ui/plugin-detail` |
`errorClears-10578` (339), `refreshInPlace-7237` (288),
`silentOvertake-10633` (367), `writeerror` (112) | 1106 |
| no `vi.mock` at all (real `GanttView`) | `configPin` (218),
`exportFileName.i18n` (222), `pluginDriverTree` (136),
`taskColumnLabel-27386` (96) | 672 |
| `./GanttView` and `./ResourceWorkload` stand-ins (`viewmode`'s
workload stand-in also writes `viewMode`) | `blockPrecedence` (281),
`dependencyAlias` (140), `viewmode` (112) | 533 |
| `@object-ui/plugin-detail` with `RecordDetailPanel` replaced (a
different stand-in in each), plus `sonner` in `drawerfetch` and
`hostRowClick-27057` | `drawerfetch` (171), `drawerlock` (91),
`hostRowClick-27057` (155) | 417 |
| an `@object-ui/react` `useNavigationOverlay` spy and `sonner`;
`navigationModeResolution-7334` stubs the record drawer,
`navigationPageSink-7334` replaces `RecordDetailPanel` |
`navigationModeResolution-7334` (225), `navigationPageSink-7334` (253) |
478 |
| `@object-ui/components` `NavigationOverlay` wrapped, plus `sonner`
(`overlayShellModes-9299` also mocks `@object-ui/plugin-detail` and
`@object-ui/react`) | `navWidthDefault` (235), `overlayShellModes-9299`
(292) | 527 |
| the harness's three mocks plus a patched `react` (`useMemo`,
`useCallback`) | `discardedReloadIdentity-10036` (348) | 348 |
| `@object-ui/permissions` (`usePermissions`) mocked | `expandFls-7230`
(225) | 225 |
| the harness's three mocks, but `ui/apps/console`'s
`registry-inputs-spec-parity.test.ts` ledger names this path (outside
the claim), so it stays a file | `elementDataSource` (243) | 243 |
| **total** | 39 files | 8271 |
- Whether to fold further is a new card the seat files after #29469
closes (amendment 2).
## Verification
At head `6a0388d8`, after `pnpm install --frozen-lockfile` and building
the closure (`turbo run build` for `@objectstack/spec`, `formula`,
`lint`, `client`, `metadata-protocol`, then
`--filter='@object-ui/plugin-gantt^...'` from `ui/`), under
`os-verify-lock`, VERDICT command-exit 0:
- `pnpm exec vitest run packages/plugin-gantt/ --maxWorkers=2` from
`ui/`: 96 files passed, 1 skipped; 788 tests passed, 114 skipped. Four
fewer files than at `main`, the same 788 / 114 tests; the skipped file
and tests are skipped on `main` too.
- `pnpm run type-check` in `ui/packages/plugin-gantt` (`tsc --noEmit &&
tsc -p tsconfig.test.json`): exit 0, 0 `error TS`.
- `pnpm run lint` in `ui/packages/plugin-gantt`: exit 0, 0 errors.
`eslint` from `ui/` on the 14 added or modified files: exit 0, 0 errors,
173 warnings. The harness's 63 warnings are the 43 the #30725 harness
had plus the 20 the four former files gave at `f18fd963`; the other 13
files changed comment or description text only.
- Derived gates (`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack`, change set 18 paths against merge base
`447226b2`): 26 derived, 26 run under `os-verify-lock` (VERDICT
command-exit 0), each exit 0 captured before any pipe; `pnpm --dir ui
exec vitest run scripts/` gave 170 files passed and 2 skipped, 4970
tests passed. `--ran` reconciliation: 26 derived, 26 run, 0
NOT-MEASURED, 0 UNRUN.
- Size: `git diff --shortstat origin/main HEAD` is 18 files, +734 /
-788, 1,522 changed lines. No open pull request touches any of the 18
files (file lists of all open PRs read after #30725 merged).
- No ablation: no tested behaviour changed; the assertions moved
verbatim.
## Human Minimum
- [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic.
(`packages/spec` not touched.)
- [x] 2. Every name I added uses the casing for its kind.
- [x] 3. No formatter ran; `pnpm lint` passes. (`ui/` is linted by its
own config; the package lints are above.)
- [x] 4. One issue, one branch off an up-to-date `main`, one pull
request.
- [x] 5. A change that publishes carries a changeset, and both
declaration lines are filled in here and in the changeset. (Nothing
publishes: `skip-changeset`.)
- [x] 6. `packages/spec` touched: its generated artifacts are
regenerated and committed. (Not touched.)
- [x] 7. No hand edits to `content/docs/references/`,
`packages/*/CHANGELOG.md` or `content/docs/releases/`.
- [x] 8. Title, body and comments are in English (the maintainer
quick-read is the allowed Chinese section).
---
_Generated by [Claude
Code](https://claude.ai/code/session_01L6bhgXNVxCQk1CCy55gFjQ)_
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01L6bhgXNVxCQk1CCy55gFjQ
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 081fb4a commit 2436b2f
18 files changed
Lines changed: 734 additions & 788 deletions
File tree
- ui
- apps/console/src/__tests__
- packages
- app-shell/src/views
- core/src/utils/__tests__
- plugin-gantt/src
- plugin-list/src/__tests__
- plugin-view/src/__tests__
- react/src/hooks/__tests__
- types/src/__tests__
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3418 | 3418 | | |
3419 | 3419 | | |
3420 | 3420 | | |
3421 | | - | |
| 3421 | + | |
3422 | 3422 | | |
3423 | 3423 | | |
3424 | 3424 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
53 | 53 | | |
54 | 54 | | |
55 | 55 | | |
56 | | - | |
| 56 | + | |
| 57 | + | |
57 | 58 | | |
58 | 59 | | |
59 | 60 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
13 | 13 | | |
14 | 14 | | |
15 | 15 | | |
16 | | - | |
| 16 | + | |
| 17 | + | |
17 | 18 | | |
18 | 19 | | |
19 | 20 | | |
| |||
This file was deleted.
0 commit comments