javascript - jest ReferenceError: Nemôžem pristúpiť k '' pred inicializáciou


Zobrazila sa mi chyba:

ReferenceError: Cannot access 'myMock' before initialization

Aj keď som rešpektoval dokumentáciu jest o hoistingu: Obmedzením parametra factory je, že keďže volania jest.mock() sú presúvané na začiatok súboru, nie je možné najskôr definovať premennú a potom ju použiť vo factory. Výnimka sa robí pre premenné, ktoré začínajú slovom 'mock'.

Robím toto:

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

Ako vidíte, obe moje premenné dodržiavajú „štandard“, ale nie sú správne presunuté (hoisted).

Chýba mi niečo?

Očividne to funguje, keď jednoducho použijem jest.fn() namiesto mojich premenných, ale nie som si istý, ako ich potom budem môcť použiť v mojom teste.

Odpoveď č. 1

Žiadna z vyššie uvedených odpovedí nevyriešila môj problém, tak tu je moje riešenie:

const mockMyMethod = jest.fn();

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

Upraviť

Predchádzajúce riešenie používalo zdvíhanie varu, ale to je zvláštne obchádzanie. Aktualizované riešenie to robí bez zdvíhania spôsobom, ktorý by bol spokojný. Funguje to preto, že mockMyMethod funkcia sa v skutočnosti nevykoná, kým nie je zavolaná metóda myMethod z mockovaného balíka.

Odpoveď č. 2

Prijatá odpoveď nezaoberá situáciou, keď potrebujete špehovať deklaráciu const, pretože je definovaná v rozsahu továrne modulu.

Pre mňa musí byť továreň na moduly nad akýmkoľvek importným príkazom, ktorý nakoniec importuje vec, ktorú chcete simulovať. Tu je ukážka kódu používajúca nestjs s knižnicou prisma.

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

Odpoveď č. 3

Aby sme objasnili, čo povedal Jason Limantoro, presuňte const nad miesto, kde je modul importovaný:

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

Odpoveď č. 4

Mali by ste presunúť svoje mockovanie nad importy; to by mohol byť zdroj vášho problému. Importy sú tiež presúvané nahor, takže viacero presunutých záznamov by bolo presúvaných v poradí.

jest.mock('./my_class', () => {
  const mockMethod = jest.fn() 
  const default = { staticMethod: jest.fn().mockReturnValue({ method: mockMethod }) };
  return { default, mockMethod };
});

import MyClass, { mockMethod } from './my_class';  // will import your mock
import * as anotherClass from './another_class';

Avšak, ak z nejakého dôvodu nemôžete urobiť to, môžete použiť doMock na zabránenie správaniu hoistingu. Ak sa to stane na vrchu vášho súboru, mala by to byť zmena 1 ku 1.

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

Tiež odporúčam používať var namiesto const alebo let pre micky. Ich správanie pri hoistovaní je mierne odlišné a niekoľkokrát som zistil, že používanie var sa zdá lepšie fungovať s vlastným hoistovaním jestu.

Odpoveď č. 5

Problém, ktorým sa dokumentácia zaoberá, je ten, že jest.mock je zdvihnutý (hoisted), ale deklarácia const nie. To má za následok, že továreň (factory) sa vyhodnotí v čase, keď je importovaný mockovaný modul, a premenná sa nachádza v dočasnej mŕtvej zóne (temporal dead zone).

Ak je potrebné pristupovať k vnoreným mockovaným funkciám, musia byť sprístupnené ako súčasť exportovaného objektu:

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

Toto platí aj pre manuálne makety v __mocks__, kde sú premenné prístupné iba vo vnútri makety.

Súvisiace články