From 3848abdc9b48838ac367aa6431495f4de73cbfe3 Mon Sep 17 00:00:00 2001 From: Augustin Mauroy <97875033+AugustinMauroy@users.noreply.github.com> Date: Wed, 12 Feb 2025 18:50:52 +0100 Subject: [PATCH] content(react-test): first draft --- ...o-test-react-app-with-node-test-runner.mdx | 175 ++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 content/post/how-to-test-react-app-with-node-test-runner.mdx diff --git a/content/post/how-to-test-react-app-with-node-test-runner.mdx b/content/post/how-to-test-react-app-with-node-test-runner.mdx new file mode 100644 index 0000000..27cc0c9 --- /dev/null +++ b/content/post/how-to-test-react-app-with-node-test-runner.mdx @@ -0,0 +1,175 @@ +--- +title: How to test a React app with Node Test Runner +description: Drastically simplify and speed up testing your React app by switching to Node Test Runner. +date: 2025-02-12 +authors: AugustinMauroy +category: use-cases +--- + +## Introduction + +Testing is a crucial part of software development, ensuring that your application behaves as expected. With the [Node.js Test Runner](https://nodejs.org/en/learn/test-runner/introduction), you can seamlessly integrate testing into your [React](https://react.dev) application. This guide will walk you through the process of setting up and running tests for a React app using the Node.js Test Runner. + +Note that this article is design for nodej.js `^22.14.0` and `^23.6`. + +> I really recommend you to read the [Node.js Test Runner guides](https://nodejs.org/en/learn/test-runner/introduction) to understand how node.js test runner works. +> This guide assumes you have a basic understanding of React and testing. + +## Installing the Dependencies + +First, you need to install the necessary dependencies. In addition to your React app dependencies, you will need the following: + +```bash +npm add --save-dev @testing-library/react @testing-library/dom jsdom global-jsdom +``` + +> **Note**: The rest of the dependencies we will use come from Node.js. + +## Writing the Component to Be Tested + +Let's create a simple React component that we will test. This component will be a counter that increments a value when a button is clicked. + +```tsx +'use client'; +import { useState } from 'react'; +import styles from './index.module.css'; +import type { FC } from 'react'; + +const Counter: FC = () => { + const [count, setCount] = useState(0); + + return ( +
+

{count}

+ +
+ ); +}; + +export default Counter; +``` + +
+ `index.module.css` + + ```css + .container { + @apply flex flex-col items-center justify-center; + + .count { + @apply text-4xl; + } + + .button { + @apply px-4 py-2 bg-blue-500 text-white rounded-md; + } + } + ``` +
+ +## Registering Node.js Loaders + +To handle TypeScript and CSS modules, you need to register the appropriate loaders. Create a file named `node-hooks/react-test.js` and add the following code: + +> To understand what is a loader, check out [this post](/blog/post/how-to-use-nodejs-loader). + +You'll need to register the loaders for TypeScript and CSS modules: + +First let's install the loaders as dev dependencies: + +```bash +npm add -D @nodejs-loaders/tsx @nodejs-loaders/css-module +``` + +Then, create the registration file: + +```js +import { register } from 'node:module'; +import jsdom from 'global-jsdom'; + +// Register the loaders +register('@nodejs-loaders/tsx', import.meta.url); +register('@nodejs-loaders/css-module', import.meta.url); + +// Create a JSDOM environment +jsdom(undefined, { + // ⚠️ Failing to specify this will likely lead to many 🤬 + url: 'https://test.example.com', +}); +``` + +> **NOTE:** You may need to use `@nodejs-loaders/alias` to allow Node.js to understand path aliases in your TypeScript files. + +## Writing the Test + +Now, let's write a test for the `Counter` component. Create a file named `index.test.tsx` in the same directory as your component: + +```tsx +import assert from 'node:assert/strict'; +import { describe, it } from 'node:test'; +import { render, fireEvent, screen } from '@testing-library/react'; +import Counter from './index.ts'; // ⚠️ We need to import the file with the .ts extension + +describe('Counter', () => { + it('should increment the count when the button is clicked', () => { + const { unmount } = render(); + + const button = screen.getByRole('button', { name: /increment/i }); + const count = screen.getByText('0'); + + assert.strictEqual(count.textContent, '0'); + + fireEvent.click(button); + + assert.strictEqual(count.textContent, '1'); + + // ⚠️ It's a good idea to unmount the component to prevent it spilling over into the DOM of other tests + unmount(); + }); +}); +``` + +### Structure of a Test File + +A typical test file structure includes: + +1. **Imports**: Import the necessary modules and components. +2. **Test Suite**: Define a test suite using `describe`. +3. **Test Case**: Define individual test cases using `it`. +4. **Render the Component**: Render the component to be tested. +5. **Perform Actions**: Simulate user interactions or other actions. +6. **Assertions**: Make assertions to verify the expected behavior. +7. **Unmount the Component**: Clean up by unmounting the component. + +## Running the Test + +To run the test, use the following command: + +```bash +node --test --import=./node-hooks/react-test.js **/*.test.tsx +``` + +You can also add a script to your `package.json` to simplify running the tests: + +```json fileName="package.json" +{ + "scripts": { + "test:unit": "node --test --import=./node-hooks/react-test.js **/*.test.tsx", + "test:watch": "node --test --watch --import=./node-hooks/react-test.js **/*.test.tsx" + } +} +``` + +> **Note**: You can add more patterns to the glob pattern to test more files. For example, `**/*.test.ts` to test all TypeScript files. + +And then to call the script you can use `--run`: + +```bash +node --run test:unit # or node --run test:watch +``` + +## Conclusion + +Testing your React app with the Node.js Test Runner is a straightforward process. By following the steps outlined in this guide, you can ensure that your components behave as expected. Happy testing!