【问题标题】:jest ReferenceError: Cannot access '' before initialization开玩笑 ReferenceError:在初始化之前无法访问“”
【发布时间】:2021-04-09 18:54:09
【问题描述】:

我收到了错误:

ReferenceError: Cannot access 'myMock' before initialization

尽管我尊重关于吊装的开玩笑文档: A limitation with the factory parameter is that, since calls to jest.mock() are hoisted to the top of the file, it's not possible to first define a variable and then use it in the factory. An exception is made for variables that start with the word 'mock'.

我正在这样做:

import MyClass from './my_class';
import * as anotherClass from './another_class';

const mockMethod1 = jest.fn();
const mockMethod2 = jest.fn();
jest.mock('./my_class', () => {
  return {
    default: {
      staticMethod: jest.fn().mockReturnValue(
        {
          method1: mockMethod1,
          method2: mockMethod2,
        })
    }
  }
});

你可以看到我的两个变量都遵守“标准”,但没有正确提升。

我错过了什么吗?

当我只传递 jest.fn() 而不是我的变量时,它显然有效,但我不确定以后如何在我的测试中使用这些。

【问题讨论】:

    标签: javascript node.js typescript unit-testing jestjs


    【解决方案1】:

    以上答案都没有解决我的问题,所以这是我的解决方案:

    var mockMyMethod: jest.Mock;
    
    jest.mock('some-package', () => ({
      myMethod: mockMyMethod
    }));
    

    在导入之前使用 const 让我感觉很奇怪。问题是:jest.mock 被吊起。为了能够在变量之前使用它,您需要使用var,因为它也被提升了。它不适用于 letconst,因为它们不是。

    【讨论】:

    • 我尝试在jest.mock 之外使用let 在内部分配它,但它失败了。使用var 解决了我的问题。谢谢。
    • 这是因为:1) Jest hoists jest.mock() 来电。 2) 以mock 开头的Jest does not hoist 变量。 3) JavaScript 中用varare always hoisted 声明的变量,而用letconst 声明的变量不是。
    【解决方案2】:

    当您需要监视 const 声明时,接受的答案无法处理,因为它是在模块工厂范围内定义的。

    对我来说,模块工厂需要高于任何最终导入您想要模拟的东西的导入语句。 这是一个使用 nestjsprisma 库的代码 sn-p。

    // app.e2e.spec.ts
    import { Test, TestingModule } from '@nestjs/testing';
    import { INestApplication } from '@nestjs/common';
    import * as request from 'supertest';
    import mockPrismaClient from './utils/mockPrismaClient'; // you can assert, spy, etc. on this object in your test suites.
    
    // must define this above the `AppModule` import, otherwise the ReferenceError is raised.
    jest.mock('@prisma/client', () => {
      return {
        PrismaClient: jest.fn().mockImplementation(() => mockPrismaClient),
      };
    });
    
    import { AppModule } from './../src/app.module'; // somwhere here, the prisma is imported
    
    describe('AppController (e2e)', () => {
      let app: INestApplication;
    
      beforeEach(async () => {
        const moduleFixture: TestingModule = await Test.createTestingModule({
          imports: [AppModule],
        }).compile();
    
        app = moduleFixture.createNestApplication();
        await app.init();
      });
    )};
    

    【讨论】:

    • 其实这不是解决问题的正确方法。将任何内容置于导入之上并期望它将按此顺序进行评估在技术上是错误的,因为 ESM 导入是由规范提升的,而 jest.mock 是由 Jest 通过 Babel 转换提升的,这也是指定的。它可能在一种设置中起作用,而在另一种设置中失败,因为行为未确定。在模拟中使用 mockPrismaClient 的正确方法是在 jest.mock 中使用 requirejest.requireActual 导入它,而不是依赖父范围中的值。
    • 到目前为止,这种方法对我来说一直适用于各种设置。但是,我从来不知道是否有“技术上正确的方法”。介意与您刚才解释的内容分享一段代码示例吗?
    • 我的意思基本上是import mpc from './utils/mockPrismaClient'; jest.mock('@prisma/client', () => { const mpc = require('./utils/mockPrismaClient').default; return { PrismaClient: jest.fn(() => mpc) } ));。因此,mock 对实用程序模块的依赖是明确指定的,并且与潜在的竞争条件无关。如果需要,这也允许将其提取到__mocks__
    【解决方案3】:

    文档解决的问题是 jest.mock 被提升但 const 声明没有。这会导致在导入模拟模块时评估工厂函数,并且变量处于临时死区。

    如果需要访问嵌套的模拟函数,则需要将它们作为导出对象的一部分公开:

    jest.mock('./my_class', () => {
      const mockMethod1 = jest.fn();
      const mockMethod2 = jest.fn();
      return {
        __esModule: true,
        mockMethod1,
        mockMethod2,
        default: {
          ...
    

    这也适用于__mocks__ 中的手动模拟,其中变量只能在模拟中访问。

    【讨论】:

    • mmmh 但文档指出以“mock”开头的变量存在异常。那很奇怪 !我会试试你的解决方案谢谢!
    • 你先生是救世主!它就像一个魅力!
    • 好的,我想我误解了文档说当时有一个例外
    • @EstusFlask 我肯定会像 Sufiane 一样阅读它。看看这里的例子:jestjs.io/docs/… 他们做的事情几乎和原来的提问者一样。
    • @Sam 他们可以更好地解释他们警告的案例。明显的区别是文档没有 anotherClass 对导入有副作用。
    【解决方案4】:

    要澄清Jason Limantoro 所说的内容,请将const 移至模块导入位置上方:

    const mockMethod1 = jest.fn(); // Defined here before import.
    const mockMethod2 = jest.fn();
    
    import MyClass from './my_class'; // Imported here.
    import * as anotherClass from './another_class';
    
    jest.mock('./my_class', () => {
      return {
        default: {
          staticMethod: jest.fn().mockReturnValue(
            {
              method1: mockMethod1,
              method2: mockMethod2,
            })
        }
      }
    });
    

    【讨论】:

      猜你喜欢
      • 2021-09-30
      • 1970-01-01
      • 2020-12-29
      • 2021-09-10
      • 2020-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多