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

3

11

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.

Reparable answered 25/10, 2023 at 10:50 Comment(1)
I solved my problem. I just forgot that I use "craco" and I run tests with craco test command. I should have added those configs into craco config in jest section instead of putting it into jest configs, which was not working.Reparable
A
8

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",
// jest.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.

Asthenosphere answered 27/10, 2023 at 8:46 Comment(2)
Thanks! Worked for me, just changed the first actual line: const Environment = require("jest-environment-jsdom");Inclose
Doesn't work for me. I get the error: TypeError: Class constructor CustomTestEnvironment cannot be invoked without 'new'Idioblast
L
2

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',
    ],
  },
};
Ludwick answered 5/12, 2023 at 15:52 Comment(2)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Shallot
Not sure how this is unclear. I was able to use this and it fixed my issue.Alcoholize
A
1

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.

Amoeba answered 29/1 at 11:16 Comment(2)
This isn't working for lattest versions of nextjs, just in case someone has a problem using itRomina
This solved the issue for me, using nextJs. Note that ReadableStream has to be added in the same way TextDecoder and TextEncoder are added. Next 14.2.3, "@testing-library/jest-dom": "^6.4.2", "@testing-library/react": "^15.0.5", "undici": "^6.15.0", "msw": "^2.2.14", "jest-environment-jsdom", "jest": "^29.7.0".Fullfledged

© 2022 - 2024 — McMap. All rights reserved.