Skip to main content

Best Practices

Atomic Testing aims to keep your tests portable and maintainable. The recommendations below are distilled from the example signup form project and from the documentation throughout this repo.

1. Start with a Storybook Scenario

Whenever possible create a Storybook story that mirrors your test scenario. Being able to render the component in isolation makes it much easier to visualise the state you expect in your tests and allows you to reuse the same setup for interactive debugging. As Storybook’s testing capabilities improve you can reuse your Atomic drivers there as well.

2. Test Values, Not HTML Markup

Focus on observable behaviour rather than the DOM structure. Use the driver APIs to read values and states—such as a field’s value or whether a button is disabled—instead of asserting on generated HTML. This keeps tests resilient to implementation changes and lets drivers work across different environments.

3. Avoid Direct React Testing Library Calls

Atomic Testing Library builds on top of React Testing Library (RTL) for DOM interactions, but calling RTL utilities directly couples your tests to a specific environment. For a deeper discussion of how Atomic Testing relates to RTL, see Atomic Testing vs React Testing Library. Prefer the methods exposed by component drivers and the TestEngine so your tests remain predictable and can be run in other environments such as Playwright or Cypress.

4. Use data-testid for Key Elements

Assign stable data-testid values to the elements you need to interact with. Locators built with byDataTestId() are both reliable and easy to read. Avoid relying solely on CSS selectors—they tend to change as the markup evolves.

5. Clean Up the Test Engine

Call testEngine.cleanUp() in afterEach hooks. Unmounting the rendered component prevents cross‑test contamination and matches the pattern used throughout the example tests.

6. Compose and Reuse Drivers

Complex widgets become easier to test when you encapsulate their behaviour in a driver. The signup example composes form drivers that can be reused in unit and end‑to‑end scenarios. Implement your own drivers when needed and use satisfies ScenePart to get strong TypeScript support.

7. Provide the Necessary Context

Wrap tested components with any required providers—such as a MUI ThemeProvider—when creating the test engine. The example project uses a createTestEngineForComponent helper to inject the theme so tests run in a realistic environment.

8. Await Driver Actions

Most driver methods return promises. Remember to await interactions and queries so tests wait for state updates before asserting results.