资讯动态

Astryx 共享测试工具链解析:基于 Vitest + Testing Library 的 monorepo 测试基座

发布时间:2026/9/15 13:32:16 来源:尧图企业网站定制
Astryx 共享测试工具链解析基于 Vitest Testing Library 的 monorepo 测试基座【免费下载链接】astryxAn open source design system thats fully customizable and agent ready项目地址: https://gitcode.com/GitHub_Trending/as/astryx导读本文围绕 Astryx 设计系统 monorepo 中的 internal/test-utils 目录展开剖析这套所有包共用一套测试能力的基座是如何搭建的。你将了解它的三个核心组成统一入口index.ts、加载在每条测试之前的setup.ts、以及只在整套测试启动时执行一次的globalSetup.ts同时结合根级 vitest.config.ts 掌握它们如何被接入、如何支撑uijsdom 组件与node纯 Node 逻辑双项目测试分区。读完即可在自己的设计系统或组件库 monorepo 中复刻同样的测试基建规避 jsdom 环境下matchMedia、Popover API、localStorage缺失与 aria-live 区域导致的脆弱断言等典型坑。一、定位为整个 monorepo 共享的 Vitest 测试工具internal/test-utils是 Astryx 仓库中一个独立的内部工具包package.json中的包名为astryxdesign/test-utils版本0.0.1标记为private: true它不对外发布只为仓库内所有包的测试服务。目录结构与职责如下表来源internal/test-utils/README.md目录/文件角色用途src/源码测试工具源码package.json配置包配置与依赖声明其源码src/目录进一步拆成三个文件来源internal/test-utils/src/README.md文件角色用途index.ts入口从testing-library/react重导出测试工具setup.ts设置Vitest 设置文件用 jest-dom 扩展匹配器globalSetup.ts全局设置Vitest 全局设置钩子重新生成 i18n 伪本地化产物依赖面非常收敛只有三样来源internal/test-utils/package.json{ dependencies: { testing-library/jest-dom: ^6.6.0, testing-library/react: ^16.3.2, testing-library/user-event: ^14.5.0 } }二、统一入口index.ts如何聚合 Testing Libraryindex.ts是整个测试工具包的对外门面内容极短却承担了关键的版本对齐作用来源internal/test-utils/src/index.tsexport * from testing-library/react; export { default as userEvent } from testing-library/user-event;它做两件事重导出testing-library/react的全部 API包括render、screen、fireEvent、waitFor等以默认导出方式重导出userEvent让测试文件可以直接import {render, screen, userEvent} from astryxdesign/test-utils。这样做最大的价值在于整个 monorepo 只存在一份 Testing Library 版本。组件库最怕不同包各自引入不同版本的 Testing Library导致 matcher 行为、user-event的时钟语义不一致从而产生本地能过、CI 挂了的版本漂移问题。把所有测试文件统一到这一个入口上版本冲突从根本上被消除。注意其main字段直接指向./src/index.tsTypeScript 源码而非编译产物说明该包只服务于仓库内测试不经构建直接消费。三、测试设置文件setup.ts中的 jsdom 环境修复setup.ts是 Vitest 的setupFiles在每条测试文件执行前加载负责两件事扩展断言匹配器与补齐 jsdom 缺失的浏览器 API来源internal/test-utils/src/setup.ts。3.1 用 jest-dom 扩展 expectimport testing-library/jest-dom/vitest;这行导入把toBeInTheDocument、toHaveTextContent、toBeVisible等 jest-dom 匹配器注册进 Vitest 的expect组件断言因此可以直接使用这些语义化匹配器。/// reference typestesting-library/jest-dom /则保证 TypeScript 能识别这些扩展后的全局类型。3.2 关键决策默认忽略 aria-live 区域这是该文件最有设计系统特色的一处配置import {configure} from testing-library/react; configure({defaultIgnore: script, style, [data-astryx-live-region]});背景是 Astryx 的useAnnounce会渲染一个视觉隐藏的 aria-live 区域data-astryx-live-region它把可见的标签文本镜像给屏幕阅读器被约 17 个组件使用如 Calendar、Pagination、Typeahead、Switch。这带来一个陷阱getByText(January 2026)可能同时命中真实标签与其镜像播报且两者是否同时存在取决于交互后的 effect 时序导致高负载下出现found multiple elements的偶发失败。因此默认配置让文本查询getByText/findByText等忽略 live 区域若测试要断言播报内容应直接按rolestatus查询该区域。3.3matchMedia双份 polyfill 与 hover 语义jsdom 原生不支持matchMedia文件里出现了两段 polyfill一段直接赋值window.matchMedia一段通过Object.defineProperty定义并特意让(hover: hover)媒体查询返回truejsdom 模拟的是桌面浏览器若返回false所有 hover 门控行为useMenuHover、HoverCard、Tooltip在测试中都会静默失效——历史上 #3121 的 hover 后点击 bug 之所以在三个组件中漏网部分原因就是没有任何单测能触达 hover 路径。需要模拟触屏设备的测试需在单测内自行覆盖该查询。3.4 其余浏览器 API polyfillPopover APIjsdom 不支持showPopover/hidePopover/togglePopover此处为HTMLElement.prototype补齐空实现防止测试 XDSTooltip 等组件时抛错localStorage当前 jsdom 构建不暴露localStorage此处用Map实现了一个最小Storage兼容对象支撑useResizable的autoSaveId持久化逻辑的测试。四、全局设置globalSetup.ts保持 i18n 产物新鲜globalSetup.ts只在整个测试套件启动前运行一次来源internal/test-utils/src/globalSetup.tsconst repoRoot resolve(HERE, .., .., ..); const script resolve( repoRoot, packages, core, scripts, build-pseudo-locale.mjs, ); execFileSync(node, [script], {stdio: inherit});它定位仓库根目录调用 packages/core/scripts/build-pseudo-locale.mjs 重新生成packages/core/locales/pseudo.json。这个文件被 git 忽略、由en.json派生属于伪本地化pseudo-locale目录用于 i18n 测试由于测试可以直接 import 它若不在套件前重新生成就会读到过期的旧产物。该钩子保证每次跑测试时伪本地化目录都是最新状态无需先执行构建步骤。五、接入方式根级vitest.config.ts中的装配与双项目分区工具包本身不直接运行而是被根级 vitest.config.ts 引用装配test: { globals: true, environment: jsdom, coverage: {provider: v8, reporter: [text, json, html]}, setupFiles: [./internal/test-utils/src/setup.ts], globalSetup: [./internal/test-utils/src/globalSetup.ts], execArgv: [--max-old-space-size4096], ... }setupFiles指向setup.ts每条测试前执行globalSetup指向globalSetup.ts套件启动前执行一次execArgv将 worker 堆上限提到 4 GB 以应对 Chat 编辑器等内存密集型测试的 OOM。Vitest 4 移除了独立的vitest.workspace.ts改为内联test.projects仓库据此把测试切成两个项目ui项目extends: true继承根配置包含packages/core、packages/lab、packages/charts、packages/richtext、packages/vega需要 jsdom、StyleX babel 转换与 jest-dom 匹配器node项目刻意不extends纯 Node 环境包含 CLI、构建工具、脚本、internal/**以及无需 DOM 的 app 级套件绕过 jsdom 实例化的开销但它自带resolve.alias把astryxdesign/theme-*裸导入映射到各主题包的src/source.ts因为主题包指向dist/而测试运行从不构建产物。两个项目均将testTimeout/hookTimeout提到 30 秒jsdom 组件套件单测 p95 约 1.8snode项目大量测试会为每条断言spawn一个全新的node bin/astryx.mjs真实进程边界fork 池必须保留默认 5s 超时在忙碌机器上会引发timed out in 5000ms的非确定性抖动。node项目还额外挂载了 vitest.global-setup.node.mjs它调用 CLI 的ensureCoreBuilt()在 worker fork 之前一次性构建astryxdesign/core因为 build-theme 套件需要编译后的 core且必须在主进程先行完成避免多个 worker 并发 clean-and-build 互相踩踏曾引发 Could not resolve dist/index.js。最后配置注释强调了分区规则凡自带独立 vitest 配置的 app/包两个项目都不可见等于不在任何 CI 任务中——新套件应加入 include 列表而不是新增第二份配置。六、测试实践中的配套使用方式测试文件直接消费统一入口例如组件测试从astryxdesign/test-utils导入render、screen、userEvent与 jest-dom 匹配器风格完全一致断言 live 区域播报文本断言默认忽略data-astryx-live-region需要验证播报时通过rolestatus直接查询该区域hover 语义默认(hover: hover)为trueuserEvent.hover()可触发真实的mouseenter/mouseleave使 HoverCard、Tooltip、菜单悬停路径可达触屏场景按需单测内覆盖node 侧套件CLI/脚本类测试在纯 Node 项目内以真实子进程边界运行无需关心 jsdom。七、小结这套基座解决的四类问题版本漂移统一入口让整个 monorepo 只存在一份 Testing Library杜绝 matcher/user-event行为不一致环境缺失setup.ts补齐matchMedia含 hover 语义、Popover API、localStorage并默认忽略 aria-live 区域避免脆弱断言产物新鲜globalSetup.ts在套件启动时重新生成伪本地化目录测试无需前置构建分区与超时ui/node双项目让 DOM 套件与纯逻辑套件各得其所30s 超时与构建前置解决了 fork 池下的非确定性失败。如果你的组件库 monorepo 也面临 jsdom 环境缺口、跨包版本不一致或 CI 偶发超时直接对照 internal/test-utils/src/setup.ts 与 vitest.config.ts 逐项迁移即可。【免费下载链接】astryxAn open source design system thats fully customizable and agent ready项目地址: https://gitcode.com/GitHub_Trending/as/astryx创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价