Skip to content

Jest Tests

Jest Tests are used to test JavaScript code. They run in Node and can work in the following workspace types:

  • Expo
  • Node 14
  • React 16
  • React 18

Test Structure

Folder Structure

Jest tests execute a .test.js file that is injected into the learner's workspace. Authors do not need to add this file.

Jest can be configured via a Babel configuration file and jest.config.js file. The contents of these files depends on the test and workspace type.

Folder Structure: React

In React 18 workspaces, .babelrc is provided with the necessary presets. Authors do not need to add this file (link to file):

{
  "presets": [
    "@babel/preset-env",
    ["@babel/preset-react", {"runtime": "automatic"}]
  ]
}

jest.config.js is also provided to use a jsdom environment that supports rendering React components. Authors do not need to add this file (link to file):

module.exports = {
  testEnvironment: 'jsdom'
};

Folder Structure: Expo

In Expo workspaces, additional configuration must be provided in each workspace by the author:

babel.config.js must include the Babel-Expo preset:

module.exports = function(api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'],
  };
};

jest.config.js must include the Jest-Expo preset and–if using the library–set up the Jest Native Testing Library:

module.exports = {
  preset: "react-native",
  setupFilesAfterEnv: [ "@testing-library/jest-native/extend-expect"],
};

Test File Structure

Jest tests are defined with test or its alias it. Assertions within are made with expect:

// Import assertion libraries and React components
import TestRenderer from 'react-test-renderer';
import MyComponent from './MyComponent';

// Provide an error message
test('MyComponent has my Hello', () => {
  // Render components and make assertions
  const component = TestRenderer.create(<MyComponent />);
  expect(component.root.findByProps({className: "intro"}).children).toEqual(['Hello']);
});

Jest supports describe blocks to group tests, which you'll need to use if you want any setup (e.g. beforeAll) or teardown (e.g. afterAll):

import React from 'react';
import { View } from 'react-native';
import { render, cleanup } from '@testing-library/react-native/pure';

import App, { styles } from './App';

describe(App, () => {
  let error;
  let viewLayout;
  let viewBoxes;

  beforeAll(() => {
    try {
      ([viewLayout, ...viewBoxes] = render(<App />).UNSAFE_queryAllByType(View));
    } catch (err) {
      error = err;
    }
  });

  afterAll(() => {
    cleanup();
  });

  it('`App` should render without errors, double-check for syntax errors.', () => {
    expect(error).toBeUndefined();
  });

  it('`App` should render a `View` component, containing three other `View` components.', () => {
    expect(viewLayout).toBeTruthy();
    expect(viewBoxes).toHaveLength(3);
  });
});

Available Test Helpers

Additional JavaScript packages are available to learners in the Learning Environment. The specific packages available will vary with each workspace type, as determined by their package.json in EIN. For example, here is React 18's package.json. Here is a set of common packages:

Package Use Case
@testing-library/react Testing utilities for React components
chai Many helpful general assertions
enzyme React testing
jsdom Building pure-JS representations of the DOM based on learner code
msw API mocking library
react-test-renderer Render React components to pure JavaScript objects, without depending on the DOM
rewire Patch in learner code files to access local, not exported variables
sinon Building mocks & stubs of functions
sinon-chai Chai extension for sinon asertions
structured Run tests based on parsing code structure rather than execution or behavior
supertest API endpoint testing

Tests execute in Node environment, so any Node APIs are available as well, such as fs, path, etc. Node versions may differ across workspace types, e.g. React 18 uses Node 16.

Example Tests

This test uses React Testing Library to render, query contents of, and "click" on the CheckboxWithLabel component.

import {fireEvent, render} from '@testing-library/react';
import CheckboxWithLabel from './CheckboxWithLabel';

it('CheckboxWithLabel changes the text after click', () => {
  const {queryByLabelText, getByLabelText} = render(
    <CheckboxWithLabel labelOn="On" labelOff="Off" />,
  );

  expect(queryByLabelText(/off/i)).toBeTruthy();

  fireEvent.click(getByLabelText(/off/i));

  expect(queryByLabelText(/on/i)).toBeTruthy();
});

This test uses React Test Renderer to render and query the contents of the MyComponent component.

import TestRenderer from 'react-test-renderer';
import MyComponent from './MyComponent';
import SubComponent from './SubComponent';

it('MyComponent contains a SubComponent with prop `bar` and an element with class `sub` containing "Sub"', () => {
  const testRenderer = TestRenderer.create(<MyComponent />);
  const testInstance = testRenderer.root;

  expect(testInstance.findByType(SubComponent).props.foo).toBe('bar');
  expect(testInstance.findByProps({className: "sub"}).children).toEqual(['Sub']);
});

This assumes we have MyComponent and SubComponent components:

import SubComponent from './SubComponent';

export default function MyComponent() {
  return (
    <div>
      <SubComponent foo="bar" />
      <p className="my">Hello</p>
    </div>
  )
}

export default function SubComponent() {
  return (
    <p className="sub">Sub</p>
  );
}

Other Guidelines

  • Actual code (real variable names, language syntax, etc. ) in feedback messages should be code-ticked (`)
  • Jest tests should follow Test standards.