<p>jest.mock factory no funciona dentro de una prueba</p>

Creado en 12 ene. 2017  ·  38Comentarios  ·  Fuente: facebook/jest

¿Quieres solicitar una función o informar de un error ?
Insecto

¿Cuál es el comportamiento actual?

Parece que la forma de crear un simulacro con una fábrica no funciona dentro de test o it . Funciona solo cuando el simulacro está definido en el nivel raíz del archivo.

Aquí está mi ejemplo de un simulacro:

jest.mock('services/feature', () => ({
    isEnabled: () => true
}));

¿Cuál es el comportamiento esperado?

Simular un archivo dentro de una prueba debería funcionar.

Proporcione su configuración exacta de Jest y mencione su versión de Jest, nodo, yarn / npm y sistema operativo.

Jest 18.0.0, nodo 7.4, macOS

Confirmed Discussion

Comentario más útil

Para cambiar el valor de retorno de un simulacro entre pruebas, puede hacer algo como esto:

jest.mock('whatever');

// Get the mock function
const whatever = require('whatever');

test('test 1', () => {
  whatever.mockImplementation(() => 'hello');
});

test('test 2', () => {
  whatever.mockImplementation(() => 'world');
});

Todos 38 comentarios

jest.mock llamadas jest.doMock . ¿Has probado eso?

Lo mismo con doMock .

En los documentos, puedo leer

Nota: Al usar babel-jest , las llamadas a simulacros se subirán automáticamente a la parte superior del bloque de código. Utilice doMock si desea evitar explícitamente este comportamiento.

Pero ... Una prueba es un bloque de código, ¿verdad? Entonces, en mi caso, no espero ver diferencias.

Aquí hay una prueba completa

it('renders with the enabled feature', () => {
  jest.mock('services/feature', () => ({
      isEnabled: () => true
  }));

  const component = renderer.create(
      <MyComponent />
  );

  const tree = component.toJSON();
  expect(tree).toMatchSnapshot();
});

¿Podría proporcionar una reproducción de esto en un repositorio de GH?

Seguro. Aquí está: https://github.com/tleunen/jest-issue-2582

Ambas pruebas muestran "Desactivado" a pesar de que una de ellas tiene un simulacro para mostrar "Activado" en su lugar.
Vea estos:
https://github.com/tleunen/jest-issue-2582/blob/master/src/MyComponent.js
https://github.com/tleunen/jest-issue-2582/blob/master/src/__tests__/MyComponent.spec.js

Gracias.

¿Algún consejo @thymikee @cpojer para este tema?
Tengo varias pruebas en el mismo archivo y me gustaría tener diferentes respuestas simuladas para cada una de ellas.

Me alegro de haber encontrado este problema, me estaba rompiendo la cabeza por qué jest.mock() no funcionaba en mi alcance describe . Lo moví a la parte superior (debajo de mis importaciones en el archivo de prueba) y funciona.

Para mí, también se aplica a jest.mock() sin una fábrica, usando una carpeta __mocks__ contiene el archivo simulado.

--editar

Obviamente, es necesario colocar la instrucción jest.mock() antes de las declaraciones de importación. Sin embargo, @tleunen , esto probablemente significa que no es posible simular el mismo archivo más de una vez, con diferentes respuestas. Tal vez le resulte más útil hacer que la función de fábrica sea más dinámica, de modo que pueda ofrecerle resultados diferentes en cada caso de prueba.

En mi opinión, sería más explícito si jest.mock() siempre se coloca fuera de los bloques describe y it . Pero esto debe indicarse claramente en los documentos.

Entonces jest.mock se está elevando al alcance de la función, por eso no funcionará con require s (y definitivamente no con import s que se elevan al alcance del módulo) si llámelo dentro de una función que no sea describe (que es tratada especialmente por Jasmine).
Su llamada jest.mock elevará a la parte superior de esa misma función (no del módulo), por eso no funcionará de la manera esperada.

En general, recomendamos configurar diferentes simulacros en beforeEach y afterEach si los desea diferentes en los casos de prueba.

@cpojer podría desarrollar esto en detalle, y si queremos elevar las llamadas a los ámbitos superiores.

Esto se debe a que está requiriendo sus módulos cuando el módulo se inicializa (usando la importación). jest.mock se llama mucho más tarde. La forma de solucionar esto es:

beforeEach(() => { // or the specific test
  jest.mock('MyModule', () => …);
  const MyModule = require('MyModule');
  …
});

etc.

Si hicieras esto antes de cada una, no tengo claro cómo diferenciarías las pruebas (entonces, ¿cómo darías un simulacro diferente para cada prueba?)

Ponerlo dentro de las pruebas en sí funciona, por supuesto.

¿Puede luego pasar el módulo simulado dentro del componente probado?

¿Qué sucede si no estoy importando / requiriendo el archivo que quiero simular (por ejemplo, una dependencia de otro archivo que estoy importando) pero quiero que esté dentro del alcance de un bloque describe / it? ¿O incluso si quiero burlarme de manera diferente para beforeEach / beforeAll test? ¿Son posibles esos casos?

// A.js depends on B.js
import A from './A';

describe('myTest', () => {

    describe('myFirstScope', () => {
        beforeAll(() => {
            jest.mock('./B', () => ({
                myFirstMethod: jest.fn(),
            }));
        });

        // tests here
    });

    describe('mySecondScope', () => {
        beforeAll(() => {
            jest.mock('./B', () => ({
                mySecondMethod: jest.fn(),
            }));
        });

        // tests here
    });
});

En ese caso, necesita solicitar A después de burlarse de B. (No usar import , sino require ).

requiriendo A después de burlarse de B

no funcionó para mí, todavía estaba viendo la simulación original de B pasar al resultado

@GoldAnna, ¿ ha encontrado una solución para este problema?

@alayor no tengo

Todas las veces que me he encontrado con este problema, ahora estoy convencido de que no estoy probando correctamente, no estoy usando jest como pretendían los autores, o una combinación de ambos. Una prueba más es que casi ninguno de los ejemplos relacionados con simulacros en la documentación de jest parecen ejemplos del mundo real ... probablemente lo sean y mi enfoque probablemente sea incorrecto.

Dicho esto, lo siguiente funciona para mí y todas las siguientes pruebas pasan. Tenga en cuenta que para volver a la versión original de ModuleB , tengo que llamar a ambos jest.resetModules() y jest.unmock('./moduleB') ... el orden de esos no importa.

// Module A
const ModuleB = require('./moduleB');
const ModuleA = function() {
  this.title = new ModuleB().title;
  return this;
};
module.exports = ModuleA;

// Module B
const ModuleB = function() {
  this.title = 'Module B - Original'
  return this;
};
module.exports = ModuleB;

// Tests
describe('Jest a few tests', () => {
  it('should do something', () => {
    jest.resetModules();
    jest.mock('./moduleB', () => function() {
      this.title = 'Module B - Mock 1'
      return this;
    });
    const ModuleA = require('./moduleA');
    const moduleA = new ModuleA();
    expect(moduleA.title).toEqual('Module B - Mock 1');
  });

  it('should do something else', () => {
    jest.resetModules();
    jest.mock('./moduleB', () => function() {
      this.title = 'Module B - Mock 2'
      return this;
    });
    const ModuleA = require('./moduleA');
    const moduleA = new ModuleA();
    expect(moduleA.title).toEqual('Module B - Mock 2');
  });

  it('should do something original', () => {
    jest.resetModules();
    jest.unmock('./moduleB');
    const ModuleA = require('./moduleA');
    const moduleA = new ModuleA();
    expect(moduleA.title).toEqual('Module B - Original');
  });
});

Oye,

Nada aquí funciona para mí.
¿Alguien puede explicar por qué no es posible usar jest.mock en su interior?

Gracias

Creo que este sigue siendo un problema que tal vez debería reabrirse como una solicitud de función. Quiero escribir pruebas de forma aislada. Volcar cosas en una carpeta de simulacros o recablear con un antes Cada uno generalmente termina con un cajón de basura de simulacros / instancias de datos extraños que se arrastran en cada prueba. Quiero escribir un pequeño simulacro y hacer un pequeño pase de prueba.

No tenemos una forma real de aislar las pruebas individuales (considerando test.concurrent ). Si adoptamos una API similar a tap o ava, sería posible, pero no creo que sea posible con las restricciones impuestas por la API global actual. ¡Súper feliz de que se demuestre que está equivocado!

Tuve una lucha con múltiples métodos aquí para refactorizar una prueba previamente escrita en mocha y proxyquire, y terminar separando la prueba en diferentes archivos para diferentes simulacros.

@gcox ¿Ha intentado burlarse (y requerir moduleA después) en el nivel superior del módulo y luego cambiar la implementación de la simulación para cada prueba que necesita un comportamiento diferente? Puede usar mockImplementation para hacerlo. Así es como hemos resuelto esto en nuestras suites de prueba.

@antgonzales Creo que es difícil de hacer si las importaciones de módulos se elevan a la parte superior de un módulo. Modificar las referencias de un módulo previamente importado parece no trivial a imposible en el nodo.

@jkomusin Definitivamente. Eso no es lo que pedía el OP, en mi opinión. Creo que estaban preguntando, específicamente, "¿Cómo obligo a require('whatever') a devolver un simulacro diferente en múltiples pruebas adyacentes en lugar del mismo objeto?".

Para cambiar el valor de retorno de un simulacro entre pruebas, puede hacer algo como esto:

jest.mock('whatever');

// Get the mock function
const whatever = require('whatever');

test('test 1', () => {
  whatever.mockImplementation(() => 'hello');
});

test('test 2', () => {
  whatever.mockImplementation(() => 'world');
});

La respuesta de @SimenB también funcionó, ¡y es mucho más simple!

@rafaeleyng pero @SimenB no funciona si lo que exportas desde el módulo no es una función ...

El ejemplo de

@schumannd tiene razón. Haga que la documentación oficial sea más clara y nítida.

Los RR.PP. siempre agradecen la mejora de los documentos 🙂

Ejemplo de módulo basado en
https://github.com/facebook/jest/issues/2582#issuecomment -378677440 ❤️

Oye, encontré esto a través del problema vinculado y lo descubrí:

jest.mock('child_process')
const childProcess = require('child_process')

describe('foo', () => {
  test('bar', () => {
    childProcess.execSync.mockImplentation(jest.fn().mockReturnValueOnce('wibble'))
    // code that itself requires child_process
    expect(childProcess.execSync.mock.results[0]).toEqual('wibble')
  })

  test('baz', () => {
    childProcess.execSync.mockImplentation(jest.fn().mockReturnValueOnce('wobble'))
    // code that itself requires child_process
    expect(childProcess.execSync.mock.results[0]).toEqual('wobble')
  })
})

Si necesita simular múltiples funciones / métodos en el código requerido, debe configurarlos por separado en lugar de usar la fábrica cuando lo hace a nivel mundial.

Si te gusto, solo necesitas una función, puedes simplificarlo todo:

jest.mock('child_process')
const { execSync } = require('child_process')

describe('foo', () => {
  test('bar', () => {
    execSync.mockImplentation(jest.fn().mockReturnValueOnce('wibble'))
    // code that itself requires child_process
    expect(execSync.mock.results[0]).toEqual('wibble')
  })

  test('baz', () => {
    execSync.mockImplentation(jest.fn().mockReturnValueOnce('wobble'))
    // code that itself requires child_process
    expect(execSync.mock.results[0]).toEqual('wobble')
  })
})

¿Qué hay de burlarse de dependencias que no funcionan como archivos json o constantes mapeadas? Por favor, aclare la documentación sobre cómo manejar esto ...

@gcox Su solución es la única que he encontrado para cuando un módulo importado bajo prueba importa otro módulo para el que tenía una simulación manual en una carpeta __mocks__ .

Por ejemplo, el archivo de prueba llama a jest.mock('./ModuleA') , que tiene un simulacro en __mocks__/ModuleA.js . Pero ModuleA no está bajo prueba, ModuleB, que requiere ModuleA, es lo que está bajo prueba. Sin su solución, ModuleB obtendría la implementación real de ModuleA, no la simulación.

Esto parece un comportamiento realmente extraño de broma. Esperaría que cuando llamo a jest.mock en un módulo, cualquier módulo bajo prueba que tenga una dependencia del módulo simulado use el mock. ¿Parece extraño que no funcione de esa manera, o lo estoy haciendo de manera completamente incorrecta?

@SimenB En su ejemplo, necesita el módulo

@SimenB trabajó para mí con su solución más simple. ¡Gracias! Ojalá pudiera encontrarlo antes antes de que pasara el tiempo con muchas formas diferentes

En mi caso, estaba burlando e importando la ruta incorrecta al módulo que quería stub. Tenía una carcasa diferente en la ruta del archivo, por lo que mi editor pensó que estaba bien, pero simplemente estaba fallando.

Era

const { stubMethod } = require("./path/to/File");
jest.mock("./path/to/File");

Cambiado a (cambiar la carcasa de File a file ):

const { stubMethod } = require("./path/to/file");
jest.mock("./path/to/file");

Espero que esto ayude a alguien más.

Jasmine spyOn() no tiene ese problema en las pruebas _dentro_. ¿Jest supuestamente usa jazmín por defecto? ¿Por qué no funciona dentro de la prueba?

Ejemplo de jazmín:

spyOn(require('moduleB'), 'functionA').and.callFake(() => true);

Lo que no entiendo muy bien cuando se trata de simular módulos es que siempre se describe como si quisieras usar el módulo principalmente en tus funciones de prueba. Por ejemplo, si observa el código de ejemplo para la función doMock en los documentos:

test('moduleName 2', () => {
  jest.doMock('../moduleName', () => {
    return {
      __esModule: true,
      default: 'default2',
      foo: 'foo2',
    };
  });
  return import('../moduleName').then(moduleName => {
    expect(moduleName.default).toEqual('default2');
    expect(moduleName.foo).toEqual('foo2');
  });
});

En este ejemplo, tiene acceso a la versión recién simulada de "moduleName" dentro de la función de prueba. Para mí es mucho más importante que mi código "no de prueba" también tenga acceso a la versión simulada del módulo. Por ejemplo, una clase que estoy usando dentro de mi prueba, que ha importado "moduleName" todavía estaría usando la versión original, no la simulada.

Parece estar relacionado: https://github.com/facebook/jest/issues/3236

Sugerencia: si tiene un módulo que exporta un valor primitivo, por ejemplo:

`` auth.js
export const isUserAdmin = getSetting ('admin');

And you want to use a mock value instead, in the test, then a simple require and assignment seems to do the trick:

```deleteUser.js
const auth = require('../auth');

describe('deleteUser', () => {
  it('can delete if admin', () => {
    auth.isUserAdmin = true;

    // call method that depends on isUserAdmin value
    // and assert on the result
  });
});

Entonces, básicamente, si desea simular un objeto que es usado indirectamente por el código, prueba la función jest.doMock() no funcionará:

import myModuleToTest from './myModuleTotest'

describe('Given my module', () => {
  it('property1 will work as expect', () => {
    // Testing parts of the module that don't need to be mocked
  })

  it('property2 will work as expected', () => {
    jest.doMock('./myOtherModule', () => {
      return {
        __esModule: true,
        default: 'default2',
        foo: 'foo2',
      };
    });

    import('./myOtherModule').then(myOtherModule => {
      // I'm not interested on the mocked module myOtherModule but on the module that makes use of it
      myModuleToTest.doSomethingToSomeProperty(); // At this point myOtherModule's original module and not its mocked version will be used by myModuleToTest
      expect(myModuleToTest.someProperty).toBe('thisWillFail'); // The test won't pass because the mocked version wasn't used
    });
  });
});

A partir de Jest 26, no hay forma de burlarse más de una vez de un módulo que exporta un Object que se usa indirectamente (me refiero a burlarse de algo más que Function ya que no hay mockFn.mockImplementation(fn) por Objects burlados). ¿Es esto correcto o me falta algo? Entonces, la única solución es tener más de un archivo de prueba para probar el mismo módulo.

Tienes que importar myModuleToTest después de tu simulacro porque si importa
antes de que el simulacro no tenga sentido. Por lo tanto, no use la importación ... en la parte superior o
dentro de la devolución de llamada porque está izado de todos modos.

El martes, 7 de julio de 2020, 10:24 p.m. Antonio Redondo [email protected]
escribió:

Básicamente, si desea simular un objeto que es utilizado indirectamente por el
código que prueba la función jest.doMock () no funcionará:

importar myModuleToTest desde './myModuleTotest'
it ('funcionará', () => {
jest.doMock ('./ myOtherModule', () => {
regreso {
__esModule: verdadero,
predeterminado: 'default2',
foo: 'foo2',
};
});

return import ('../ myOtherModule'). luego (myOtherModule => {
// No estoy interesado en el módulo simulado myOtherModule sino en el módulo que lo usa
myModuleToTest.doSomethingToSomeProperty (); // En este punto, myModuleToTest utilizará el módulo original de myOtherModule y no su versión simulada
esperar (myModuleToTest.someProperty) .toBe ('thisWillFail'); // La prueba no pasa porque no se usó la versión simulada
});});

A partir de Jest 26, no hay forma de simular un módulo que exporta un objeto (I
significa algo más que una función) que se usa indirectamente. Es esto
correcto o me falta algo? La única solución entonces es tener más
de un archivo de prueba para probar el mismo módulo.

-
Estás recibiendo esto porque hiciste un comentario.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/facebook/jest/issues/2582#issuecomment-655110424 , o
darse de baja
https://github.com/notifications/unsubscribe-auth/AAJR3UW6HARW44ZLKAUB7PLR2N77NANCNFSM4C4I7QSQ
.

¿Fue útil esta página
0 / 5 - 0 calificaciones