Necesito probar una función que abre una nueva pestaña en el navegador
openStatementsReport(contactIds) {
window.open(`a_url_${contactIds}`);
}
Me gustaría burlarme de la open
función de la ventana para poder verificar que se haya pasado la URL correcta a la open
función.
Usando Jest, no sé cómo burlarme del window
. Intenté configurarlo window.open
con una función simulada, pero de esta manera no funciona. A continuación se muestra el caso de prueba
it('correct url is called', () => {
window.open = jest.fn();
statementService.openStatementsReport(111);
expect(window.open).toBeCalled();
});
pero me da el error
expect(jest.fn())[.not].toBeCalled()
jest.fn() value must be a mock function or spy.
Received:
function: [Function anonymous]
¿Qué debo hacer con el caso de prueba? Se agradece cualquier sugerencia o sugerencia.
javascript
mocking
jestjs
danny
fuente
fuente
window
porglobal
Un método que funcionó para mí fue el siguiente. Este enfoque me ha permitido poner a prueba un código que debe trabajar tanto en el navegador y en el nodo, ya que permitió que fije
window
aundefined
.Esto fue con Jest 24.8 (creo):
let windowSpy; beforeEach(() => { windowSpy = jest.spyOn(window, "window", "get"); }); afterEach(() => { windowSpy.mockRestore(); }); it('should return https://example.com', () => { windowSpy.mockImplementation(() => ({ location: { origin: "https://example.com" } })); expect(window.location.origin).toEqual("https://example.com"); }); it('should be undefined.', () => { windowSpy.mockImplementation(() => undefined); expect(window).toBeUndefined(); });
fuente
Object.defineProperty
ya que esto permite no afectar otras pruebas al burlarse.También podemos definirlo usando
global
ensetupTests
// setupTests.js global.open = jest.fn()
Y llámelo usando
global
en la prueba real:// yourtest.test.js it('correct url is called', () => { statementService.openStatementsReport(111); expect(global.open).toBeCalled(); });
fuente
Hay un par de formas de simular globales en Jest:
mockImplementation
enfoque (la mayoría de las formas de Jest), pero funcionará solo para aquellas variables que tienen alguna implementación predeterminada proporcionada porjsdom
,window.open
es una de ellas:test('it works', () => { // setup const mockedOpen = jest.fn(); // without making a copy you will have a circular dependency problem const originalWindow = { ...window }; const windowSpy = jest.spyOn(global, "window", "get"); windowSpy.mockImplementation(() => ({ ...originalWindow, // in case you need other window properties to be in place open: mockedOpen })); // tests statementService.openStatementsReport(111) expect(mockedOpen).toBeCalled(); // cleanup windowSpy.mockRestore(); });
window
variables, por ejemplowindow.href
.test('it works', () => { // setup const mockedOpen = jest.fn(); const originalOpen = window.open; window.open = mockedOpen; // tests statementService.openStatementsReport(111) expect(mockedOpen).toBeCalled(); // cleanup window.open = originalOpen; });
En lugar de usar el valor global directamente, podría ser más limpio importarlo desde otro archivo, por lo que burlarse se volverá trivial con Jest.
./test.js
jest.mock('./fileWithGlobalValueExported.js'); import { windowOpen } from './fileWithGlobalValueExported.js'; import { statementService } from './testedFile.js'; // tests test('it works', () => { statementService.openStatementsReport(111) expect(windowOpen).toBeCalled(); });
./fileWithGlobalValueExported.js
export const windowOpen = window.open;
./testedFile.js
import { windowOpen } from './fileWithGlobalValueExported.js'; export const statementService = { openStatementsReport(contactIds) { windowOpen(`a_url_${contactIds}`); } }
fuente
Puedes probar esto:
import * as _Window from "jsdom/lib/jsdom/browser/Window"; window.open = jest.fn().mockImplementationOnce(() => { return new _Window({ parsingMode: "html" }); }); it("correct url is called", () => { statementService.openStatementsReport(111); expect(window.open).toHaveBeenCalled(); });
fuente
Encontré una manera fácil de hacerlo: eliminar y reemplazar
describe('Test case', () => { const { open } = window; beforeAll(() => { // Delete the existing delete window.open; // Replace with the custom value window.open = jest.fn(); // Works for `location` too, eg: // window.location = { origin: 'http://localhost:3100' }; }); afterAll(() => { // Restore original window.open = open; }); it('correct url is called', () => { statementService.openStatementsReport(111); expect(window.open).toBeCalled(); // Happy happy, joy joy }); });
fuente
Si es similar al problema de ubicación de la ventana en https://github.com/facebook/jest/issues/890 , puede intentar [ajustado]
delete global.window.open; global.window = Object.create(window); global.window.open = jest.fn();
fuente
En mi componente al que necesito acceso
window.location.search
, esto es lo que hice en la prueba de broma:Object.defineProperty(global, "window", { value: { location: { search: "test" } } });
En caso de que las propiedades de la ventana deban ser diferentes en diferentes pruebas, podemos poner la simulación de ventana en una función y hacerla modificable para anularla para diferentes pruebas:
function mockWindow(search, pathname) { Object.defineProperty(global, "window", { value: { location: { search, pathname } }, writable: true }); }
Y reiniciar después de cada prueba
afterEach(() => { delete global.window.location; });
fuente
Estoy asignando directamente
jest.fn()
awindow.open
.window.open = jest.fn() // ...code expect(window.open).toHaveBeenCalledTimes(1) expect(window.open).toHaveBeenCalledWith('/new-tab','__blank')
fuente
En su configuración de broma, agregue setupFilesAfterEnv: ["./setupTests.js"], cree ese archivo y agregue el código que desea ejecutar antes de las pruebas
//setupTests.js window.crypto = { ..... };
Ref: https://jestjs.io/docs/en/configuration#setupfilesafterenv-array
fuente