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