Testing Pyramid
Definition for Frontend Apps
Unit Tests
individual and isolated components or functions work as expected
Integration Tests
several components work together in harmony, mock as little as possible (i.e. only mock network requests and animation libraries)
E2E Tests
A robot that clicks through the app and verifies behaviour.
Static Qualitychecks
Catch typos and type errors as you write the code
Code Style & Code Quality
Typos
Autofixing
These two work well together!
Type errors
Missing parameters
etc..
TSLint will be deprecated in favour of ESLint.
Jasmine
around since 2009
comes with assertions, mocking and spying tools
faster for smaller projects
Mocha + Chai + Sinon
around since 2011
Mocha = Test Runner, Chai = Assertion librar, Sinon = Stubs, Spys, Mocks
harder to set up, more configuration needed
allows for more control and customization
Jest
open sourced in 2014
everything out of the box for Vanilla- and DOM-testing (jsdom)
initially based on Jasmine => similar API
snapshot testing, parallel execution -> fast for big projects
Jest
Recommendation:
Reasons:
Easy to setup and use
Fast (parallel execution)
DOM Testing out of the box
Features like mocking, coverage, snapshot testing out of the box
Maintained and used by Facebook
Big and growing community
Jest 24k
Mocha 17k
Jasmine 14k
Github Stars
npm trends
class Cow {
constructor(name) {
this.name = name || "Anon cow";
}
greets(target) {
if (!target) throw new Error("missing target");
return this.name + " greets " + target;
}
}
export default Cow;
ES6 Class
import Cow from "../Cow";
describe("#greets", function() {
it("should throw Error if no target is passed in", () => {
expect(() => new Cow().greets()).toThrow(Error);
});
it("should greet passed target", () => {
const greetings = new Cow("Kate").greets("Baby");
expect(greetings).toEqual("Kate greets Baby");
});
});
Jest
import $ from "jquery";
import fetchCurrentUser from "./fetchCurrentUser.js";
/**
* jQuery Plugin for displaying a User
*/
function displayUser() {
fetchCurrentUser(user => {
const { loggedIn, fullName } = user;
const loggedText = "Logged " + (loggedIn ? "In" : "Out");
$(this).text(fullName + " - " + loggedText);
});
}
$.fn.displayUser = displayUser;
export default displayUser;
DOM Manipuation
e.g. through jQuery
JSDOM
pure JavaScript Implementation of web standards (DOM, HTML) for usage with Node.js
JSDOM
// Construct HTML as String
const htmlString = `
<!DOCTYPE html>
<p>Hello world</p>
`
// Create DOM object with JSDOM
const dom = new JSDOM(htmlString);
// Use standard JavaScript API on DOM object as you would in a browser
console.log(dom.window.document.querySelector("p").textContent);
// => "Hello world"
Component Testing
Button
Image
Product
Drop-down
SizeSelector
ProductInfo
Component Testing
Component Testing
Button
Image
Product
Drop-down
SizeSelector
ProductInfo
dom-testing-library
DOM Testing Abstraction
DOM Testing Library
querying DOM nodes in a way that's similar to how the user finds elements on the page
// By Text
const submitButton = getByText(container, /send data/i)
// By Label Text
const inputNode = getByLabelText(container, 'Username')
// By Placeholder Text
const inputNode = getByPlaceholderText(container, 'Username')
// By Alt Text
const incrediblesPosterImg = getByAltText(container, /incredibles.*poster$/i)
// By Title
const deleteElement = getByTitle(container, 'Delete')
// By Display Value
const lastNameInput = getByDisplayValue(container, 'Norris')
// By Role
const dialogContainer = getByRole(container, 'dialog')
// By Test ID
const usernameInputElement = getByTestId(container, 'username-input')
Vue Testing Library
<template>
<div>
<span data-testid="test1">Hello World</span>
</div>
</template>
// src/TestComponent.spec.js
import 'jest-dom/extend-expect'
import { render } from 'vue-testing-library'
import TestComponent from './TestComponent'
describe("TestComponent", () => {
it('renders Hello World', () => {
// render() returns several query* and get* methods
const { queryByTestId } = render(TestComponent)
// jest-dom brings more matchers like toHaveTextContent
expect(queryByTestId('test1')).toHaveTextContent('Hello World')
});
});
./src/TestComponent.vue
./src/TestComponent.spec.js
Feature: Sum a Pair
It sums a pair of numbers
Scenario: adds 1 + 2 to equal 3
Given 1
When add 2
Then the sum is 3
jest-cucumber
defineFeature(feature, test => {
test('adds 1 + 2 to equal 3', ({ given, when, then }) => {
let x: number;
let z: number;
given('1', () => {
x = 1;
});
when('add 2', () => {
z = sum(x, 2);
});
then('the sum is 3', () => {
expect(z).toBe(3);
});
});
});
Links & Documentation
Articles
AssertJS Talks
Delightful JavaScript Testing with Jest