Install
openclaw skills install @bovinphang/fec-component-testingUse 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.
openclaw skills install @bovinphang/fec-component-testing#Component testing
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.
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.
Each test keeps Arrange / Act / Assert clearly segmented: preparing data and rendering, performing user actions, asserting user-visible results or exposing contracts.
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");
});
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);
});
Prefer roles, labels, and visible text; only use data-testid when there is no stable semantics.
vi.mock("../api/users", () => ({
fetchUsers: vi.fn(async () => [{ id: "1", name: "Ada" }]),
}));
Each complex component covers at least:
function setup() {
const user = userEvent.setup();
const onSubmit = vi.fn();
render(<ProfileForm onSubmit={onSubmit} />);
return { user, onSubmit };
}
Put the repetitive rendering logic into setup, but don't hide the core actions and assertions of the test.
findBy* or waitFor for asynchronous assertions, do not use fixed delays.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.