Skip to content

Instantly share code, notes, and snippets.

@luishrd
Last active May 25, 2018 16:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save luishrd/28caa9dfcd4af461cb6bfc075c4da76a to your computer and use it in GitHub Desktop.
Save luishrd/28caa9dfcd4af461cb6bfc075c4da76a to your computer and use it in GitHub Desktop.
Client Testing
const utilities = require('../index');
describe.skip('default', () => {
it('run the tests', () => {});
});
describe('add function', () => {
// afterAll(() => {
// console.log('after all ran');
// });
// beforeEach(() => {
// console.log('before each ran');
// });
it('async with async/await', async () => {
await new Promise(resolve => setTimeout(resolve, 1000));
});
it('should add two numbers', () => {
// arrange
const add = utilities.add;
// act
const seven = add(3, 4);
const four = add(0, 4);
const minusThree = add(1, -4);
// assert
expect(seven).toBe(7);
expect(four).toBe(4);
expect(minusThree).toEqual(-3);
});
it('checks identity', () => {
const numbers = [1, 2, 3];
// const actual = [1, 2, 3];
const actual = numbers;
expect(numbers).toBe(actual);
});
it('checks that it is an array', () => {
const numbers = [1, 2, 3];
const expected = 'array';
const actual = Array.isArray(numbers);
expect(actual).toBe(true);
});
it('async using callback', done => {
setTimeout(done, 1000);
});
it('async with promises', () => {
return new Promise(resolve => setTimeout(resolve, 1000));
});
function makeThing(args) {
return {
args,
};
}
});

(Automated) Testing

Day 1

  • why?
  • how?
  • what? comes from experience and the system we're testing and even the tech stack.
  • when? test-first vs test after.

Confidence (in the sense of trusting your code). Verifying correctess.

We write code to test our code.

Why learn it?

  • good for resume.
  • can work on QA and DevOps.
  • helps understand how an application works.
  • prevents regressions.
  • safety net.

Tooling: Test runner (Mocha) + assertion library (Chai).

We are using Jest.

What could happen if I have no tests.

  • test manually, as the app grows, the time needed will not scale.
  • regressions, code that used to work breaks.
  • you just don't know if the code is correct for all cases.
  • adding new features becomes slow.

Types

  • unit tests. Fastest.
  • integration tests.
  • end to end. Slow.
  • component testing. (for component based frameworks, like React, Angular, Vue, etc.)
  • snapshot testing. (unique to our stack/tools)
  • coverage test.
  • functional testing.
  • performance testing.
  • aceptance test.

We'll concentrate on:

  • unit
  • component
  • snapshot

Watch Mode

  • instead of running the tests manually use watch mode.
  • tests run automatically as files change.
  • only tests pertaining to changed files run.
  • Jest detects changes automatically.
  • change the npm test script to: jest --watch.
  • changing the code or the tests will re-run the tests.
  • using ctrl + c will stop the test runner/watcher.

Jest Matchers (assertions or expectations)

Documentation on Matchers.

Some commonly used (and useful) matchers.

to be or not to be, that is the question.

  • Not: reverses the assertion.
  • toBe: that two values are equivalent using strict equality (checks reference/identity).
  • toEqual: that two values are equivalent by looking at the values (if walks like a duck, it's a duck). For two different arrays with the same values, toBe fails and toEqual succeeds.
  • toContain: checks that a value exists in an array.
  • toHaveLength: checks the lenght of an array. Like toContain, it is more readable than using toEqual and toBe combined with array methods.

Day 2

Review

  • can we install Jest globally?
  • can Jest tests be run as part of the build and deployment processes?
  • characteristics of unit tests
    • fast.
    • simple to write and execute.
    • used to test correctness.
    • written by developers.
    • the tool for doing TDD/BDD.
  • why is watch mode convenient? how can we "turn it on" when running our tests?

Today

  • drawbacks of testing.
  • more about Jest.
  • the other way to have Jest run tests (colocated ending in .spec.js or .test.js).
  • the other types of tests (component and snapshot).
  • setup and teardown globals.
  • skipping and isolating tests.
  • testing asynchronous operations.
  • fakes, stubs, and mock functions aka spies.

Drawbacks of Testing

  • more code to write, and maintain.
  • more tooling.
  • additional dependencies.
  • may provide a false sense of security.
  • trivial test failures may break the build.

More about Jest

  • a test runner + cli in npm package.
  • made by Facebook and included out of the box with create-react-app.
  • general purpose, but works very well with React applications.
  • recommended by the React team.
  • can:
    • run tests (mocha too)
    • asynchronous code testing (mocha too).
    • spies included.
    • snapshot testing.
    • module mocking.
  • includes coverage reports

Running Tests

  • any file inside a __tests__ folder will be run automatically.
  • any file that ends in .spec.js or .test.js will also be executed automatically.

Component Tests

  • appearance and functionality of a component.
  • highly sensitive to small changes.
  • great against regression.
  • verifies changes to component output resulting from changes to state.
  • does not verify interaction between components.

Snapshot Tests

  • sub-type of component testing.
  • very useful to spot regressions.
  • automatically generated by Jest.
  • a snapshot is a JSON based record of a component's output.
  • snapshots are saved to a __snapshots__ folder as a sibling of the tested component.
  • the snapshots are commited to source control.
  • during testing, the components are automatically compared to their last recorded snapshot.
  • checks current output against prior output.
  • fails with any change to the component.

Snapshot Workflow

  • first, install react-test-renderer if you haven't.
  • second import renderer from 'react-test-renderer';.
  • then import { TheComponent } from './TheComponent';.
  • create a tree.
  • run the assertion to match snapshot.
import renderer from 'react-test-renderer';
import { TheComponent } from './TheComponent';
const tree = renderer.create(<TheComponent />);

expect(tree.toJSON()).toMatchSnapshot();
  • the first time, the snapshot is created.
  • when the snapshot fails, the developer can decide to update the snapshot if the change was intended.
  • to update snapshot: jest TheComponent -u or --update (if you used create-react-app the command is yarn test -u), but, ain't nobody got time for that.

Snapshot Pros and Cons

  • fast and semi-automatic.

  • catches regressions that could be missed by humans.

  • works with any library that generates HTML components (Angular, Vue, React).

  • better than no tests at all to protect applications from regressions.

  • easy to override, save new snapshot.

  • protects only against regression.

  • easy to break, smallest change will fail test suite.

  • adds more files to the repository.

  • waste of time to have them while actively making changes to components.

Setup and Teardown Globals

  • exist in the global scope like describe and it.
  • beforeAll: runs once before the first test.
  • beforeEach: runs before the tests, good for setup code. // test runs
  • afterEach: runs after the tests, good for clean up.
  • afterAll: runs once after the last test.

Skipping and Isolating Tests

  • skipping tests: it.skip()
  • isolating is used to pick the tests you want to run: it.only()
  • it also works at the test suite level: describe.only() or describe.skip()

Testing Asynchoronous Code

  • does not complete right away.
  • Jest must be notified that the test completed.
  • techiques:
    • invoke a done() callback that is passed to the test.
    • return a promise from a test.
    • pass an async function to describe. Preferred and cleanest syntax.

Mocks

  • a duplicate of a unit of code that has no implementation.

  • has the same API (method names, return value type and shape must be returned) of the original unit, but has no side effects.

  • prevent side effects.

  • reduce dependencies.

  • isolate tests to simplify testing.

  • add mocks to a __mocks__ folder, next to the mocked module.

  • to mock npm modules, just name your mock the same as the module and it will be loaded automatically.

    • folder must be at the root of the application, next to node_modules folder.
    • add a file inside the folder with the name of the module you want to mock.
  • to mock local files:

    • add the __mocks__ folder at the same level of the file to mock.
    • where the mock is needed (inside the test file) call jest.mock('path to code file to be mocked');.

Spies

Spies are functions that provide information about how they are used.

  • counts function calls.

  • records arguments passed to it when it is called.

  • we can return fake values in order to test specific scenarios.

  • to create spies: const jamesBond = jest.fn();. This creates a noop function.

  • passing a funcion as the first argument, wraps that function into a spy that then keeps track of useful information.

{
"name": "testing",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "jest --watch"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"jest": "^22.4.4"
}
}
// at root folder, rename to index.js had to name it this becuase two files can't have the same name on a gist
function add(a, b) {
return a + b;
}
module.exports = {
add: add,
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment