Frontend testing

 

“BUG” is a huge emotional word for

Software Engineers

by Israel Romero and Thomas Truong

TOPICS

  • React Testing Library
  • Test Examples
  • Setup
  • Extension
  • Build
  • Coverage
  • Future

react Testing library

A library providing the implementation (methods/functions) to mount React components (in a virtual DOM) + the means to access (and interact) with the tree that is created as a result.

  • Mounts components = Integration testing
  • It is just a library , we need a test runner (Jest)
  • It accounts for the asynchronous nature of Web components
  • Almost always we will need mocking, but that is not RTL itself

get By

import { useEffect, useState } from "react";

import "./App.css";

function App() {
  const [name, setName] = useState();

  useEffect(() => {
    fetch("https://swapi.dev/api/people/1")
      .then((response) => response.json())
      .then((data) => {
        setName(data.name);
      });
  }, []);

  return (
    <>
      <h1>Star Wars</h1>
      <span>name: {name}</span>
    </>
  );
}

export default App;
import { render, screen } from "@testing-library/react";

import App from "./App";

it("renders text", () => {
  render(<App />);
  expect(screen.getByText(/star wars/i)).toBeVisible();
});

find BY

import { useEffect, useState } from "react";

import "./App.css";

function App() {
  const [name, setName] = useState();

  useEffect(() => {
    fetch("https://swapi.dev/api/people/1")
      .then((response) => response.json())
      .then((data) => {
        setName(data.name);
      });
  }, []);

  return (
    <>
      <h1>Star Wars</h1>
      <span>name: {name}</span>
    </>
  );
}

export default App;
import { render, screen } from "@testing-library/react";

import App from "./App";

it("renders Luke", async () => {
  render(<App />);
  expect(await screen.findByText(/Luke/i)).toBeVisible();
});

QUERY BY

import { useEffect, useState } from "react";

import "./App.css";

function App() {
  const [name, setName] = useState();

  useEffect(() => {
    fetch("https://swapi.dev/api/people/1")
      .then((response) => response.json())
      .then((data) => {
        setName(data.name);
      });
  }, []);

  return (
    <>
      <h1>Star Wars</h1>
      <span>name: {name}</span>
    </>
  );
}

export default App;
import { render, screen } from "@testing-library/react";

import App from "./App";

it("something that is not there", () => {
  render(<App />);
  expect(screen.queryByText(/Darth Vader/i)).toBeNull();
});

Mocking

  • Mocking modules is bread and butter of testing
  • Provided by your test runner (Jest)
import { render, screen } from "@testing-library/react";
import "@testing-library/jest-dom";
import App from "./App";

const mockFetch = jest
  .fn()
  .mockReturnValue(
    Promise.resolve({ json: () => Promise.resolve({ name: "Luke Skywalker" }) })
  );

window.fetch = mockFetch;

describe("App Component", () => {
  beforeEach(() => {
    render(<App />);
  });

  it("Title is displayed", () => {
    expect(screen.getByText(/star wars/i)).toBeVisible();
  });

  it("Luke is displayed after the fetch", async () => {
    expect(screen.queryByText(/luke/i)).toBeNull();
    expect(mockFetch).toHaveBeenCalled();
    expect(await screen.findByText(/luke/i)).toBeVisible();
  });
});

Test EXAMPLES

We will be presenting a test demo in Web Members. It can be accessed at the link below:

 

https://github.com/HelloSelf/HelloSelfWeb/pull/621/files

setup

react-scripts

React-scripts is a preconfigured set of commands that come out of the box with create-react-app

 

react-scripts test command expects the tests folder to follow a certain conversation and doesn't work well with extensions.

JEST

  • Add a new file json.config.json
  • Add ts-jest to package.json
  • Add '@babel/preset-env' to .babelrc
scripts: {
  ...
  "test": "jest",
  ...
}

Config

{
    "preset": "ts-jest",
    "testEnvironment": "jsdom",
    "transform": {
        "^.+\\.(js|jsx)$": "babel-jest"
    },
    "moduleNameMapper": {
        "\\.(svg|woff|png|mp3)": "<rootDir>/src/__mocks__/fileMock.ts"
    },
    "setupFiles": ["<rootDir>/src/setupTests.js"],
    "testPathIgnorePatterns": [
        "/node_modules/",
        "src/components/calendars/**/AddAvailabilityForm.test.tsx",
    ]
}

Babel

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

jEST vscode EXTENSION

https://marketplace.visualstudio.com/items?itemName=Orta.vscode-jest

tEST EXPLORER

Running test

Demo

debugging test

Demo

build

SCRIPTs

"test": "jest",
"test:ci": "yarn test --maxWorkers=2 --watchAll=false",
"test:ci:cov": "yarn test:ci --coverage",
"test:cov": "yarn test --coverage",

pr template

## Description

_Please include a summary of the changes_

**Link to JIRA ticket**

## Checklist

-   [ ] Tested with feature branch
-   [ ] Added unit test for feature

feature branch

- name: Run test
  run: yarn test:ci:cov --json --outputFile=jest-results.json

- name: Post test results 🚨
  if: failure()
  uses: im-open/process-jest-test-results@v2.1.3
  with:
    github-token: ${{ secrets.GITHUB_TOKEN }}
    results-file: 'jest-results.json'

deploy to dev, prod 

jobs:
	development:
    		steps:
			- name: Run test
			  run: yarn test:ci:cov

			- name: Build
			  run: yarn build

	production:
        	steps:
			- name: Run test
			  run: yarn test:ci

coverage

badge

- name: Run test
  run: yarn test:ci:cov
  
- name: Add coverage badge
  uses: we-cli/coverage-badge-action@main

threshold

    "coverageThreshold": {
        "./src/components/calendars/FullCalendar/components/appointments/": {
            "lines": 43
        },
        "./src/helpers/": {
            "lines": 20
        }
    }

jest.config.json

report

./coverage/lcov-report/index.html

FUTURE

coverage on github pages

PULL REQUEST COVERAGE

CODE QUALITY/COVERAGE TOOL

tdd/bdd

conclusion

PROS

CONS

  • Refactor code with confidence
  • Great way to document code
  • Find unexpected bugs
  • Unit test can't catch every error (false confidence)
  • Learning curve for writing unit test
  • Slower build

TESTING... COMPLETE

Frontend Testing

By Thomas Truong

Frontend Testing

  • 43