Justin D. Harris
Justin D. Harris

Reputation: 2285

`ReferenceError: TextEncoder is not defined` when running `react-scripts test --env=jsdom`

I'm using a TensorFlow encoder in my application. It works fine in my browser when the application is running but I get issues when testing that it builds:

$ npx react-scripts test --env=jsdom
FAIL  src/App.test.js
  ● Test suite failed to run

    ReferenceError: TextEncoder is not defined

      16 | import TextField from '@material-ui/core/TextField';
      17 | import Typography from '@material-ui/core/Typography';
    > 18 | import * as mobilenet from '@tensorflow-models/mobilenet';
         | ^
      19 | import * as UniversalSentenceEncoder from '@tensorflow-models/universal-sentence-encoder';
      20 | import * as tf from '@tensorflow/tfjs';
      21 | import axios from 'axios';

      at new PlatformBrowser (node_modules/@tensorflow/tfjs-core/src/platforms/platform_browser.ts:26:28)
      at Object.<anonymous> (node_modules/@tensorflow/tfjs-core/src/platforms/platform_browser.ts:50:30)
      at Object.<anonymous> (node_modules/@tensorflow/tfjs-core/src/index.ts:29:1)
      at Object.<anonymous> (node_modules/@tensorflow/tfjs-converter/src/executor/graph_model.ts:18:1)
      at Object.<anonymous> (node_modules/@tensorflow/tfjs-converter/src/index.ts:17:1)
      at Object.<anonymous> (node_modules/@tensorflow-models/mobilenet/dist/index.js:38:14)
      at Object.<anonymous> (src/components/model.js:18:1)
      at Object.<anonymous> (src/App.js:8:1)
      at Object.<anonymous> (src/App.test.js:3:1)

I'd like to get rid of that error. I've tried using the 'text-encoding' package but I'm not sure how get TextEncoder properly defined before the import happens.

Maybe I can set a different option for --env?

I get the same error without --env=jsdom. I believe I added it after getting similar types of not defined errors and it corrected an issue.

Here is my test:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

it('renders without crashing', () => {
  const div = document.createElement('div');
  ReactDOM.render(<App />, div);
  ReactDOM.unmountComponentAtNode(div);
});

So setting --env=node does not work either because: ReferenceError: document is not defined.

Upvotes: 45

Views: 58378

Answers (12)

Alex Lee
Alex Lee

Reputation: 64

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

it worked for me! for newbie: remember to add lib:

yarn add util

Upvotes: 3

Rajoe
Rajoe

Reputation: 141

None of the previously posted solutions worked in our case. The only thing that did help was adding the following lines to our jest.config.js file:

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

Upvotes: 6

Andrea Giammarchi
Andrea Giammarchi

Reputation: 3198

An alternative approach is to wrap jest-environment-jsdom module with something that augment the env once and use that file instead in jest.config.js ... at least this solution worked well for us and it can be extended to include more missing globals.

Upvotes: 0

ayxos
ayxos

Reputation: 408

According to the latest jest v28 and react 18 I had to modify a bit the script

so my preSetup.js

const Environment = require('jest-environment-jsdom-global');
/**
 * A custom environment to set the TextEncoder
 */
module.exports = class CustomTestEnvironment extends Environment {
    constructor({ globalConfig, projectConfig }, context) {
        super({ globalConfig, projectConfig }, context);
        if (typeof this.global.TextEncoder === 'undefined') {
            const { TextEncoder } = require('util');
            this.global.TextEncoder = TextEncoder;
        }
    }
};

Upvotes: 3

Clark
Clark

Reputation: 309

Add this to src/setupTests.ts

import '@testing-library/jest-dom';
import { TextEncoder } from 'util';

global.TextEncoder = TextEncoder;

Upvotes: 5

farzad
farzad

Reputation: 409

Although all other answers seems to work fine, but I couldn't use any of them in my react-scripts app.

to fix the problem, I used this approach and it solved my issue.

This approach doesn't require adding a test environment as jest config.

Upvotes: 0

xiaotian
xiaotian

Reputation: 129

next babel works

  ● Test suite failed to run

    ReferenceError: TextEncoder is not defined

      1 | import assert from 'assert'
    > 2 | import { fromUrl, parseDomain, ParseResultType } from 'parse-domain'
        | ^
      3 | import { toUnicode } from 'punycode'
// ...
setupFiles: [`<rootDir>/jest-shim.js`],
testEnvironment: 'jest-environment-jsdom',
// ...
import { TextDecoder, TextEncoder } from 'util'

global.TextEncoder = TextEncoder
global.TextDecoder = TextDecoder

Upvotes: 2

Mosesoak
Mosesoak

Reputation: 251

Thanks for these answers. A simpler format that seems to work, at least with testEnvironment: 'jsdom' is:

  setupFiles: [`<rootDir>/jest-shim.js`],

jest-shim.js:

import { ArrayBuffer, TextDecoder, TextEncoder, Uint8Array } from 'util';

global.TextEncoder = TextEncoder;
global.TextDecoder = TextDecoder;
global.ArrayBuffer = ArrayBuffer;
global.Uint8Array = Uint8Array;

Upvotes: 23

Brendon
Brendon

Reputation: 727

Doesnt work using below config

"testEnvironment": "<rootDir>/tests/custom-test-env.js"

const NodeEnvironment = require('jest-environment-node');

// A custom environment to set the TextEncoder that is required by mongodb.
module.exports = class CustomTestEnvironment extends NodeEnvironment {
  async setup() {
    await super.setup();
    if (typeof this.global.TextEncoder === 'undefined') {
      const { TextEncoder } = require('util');
      this.global.TextEncoder = TextEncoder;
    }
  }
}

using "jest": "^28.0.3",

Upvotes: 0

Nibedita Pattnaik
Nibedita Pattnaik

Reputation: 207

I am getting same error for my Node.Js project. For testing purpose I used jest there. So following steps are resolved my issue

step-1: on the root folder of your project add a file named as jest.config.js

step-2: Add the following lines in the jest.config.file:

    module.exports = {
        testEnvironment: "node"
    };

Upvotes: 17

Mostafa Roghanian
Mostafa Roghanian

Reputation: 562

I faced this problem when using mongodb. I used @Phoenix solution with a little change.

First I used jest-environment-node instead of jest-environment-jsdom:

const NodeEnvironment = require('jest-environment-node');

// A custom environment to set the TextEncoder that is required by mongodb.
module.exports = class CustomTestEnvironment extends NodeEnvironment {
  async setup() {
    await super.setup();
    if (typeof this.global.TextEncoder === 'undefined') {
      const { TextEncoder } = require('util');
      this.global.TextEncoder = TextEncoder;
    }
  }
}

Then I added the environment in the jest configs for all tests as Cava said in the comments:

// package.json
{
  ...
  "jest": {
    ...
    "testEnvironment": "<rootDir>/tests/custom-test-env.js"
  }
  ...
}

Upvotes: 4

Phoenix
Phoenix

Reputation: 632

jsdom Doesn't seem to have TextEncoder defined in global for the DOM. So you can fill it in with the node.js one.

test/custom-test-env.js:

const Environment = require('jest-environment-jsdom');

/**
 * A custom environment to set the TextEncoder that is required by TensorFlow.js.
 */
module.exports = class CustomTestEnvironment extends Environment {
    async setup() {
        await super.setup();
        if (typeof this.global.TextEncoder === 'undefined') {
            const { TextEncoder } = require('util');
            this.global.TextEncoder = TextEncoder;
        }
    }
}

npx react-scripts test --env=./test/custom-test-env.js

Upvotes: 43

Related Questions