How to test Web Workers with Jest

Andrea Stagi

Andrea Stagi

Oct 20, 2020
2 min read
Share on Twitter or LinkedIn

As you could read in Alex's article, Use Web Workers in your Vue.js Components for Max Performance, you can use Web Workers to maximize performance in your Vue.js app instead of running heavy tasks in the main thread which is UI-blocking.

But how can we test Web Workers? Webpack-bundled Web Workers are not supported by Jest so we have to mock the worker in order to test it! Let's see how to do in 3 simple steps, starting from a simple Vue app to calculate the Fibonacci number, where fibonacci function is the heavy task performed by the Web worker (you can follow the code here)

First of all we need to isolate the main functionality of our worker, in this case is really straightforward because it's just our fibonacci function (src/fibonacci.js)

let fibonacci = (num) => {
  if (num <= 1) return 1;
  return fibonacci(num - 1) + fibonacci(num - 2);
}

export default fibonacci

and keep the worker minimal (src/fibonacci.worker.js):

import fibonacci from "./fibonacci";

self.onmessage = async function (e) {
  self.postMessage(fibonacci(e.data));
};

This way we can mock just the Web Worker part of our implementation (src/__mocks__/fibonacci.worker.js)

import fibonacci from "../fibonacci";

export default class fibonacciWorker {
  constructor() {
    // Note that `onmessage` should be overwritten by the code using the worker.
    this.onmessage = () => { };
  }

  postMessage(data) {
    this.onmessage({ data: fibonacci(data) });
  }
}

and easily test the main functionality

import { shallowMount } from '@vue/test-utils'
import App from '@/App.vue'

jest.mock("@/fibonacci.worker")

describe('Fibonacci App.vue', () => {
  it('should calculate Fibonacci number', async () => {
    const wrapper = shallowMount(App)
    await wrapper.find('input').setValue('10')
    await wrapper.find('button').trigger('click')
    expect(wrapper.find('.result').element.innerHTML).toBe('Result: 89')
  })
})

I created workerloader-jest-transformer to generalize this solution so that all workers are mocked at once. This Jest transformer helps you to test Web Workers loaded with Webpack worker-loader module in Jest. It's easy to use, install it with

yarn add workerloader-jest-transformer --dev

and add the tranformation rule to your Jest configuration:

transform: {
  "^.+\\.worker.[t|j]sx?$": "workerloader-jest-transformer"
}

This transformer is inspired by jsdom-worker and implements Web Worker API for JSDOM, so you can remove any mocking code as you can see here.

Workerloader-jest-transformer is highly experimental and code is available on Github, any contribution and advice would be greatly appreciated!

Don't miss out anything about Vue, your favourite framework.

Subscribe to receive all the articles we publish in a concise format, perfect for busy devs.

Related Articles

The new Provide and Inject in Vue 3

Getting stuck into the prop drilling? Learn how provide/inject can make your components more flexible and independent in this short tutorial.

Anthony Konstantinidis

Anthony Konstantinidis

Jul 18, 2022

The 101 guide to Script Setup in Vue 3

Don't you know about Script Setup yet? Check out this short article now and learn the nicest way to define a Vue component right now!

Anthony Konstantinidis

Anthony Konstantinidis

Jun 20, 2022

Hybrid Rendering: the secret way to smoothly test Vue.js components

Find out how to combine Deep and Shallow Rendering in order to achieve a flexible solution to test your Vue.js combining the best of both worlds.

Alex Jover Morales

Alex Jover Morales

Mar 7, 2022

Sponsors

VueDose is proudly supported by its sponsors. If you enjoy it, consider supporting it to ensure the project maintainability.

Silver
Learning Partner