fix(create-plugin): 让脚手架产物的 npm test 从第一次就能跑 (#3716) - #3733
Conversation
The generator wrote `src/<Pascal>Impl.test.tsx` importing
`@testing-library/react` and asserting with `toBeInTheDocument()`, plus a
`test: 'vitest run'` script, while the generated `devDependencies` declared
neither library and the generated `vite.config.ts` had no `test` block. All
three failure modes stacked, so `pnpm test` in a freshly scaffolded plugin was
red on the very first run.
- declare `@testing-library/react`, `@testing-library/jest-dom` and `jsdom`,
each range copied verbatim from this monorepo's own root manifest rather
than invented
- add `test: { globals: true, environment: 'jsdom', setupFiles: [...] }` to the
generated Vite config (`globals` is load-bearing: RTL only registers its
automatic cleanup when `afterEach` exists as a global)
- write `vitest.setup.ts` registering the jest-dom matchers, via the `/vitest`
entry point so it does not depend on a global `expect`
- move the templates to `src/templates.ts` so the generated artifacts can be
pinned without executing the CLI (`index.ts` calls `program.parse()` at
import time), and pin them: every bare import in the generated example test
must be a declared dependency, `setupFiles` must name a file the generator
writes, and the three ranges must equal the repo root's
Fixes #3716
Co-Authored-By: Claude <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
…ed source The pin only read the example test, so an undeclared import added to any other template — including the side-effect `import 'pkg';` form the generated Vitest setup file uses — would not have been caught. It now walks every generated `.ts`/`.tsx` file, folds subpath specifiers onto their package name (so `@testing-library/jest-dom/vitest` is checked against the declared `@testing-library/jest-dom`) and skips Node builtins (the generated Vite config imports `path`, which nothing has to declare). Verified by probe: planting `import 'chai-dom';` in the setup template turns it red with "vitest.setup.ts imports chai-dom, which is not declared". Co-Authored-By: Claude <noreply@anthropic.com>
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
CI's `check-type-check-coverage.mjs` caught what the package-scoped `pnpm type-check` could not: `tsconfig.json` excludes `**/*.test.ts` (correctly — it is the build config), so the new `templates.test.ts` was read by no `tsc` invocation at all. An unchecked test can assert a contract the compiler never checked and then read as evidence that the contract holds. Adds `tsconfig.test.json` on the `packages/types` pattern (emit-free, `paths` dropped, `types: ["node"]` for the manifest read) and chains it from `type-check`, which is the script CI runs. Zero errors; the guard now reports 23/38 packages compiling their tests, up from 22. Co-Authored-By: Claude <noreply@anthropic.com>
|
补记两个 commit,以及 CI 抓到的一条本地跑法抓不到的问题。
反证跑过,不是想当然:往 setup 模板里种一个
值得记下来的是为什么本地没抓到:我确实手动用一份临时 tsconfig 编过这个文件(0 error),但只把它当"确认我没写错",没把"没有任何常驻程序读它"本身当成缺陷;而包内 修法照 补充的本地验证: Generated by Claude Code |
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
Fixes #3716
前提复核(在
origin/main=4e93e40d上重核,非分诊时的0cf8f0f)卡片的三条事实全部成立,且逐条跑成了真实失败,不是读代码推断的:
test: 'vitest run'脚本src/index.ts:140devDependencies只有五项:154-160,无@testing-library/react/@testing-library/jest-dom/jsdom:362vite.config.ts无test段environment/jsdom/setupFiles零命中用修复前的生成器生成一个插件、只按它自己声明的依赖搭
node_modules(离线软链,不联网装),vitest run的真实输出:把三个库补进那份
node_modules、但保留原样的vite.config.ts(仍无test段),第二层失败随即露出 —— 印证卡片「即便补上依赖,默认 node 环境仍渲染不了」这一条:改了什么(路线 A,按分诊裁决)
devDependencies补@testing-library/react、@testing-library/jest-dom、jsdom;vite.config.ts增加test: { globals: true, environment: 'jsdom', setupFiles: ['./vitest.setup.ts'] };vitest.setup.ts,注册 jest-dom 的 matcher;src/index.ts抽到新文件src/templates.ts(纯函数,无副作用),使产物本身可被单测断言 ——index.ts在 import 时就program.parse(),任何测试都无法 import 它来看它生成了什么,只能去 grep 源码字符串,而那正是「改坏了还绿着」的写法。抽出后index.ts里的写盘逻辑收敛成一个循环,buildPluginFiles()是「一个插件包含哪些文件」的唯一真相。同一包内
README.md的产物树补上第 9 个文件(本 PR 使它少一行,属于本次改动直接造成的失真,故一并修)。版本区间的来源(分诊裁决 #2:不许现编)
三条全部有仓内锚点,逐字抄:
@testing-library/react^16.3.2package.jsondevDependencies(apps/console同值)@testing-library/jest-dom^7.0.0package.jsondevDependencies(apps/console同值)jsdom^30.0.1package.jsondevDependencies没有「无锚点、取当前 major」的条目。
@testing-library/dom故意不声明:它是@testing-library/react16 的 peer,由本仓.npmrc的auto-install-peers=true装上 ——apps/console也正是只声明这三个而非四个。这些字面量写在
.ts里,不在 #3711 那条版本声明门禁的扫描面上,所以给它加了门禁:templates.test.ts读仓根package.json,断言模板里的三个区间与仓根逐字相等。以后谁升了仓根的 RTL 而没同步模板,这条测试红,并在失败信息里指到src/templates.ts。两个不显眼但承重的选择
globals: true不是装饰:@testing-library/react只在afterEach作为全局存在时才注册它的自动cleanup()(dist/index.js:if (typeof afterEach === 'function'))。不开 globals,示例测试今天照样绿,但作者写第二个测试的那天开始 DOM 静默泄漏。这也与仓内 15 个包的test段一致。/vitest子入口:裸入口import '@testing-library/jest-dom'扩展的是全局expect,一旦作者把globals关掉,matcher 注册就静默失效;/vitest入口显式import { expect } from 'vitest',与 globals 开关解耦。钉子(9 条,
packages/create-plugin/src/__tests__/templates.test.ts)不是 grep 源码,而是断言在生成器写盘用的同一份 file map 上。其中两条是结构性的,比字符串匹配值钱:
package.json声明过的依赖 —— 这就是本 bug 的一般化形式:以后谁往示例测试里再加一个没声明的 import,红;vite.config.ts里setupFiles指的那个路径,必须是生成器真的会写出来的文件 —— 防的是「配置指向一个不存在的 setup 文件」这种半拉子状态。反向验证(方向先判、再跑)
预判是常规的「红」方向:把三处改动回退(去掉三个依赖、去掉
test段、不再写 setup 文件),9 条里应有 5 条转红。实测 7 条红,预判的条数错了(我把 vite.config 的三条断言当成两条数,又漏数了 file map 那条),方向没错。留绿的两条值得写下来,因为它们正是「因为什么都没产出所以还绿着」的形状:
has its jest-dom matchers registered by the setup file—— 它断言的是buildVitestSetup()这个函数的返回值,而回退只是不再把它写进 file map,函数本身还在,于是照样绿。真正能抓住「setup 文件不再被写出」的是它旁边那两条 map 级断言(points setupFiles at a file the generator actually writes、file map 清单),所以这条是被配对覆盖的,不是唯一的钉子。keeps every path inside the generated plugin directory—— 与本次回退无关的路径穿越断言。产物一致性(裁决 #4)
node dist/index.js heat-map真的生成一遍,9 个文件齐全(含vitest.setup.ts),然后用只含它自己声明的依赖的离线node_modules跑它自己的vitest run:链进去的实际版本 ——
jsdom 30.0.1、@testing-library/react 16.3.2、@testing-library/jest-dom 7.0.0、vitest 4.1.10—— 全部落在模板声明的区间内。未做联网pnpm install(裁决说不必,也确实慢且易 flaky);build 侧三个包(vite/@vitejs/plugin-react/vite-plugin-dts)链的是仓内现有版本,高于模板声明的区间,这一点见下。不在本 PR 范围,但本 PR 造成或撞见的
content/docs/utilities/create-plugin.mdx需要跟进(属 create-plugin.mdx 描述的是一个不存在的脚手架:提示词、产物目录、dev 脚本、配置文件、版本与依赖清单全部与真实生成器不符 #3715 席位,本 PR 按裁决未碰):该页「Generated Structure」树现在少了第 9 个产物vitest.setup.ts;而且该页有一句把「manifest literal」指向packages/create-plugin/src/index.ts,本 PR 之后那份字面量在src/templates.ts。已在 create-plugin.mdx 描述的是一个不存在的脚手架:提示词、产物目录、dev 脚本、配置文件、版本与依赖清单全部与真实生成器不符 #3715 下留评说明。vite ^7.3.1vs 仓根^8.2.0、@vitejs/plugin-react ^4.2.1vs 仓内插件普遍^6.0.5、vite-plugin-dts ^4.5.4vs^5.0.3、typescript ^5.9.3vs^6.0.3、vitest ^4.0.18vs^4.1.10),另开 issue,未在本 PR 动 —— 本 PR 只负责它新增的那三条有锚点。顺带记录:生成的vite.config.ts用__dirname,vite 8 的 native configLoader 已就此告警。本地验证
注:
pnpm --filter @object-ui/create-plugin test这条跑不了 —— 它是包目录 cwd 启动 vitest,被scripts/vitest-invocation-guard.mjs(objectui#3378)按设计拒绝。上面用的是它指定的仓根跑法。Generated by Claude Code