mswjs / msw

Industry standard API mocking for JavaScript.
https://mswjs.io
MIT License
15.97k stars 519 forks source link

ReferenceError: BroadcastChannel is not defined (upgrade msw from 2.5.2 to 2.6.0) #2340

Closed okhomenko closed 2 weeks ago

okhomenko commented 3 weeks ago

Prerequisites

Environment check

Browsers

Chromium (Chrome, Brave, etc.)

Reproduction repository

https://github.com/mswjs/msw/issues

Reproduction steps

npm test

Current behavior

ReferenceError: BroadcastChannel is not defined

Expected behavior

Build doesn't fail

kimroen commented 3 weeks ago

Hi! You don't mention it, but in case you're using jest with jsdom, the jest-fixed-jsdom package just released a fix for this that defines BroadcastChannel when running this way: https://github.com/mswjs/jest-fixed-jsdom/issues/18

liviuciulinaru commented 2 weeks ago

Great solution @kimroen. It worked

I just copied the file in my project, as I needed to add a fix for ReferenceError: TransformStream is not defined too

this.global.TransformStream = TransformStream;
Avi-Cohen-Nehemia commented 2 weeks ago

Great solution @kimroen. It worked

I just copied the file in my project, as I needed to add a fix for ReferenceError: TransformStream is not defined too

this.global.TransformStream = TransformStream;

@liviuciulinaru Where in project did you copy it to? Mind sharing in a bit more detail? I prefer to avoid relying on this package

Scooties commented 2 weeks ago

I've run into the same issue when using JSDOM. Both BroadcastChannel and TransformStream are undefined in JSDOM.

For those who don't want to use jest-fixed-jsdom (or in case you are already using a custom test environment), you can also add the polyfills to your own custom test environment.

In <rootDir>/<path-to-test-setup>/yourTestEnv.ts;

import {
    type JestEnvironmentConfig,
    type EnvironmentContext
} from '@jest/environment';
import Environment from 'jest-environment-jsdom';

export default class CustomTestEnvironment extends Environment {
    constructor(config: JestEnvironmentConfig, context: EnvironmentContext) {
        super(config, context);

        this.global.BroadcastChannel = BroadcastChannel;
        this.global.TransformStream = TransformStream;
    }
}

And don't forget to make Jest use your test environment;

In jest.config.ts;

const config = {
    ...,
    testEnvironment: '<rootDir>/<path-to-test-setup>/yourTestEnv.ts'
}

export default config;
kettanaito commented 2 weeks ago

Thanks for reporting this. We don't address Jest/JSDOM-related issues.

Both BroadcastChannel and TransformStream are undefined in JSDOM.

I've spent an ungodly amount of time battling this. JSDOM is broken by design. If you can, migrate to something else. If you can't use jest-fixed-jsdom for the hackery it provides to patch the holes.

ctklc commented 2 weeks ago

This problem is not only related to jsdom. I migrated to happy-dom recently and still having this issue with the latest version. And this is not the only polyfill I have to define. I have this file with me:

// jest.polyfills.js
const { TextDecoder, TextEncoder } = require("node:util");
const { BroadcastChannel } = require("node:worker_threads");

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

And:

// jest.config.js
{
  ...
  setupFiles: ["<rootDir>/jest.polyfills.js"],
  ...
}

If I delete one of these I got these errors:

Test suite failed to run
    ReferenceError: TextEncoder is not defined
      at Object.<anonymous> (node_modules/@mswjs/interceptors/src/utils/bufferUtils.ts:1:17)
      at Object.<anonymous> (node_modules/@mswjs/interceptors/lib/node/chunk-DRXVDC32.js:5:24)
      at Object.<anonymous> (node_modules/@mswjs/interceptors/lib/node/interceptors/XMLHttpRequest/index.js:3:24)
      at Object.<anonymous> (node_modules/msw/src/node/SetupServerApi.ts:3:43)

Or

ReferenceError: TextDecoder is not defined
      at decodeBuffer (node_modules/@mswjs/interceptors/src/utils/bufferUtils.ts:8:19)
      at XMLHttpRequestController.responseBufferToText (node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts:460:30)
      at XMLHttpRequestController.get response [as response] (node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts:505:35)
      at XMLHttpRequest.get [as response] (node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts:384:25)
      at next (node_modules/@mswjs/interceptors/src/utils/createProxy.ts:81:24)
      at Object.handler.get (node_modules/@mswjs/interceptors/src/utils/createProxy.ts:86:11)
      at Proxy.<anonymous> (node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts:148:32)
      at node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts:645:50
          at Array.forEach (<anonymous>)
      at XMLHttpRequestController.trigger (node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts:645:19)
      at finalizeResponse (node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts:415:12)
      at readNextResponseBodyChunk (node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts:436:11)

Or now as described:

Test suite failed to run
    ReferenceError: BroadcastChannel is not defined
    > 11 |     await delay(50);
         |              ^
      12 |
      at Object.<anonymous> (node_modules/msw/src/core/ws.ts:20:26)
      at Object.<anonymous> (node_modules/msw/src/core/index.ts:13:40)

Hope this helps @kettanaito!