Writing a testable components library with NX in under 10 minutes

Gal Koren
Soluto by asurion
Published in
6 min readJun 17, 2022
Writing a testable components library with NX in under 10 minutes

It’s no secret that a components library is a great way to share components between teams, save time, and simplify complex projects. I won’t delve into every single advantage of a component library (you can easily find them by googling), but there’s still a lot to write about its implementation.

When we decided to create our own components library, we planned to do it the old-fashioned way — manually install and configure React, Storybook, Cypress, Jest, etc. That’s one way to do it. However, a colleague suggested we use NX, a smart, fast, and extensible build system with first-class monorepo support and powerful integrations. After reviewing this suggestion, I was blown away. This new method saves a ton of time — 2–3 days in the short term, and months in the long term. I just had to share it with the world.

This is our list of tech ingredients:

I also recommend using the vscode extension for NX to make things easier for you.

1. Setup an NX workspace

We begin by creating an NX workspace:

Run the following command:

components-library is the name of the workspace/repo
package manager — In this example I chose Yarn
preset — I chose TypeScript (it’s an empty workspace with TypeScript support)

After running this command your project structure should look like this:

2. Scaffold a React components library

Next, let’s create our React components library,

a. Install React plugin:

yarn add -D @nrwl/react

b. Generate the library:

Note — you can do it from GUI, and you don’t have to specify everything in advance. It applies to all generators.

After the installation, you’ll see that a new folder was created inside the packages folder with your library name — my-new-library. You can also find an example component called my-new-library.tsx, and a unit test next to it, called my-new-library.spec.tsx:

  • In an NX project, all commands for a project are stored in project.json, similarly to the npm scripts on package.json.

These are the commands included inside packages/my-new-library/project.json:

Build - yarn nx build my-new-library
Lint - yarn nx lint my-new-library
Test - yarn nx test my-new-library

3. Setup Storybook

At this point, we’ll want to start developing components for the library. In order to do so, we are going to add Storybook to our project.

Generating Storybook

During the installation process, NX will ask you if you want to configure Cypress, which

will run e2e tests against Storybook.

If we take another look in the packages/my-new-library/project.json file, we will see two new targets:

storybook - yarn nx storybook my-new-library
build-storybook - yarn nx build-storybook my-new-library

Note — The vs code extension will add shortcuts for running the targets when browsing the project.json file.

4. Developing your component

To start your Storybook server:

yarn nx storybook my-new-library

This will open the storybook interface. The default location is: http://localhost:4400

It’ll look like this:

When you change the code in my-new-library.tsx, the changes automatically reflect in the browser. Now you can easily develop your component.

5. Cypress e2e with storybook

If you choose to install Cypress e2e too, you’ll see a new folder inside packages, named my-new-library-e2e. The generation process already creates one test file for your component. You can see it inside the integration my-new-library-e2e folder.

In order to run the e2e tests, you just need to look at the command in the packages/my-new-library-e2e/project.json file.

Now run:

yarn nx e2e my-new-library-e2e

And this is the e2e test result:

6. Create a plugin with a component generator

The plugin

To create a new component with tests and stories in one command, we need to create a new plugin. We are going to add our component generator within that plugin.

Nx plugins are npm packages that contain generators and executors to extend an NX workspace. Generators are blueprints for new files from templates, and executors run those files. These plugins also update the nx.json when generating new libs or apps.

Our next steps:

a. Install the NX plugin

yarn add -D @nrwl/nx-plugin

b. Generate a new plugin project:

yarn nx generate @nrwl/nx-plugin:plugin workspace

It will contain all our workspace generators.
It will also create two new folders:
packages/workspace — where all the generators will be stored
packages/workspace-e2e — where all the generator tests will be stored

NX creates a default generator and executors, which you can delete:

  • Delete the packages/workspace/src/generators/workspace folder
  • Delete the packages/workspace/src/executrors/build/executror.spec.ts file
  • Delete the workspace configuration from the executors.json and generators.json files that are stored inside the packages/workspace folder.

Executors.json should look like this:

Generators.json should look like this:

The component generator

Now, let’s write the component generator.

Run:

a. Edit the packages/workspace/src/generators/component/schema.json file. I wanted to add the parameters that the generator needs in order to create a new component, so I’ve added two parameters, project and name:

b. Edit packages/workspace/src/generators/component/schema.d.ts (It’s the type of schema.json)

c. And now you’ll have to write the code in the packages/workspace/src/generators/component/generator.ts file.

In our generator, we’re going to use the generators we ran before

  • reactComponentGenerator — for creating a new component
  • componentStoryGenerator — for creating a new Storybook for that component
  • componentCypressGenerator — for creating a new Cypress tests for the component

And it should look like this:

I’ve also added some tests in packages/workspace/src/generators/component/generator.spec.ts.

You can now easily add a new component to your project by running the following command:

When new-component-name is the component name, and my-new-library is the project name.

And it’s created these files:

new-component-name-spec.tsx — unit test
new-component-name-spec.tsx — Storybook
new-component-name.tsx — the component code
new-component-name.spec.ts — Cypress e2e test

Now run the storybook again

yarn nx storybook my-new-library

And the new component is good to go 🚀

You can see the full repository here, where you’ll find the command I ran on the commit log.

I hope this method saves you all the time it saves me. I’d love to hear other experiences using this method in the comments for this post, or at gal.koren@asurion.com.

Good luck!

--

--