Simplify and standardize testing structure

This commit is contained in:
adilallo
2026-01-28 14:04:04 -07:00
parent e7a31789e3
commit 7ea724a8d9
95 changed files with 1534 additions and 15485 deletions
+208
View File
@@ -0,0 +1,208 @@
## Testing Guide
### Philosophy
- **Test behaviour, not implementation**: Focus on what the user can see and do, not internal details.
- **Single source of truth per component**: Each component should have **one consolidated test file**.
- **Accessibility is mandatory**: Basic a11y checks run as part of every component suite.
- **E2E is sparse**: Only cover critical user journeys that span pages or systems.
### Test Structure
The test directory structure is organized as follows:
```text
tests/
components/ # All component-focused tests (Vitest + RTL)
Button.test.tsx
Input.test.tsx
Checkbox.test.tsx
Select.test.tsx
Switch.test.tsx
pages/ # Page-level tests (home, blog, etc.)
home.test.jsx
blog.test.jsx
e2e/ # True endtoend flows + visual regression (Playwright)
homepage.spec.ts
user-journeys.spec.ts
visual-regression.spec.ts
performance.spec.ts
utils/ # Shared test utilities
componentTestSuite.tsx
msw/ # MSW server setup for mocking
server.ts
accessibility/
e2e/ # E2E accessibility checks (WCAG compliance)
wcag-compliance.spec.ts
```
**Component tests** (`tests/components/`) use the standard `componentTestSuite` utility to ensure consistent baseline coverage for all UI components. **Page tests** (`tests/pages/`) cover page-level rendering and flows. **E2E tests** (`tests/e2e/`) focus on critical user journeys, visual regression, and performance. **Accessibility E2E** (`tests/accessibility/e2e/`) provides high-level WCAG compliance checks.
### Standard Component Test Suite
Use the shared suite in `tests/utils/componentTestSuite.tsx` to get a consistent baseline:
```ts
import Component from "../../app/components/Component";
import {
componentTestSuite,
type ComponentTestSuiteConfig,
} from "../utils/componentTestSuite";
type Props = React.ComponentProps<typeof Component>;
const config: ComponentTestSuiteConfig<Props> = {
component: Component,
name: "Component",
props: {
/* default props */
} as Props,
requiredProps: ["label"],
optionalProps: {
disabled: true,
},
queries: {
getPrimaryElement: (s) => s.getByRole("button"),
},
variants: {
disabled: {
props: { disabled: true },
assert: (el) => {
expect(el).toBeDisabled();
},
},
error: {
props: { error: true } as Partial<Props>,
assert: (el) => {
expect(el).toHaveClass("border-[var(--color-border-default-utility-negative)]");
},
},
},
testCases: {
renders: true,
accessibility: true,
keyboardNavigation: true,
disabledState: true,
errorState: true,
},
};
componentTestSuite<Props>(config);
```
#### What the Standard Suite Covers
- **Rendering**
- Component renders without throwing using the provided `props`.
- Required props are present and do not break rendering.
- Optional props can be applied without breaking.
- **Accessibility**
- Runs `axe` against the rendered output.
- Fails on common WCAG 2.1 issues (roles, labels, contrast, etc.).
- **Keyboard Navigation**
- Ensures the primary element can receive focus.
- Smoketests basic keyboard activation (`Enter`, `Space`) without runtime errors.
- **Disabled State**
- Uses `variants.disabled` to verify disabled behaviour (e.g., `aria-disabled`, `disabled` attribute, tab index).
- **Error State**
- Uses `variants.error` to verify error styling/attributes when applicable.
### When to Add Custom Tests
Use the standard suite for **baseline coverage**, then add custom `describe` blocks in the same file when:
- The component has **important variants** (different sizes, modes, label variants).
- There is **nontrivial interaction** (menus, dropdowns, complex keyboard behaviour).
- You need to exercise **stateful flows** (forms, validation, error messages).
Example (inside the same `*.test.tsx` file):
```ts
describe("Input behaviour specifics", () => {
it("calls onChange when user types", async () => {
// ...
});
});
```
### Test Commands
- **All component tests** (Vitest + RTL):
```bash
npm test
```
- **Component-only tests** (faster inner loop, focused on `tests/components/`):
```bash
npm run test:component
# filter by name:
npm run test:component -- --run tests/components/Button.test.tsx
```
- **E2E tests only** (Playwright):
```bash
npm run test:e2e
# or, equivalently:
npm run e2e
```
### What to Test vs. What Not to Test
- **Do test**
- Public behaviour: visible text, roles, labels, ARIA, keyboard paths.
- State transitions that users rely on (error -> success, disabled -> enabled).
- Critical component interactions (clicks, form submissions, dropdown selection).
- Accessibility invariants (no axe violations, basic keyboard support).
- **Avoid testing**
- Pure styling details that are likely to change frequently (exact shadow radius, minor spacing).
- Internal implementation details (private helpers, hook internals, memoisation specifics).
- Responsive visibility in JSDOM (use Playwright visual / responsive tests instead).
### Adding Tests for a New Component (≈5 minutes)
1. **Create the component file** in `app/components/`.
2. **Create a test file** in `tests/components/ComponentName.test.tsx`.
3. **Wire the standard suite** using `componentTestSuite`.
4. **Add 13 custom tests** for any unique behaviours.
5. Run:
```bash
npm run test:component -- --run tests/components/ComponentName.test.tsx
```
### E2E and Visual Regression
- Use **Playwright** for:
- Critical user journeys (e.g., create rule, navigate blog, key flows).
- Responsive behaviour and crossbrowser checks.
- Visual regression (`tests/e2e/visual-regression.spec.ts`).
```bash
npm run test:e2e
npm run visual:test
```
### Accessibility Testing
Accessibility is tested at two levels:
1. **Component-level accessibility** (`tests/components/*.test.tsx`):
- Automatically covered by `componentTestSuite` using `jest-axe`
- Tests roles, labels, ARIA attributes, keyboard navigation
- Runs as part of every component test suite
2. **Full-page accessibility** (`tests/accessibility/e2e/wcag-compliance.spec.ts`):
- E2E tests using Playwright and `@axe-core/playwright`
- Validates WCAG 2.1 AA compliance across entire pages
- Tests complete user journeys for accessibility barriers
This two-tier approach ensures both individual components and full page experiences meet accessibility standards.