Setting up Jest to work with Laravel-Mix, Webpack, Babel

Setting up Jest to work with Laravel-Mix, Webpack, Babel

Photo by Fotis Fotopoulos on Unsplash

Sharing my experiences in making Jest work with Laravel-Mix, Webpack and Babel

Jest has established itself as one the leading libraries for TDD (Test Driven Development) for ReactJS; perhaps being created by developers at FB itself has furthered its cause.

So when I wanted to learn ReactJS (which had been on my TODO list for as long as I can remember now) I naturally picked up Jest as my library of choice. However, there was a catch, I was working on a Laravel application so had to get Jest to work with Webpack and Babel in a Laravel app, most of what I document below are steps collated from a default ReactJS-only app to things I learnt about Babel(phew!) in the process.

Packages Installation

Can’t be any simpler than a few commands so here are the commands of libraries I installed to the project

Base packages required for ReactJS testing:

"@testing-library/dom": "7.2.0",
"@testing-library/jest-dom": "5.3.0",
"@testing-library/react": "10.0.2",

Supporting libraries to get Jest to behave well with Laravel-mix

"jest": "25.2.7",
"jsdom": "16.2.2",
"enzyme": "3.11.0",
"enzyme-adapter-react-16": "1.15.2",
"enzyme-to-json": "3.4.4",
"eslint-plugin-jest": "23.8.2",
"babel-jest": "25.2.6",

After this, you need to configure Jest

    "jest": {
        "verbose": true,
        "collectCoverage": true,
        "name": "unit-tests",
        "displayName": "UnitTests",
        "rootDir": "./resources/js",
        "testRegex": "tests/.*.test.js$",
        "moduleDirectories": [
            "<rootDir>/components",
            "<rootDir>/containers",
            "<rootDir>/views",
            "node_modules"
        ],
        "moduleNameMapper": {
            "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "__mocks__/fileMock.js",
            "\\.(css|scss)$": "identity-obj-proxy"
        },
        "setupFiles": [
            "<rootDir>/tests/setup/enzyme.js",
            "<rootDir>/tests/setup/jsdom.js"
        ],
        "transform": {
            "^.+\\.js$": "babel-jest"
        },
        "snapshotSerializers": [
            "enzyme-to-json/serializer"
        ]
    },
    "dependencies": {}
}

We need to provide a mocked file return for all static files, the block in moduleNameMapper does precisely that. Since I’m using JSdom and enzyme with jest I added them in the setupFiles section. I’m essentially adding boilerplate configuration code here so it’s available on all unit tests without having to set this up in the before blocks of each of the tests.

import { configure } from "enzyme";
import Adapter from "enzyme-adapter-react-16";

configure({ adapter: new Adapter() });
/* eslint-disable no-undef */
const { JSDOM } = require('jsdom');

const jsdom = new JSDOM('<!doctype html><html><body></body></html>',{
  url: 'http://adminpanel.test'
});
const { window } = jsdom;

function copyProps(src, target) {
  Object.defineProperties(target, {
    ...Object.getOwnPropertyDescriptors(src),
    ...Object.getOwnPropertyDescriptors(target),
  });
}

global.window = window;
global.document = window.document;
global.navigator = {
  userAgent: 'node.js',
};
global.requestAnimationFrame = function (callback) {
  return setTimeout(callback, 0);
};
global.cancelAnimationFrame = function (id) {
  clearTimeout(id);
};
copyProps(window, global);

Object.keys(document.defaultView).forEach((property) => {
  if (typeof global[property] === 'undefined') {         
    global[property] = document.defaultView[property];   
  }                                                      
});

We also configure Jest to use the babel compiler in the transform section.

/* eslint-disable no-undef */
module.exports = {
    comments: false,
    presets: [["@babel/preset-env"], ["@babel/preset-react"]],
    plugins: [
        "@babel/plugin-syntax-dynamic-import",
        ["@babel/plugin-proposal-class-properties", { loose: true }]
    ],
    ignore: ["node_modules"]
};

That’s it! You can now run your jest tests without hacking through webpack configuration unlike as suggested in quite some forums.