Jest kullanarak JavaScript pencere nesnesiyle nasıl dalga geçilir?


106

Tarayıcıda yeni bir sekme açan bir işlevi test etmem gerekiyor

openStatementsReport(contactIds) {
  window.open(`a_url_${contactIds}`);
}

İşleve opendoğru URL'nin iletildiğini doğrulayabilmek için pencerenin işleviyle dalga geçmek istiyorum open.

Jest'i kullanarak nasıl alay edeceğimi bilmiyorum window. window.openSahte bir işlevle ayarlamayı denedim ama bu yol çalışmıyor. Aşağıda test durumu var

it('correct url is called', () => {
  window.open = jest.fn();
  statementService.openStatementsReport(111);
  expect(window.open).toBeCalled();
});

ama bana hata veriyor

expect(jest.fn())[.not].toBeCalled()

jest.fn() value must be a mock function or spy.
    Received:
      function: [Function anonymous]

Test senaryosuna ne yapmalıyım? Herhangi bir öneri veya ipucu takdir edilmektedir.

Yanıtlar:


85

Yerine windowkullanımıglobal

it('correct url is called', () => {
  global.open = jest.fn();
  statementService.openStatementsReport(111);
  expect(global.open).toBeCalled();
});

ayrıca deneyebilirsin

const open = jest.fn()
Object.defineProperty(window, 'open', open);

3
Bunu denedim ama benim için çalışmadı. Benim durumum tuhaf, yerel olarak alay etmek işe yarıyor ama Travis'te PR birleşmesi için değil ... herhangi bir fikrin var mı?
Alex JM

@AlexJM aynı sorunu yaşıyor musunuz? paylaşmayı unutmayın pencere nesnesi ile nasıl alay edersiniz?
danny

1
Ben sadece testlerimde window.property tanımlıyorum
maracuja-juice

@ Andreas, pencereyi tanımlanmamış stackoverflow.com/questions/59173156/…
DILEEP THOMAS

Teşekkürler! Saat sonra, sadece değişime ihtiyaç windowiçinglobal
SrAxi

59

Benim için işe yarayan bir yöntem şuydu. Bu yaklaşım, ayarlamama izin verdiği için hem tarayıcıda hem de Düğümde çalışması gereken bazı kodları test etmeme izin windowverdi undefined.

Bu Jest 24.8 ile oldu (inanıyorum):

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

Bu Object.defineProperty, alay ederken diğer testleri etkilememeye izin verdiğinden çok daha iyi .
Sergey

10

Biz de kullanarak tanımlayabilirsiniz globaliçindesetupTests

// setupTests.js
global.open = jest.fn()

Ve bunu globalgerçek testte kullanarak arayın :

// yourtest.test.js
it('correct url is called', () => {
    statementService.openStatementsReport(111);
    expect(global.open).toBeCalled();
});

7

Jest'te küresellerle dalga geçmenin birkaç yolu vardır:

  1. Kullanım mockImplementationyaklaşımı (yol gibi çoğu Jest), ancak sağladığı bazı varsayılan uygulaması vardır bu değişkenler için sadece çalışacak jsdom, window.openbunlardan biri:
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();
});
  1. Değeri doğrudan global özelliğe atayın, en doğrusu, ancak bazı windowdeğişkenler için hata mesajlarını tetikleyebilir, örn window.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;
});
  1. Küreselleri doğrudan kullanmayın (biraz yeniden düzenleme gerektirir)

Global değeri doğrudan kullanmak yerine, onu başka bir dosyadan içe aktarmak daha temiz olabilir, bu nedenle Jest ile alay etmek önemsiz hale gelecektir.

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

5

Bunu deneyebilirsiniz:

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

5

Bunu yapmanın kolay bir yolunu buldum: sil ve değiştir

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


3

Bileşenimde erişmem gerekiyor window.location.search, jest testinde yaptığım şuydu:

Object.defineProperty(global, "window", {
  value: {
    location: {
      search: "test"
    }
  }
});

Pencere özelliklerinin farklı testlerde farklı olması gerektiğinde, pencere alayını bir işleve yerleştirebilir ve farklı testler için geçersiz kılmak için yazılabilir hale getirebiliriz:

function mockWindow(search, pathname) {
  Object.defineProperty(global, "window", {
    value: {
      location: {
        search,
        pathname
      }
    },
    writable: true
  });
}

Ve her testten sonra sıfırlayın

afterEach(() => {
  delete global.window.location;
});

3

Ben doğrudan tahsis edeceğim jest.fn()için window.open.

window.open = jest.fn()
// ...code
expect(window.open).toHaveBeenCalledTimes(1)
expect(window.open).toHaveBeenCalledWith('/new-tab','__blank')

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.