ReferenceError: TextEncoder is not defined during test running with jest and msw v2.0

6k views Asked by At

I have a working react app, where I use msw for mocking BE in browser and in tests (Jest). With msw v1.3.0 everything works perfectly fine, I've decided to update it v2.0 and there I've encountered problems. All my tests fail because of the error ReferenceError: TextEncoder is not defined. In browser mode it works fine though.

I've contacted msw support and they told me this issue is Jest related. I've tried many workarounds how to define TextEncoder in usual cases where that might work, but all in vain.

p.s. all versions are new (node: v18.14.2, npm: v9.5.0, typescript: v4.9.5, react: v18.2.0, jest: v27.5.1). And I run my tests with craco test


I've tried to create a separate jest.config.js file and define TextEncoder like this:

module.exports = {
  globals: {
     TextEncoder: require('util').TextEncoder,
     TextDecoder: require('util').TextDecoder,
  }
}

and from the file:

module.exports = {
  setupFiles: ['<rootDir>/setupFiles.js'],
}

I've tried to import TextEncoder from 'util' and 'node:util':

const { TextDecoder, TextEncoder } = require('node:util');

Object.defineProperties(globalThis, {
  TextDecoder: { value: TextDecoder, writable: true },
  TextEncoder: { value: TextEncoder, writable: true },
});

I've tried to import it from the different external 'text-encoding' libraries. And add testEnvironment: 'node' in configs. But all of that doesn't work for my case.

3

There are 3 answers

1
Shanon Jackson On

My suspicion is that these "environment" libraries use VM another library internally to create a sandbox. Both JSDOM and it's competitor HappyDOM don't have an implementation for TextDecoder / TextEncoder present on their globals and therefore not only are they not found, but you can't add them without access to their global context inside the VM.

The reason they do this is they emulate the browser, and it wouldn't make sense if for example 'fs' or other node standard libraries to be accessible.

Try this and let me know if it works; Works for me on Node 18.18.2 with MSW 2.0

// inside your jest.setup.js
testEnvironment: "./jest.environment.js",
// test.environment.js

const Environment = require("jest-environment-jsdom").default;

module.exports = class CustomTestEnvironment extends Environment {
    async setup() {
        await super.setup();
        this.global.TextEncoder = TextEncoder;
        this.global.TextDecoder = TextDecoder;
        this.global.Response = Response;
        this.global.Request = Request;
        
    }
};

I would consider this solution a partial hack, but your options are pretty limited outside of creating a PR or issue with JSDOM or HappyDOM to add support for these.

2
Gabriel Iñigo On

This work for me

//setup.jest.js
import { TextDecoder, TextEncoder } from 'util';
global.TextEncoder = TextEncoder;
global.TextDecoder = TextDecoder;

Then calling within jest.config.js file with attr -> "setupFiles"

module.exports = {
  // preset: 'ts-jest',
  testEnvironment: 'jsdom',
  setupFiles: ['<rootDir>/setup.jest.js'],
  globals: {
    Uint8Array: Uint8Array,
  },
  transformIgnorePatterns: [`/node_modules/(?!${esModules})`],
  transform: {
    '^.+.[tj]sx?$': [
      'babel-jest',
    ],
  },
};
1
buzypi On

This has now been updated in the documentation of MSW:

https://mswjs.io/docs/migrations/1.x-to-2.x/#requestresponsetextencoder-is-not-defined-jest

But ensure that you use undici v5 in your package.json.