- Docs
- provides virtual DOM for tests
- renders components into virtual DOM
- searches virtual DOM
- interacts with virtual DOM
- test runner
- finds tests
- runs tests
- determines whether tests pass or fail
- create virtual DOM for argument JSX
- access virtual DOM via screen global
import { render, screen } from "@testing-library/react";
import App from "./App";
test("renders learn react link", () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});
`expect(linkElement).toBeInTheDocument();'
-
expect
- jest global, starts the assertion
-
expect argument
- subject of the assertion
-
matcher
- comes form Jest-DOM
-
marcher argument
- refines matcher
-
another examples
expect(element.textContent).toBe("hello");
expect(elementsArray).toHaveLength(7);
- Read the docs for events using
dom-testing-library
- In most cases, it's recommended to use the user-event which provides advanced simulation of browser interactions than the built-in
fireEvent
method
npm install --save-dev @testing-library/user-event @testing-library/dom
import { screen } from "@testing-library/dom";
import userEvent from "@testing-library/user-event";
test("types inside textarea", () => {
document.body.innerHTML = `<textarea />`;
userEvent.type(screen.getByRole("textbox"), "Hello, World!");
expect(screen.getByRole("textbox")).toHaveValue("Hello, World!");
});
- Docs
- Purpose:
- intercept network calls
- return specified responses
- Prevent network calls during tests
- Set up test conditions using server responses
npm i msw
- create handlers
- create test server
- make sure test server listens during all tests
- reset after each test
res.get("http://localhosT:3030/acoops", (req, res, ctx) => {});
- handler type: rest or graphql
- http method to mock: get, post, etc
- full url to mock
- response resolver function
- req: request object
- res: function to create response
- ctx: utility to build response
- comes with cra
src/setup/Tests.js
imports it before each test, makes matchers available- DOM-based matchers
toBeVisible()
ortoBeChecked
- more on matchers Docs
command[All]ByQueryType
command:
-
get: expect element to be in the DOM
-
query: expect element not to be in the DOM
-
find: expect element to appear async
-
when expecting async updates use:
await findAllByRole
-
there are some cases when multiple components are mounted aynchronously, in this case,
await findAllBy
isn't enough -
it's necessary to wrap the query in the
waitFor
statement
await waitFor(async () => {
const alerts = await screen.findAllByRole("alert");
expect(alerts).toHaveLength(2);
});
[All]:
- (exclude): expect only one match
- (include): expect more than one match
QueryType:
-
Role: most preferred
-
AltText: (images)
-
Text: (display elements)
-
Form elements:
- PlaceholderText
- LabelText
- DisplayValue
-
more on Queries
- write tests before writing code
- then write code according to "spec" set set by tests
- "red-green" testing
- tests fail before code is written
- makes a huge difference in how it feels to write tests
- part of the coding process, not a "chore" to do at the end
- more efficient
- re-run tests "for free" after changes
- unit tests
- tests one unit of code in isolation
- integration tests
- how multiple units work together
- functional tests
- tests a particular function of software
- acceptance / e2e test
- use actual browser and server(Cypress/Selenium)
- different mindset from unit testing
- include all relevant units, test behavior
- close to how users interact with software
- robust tests
- more difficult to debug failing tests
- isolated: mock dependencies, test internals
- easy to pinpoint failures
- further from how users interact with software
- more likely to break with refactoring
- for more complicated functions, unit tests help with:
- covering all possible edge cases
- determining what caused functional tests to fail
- issues with functional tests:
- high-level makes them resistant to refactors
- high-level makes them difficult to diagnose
- BDD: Behavior-Driven Development
- Testing Library encourages behavior over implementation
- RTL recommends finding elements by accessibility handles
- About Queries
- it's preferable to use the
getByRole
query since it's more accessible-friendly - W3C role definitions
- a role can be added to an element via the
role
attribute - some elements already have built-in roles:
button, a
- a role can be added to an element via the
- If you can't find an element like a screen reader would,
- then your app isn't friendly to screen readers
- Functions separate from components
- used by several components
- complex logic
- unit test if
- complex logic difficult to test via functional tests
- too many edge cases
To manage formatting and linting use eslint with prettier
npm i eslint-plugin-testing-library eslint-plugin-jest-dom
Once installed, create a .eslintrc.json
file to set the configuration:
{
"plugins": ["testing-library", "jest-dom"],
"extends": [
"react-app",
"react-app/jest",
"plugin:testing-library/recommended",
"plugin:testing:library/react",
"plugin:jest-dom/recommended"
]
}
- make context with
createContext
- make custom hook with
useContext
- make context provider with internal state via
useState
- Provider value is array
[state, setState]
- Provider value is array
- any component that has access to the Provider will access the state in the context
- export custom hook and provider