Create a Typescript NextJS Project with Jest & Cypress

Will Kelly
4 min readFeb 18, 2022

--

Having a solid boilerplate that can be easily transitioned into a production app is a great thing to have around. It is often much more work to resolve dependencies or make deeper structural changes after you are already at 10–20k lines of code.

In this post, I’ll go through setting up a project with this stack. In some future posts, I’ll detail some extended versions for different use-cases.

If you’re looking to just fork the repo and spin it up, check out the links at the bottom of this post.

Let’s get started.

I’ll be using VSCode, with a few helpful extensions:

I’ll also be deploying to Vercel, and using GitHub for git hosting (& some CI).

First let’s create a folder, init a NextJS app with Typescript, make the initial commit to github, and see our app deployed to Vercel.

yarn create next-app --typescript
> ✔ What is your project named? boilerplate-next
...
cd boilerplate-next
yarn dev

Then you’ll see the default next page.

Go to Github, create a new repository, then:

git remote add origin git@github.com:<USERNAME>/boilerplate-next.git
git push -u origin main

And you’ll see your code at:

  • https://github.com/<USERNAME>/boilerplate-next

Then go to Vercel to import your Git repo. Add the Git repo by signing in and clicking the import button once your Github account is linked.

In the configuration, make sure NextJs is selected, and submit to deploy your boilerplate. You should then be congratulated with the below:

You can click the preview image to see the deployment, or open up the dashboard by clicking the button for more detailed config.

The NextJS Typescript starter is great, but let’s add a bit more tooling that should end up being useful as the project grows.

yarn add -D ts-node prettier jest husky lint-staged eslint-config-prettier eslint-plugin-jest-dom @testing-library/jest-dom @testing-library/react @types/testing-library__jest-dom @types/testing-library__react @typescript-eslint/eslint-plugin

These packages will give us a good foundation for formatting and testing.

Also add this under scripts to run our tests (and a CI option for later):

"scripts": { 
...
"test": "jest --watch",
"test:ci": "jest --ci"
}

Then we will edit a few configuration files for all the tools we installed.

touch jest.config.ts

The tsconfig.json is almost there from the Next initialization, but add a few things (mostly types, and excluding a cypress folder that we will add later)

Also add a prettier config: touch .prettierrc.json

And edit our .eslintrc.json with the new plugins we installed:

Then lets enable husky pre-commit hooks in a clever way, saving some compute by only linting the staged code.

yarn husky install

Add an entry to package.json :

"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},

Add the script to the .husky folder, touch .husky/pre-commit with:

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
yarn lint-staged

You may need to make the husky script executable with chmod +x ./pre-commit

And finally create a lint-staged.config.js in the root of the project:

You can then add the edited files and commit to git (running and passing the husky hook).

At this point, your project should look something like this

Next up, let’s configure out test suite. We’ll be using Jest (which we already installed), Cypress, and Github actions.

First, lets install Cypress:

yarn add -D cypress @types/cypress

add a config file:

// cypress.json 
{}

as well as add a script in package.json :

"scripts": { 
...
"cypress": "cypress open"
}

and finally initialize with yarn cypress open which will generate a folder.

Let’s convert this to Typescript to keep things consistent.

NOTE

Jest and Cypress have some conflicting underlying types due to both running tests suites. If you don’t handle this, you will almost surely run into some type issues in the test files.

We will resolve this by creating a dedicated tsconfig.json for the cypress folder

touch cypress/tsconfig.json

and double check your root tsconfig.json has cypress excluded.

Then in the cypress folder, go ahead and delete the default files in cypress/integration and refactor plugins/index.js support/commands.js and support/index.js to .ts files.

cypress/plugins/index.ts

fix the export with:

cypress/support/commands.ts

const asModule = {}
export default asModule

and finally create a test in cypress/integration/app.spec.ts

… and then actually add the nav functionality in the pages folder.

touch pages/about.tsx

and edit the index.tsx page so that it has the link to /about

Now, start up the app with yarn dev in one terminal, then yarn cypress to run the test. It should open the client and run the test:

Next up, let’s add a Jest test to make sure that works as well.

mkdir __tests__
touch __tests__/index.test.tsx

Then populate the file with:

Verify it works by running yarn test

At this point, your project should look like this

Now let’s set up CI with Github actions.

mkdir .github
mkdir .github/workflows
touch .github/workflows/test.yml

We will use the Cypress action, and add some steps to run our build and Jest tests.

Go ahead and commit it to verify that Github actions runs successfully.

You should get a checkmark after the action completes, to double check your work thus far, you can see our current progress here

You can also check your action workflows under the actions tab, or go directly via:

Since this is already gotten fairly lengthy, will go ahead and finish this post here.

Check out the repo here: https://github.com/wk0/boilerplate-next

Stars are appreciated!

Also check out my website: https://wk0.dev (contact info available)

Stay tuned for updates

Sign up to discover human stories that deepen your understanding of the world.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Responses (2)

Write a response