32
votes

Jest ReferenceError: Impossible d'accéder à '' avant l'initialisation

J'obtiens l'erreur:

ReferenceError: Impossible d'accéder à `` MyMock '' avant l'initialisation

Même si j'ai respecté la documentation de la plaisanterie sur le palanting: Une limitation avec le paramètre d'usine est que, puisque les appels à jest.mock () sont hissés en haut du fichier, il n'est pas possible de définir d'abord une variable puis de l'utiliser dans l'usine. Une exception est faite pour les variables qui commencent par le mot «simulé».

Je fais ceci:

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

Comme vous pouvez le voir, mes deux variables respectent la "norme" mais ne sont pas correctement hissées.

Suis-je en train de manquer quelque chose?

Évidemment, cela fonctionne lorsque je passe plaisante .fn () au lieu de mes variables, mais je ne sais pas comment pouvoir les utiliser dans mon test plus tard.


0 commentaires

4 Réponses :


7
votes

Le problème que la documentation aborde est que jest.mock est hissé mais const ne l'est pas. Il en résulte que la fonction d'usine est évaluée au moment où le module moqué est importé et une variable étant dans la zone morte temporelle.

S'il est nécessaire d'accéder aux fonctions moquées imbriquées, ils doivent être exposés dans le cadre de l'objet d'exportation: / p>

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

Cela s'applique également aux maquettes manuelles dans __ Mocks __ où les variables sont accessibles à l'intérieur d'une maquette uniquement.


6 commentaires

Mmmh Pourtant, la documentation indique qu'il existe une exception pour la variable à commencer par le mot "simulé". C'est étrange ! Je vais essayer votre solution merci!


Vous monsieur êtes un sauveur! il fonctionne comme un charme !


Heureux que cela ait aidé. Il n'y a pas d'exception d'une manière que les variables sont gérées, il faut simplement une variable pour contenir Mock pour désigner qu'un développeur est pleinement conscient des conséquences.


Ok, je suppose que j'ai mal compris le doc en déclarant qu'il y avait alors une exception


@ESTUSFLASK Je le lis définitivement de la même manière que Sufiane est. Jetez un œil à l'exemple ici: Jestjs.io/docs/… Ils font presque exactement la même chose que le demandeur d'origine essaie de faire.


@Sam, ils pourraient faire un meilleur travail pour expliquer le cas dont ils mettent en garde. La différence évidente est que la documentation n'a pas une autre classe qui fait des effets secondaires sur l'importation.



14
votes

La réponse acceptée ne gère pas lorsque vous devez espionner la déclaration const , comme il est défini à l'intérieur de la portée de l'usine du module.

Pour moi, l'usine de module doit être ci-dessus toute instruction d'importation qui finalement importe la chose que vous souhaitez vous moquer. Voici un extrait de code utilisant un nestjs avec Prisma Library.

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


3 commentaires

En fait, ce n'est pas une façon correcte de résoudre le problème. Il est techniquement faux de mettre quoi que ce soit au-dessus des importations et de s'attendre à ce qu'il soit évalué dans cet ordre, car les importations ESM sont hissées par les spécifications, et JEST.Mock est hissé par Jest via Babel Transform, cela est également spécifié. Cela peut fonctionner dans une configuration et échouer dans un autre car le comportement est indéterminé. Une façon correcte d'utiliser MockPrismaclient dans une simulation consiste à l'importer avec exiger ou jest.requireactual à l'intérieur jest.mock au lieu de compter sur une valeur de la portée des parents.


Jusqu'à présent, cette méthode a toujours fonctionné pour moi pour une variété de configurations. Cependant, je n'ai jamais su s'il existe une "façon techniquement bonne de le faire". Vous êtes en train de partager un exemple de code à ce que vous venez d'expliquer?


Je voulais dire que c'est Importer des MPC de './utils/mockprimaclient'; Jest.Mock ('@ Prisma / Client', () => {const mpc = required ('./ utils / mockprimaclient'). Default; return {prisMaclient: jest.fn (() => MPC)})); . La dépendance de Mock sur le module d'utilité est donc explicitement spécifiée et n'est pas liée aux conditions de course potentielles. Cela lui permet également d'être extrait de __ Mocks __ si nécessaire.



12
votes

Pour clarifier ce que Jason Limantoro a déclaré, déplacez le const ci-dessus où le module est importé :

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


0 commentaires

28
votes

Aucune des réponses ci-dessus n'a résolu mon problème, alors voici ma solution:

var mockMyMethod: jest.Mock;

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

Quelque chose sur l'utilisation de const des importations me semble bizarre. Le truc est: jest.mock est hissé. Pour pouvoir utiliser une variable avant elle, vous devez utiliser var , car il est également hissé. Cela ne fonctionne pas avec let et const parce qu'ils ne le sont pas.


2 commentaires

J'essayais d'utiliser let en dehors du jest.mock pour l'affecter en interne et il échouait. L'utilisation de var a résolu mon problème. Merci.


En effet: 1) plaisanterie jest.mock () appels. 2) Jest ne fait pas que les variables ne hissent pas > Mock . 3) Les variables déclarées avec var sont toujours hissées en javascript, tandis que les variables déclarées avec laissent < / code> et const ne le sont pas.