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. For a full list of locator helpers see the API overview. 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.