fec-component-testing · diff
git:20260529.c76cc44 to git:20260611.9d7f5e4
39 added, 39 removed. Audit A to A.
---
name: fec-component-testing
- description: Use when authoring or reviewing frontend unit, component, or light integration tests close to UI code, including React Testing Library, Vue Test Utils, hooks/composables, props/emits, callbacks, accessible queries, user-event interactions, mocks, loading/error/empty states, and regression coverage. For layer planning, real-browser journeys, or existing validation failures, choose the matching testing or validation workflow first; Chinese triggers include 组件测试, 组件单测, 单元测试, 轻量集成测试.
+ description: Use when authoring or reviewing frontend unit, component, or light integration tests close to UI code, including React Testing Library, Vue Test Utils, hooks/composables, props/emits, callbacks, accessible queries, user-event interactions, mocks, loading/error/empty states, and regression coverage. For layer planning, real-browser journeys, or existing validation failures, choose the matching testing or validation workflow first; Chinese triggers include component testing, Component unit testing, unit testing, lightweight integration testing.
---
- # 组件测试
+ #Component testing
## Purpose
- 用贴近代码和用户行为的测试验证纯逻辑、组件契约与轻量模块协作,减少重构和 UI 交互回归。
+ Use tests close to the code and user behavior to verify pure logic, component contracts, and lightweight module collaboration to reduce refactoring and UI interaction regression.
## Procedure
- ### 1. 先确定测试层级
+ ### 1. First determine the test level
- - 单元测试:纯函数、hooks/composables、utils、状态逻辑、schema。
- - 组件测试:props/emits、回调、用户交互、loading/error/empty、mock 边界。
- - 轻量集成测试:表单 + API mock + Router/Store/Provider 上下文。
+ - Unit testing: pure functions, hooks/composables, utils, state logic, schema.
+ - Component testing: props/emis, callbacks, user interaction, loading/error/empty, mock boundaries.
+ - Lightweight integration testing: form + API mock + Router/Store/Provider context.
- 跨页面真实浏览器流程分流到 E2E workflow;测试层选择不清楚时先做测试分层规划。
+ The cross-page real browser process is offloaded to the E2E workflow; if the test layer selection is unclear, do the test layering planning first.
- ### 2. 优先按用户可感知行为测试
+ ### 2. Prioritize testing based on user-perceivable behavior
- 每个测试保持 Arrange / Act / Assert 清晰分段:准备数据和渲染、执行用户动作、断言用户可见结果或公开契约。
+ Each test keeps Arrange / Act / Assert clearly segmented: preparing data and rendering, performing user actions, asserting user-visible results or exposing contracts.
```tsx
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { SearchBox } from "./SearchBox";
test("submits the entered keyword", async () => {
const user = userEvent.setup();
const onSearch = vi.fn();
render(<SearchBox onSearch={onSearch} />);
await user.type(screen.getByRole("searchbox", { name: /keyword/i }), "orders");
await user.click(screen.getByRole("button", { name: /search/i }));
expect(onSearch).toHaveBeenCalledWith("orders");
});
```
- ### 3. Vue 组件使用可访问查询或明确文本断言
+ ### 3. Vue components use accessible queries or explicit text assertions
```ts
import { mount } from "@vue/test-utils";
import UserMenu from "./UserMenu.vue";
test("emits logout when the logout item is clicked", async () => {
const wrapper = mount(UserMenu, {
props: { userName: "Ada" },
});
await wrapper.get('[data-testid="logout-button"]').trigger("click");
expect(wrapper.emitted("logout")).toHaveLength(1);
});
```
- 优先使用角色、标签和可见文本;仅在没有稳定语义时使用 `data-testid`。
+ Prefer roles, labels, and visible text; only use `data-testid` when there is no stable semantics.
- ### 4. 控制 mock 边界
+ ### 4. Control mock boundaries
```ts
vi.mock("../api/users", () => ({
fetchUsers: vi.fn(async () => [{ id: "1", name: "Ada" }]),
}));
```
- - mock 网络、时间、路由和浏览器 API。
- - 不 mock 被测组件的内部函数。
- - 对设计系统基础组件只做轻量 mock,保留可访问行为。
- - mock 数据应表达业务场景,不使用只有测试作者能理解的随意字符串。
- - 共享 fixture 应保持可读,复杂对象用 builder 补默认值;每个测试只覆盖与场景相关的字段。
- - mock 网络时优先模拟用户可见结果和错误形状,不复制后端实现细节。
+ - Mock network, time, routing and browser APIs.
+ - Do not mock the internal functions of the component under test.
+ - Only make light mocks of the basic components of the design system to retain accessible behaviors.
+ - Mock data should express the business scenario and not use arbitrary strings that only the test author can understand.
+ - Shared fixtures should remain readable, and complex objects should use builders to fill in default values; each test only covers the fields relevant to the scenario.
+ - When mocking the network, give priority to simulating user-visible results and error shapes, and do not copy back-end implementation details.
- ### 5. 覆盖关键状态
+ ### 5. Override key status
- 每个复杂组件至少覆盖:
+ Each complex component covers at least:
- - 默认渲染。
- - 用户交互和回调。
+ - Default rendering.
+ - User interaction and callbacks.
- loading / empty / error。
- - 权限或禁用态。
- - 键盘交互和焦点行为(适用时)。
+ - Permission or disabled status.
+ - Keyboard interaction and focus behavior (when applicable).
- ### 6. 保持测试可维护
+ ### 6. Keep tests maintainable
```ts
function setup() {
const user = userEvent.setup();
const onSubmit = vi.fn();
render(<ProfileForm onSubmit={onSubmit} />);
return { user, onSubmit };
}
```
- 将重复渲染逻辑放入 `setup`,但不要隐藏测试的核心操作和断言。
+ Put the repetitive rendering logic into `setup`, but don't hide the core actions and assertions of the test.
- ### 7. 回归测试先证明问题
+ ### 7. Regression testing proves the problem first
- - Bug 修复先写能复现失败的最小测试。
- - 失败原因应指向用户行为或公开契约,而不是导入错误、测试环境或等待方式。
- - 修复后保留回归测试,避免把验证只留在手工步骤里。
+ - Bug fixes should be written first to create the smallest test that can reproduce the failure.
+ - Reasons for failure should point to user behavior or public contracts, not import errors, test environments, or wait methods.
+ - Keep regression testing after fixing to avoid leaving verification only in manual steps.
## Constraints
- - 避免测试实现细节,例如内部 state 名称、私有函数调用、DOM 层级快照。
- - 不把 snapshot 作为交互组件的主要断言;它只能辅助检查稳定静态输出。
- - 异步断言使用 `findBy*` 或 `waitFor`,不要用固定延迟。
- - 测试名称应描述用户场景,而不是函数名。
- - 组件测试不能替代 E2E;路由、真实浏览器兼容和跨页流程仍需 E2E。
- - 不在测试里复制组件实现逻辑;否则测试会和错误实现一起通过。
- - 不在测试间共享可变 fixture、全局 store 或 fake timer 状态;每个用例独立 setup 和 cleanup。
+ - Avoid testing implementation details such as internal state names, private function calls, DOM hierarchy snapshots.
+ - Do not use snapshot as the main assertion for interactive components; it can only assist in checking stable static output.
+ - Use `findBy*` or `waitFor` for asynchronous assertions, do not use fixed delays.
+ - Test names should describe user scenarios, not function names.
+ - Component testing is not a replacement for E2E; routing, real-browser compatibility, and cross-page flows still require E2E.
+ - Do not copy component implementation logic in tests; otherwise the test will pass with the wrong implementation.
+ - No mutable fixtures, global store or fake timer state shared between tests; each use case has independent setup and cleanup.
## Expected Output
- 产出与组件同目录或项目约定目录下的测试文件,覆盖核心交互、状态和回归场景。验证时运行项目现有 test 命令,确认失败信息能定位到用户行为或组件契约。
+ Produce test files in the same directory as the component or in the directory agreed upon by the project, covering core interactions, status and regression scenarios. During verification, run the existing test command of the project to confirm that the failure information can be located to user behavior or component contract.