Testing: jest
Simple unit testing of plain old JavaScript functions
Jest is package for unit testing in JavaScript.
- Jest Documentation: https://jestjs.io/docs/en/getting-started
Example
As an example of plain old unit testing, consider the function reformatEmail
defined in utils/email.js
in the project-idea-reviewer-nextjs
:
function throwError(message) {
throw new Error(message);
}
export function reformatEmail(email) {
typeof email === "string" || throwError("email should be of type string");
email || throwError("email should not be an empty string");
return email.replace("@umail.ucsb.edu", "@ucsb.edu");
}
The function reformatEmail
is pure functional javascript code that could be used anywhere in front end or back end code:
- The function has no side effects
- The function calculates a value based solely on it’s parameters
When you have the opportunity to factor some logic out into such a function, it is straightforward to write test cases using
a tool called jest
to unit test this code. Here is an example of test cases for this code, from the file __tests__/email.js
import { reformatEmail } from "../utils/email";
describe("utils/email", () => {
describe("reformatEmail", () => {
it("converts @umail.ucsb.edu to @ucsb.edu", () => {
expect(reformatEmail("tkomarlu@umail.ucsb.edu")).toBe(
"tkomarlu@ucsb.edu"
);
});
it("throws an error when parameter is not of type string", () => {
expect(() => {
reformatEmail(42);
}).toThrow("email should be of type string");
});
it("throws an error when parameter is an empty string", () => {
expect(() => {
reformatEmail("");
}).toThrow("email should not be an empty string");
});
});
});
A few notes:
- The
describe
blocks here are used to structure a test suite. They have no effect other than- scoping for things such as
before
andbeforeEach
function that can be used to set up test cases - messages that appear in the test output to group related tests together.
- scoping for things such as
- The
it
blocks give a name to each test. The intention is that the parameter is a sentence or phrase starting withit
that describes what the feature being tested is supposed to do. - The other functions such as
expect
,.toBe
and.throw
are documented here: https://jestjs.io/docs/en/getting-started
When jest is configured in a project, you can run jest tests like this:
project-idea-reviewer-nextjs % npm run test:jest
> project-idea-reviewer-nextjs@0.1.0 test:jest /Users/pconrad/github/ucsb-cs48-s20/project-idea-reviewer-nextjs
> jest
PASS __tests__/email.js
utils/email
reformatEmail
✓ converts @umail.ucsb.edu to @ucsb.edu (2ms)
✓ throws an error when parameter is not of type string (1ms)
✓ throws an error when parameter is an empty string (1ms)
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 1.142s, estimated 3s
Ran all test suites.
project-idea-reviewer-nextjs %
Configurating a project for jest
To configure your project for jest testing, you will need to take these steps:
-
In the root of your project, create a file called
jest.config.js
with these contents:module.exports = { transform: { "^.+\\.jsx?$": "babel-jest", }, testPathIgnorePatterns: ["/node_modules/", "/cypress/"], };
This tells jest to
- ignore files under
/node_modules
(since it’s not our responsibility to run those tests; those are the modules imported when we donpm install
) - ignore files under
/cypress
(those tests get run when we run cypress testing`
- ignore files under
-
In
package.json
, add this line underscripts
:"test:jest": "jest",
This enables the
npm run test:jest
command to work. -
If you do not already have it, add this:
"test": "npm-run-all test:*",
This makes
npm test
run all of the commands that start withtest:
includingtest:jest
, but potentially alsotest:cypress
andtest:format
if those are defined (and any other tests you may have.) -
In the
devdependencies
section of yourpackage.json
, add these lines:"jest": "^25.4.0", "npm-run-all": "^4.1.5",
Then run
npm install
-
If you do not already have it, add a file called
.babelrc
with the following contents:{ "presets": ["next/babel"] }
This ensures that babel knows how to properly interact with jest, cypress, storybook, etc.
-
You should now be able to run
npm test:jest
and see your tests cases under__tests__
run and produce output.If that’s not the case, ask the staff for help.
Related topics:
- Testing: Acceptance Testing—Criteria for being 'done' with an issue
- Testing: Agile Testing (Crispin and Gregory)—Material from the book by Lisa Crispin and Janet Gregory, Agile Testing: A Practical Guide for Testers and Agile Teams
- Testing: Automation—How to make testing an automatic part of your process
- Testing: End to End Testing—Intro to End to End Testing, and Framework Specific Examples
- Testing: Jacoco Reports—How to interpret the reports (red, yellow, green)
- Testing: Jacoco via Maven—Setting up Jacoco test coverage, using Maven
- Testing: Unit Testing with Jest—Setting up Jest for Next.JS projects
- Testing: Mocking—Intro to Mocking in Tests, and Framework-specific Examples