在运行`react-scripts test --env=jsdom`时出现了`ReferenceError: TextEncoder is not defined`的错误。

36

我在我的应用程序中使用了一个TensorFlow编码器。当应用程序正在运行时,它在我的浏览器中正常工作,但是当我测试它是否成功构建时,出现了问题:

$ npx react-scripts test --env=jsdom
FAIL  src/App.test.jsTest 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)

我想要摆脱那个错误。我尝试使用“text-encoding”包,但我不确定如何在导入发生之前正确定义TextEncoder。

也许我可以为--env设置不同的选项?

在没有--env=jsdom的情况下,我会收到相同的错误。我相信在遇到类似未定义错误时添加它后,它纠正了一个问题。

这是我的测试:

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);
});

所以设置 --env=node 也不起作用,因为: ReferenceError: document is not defined


1
提供的全局 polyfill 编码器解决了我类似问题的解决方案 https://dev59.com/ylEG5IYBdhLWcg3wTJfV#68468204 - David Dal Busco
12个回答

41

jsdom在全局的DOM中似乎没有定义TextEncoder,因此您可以使用node.js的TextEncoder来填充它。

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


3
由于typeof TextEncoder === 'undefined'总是返回false,需要将其更改为:typeof this.global.TextEncoder === 'undefined' - EliSherer
3
我已经完成了这个任务,并在 jest.config.js 文件中添加了 'testEnvironment': '<rootDir>/test/custom-test-env.js' - Cava
@SerdarD. 'custom-js-dom-env.ts' 无法在 --isolatedModules 下编译,因为它被视为全局脚本文件。请添加一个导入、导出或空的 export {} 语句以使其成为模块。ts(1208)。如果我添加一个空的 export {},则在测试运行时会出现 Unexpected token 'export' - Paul
没关系,我的解决方法是使用 window.document 而不是 JSDom。 - Paul
7
我会尽可能简洁地翻译以下内容:你尝试按照描述的方法进行操作,但是遇到了一个错误:“TypeError: Class extends value #<Object> is not a constructor or null”。你不得不切换到jest-environment-jsdom-global - Ruben Martinez Jr.
显示剩余2条评论

17

感谢这些答案。一个似乎起作用的更简单的格式,至少使用 testEnvironment: 'jsdom' 是:

  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;

这对我解决了TextEncoder错误(jest 28 w/babel),但是在import NextAuth from 'next-auth'时,我遇到了TypeError: Uint8Array is not a constructor :( - Devin Rhode
1
好的,如果我只是删除 global.Uint8Array = Uint8Array; 那么关于 Uint8Array 的错误就会消失! - Devin Rhode
1
我喜欢这个解决方案,因为它非常简单易懂,视觉上也非常干净。 - Devin Rhode

17

我的Node.Js项目也遇到了相同的错误。为了测试目的,我在那里使用了jest。因此,以下步骤解决了我的问题

步骤1:在您的项目根文件夹中添加一个名为jest.config.js的文件

步骤2:在jest.config.file中添加以下行:

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

3
谢谢。这对我有用,而且是更简洁、更短的解决方法。 - Yada
这值得100个赞!!! - dragonfly02
1
如果你正在使用一个NodeJS项目,那么这个应该在文档中更加突出。 - a53-416
1
你也可以保留默认设置node,并在测试文件开头添加一个docblock:/** * @jest-environment jsdom */ test('在这个测试文件中使用jsdom', () => { const element = document.createElement('div'); expect(element).not.toBeNull(); });参考文献:https://jestjs.io/docs/configuration#testenvironment-string - Chukwuma Nwaugha

4

在使用MongoDB时,我遇到了这个问题。我采用了@Phoenix的解决方案,稍作修改。

首先,我使用jest-environment-node而不是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;
    }
  }
}

接着我按照Cava在评论中提到的做法,在jest配置中为所有测试添加了环境:

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

我不得不添加一个解码器,但这对我完全起作用了!谢谢! - Lakshya
1
以下是一个示例自定义环境配置文件,其中包含更多的赋值,并且对我有效。点击此处查看。 - Roman Mkrtchian

3
根据最新的jest v28和react 18,我不得不稍微修改一下脚本。
所以我的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;
        }
    }
};

3

之前发布的解决方案在我们的情况下都没有起作用。唯一有效的方法是将以下行添加到我们的jest.config.js文件中:

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


2

下一个Babel工作

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

4
您的回答可以通过补充支持性资料来改进。请[编辑]以添加更多细节,例如引用或文献,以便其他人可以确认您的答案是否正确。您可以在帮助中心中找到有关如何编写好答案的更多信息。 - Community

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

这对我有用!对于新手:记得添加库:

yarn add util

迄今为止,这是一群答案中最干净的回答。 - iwasrobbed
迄今为止,这是一群答案中最干净的回答。 - undefined

1

将此内容添加到 src/setupTests.ts 文件中

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

global.TextEncoder = TextEncoder;

0

尽管所有其他答案似乎都能正常工作,但我无法在我的react-scripts应用程序中使用它们中的任何一个。

为了解决问题,我使用了这种方法 ,并解决了我的问题。

这种方法不需要添加一个jest配置作为测试环境。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接