ReactJSDay 2019 Testing Course

About us

Stefano Magni

Senior front-end developer

Jaga Santagostino

Fullstack JavaScript developer

About the GitBook

All the contents and the code of the course are available at

noriste.github.io/reactjsday-2019-testing-course/

(bit.ly/2lneJtO)

What is a test?

A test is code that throws an error when the actual result of something does not match the expected output.

const sum = (a, b) => a + b;
const subtract = (a, b) => a - b;

let result, expected;

result = sum(3, 7);
expected = 10;
if (result !== expected) {
  throw new Error(`${result} is not equal to ${expected}`);
}

result = subtract(7, 3);
expected = 4;
if (result !== expected) {
  throw new Error(`${result} is not equal to ${expected}`);
}

A first test with Jest

The previous "tests" rewritten for Jest (and the Jest output,when launched in the terminal).

const sum = (a, b) => a + b;
const subtract = (a, b) => a - b;

test("Should sum", () => {
  expect(sum(3, 7)).toEqual(10);
});
test("Should subtract", () => {
  expect(subtract(7, 3)).toEqual(4);
});
PASS  tests/test-introdution/base.test.js
  ✓ Should sum (1ms)
  ✓ Should subtract

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        0.08s, estimated 1s

context / describe

They allow organizing tests.

const sum = (a, b) => a + b;
const subtract = (a, b) => a - b;

describe("Math operations", () => {
  test("Should sum", () => {
    expect(sum(3, 7)).toEqual(10);
  });
  test("Should subtract", () => {
    expect(subtract(7, 3)).toEqual(4);
  });
});
 PASS  tests/test-introdution/describe.test.js
  Math operations
    ✓ Should sum (1ms)
    ✓ Should subtract

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        0.072s, estimated 1s

only / skip

They allow isolating the tests.

const sum = (a, b) => a + b;
const subtract = (a, b) => a - b;

describe("Math operations", () => {
  test.only("Should sum", () => {
    expect(sum(3, 7)).toEqual(10);
  });
  test("Should subtract", () => {
    expect(subtract(7, 3)).toEqual(4);
  });
});
PASS  tests/test-introdution/only.test.js
  Math operations
    ✓ Should sum (2ms)
    ○ skipped Should subtract

Test Suites: 1 passed, 1 total
Tests:       1 skipped, 1 passed, 2 total
Snapshots:   0 total
Time:        0.066s, estimated 1s
const sum = (a, b) => a + b;
const subtract = (a, b) => a - b;

describe("Math operations", () => {
  test.skip("Should sum", () => {
    expect(sum(3, 7)).toEqual(10);
  });
  test("Should subtract", () => {
    expect(subtract(7, 3)).toEqual(4);
  });
});
PASS  tests/test-introdution/skip.test.js
  Math operations
    ✓ Should subtract (1ms)
    ○ skipped Should sum

Test Suites: 1 passed, 1 total
Tests:       1 skipped, 1 passed, 2 total
Snapshots:   0 total
Time:        0.066s, estimated 1s

before / beforeEach / after / afterEach

They allow running common code before/after the tests.

const sum = (a, b) => a + b;
const subtract = (a, b) => a - b;

describe("Math operations", () => {
  let i = 0;
  afterEach(() => {
    i++;
    console.log(`${i} tests run`);
  });
  test("Should sum", () => {
    expect(sum(3, 7)).toEqual(10);
  });
  test("Should subtract", () => {
    expect(subtract(7, 3)).toEqual(4);
  });
});
PASS  tests/test-introdution/after-each.test.js
  Math operations
    ✓ Should sum (1ms)
    ✓ Should subtract (1ms)

  console.log tests/test-introdution/after-each.test.js:8
    1 tests run

  console.log tests/test-introdution/after-each.test.js:8
    2 tests run

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        0.311s, estimated 1s

Why testing?

  • to control that the code does what we expect
     

  • to avoid direct and indirect regressions
     

  • to reproduce corner cases
     

  • to leverage the speed of an automated tool
     

  • to leverage forever the automatic checks

Why testing?

  • to tell a story about the code
     

  • to prevent problems instead of facing them
     

  • to kill refactoring fear
     

  • to get us working with a lower cognitive load

Some testing rules

• we must write the test as soon as we write the code
 

• false-negative tests are evil
 

• the tests must be simple to be read
 

avoid DRYing the test code too early
 

avoid conditional tests
 

care about the test feedback in case of failures

Some testing rules

• the tests must be deterministic and independent
 

 sleep(1000) is evil too


the test must fail before you write the code and succeed when you have written the code

 

the tests must be fast, as fast as possible

 

never do white-box testing

Some testing rules

• code coverage helps us find what we have not tested yet, it is not an end in itself

 

• if you're not enough confident about your application, think twice about your tests

 

• you should not test external services, third-party libraries, and native APIs

 

• last but not least: remember that testing and TDD are two different things

Testing fun

• tests allow you to study
 

testing throw responsibility away (in good meaning) because you are no more an elephant in a glass shop. Instead, while touching some code, you are part of a protected-by-tests sandbox, coding becomes easier

Types of test

⚛️

⚛️ ⚛️ ⚛️

⚛️ ⚛️ ⚛️

Unit testing:

> function() {}

Integration testing:

> function() {

    function() {}

    function() {}

    function() {}

}

React unit/component testing:

React Integration testing:

With Jest

With Jest + React Testing Library

Types of test

UI Integration testing:

With Cypress (Chrome) + Cypress Testing Library

⚛️ ⚛️ ⚛️

⚛️ ⚛️ ⚛️

E2E testing:

⚛️ ⚛️ ⚛️

⚛️ ⚛️ ⚛️

Standard approach

Unit tests

Integration tests

UI tests

This course approach

Unit tests

Integration tests

UI tests

Made with Slides.com