Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ReferenceError: TextEncoder is not defined (updating to v2) #1796

Closed
4 tasks done
Danielvandervelden opened this issue Oct 26, 2023 · 31 comments
Closed
4 tasks done

ReferenceError: TextEncoder is not defined (updating to v2) #1796

Danielvandervelden opened this issue Oct 26, 2023 · 31 comments
Labels
bug Something isn't working needs:triage Issues that have not been investigated yet. scope:node Related to MSW running in Node

Comments

@Danielvandervelden
Copy link

Prerequisites

Environment check

  • I'm using the latest msw version
  • I'm using Node.js version 18 or higher

Node.js version

18.16.0

Reproduction repository

https://github.com/Danielvandervelden/msw-issue

Reproduction steps

npm i && npm run test

Current behavior

src/example.test.ts
  ● Test suite failed to run

    ReferenceError: TextEncoder is not defined

      1 | import "@testing-library/jest-dom";
    > 2 | import { HttpResponse, http } from "msw";
        | ^
      3 | import { setupServer } from "msw/node";
      4 |
      5 | const server = setupServer();

      at Object.<anonymous> (node_modules/@mswjs/interceptors/lib/node/chunk-3LFH2WCF.js:2:15)
      at Object.<anonymous> (node_modules/@mswjs/interceptors/lib/node/index.js:7:24)
      at Object.<anonymous> (node_modules/msw/lib/core/utils/matching/matchRequestUrl.js:26:27)
      at Object.<anonymous> (node_modules/msw/lib/core/handlers/HttpHandler.js:51:30)
      at Object.<anonymous> (node_modules/msw/lib/core/http.js:24:26)
      at Object.<anonymous> (node_modules/msw/lib/core/index.js:38:19)
      at Object.<anonymous> (src/example.test.ts:2:1)

Expected behavior

No error, the tests should pass, we are only registering a route to the server in an individual it function.

@Danielvandervelden Danielvandervelden added bug Something isn't working needs:triage Issues that have not been investigated yet. scope:node Related to MSW running in Node labels Oct 26, 2023
@oschwede
Copy link

In the migration guide there is a section about node globals not being available in jsdom environments. You can try using the suggested solution there to also make TextEncoder and TextDecoder available.

https://mswjs.io/docs/migrations/1.x-to-2.x#remap-fetch-api-globals

@naghtigal
Copy link

In the migration guide there is a section about node globals not being available in jsdom environments. You can try using the suggested solution there to also make TextEncoder and TextDecoder available.

https://mswjs.io/docs/migrations/1.x-to-2.x#remap-fetch-api-globals

I just was trying this as was suggested, but it doesn't really help:

In my jest.config.js:
globals: { TextEncoder: TextEncoder, TextDecoder: TextDecoder },

still produce ReferenceError: TextEncoder is not defined

@joel-daros
Copy link

joel-daros commented Oct 26, 2023

I have the same issue with a Create React App:

Reproduction Repository:

https://github.com/joel-daros/msw2-text-encoder-issue

 FAIL  src/App.test.tsx
  ● Test suite failed to run

    ReferenceError: TextEncoder is not defined

    > 1 | import { setupServer } from "msw/node";
        | ^

@Danielvandervelden
Copy link
Author

Danielvandervelden commented Oct 26, 2023

In the migration guide there is a section about node globals not being available in jsdom environments. You can try using the suggested solution there to also make TextEncoder and TextDecoder available.

https://mswjs.io/docs/migrations/1.x-to-2.x#remap-fetch-api-globals

Thank you for your reply. I have indeed seen this, but unfortunately this does not solve the issue. I have updated the repository to include the globals to showcase this.

From my experimentation I'm noticing that when I explicitly remove the testEnvironment: "jest-environment-jsdom" from the jest.config.js it starts working. You can tests this in the repo as well. However, for my unit tests I need this.

Perhaps there's something happening within the jest-environment-jsdom package that is overriding something within msw, however I do not know what.

@mbaumanndev
Copy link

As a workaround, I managed to make it work by adding this to my jest setupTest:

import { TextEncoder } from 'node:util'

global.TextEncoder = TextEncoder

@kettanaito kettanaito changed the title Upgrading from v1 to v2, ReferenceError: TextEncoder is not defined ReferenceError: TextEncoder is not defined (updating to v2) Oct 27, 2023
@kettanaito
Copy link
Member

Solution

I've updated the docs to include the fix:

Please follow these instructions to have Jest set up correctly.

@naghtigal
Copy link

naghtigal commented Oct 27, 2023

@kettanaito , thanks, it works.

Side note, there is a mistype in doc

Reflect.set(globalThis, 'Respose', Respose)

should be

Reflect.set(globalThis, 'Response', Response)

@grzegorz-zadora
Copy link

@Danielvandervelden

Thank you for your reply. I have indeed seen this, but unfortunately this does not solve the issue. I have updated the repository to include the globals to showcase this.

From my experimentation I'm noticing that when I explicitly remove the testEnvironment: "jest-environment-jsdom" from the jest.config.js it starts working. You can tests this in the repo as well. However, for my unit tests I need this.

Perhaps there's something happening within the jest-environment-jsdom package that is overriding something within msw, however I do not know what.

Maybe you are using the import statement instead of the require() function in the polyfills file?

The modules in the polyfills file must be loaded in the correct order, so require() is the only option.

@sernaferna
Copy link

Solution

I've updated the docs to include the fix:

Please follow these instructions to have Jest set up correctly.

This solution doesn't work with create-react-app applications, where you can't specify setupFiles for Jest. The jest.config.js file is ignored, and setting the setupFiles param in package.json spits out the error below. Is there a way to get msw working that doesn't require ejecting a CRA app?

Out of the box, Create React App only supports overriding these Jest options:

  • clearMocks
  • collectCoverageFrom
  • coveragePathIgnorePatterns
  • coverageReporters
  • coverageThreshold
  • displayName
  • extraGlobals
  • globalSetup
  • globalTeardown
  • moduleNameMapper
  • resetMocks
  • resetModules
  • restoreMocks
  • snapshotSerializers
  • testMatch
  • transform
  • transformIgnorePatterns
  • watchPathIgnorePatterns.

These options in your package.json Jest configuration are not currently supported by Create React App:

  • setupFiles

If you wish to override other Jest options, you need to eject from the default setup. You can do so by running npm run eject but remember that this is a one-way operation. You may also file an issue with Create React App to discuss supporting more options out of the box.

@grzegorz-zadora
Copy link

@sernaferna it appears that using craco is the sole way to avoid ejecting in your case

@mattcosta7
Copy link
Contributor

mattcosta7 commented Nov 7, 2023

Solution

I've updated the docs to include the fix:

Please follow these instructions to have Jest set up correctly.

This solution doesn't work with create-react-app applications, where you can't specify setupFiles for Jest. The jest.config.js file is ignored, and setting the setupFiles param in package.json spits out the error below. Is there a way to get msw working that doesn't require ejecting a CRA app?

Out of the box, Create React App only supports overriding these Jest options:

  • clearMocks
  • collectCoverageFrom
  • coveragePathIgnorePatterns
  • coverageReporters
  • coverageThreshold
  • displayName
  • extraGlobals
  • globalSetup
  • globalTeardown
  • moduleNameMapper
  • resetMocks
  • resetModules
  • restoreMocks
  • snapshotSerializers
  • testMatch
  • transform
  • transformIgnorePatterns
  • watchPathIgnorePatterns.

These options in your package.json Jest configuration are not currently supported by Create React App:

  • setupFiles

If you wish to override other Jest options, you need to eject from the default setup. You can do so by running npm run eject but remember that this is a one-way operation. You may also file an issue with Create React App to discuss supporting more options out of the box.

You can always avoid react-scripts test as the test command, and instead use jest directly there, with a custom jest.config.js file. You may need to copy some of the create-react-app jest config, but that's likely pretty straightforward.

patch-package is probably the simplest option, or something like craco.

Migrating off create-react-app to a non-dead project, and one that allows for proper configuration of tools would be ideal.

Create React App often recommended forking to customize in the past, and that's also viable

@joel-daros
Copy link

joel-daros commented Nov 7, 2023

@sernaferna it appears that using craco is the sole way to avoid ejecting in your case

Unfortunately craco doesn’t work either. I’ve updated my reproduction repo with Craco, and even after adding a custom craco config for Jest, the test still get stuck when useFakeTimers() is used .

https://github.com/joel-daros/msw2-text-encoder-issue

// craco.config.ts

import { CracoConfig } from "@craco/types";

const cracoConfig: CracoConfig = {
  jest: {
    configure: (jestConfig, { env, paths, resolve, rootDir }) => {
      return {
        ...jestConfig,
        setupFiles: [`${rootDir}/src/jest.polyfills`],
      };
    },
  },
};

export { cracoConfig as default };

I know that CRA is dead and outdated package, but it's still widely used in many projects. I don’t have the option to eject our apps, because there are some many other internal factors involved.

We might think in a different solution, otherwise, I think this can be a big barrier to migrate to MSW 2 or even the main reason to move to other alternatives in the long run.

@sernaferna
Copy link

Well it was a journey, but I got there in the end.

  1. Using craco allowed me to use the setupFiles option, and get me past this issue per the msw documentation on setting up polyfills
  2. ... which led to an unexpected token: export error, which I fixed from advice I got on this issue: Jest: SyntaxError: Unexpected token 'export' on "@bundled-es-modules/js-levenshtein" #1810
  3. ... which led to relative URLs not being resolved, which I fixed with advice I got from this issue: Node interceptors don't resolve relative URLs when "location" is present #1625
  4. ... which led to everything working, except my mocked APIs were never being called. But I realised I'd been working on this update for so long that there had been three patch releases since I started, so getting up to 2.0.4 fixed it.

@RobinHerbots
Copy link

@sernaferna it appears that using craco is the sole way to avoid ejecting in your case

Unfortunately craco doesn’t work either. I’ve updated my reproduction repo with Craco, and even after adding a custom craco config for Jest, the test still get stuck when useFakeTimers() is used .

https://github.com/joel-daros/msw2-text-encoder-issue

// craco.config.ts

import { CracoConfig } from "@craco/types";

const cracoConfig: CracoConfig = {
  jest: {
    configure: (jestConfig, { env, paths, resolve, rootDir }) => {
      return {
        ...jestConfig,
        setupFiles: [`${rootDir}/src/jest.polyfills`],
      };
    },
  },
};

export { cracoConfig as default };

I know that CRA is dead and outdated package, but it's still widely used in many projects. I don’t have the option to eject our apps, because there are some many other internal factors involved.

We might think in a different solution, otherwise, I think this can be a big barrier to migrate to MSW 2 or even the main reason to move to other alternatives in the long run.

You can solve it by putting the polyfills in different files.

import { TextDecoder, TextEncoder } from 'node:util';
Reflect.set(globalThis, 'TextDecoder', TextDecoder);
import { Blob, File } from 'node:buffer';

Reflect.set(globalThis, 'Blob', Blob);
Reflect.set(globalThis, 'File', File);

and so on ...
and in your craco.config you add:

   jestConfig.setupFiles = [
        `${rootDir}/src/jest.polyfills1.js`,
        `${rootDir}/src/jest.polyfills2.js`,
        `${rootDir}/src/jest.polyfills3.js`
      ];```

@sernaferna
Copy link

I didn't need to create multiple polyfill files, it worked with just one for me, but the other thing I'd mention is that there have been a few releases lately that broke my tests, causing me to spend a few hours troubleshooting, only to get the next build and it would start working again. So if you've followed all of the advice in the comments above and it's still not working, try

  1. Getting the latest version, or
  2. If you already have the latest version, reverting back one patch release

@gopal-panigrahi
Copy link

Solution

I've updated the docs to include the fix:

Please follow these instructions to have Jest set up correctly.

This solution doesn't work with create-react-app applications, where you can't specify setupFiles for Jest. The jest.config.js file is ignored, and setting the setupFiles param in package.json spits out the error below. Is there a way to get msw working that doesn't require ejecting a CRA app?

Out of the box, Create React App only supports overriding these Jest options:

  • clearMocks
  • collectCoverageFrom
  • coveragePathIgnorePatterns
  • coverageReporters
  • coverageThreshold
  • displayName
  • extraGlobals
  • globalSetup
  • globalTeardown
  • moduleNameMapper
  • resetMocks
  • resetModules
  • restoreMocks
  • snapshotSerializers
  • testMatch
  • transform
  • transformIgnorePatterns
  • watchPathIgnorePatterns.

These options in your package.json Jest configuration are not currently supported by Create React App:

  • setupFiles

If you wish to override other Jest options, you need to eject from the default setup. You can do so by running npm run eject but remember that this is a one-way operation. You may also file an issue with Create React App to discuss supporting more options out of the box.

For create-react-app, without using craco or without ejecting the project, I solved it by following the below steps :

  1. Created a jest.polyfills.js file as specified in Request/Response/TextEncoder is not defined (Jest)
  2. Added following import statement in the default setupTests.js file in create-react-app project.
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import "@testing-library/jest-dom";
import "./test/jest.polyfills";
import { server } from "./test/server";

beforeAll(() => server.listen({ onUnhandledRequest: "error" }));
beforeEach(() => server.resetHandlers());
afterAll(() => server.close());

  1. Added transformIgnorePatterns in jest option in package.json
"jest": {
    "transformIgnorePatterns": [
      "/node_modules/(?!(@bundled-es-modules)/).*/"
    ]
  }
  1. And voila, the tests starts to intercept the requests.

Note: Same can be followed for typescript

@joel-daros
Copy link

Solution

I've updated the docs to include the fix:

Please follow these instructions to have Jest set up correctly.

I don't think this works anymore in Undici 6.x

All my test failing with the error:

ReferenceError: ReadableStream is not defined

@marliesparzinski
Copy link

marliesparzinski commented Dec 7, 2023

Solution

I've updated the docs to include the fix:

Please follow these instructions to have Jest set up correctly.

I don't think this works anymore in Undici 6.x

All my test failing with the error:

ReferenceError: ReadableStream is not defined

I found this, it might help for you as well: langchain-ai/langchainjs#2815

So basically I added this to the jest.polyfills.js file:

import { ReadableStream } from 'node:stream/web'
if (globalThis.ReadableStream === undefined) {
  globalThis.ReadableStream = ReadableStream
}

@ddcech
Copy link

ddcech commented Dec 11, 2023

@marliesparzinski I added your code to my jest.polyfills.js file. It was important to add it to the top of the file. However another error shows

DataCloneError: Transferring of ReadableStream cannot be properly polyfilled in this engine

@tylerpashigian
Copy link

Solution

I've updated the docs to include the fix:

Please follow these instructions to have Jest set up correctly.

I don't think this works anymore in Undici 6.x

All my test failing with the error:

ReferenceError: ReadableStream is not defined

Did you figure this out? Also running into this issue.

@joel-daros
Copy link

joel-daros commented Dec 12, 2023

Yes, check the solution here: #1916 (comment)

@Borisjavier1
Copy link

As a workaround, I managed to make it work by adding this to my jest setupTest:

import { TextEncoder } from 'node:util'

global.TextEncoder = TextEncoder

This worked for me! Project with create-react-app

@yaswanthmaddula-sureify
Copy link

As a workaround, I managed to make it work by adding this to my jest setupTest:

import { TextEncoder } from 'node:util'

global.TextEncoder = TextEncoder

This did not work for me. Still gives the same error. I am using react-scripts: 5.0.1

@m-nathani
Copy link

why is this closed ? 🤔 i am facing an error.. still facing this issue afte the official docs mentioned too.

@Danielvandervelden
Copy link
Author

We as a company/team decided to just stay on v1.0. It works out of the box without having to jump through any hoops. Since we just use it for testing we won't have any severe vulnerability issues anyway. Probably we'll try to update at a later point. And that's honestly my advice for anyone else trying to upgrade.

@jhaeberli
Copy link

Another one here...
We are using CRA with Jest.
It's annoying to find out there's no solution yet. So many problems. Applied Jest polyfill, with the readableStream patch and got the unexpected token error on a DatePicker, hence, lots of tests are failing.
How can I convince the management to migrate to Vitest simply because of this? I already convince them to migrate to MSW v2.0 after so little support with GraphQL. I even registered in Discord only to find out nothing useful.
A big warning should be included in the migration guide for users with CRA and Jest, stating that even the published workaround is not solving the issue.

@christopher-theagen
Copy link

.jest/setup.js

import { TextEncoder, TextDecoder } from 'util';

global.TextEncoder = TextEncoder;
global.TextDecoder = TextDecoder;

@narekboshyan
Copy link

please just downgrade your msw to 1.3.3. i had similliar issues i just downgraded it to 1.3.3 and it worked as expected

@dnyn92
Copy link

dnyn92 commented Apr 29, 2024

Solution

I've updated the docs to include the fix:

Please follow these instructions to have Jest set up correctly.

I have followed this guide and additionally added this to get rid of the readablestream error

import { ReadableStream } from 'node:stream/web'
if (globalThis.ReadableStream === undefined) {
  globalThis.ReadableStream = ReadableStream
}

Now I get this error: ReferenceError: clearImmediate is not defined

I cannot find a remedy. Will migrate back to 1.3.2 for now

@MakotoE
Copy link

MakotoE commented Jul 1, 2024

I was able to fix it with these steps:

  1. Define all node globals in the setup. Install undici. Make ReadableStream, TransformStream, and clearImmediate global.
const {TextDecoder, TextEncoder} = require('node:util');
const {ReadableStream, TransformStream} = require('node:stream/web');
const {performance} = require('node:perf_hooks');

Object.defineProperties(globalThis, {
    TextDecoder: {value: TextDecoder},
    TextEncoder: {value: TextEncoder},
    ReadableStream: {value: ReadableStream},
    TransformStream: {value: TransformStream},
    performance: {value: performance},
});

const {Blob, File} = require('node:buffer');
const {fetch, Headers, FormData, Request, Response} = require('undici');
const {clearImmediate} = require('node:timers');

Object.defineProperties(globalThis, {
    fetch: {value: fetch, writable: true},
    Blob: {value: Blob},
    File: {value: File},
    Headers: {value: Headers},
    FormData: {value: FormData},
    Request: {value: Request},
    Response: {value: Response},
    clearImmediate: {value: clearImmediate},
});
  1. Fix Cannot find module ‘msw/node’ with customExportConditions.

The JS ecosystem is such a joke. Dependencies are holding each other up with scotch tape. Break one and the entire tower falls. It's so bad that frameworks are recommending a new test framework to fix all issues. But when that test framework goes unsupported and meanwhile node v30.x comes out, deprecating many dependencies used in that framework.

corvidian added a commit to City-of-Helsinki/haitaton-ui that referenced this issue Sep 6, 2024
The API for adding mocks was changed completely.

Getting MSW 2 to work with Jest and create-react-app needed some
workarounds. These were the primary sources for these work-arounds:
- https://mswjs.io/docs/migrations/1.x-to-2.x/
- mswjs/msw#1796
corvidian added a commit to City-of-Helsinki/haitaton-ui that referenced this issue Sep 6, 2024
The API for adding mocks was changed completely.

Getting MSW 2 to work with Jest and create-react-app needed some
workarounds. These were the primary sources for these work-arounds:
- https://mswjs.io/docs/migrations/1.x-to-2.x/
- mswjs/msw#1796
corvidian added a commit to City-of-Helsinki/haitaton-ui that referenced this issue Sep 6, 2024
The API for adding mocks was changed completely. Rewrite all mocks.

Getting MSW 2 to work with Jest and create-react-app needed some
workarounds. These were the primary sources for these work-arounds:
- https://mswjs.io/docs/migrations/1.x-to-2.x/
- mswjs/msw#1796

Remove unused handlers and branches from handlers.ts.

* Bump msw from 1.3.3 to 2.4.2

Bumps [msw](https://github.com/mswjs/msw) from 1.3.3 to 2.4.2.
- [Release notes](https://github.com/mswjs/msw/releases)
- [Changelog](https://github.com/mswjs/msw/blob/main/CHANGELOG.md)
- [Commits](mswjs/msw@v1.3.3...v2.4.2)

---
updated-dependencies:
- dependency-name: msw
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Topias Heinonen <topias.heinonen@gofore.com>
@ahelmi365
Copy link

i just downgraded it to 1.3.3 and it worked as expected

This works for me, thank you! Just downgraded it to 1.3.3.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working needs:triage Issues that have not been investigated yet. scope:node Related to MSW running in Node
Projects
None yet
Development

No branches or pull requests