1614659569
Learn how to test React applications with Jest and React Testing Library, a popular combination and official recommendation from React.
Testing is an essential practice in software engineering. It helps build robust and high-quality software and boosts the team’s confidence in the code, making the application more flexible and prone to fewer errors when introducing or modifying features.
Highly efficient teams make testing a core practice in their everyday routines, and no feature is released before automated tests are in place. Some developers even write the tests before writing the features, following a process called TDD (Test Driven Development).
In this article, we’ll test React applications with Jest and React Testing Library, a popular combination of a JavaScript testing framework and a React utility for testing components. It’s also the official recommendation given on React’s documentation.
Testing is the process of automating assertions between the results the code produces and what we expect the results to be.
When testing React applications, our assertions are defined by how the application renders and responds to user interactions.
There are many different types of testing paradigms and philosophies. This article will focus on creating unit and component tests (or integration tests).
Jest is a JavaScript testing framework that allows developers to run tests on JavaScript and TypeScript code and integrates well with React.
It’s a framework designed with simplicity in mind and offers a powerful and elegant API to build isolated tests, snapshot comparison, mocking, test coverage, and much more.
React Testing Library is a JavaScript testing utility built specifically for testing React components. It simulates user interactions on isolated components and asserts their outputs to ensure the UI is behaving correctly.
#react #javascript #testing #jest
1598839687
If you are undertaking a mobile app development for your start-up or enterprise, you are likely wondering whether to use React Native. As a popular development framework, React Native helps you to develop near-native mobile apps. However, you are probably also wondering how close you can get to a native app by using React Native. How native is React Native?
In the article, we discuss the similarities between native mobile development and development using React Native. We also touch upon where they differ and how to bridge the gaps. Read on.
Let’s briefly set the context first. We will briefly touch upon what React Native is and how it differs from earlier hybrid frameworks.
React Native is a popular JavaScript framework that Facebook has created. You can use this open-source framework to code natively rendering Android and iOS mobile apps. You can use it to develop web apps too.
Facebook has developed React Native based on React, its JavaScript library. The first release of React Native came in March 2015. At the time of writing this article, the latest stable release of React Native is 0.62.0, and it was released in March 2020.
Although relatively new, React Native has acquired a high degree of popularity. The “Stack Overflow Developer Survey 2019” report identifies it as the 8th most loved framework. Facebook, Walmart, and Bloomberg are some of the top companies that use React Native.
The popularity of React Native comes from its advantages. Some of its advantages are as follows:
Are you wondering whether React Native is just another of those hybrid frameworks like Ionic or Cordova? It’s not! React Native is fundamentally different from these earlier hybrid frameworks.
React Native is very close to native. Consider the following aspects as described on the React Native website:
Due to these factors, React Native offers many more advantages compared to those earlier hybrid frameworks. We now review them.
#android app #frontend #ios app #mobile app development #benefits of react native #is react native good for mobile app development #native vs #pros and cons of react native #react mobile development #react native development #react native experience #react native framework #react native ios vs android #react native pros and cons #react native vs android #react native vs native #react native vs native performance #react vs native #why react native #why use react native
1599639298
Testing is complicated. I’ve certainly never been good at it. For the longest time, I’ve only been focused on basic function input-output unit tests. Why? Because they were easy — you didn’t need to render HTML, you didn’t need to query DOM elements, you didn’t need to interact with said DOM elements. But of course, React component testing is a necessity for any mature codebase. And it finally came time for me to sit down and figure it out.
That’s when I discovered React Testing Library. And suddenly, everything seemingly became much simpler. All the complexities that I’ve encountered, but not understood, that made me put off React component testing disappeared. Hopefully, the same will happen for you.
#react-testing-library #unit-testing #react #jest #interaction-testing
1603955580
Like most, when I first started using Testing Library, I used Fire Event to test component interactions. After all, this API shipped with the library itself and was used in the test examples in the documentation. But I soon discovered that Fire Event had serious limitations. I would try clicking something and the expected effect did not happen. Why?
To understand this issue, we need to better understand browser events. When a user clicks something in their browser, multiple events are triggered — mouseDown
, mouseUp
, click
, and focus
. Similarly, when typing something, the keyDown
, keyUp
, and keyPress
events all trigger! Because a single user interaction could trigger multiple events, developers have multiple options for implementation. This is where I ran into my issue.
Fire Event, unfortunately, requires you to use the method for the corresponding event handler to trigger. If an element has an onClick
event handler, I have to use fireEvent.click
; if an element has an onMouseDown
event handler, I have to use fireEvent.mouseDown
. In other words, I need to know the exact implementation of the event handler to successfully use fireEvent
.
#react #jest #integration-testing #unit-testing #react-testing-library #react native
1626158760
Learn how to write unit tests for your React components using Jest and the React Testing Library.
We will be writing some unit tests for React components using the Jest framework (https://jestjs.io/). We will begin by creating a react app using create-react-app. Then we will create a component & write some unit tests for it. We will finish by writing some snapshot tests to verify changes to the component tree.
Don’t forget to Subscribe here: https://www.youtube.com/channel/UCWkzkhQ3syxBjjAYwqCbzYg?sub_confirmation=1
#react #jest #react testing library
1632798688
Learn how to set up Next.js with three commonly used testing tools: Cypress, Jest, and React Testing Library.
Cypress is a test runner used for End-to-End (E2E) and Integration Testing.
You can use create-next-app
with the with-cypress example to quickly get started.
npx create-next-app --example with-cypress with-cypress-app
To get started with Cypress, install the cypress
package:
npm install --save-dev cypress
Add Cypress to the package.json
scripts field:
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"cypress": "cypress open",
}
Run Cypress for the first time to generate examples that use their recommended folder structure:
npm run cypress
You can look through the generated examples and the Writing Your First Test section of the Cypress Documentation to help you get familiar with Cypress.
Assuming the following two Next.js pages:
// pages/index.js
import Link from 'next/link'
export default function Home() {
return (
<nav>
<Link href="/about">
<a>About</a>
</Link>
</nav>
)
}
// pages/about.js
export default function About() {
return (
<div>
<h1>About Page</h1>
</div>
)
}
Add a test to check your navigation is working correctly:
// cypress/integration/app.spec.js
describe('Navigation', () => {
it('should navigate to the about page', () => {
// Start from the index page
cy.visit('http://localhost:3000/')
// Find a link with an href attribute containing "about" and click it
cy.get('a[href*="about"]').click()
// The new url should include "/about"
cy.url().should('include', '/about')
// The new page should contain an h1 with "About page"
cy.get('h1').contains('About Page')
})
})
You can use cy.visit("/")
instead of cy.visit("http://localhost:3000/")
if you add "baseUrl": "http://localhost:3000"
to the cypress.json
configuration file.
Since Cypress is testing a real Next.js application, it requires the Next.js server to be running prior to starting Cypress. We recommend running your tests against your production code to more closely resemble how your application will behave.
Run npm run build
and npm run start
, then run npm run cypress
in another terminal window to start Cypress.
Note: Alternatively, you can install the
start-server-and-test
package and add it to thepackage.json
scripts field:"test": "start-server-and-test start http://localhost:3000 cypress"
to start the Next.js production server in conjuction with Cypress. Remember to rebuild your application after new changes.
You will have noticed that running Cypress so far has opened an interactive browser which is not ideal for CI environments. You can also run Cypress headlessly using the cypress run
command:
// package.json
"scripts": {
//...
"cypress": "cypress open",
"cypress:headless": "cypress run",
"e2e": "start-server-and-test start http://localhost:3000 cypress",
"e2e:headless": "start-server-and-test start http://localhost:3000 cypress:headless"
}
You can learn more about Cypress and Continuous Integration from these resources:
Jest and React Testing Library are frequently used together for Unit Testing.
You can use create-next-app
with the with-jest example to quickly get started with Jest and React Testing Library:
npx create-next-app --example with-jest with-jest-app
To manually set up Jest and React Testing Library, install jest
, @testing-library/react
, @testing-library/jest-dom
as well as some supporting packages:
npm install --save-dev jest babel-jest @testing-library/react @testing-library/jest-dom identity-obj-proxy react-test-renderer
Configuring Jest
Create a jest.config.js
file in your project's root directory and add the following configuration options:
// jest.config.js
module.exports = {
collectCoverageFrom: [
'**/*.{js,jsx,ts,tsx}',
'!**/*.d.ts',
'!**/node_modules/**',
],
moduleNameMapper: {
/* Handle CSS imports (with CSS modules)
https://jestjs.io/docs/webpack#mocking-css-modules */
'^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy',
// Handle CSS imports (without CSS modules)
'^.+\\.(css|sass|scss)$': '<rootDir>/__mocks__/styleMock.js',
/* Handle image imports
https://jestjs.io/docs/webpack#handling-static-assets */
'^.+\\.(jpg|jpeg|png|gif|webp|svg)$': '<rootDir>/__mocks__/fileMock.js',
},
testPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/.next/'],
testEnvironment: 'jsdom',
transform: {
/* Use babel-jest to transpile tests with the next/babel preset
https://jestjs.io/docs/configuration#transform-objectstring-pathtotransformer--pathtotransformer-object */
'^.+\\.(js|jsx|ts|tsx)$': ['babel-jest', { presets: ['next/babel'] }],
},
transformIgnorePatterns: [
'/node_modules/',
'^.+\\.module\\.(css|sass|scss)$',
],
}
You can learn more about each option above in the Jest docs.
Handling stylesheets and image imports
These files aren't useful in tests but importing them may cause errors, so we will need to mock them. Create the mock files we referenced in the configuration above - fileMock.js
and styleMock.js
- inside a __mocks__
directory:
// __mocks__/fileMock.js
(module.exports = "test-file-stub")
// __mocks__/styleMock.js
module.exports = {};
For more information on handling static assets, please refer to the Jest Docs.
Extend Jest with custom matchers
@testing-library/jest-dom
includes a set of convenient custom matchers such as .toBeInTheDocument()
making it easier to write tests. You can import the custom matchers for every test by adding the following option to the Jest configuration file:
// jest.config.js
setupFilesAfterEnv: ['<rootDir>/jest.setup.js']
Then, inside jest.setup.js
, add the following import:
// jest.setup.js
import '@testing-library/jest-dom/extend-expect'
If you need to add more setup options before each test, it's common to add them to the jest.setup.js
file above.
Absolute Imports and Module Path Aliases
If your project is using Module Path Aliases, you will need to configure Jest to resolve the imports by matching the paths option in the jsconfig.json
file with the moduleNameMapper
option in the jest.config.js
file. For example:
// tsconfig.json or jsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/components/*": ["components/*"]
}
}
}
// jest.config.js
moduleNameMapper: {
'^@/components/(.*)$': '<rootDir>/components/$1',
}
Add a test script to package.json
Add the Jest executable in watch mode to the package.json
scripts:
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"test": "jest --watch"
}
jest --watch
will re-run tests when a file is changed. For more Jest CLI options, please refer to the Jest Docs.
Create your first tests
Your project is now ready to run tests. Follow Jests convention by adding tests to the __tests__
folder in your project's root directory.
For example, we can add a test to check if the <Index />
component successfully renders a heading:
// __tests__/index.test.jsx
/**
* @jest-environment jsdom
*/
import React from 'react'
import { render, screen } from '@testing-library/react'
import Home from '../pages/index'
describe('Home', () => {
it('renders a heading', () => {
render(<Home />)
const heading = screen.getByRole('heading', {
name: /welcome to next\.js!/i,
})
expect(heading).toBeInTheDocument()
})
})
Note: The
@jest-environment jsdom
comment above configures the testing environment asjsdom
inside the test file because React Testing Library uses DOM elements likedocument.body
which will not work in Jest's defaultnode
testing environment. Alternatively, you can also set thejsdom
environment globally by adding the Jest configuration option:"testEnvironment": "jsdom"
injest.config.js
.
Optionally, add a snapshot test to keep track of any unexpected changes to your <Index />
component:
// __tests__/snapshot.js
import React from 'react'
import renderer from 'react-test-renderer'
import Index from '../pages/index'
it('renders homepage unchanged', () => {
const tree = renderer.create(<Index />).toJSON()
expect(tree).toMatchSnapshot()
})
Note: Test files should not be included inside the pages directory because any files inside the pages directory are considered routes.
Running your test suite
Run npm run jest
to run your test suite. After your tests pass or fail, you will notice a list of interactive Jest commands that will be helpful as you add more tests.
#next #testing #cypress #jest #react #test #webdev