जेस्ट का उपयोग करके जावास्क्रिप्ट विंडो ऑब्जेक्ट को कैसे मॉक करें?


112

मुझे एक फ़ंक्शन का परीक्षण करने की आवश्यकता है जो ब्राउज़र में एक नया टैब खोलता है

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

मैं विंडो के openफंक्शन को मॉक करना चाहूंगा ताकि मैं यह सत्यापित कर सकूं कि फंक्शन में सही URL पास हो गया openहै।

जेस्ट का उपयोग करना, मुझे नहीं पता कि कैसे मॉक करना है window। मैं window.openएक नकली समारोह के साथ सेट करने की कोशिश की, लेकिन इस तरह से काम नहीं करता है। नीचे परीक्षण का मामला है

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

लेकिन यह मुझे त्रुटि देता है

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

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

मुझे परीक्षण के मामले में क्या करना चाहिए? किसी भी सुझाव या संकेत की सराहना की है।

जवाबों:


91

windowउपयोग के बजायglobal

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

आप भी कोशिश कर सकते हैं

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

3
यह कोशिश की लेकिन मेरे लिए काम नहीं कर रहा। मेरा मामला अजीब है, मॉकिंग स्थानीय रूप से काम करता है लेकिन ट्रैविस में पीआर मर्ज के लिए नहीं ... कोई विचार?
एलेक्स जेएम

@ एलेक्स जेएम आपके पास एक ही मुद्दा है? मन साझा करने के लिए कैसे आप खिड़की वस्तु नकली?
डैनी

1
मैं बस अपने परीक्षणों में
विंडो.प्रॉपर्टी

@ एंड्रियास वहाँ अपरिभाषित के रूप में खिड़की उपहास करने के लिए किसी भी तरह से है stackoverflow.com/questions/59173156/...
दिलीप थॉमस

धन्यवाद! घंटे के बाद, मैं सिर्फ परिवर्तन करने की जरूरत windowके लिएglobal
SrAxi

70

मेरे लिए काम करने वाली एक विधि निम्नलिखित थी। इस दृष्टिकोण ने मुझे कुछ कोड का परीक्षण करने की अनुमति दी जो ब्राउज़र और नोड दोनों में काम करना चाहिए, क्योंकि इसने मुझे सेट windowकरने की अनुमति दी थी undefined

यह जेस्ट 24.8 के साथ था (मेरा मानना ​​है):

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

1
यह बहुत बेहतर है Object.definePropertyक्योंकि यह मॉकिंग के दौरान अन्य परीक्षणों को प्रभावित नहीं करने देता है।
सेर्गेई

यह स्वीकृत उत्तर होना चाहिए क्योंकि यह वास्तविक वैश्विक संपत्ति को बदलने के बजाय
नकली

10

हम यह भी का उपयोग कर इसे परिभाषित कर सकते हैं globalमेंsetupTests

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

और globalवास्तविक परीक्षा में इसका उपयोग करें :

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

7

जेस्ट में ग्लोबल्स को मॉक करने के कुछ तरीके हैं:

  1. mockImplementationदृष्टिकोण का उपयोग करें (ज्यादातर जेस्ट की तरह), लेकिन यह केवल उन चरों के लिए काम करेगा जिनके द्वारा कुछ डिफ़ॉल्ट कार्यान्वयन प्रदान किया गया है jsdom, window.openउनमें से एक है:
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. वैश्विक संपत्ति पर सीधे मान निर्दिष्ट करें, सबसे सीधे आगे लेकिन कुछ windowचर जैसे त्रुटि संदेशों को ट्रिगर कर सकता है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. सीधे ग्लोबल्स का उपयोग न करें (थोड़ा सा रीफ्रैक्टिंग की आवश्यकता होती है)

वैश्विक मूल्य का सीधे उपयोग करने के बजाय इसे किसी अन्य फ़ाइल से आयात करने के लिए क्लीनर हो सकता है, इसलिए मॉकिंग जेस्ट के साथ तुच्छ हो जाएगा।

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

7

मुझे यह करने का एक आसान तरीका मिला: हटाएं और बदलें

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

7

मेरे कंपोनेंट में मुझे एक्सेस की आवश्यकता है window.location.search, यही मैंने जेस्ट टेस्ट में किया है:

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

यदि हम अलग-अलग परीक्षणों में विंडो गुण अलग-अलग होने चाहिए, तो हम एक फंक्शन में विंडो मॉकिंग कर सकते हैं, और विभिन्न परीक्षणों के लिए इसे ओवरराइट कर सकते हैं:

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

और प्रत्येक परीक्षण के बाद रीसेट करें

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

5

आप यह कोशिश कर सकते हैं:

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


4

मैं सीधे असाइन jest.fn()कर रहा हूं window.open

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.