Heim > Web-Frontend > js-Tutorial > Hauptteil

Jest Recap: Safely Mock Properties and Methods of Global Objects

WBOY
Freigeben: 2024-07-19 15:10:32
Original
138 人浏览过

Jest Recap: Safely Mock Properties and Methods of Global Objects

TL;DR:

  • You want to avoid that overridden/mocked properties/methods affect other tests.
  • For local objects (created and owned by this test) you can (and should) use
    • localObject.theAnswer = 42 and
    • localObject.calcTheAnswer = jest.fn(() => 42).
  • For global objects you should use
    • jest.replaceProperty(globalObject, "theAnswer", 42) and
    • jest.spyOn(globalObject, "calcTheAnswer").mockReturnValue(42).
  • Make sure jest.restoreAllMocks() is called in an afterEach() hook.

What?

In a perfect world codebase there is no need to manipulate global objects, but the world codebases are messy - and so is testing.

What you want to avoid at all costs, is for one test to affect the other. Tests should be meaningful regardless of their order or if some tests are skipped.

Mocking Properties

A naive approach to mock values is to just set the properties to whatever value you need in your test.
This is fine as long as you change values in local objects owned (created by) this specific test:

describe("override properties of local objects", () => {
    it("works and is harmless", () => {
        const myArray = [1];
        myArray.length = 0;
        expect(myArray).toHaveLength(0);
    });
    it("does not affect the next test", () => {
        const myArray = [1];
        expect(myArray).toHaveLength(1);
    });
});
Nach dem Login kopieren

If you do that for global objects, it gets messy:

describe("don't override properties of global objects", () => {
    it("works before the property is overridden", () => {
        expect(window.innerWidth).toBeGreaterThan(0);
    });
    it("works, but is evil", () => {
        window.innerWidth = 0;
        expect(window.innerWidth).toBe(0);
    });
    it("fails in the test after the property was overridden", () => {
        expect(() => {
            expect(window.innerWidth).toBeGreaterThan(0); // <-- ERROR: expect(received).toBeGreaterThan(expected)
        }).toThrow(Error);
    });
});
Nach dem Login kopieren

This is what jest.replaceProperty() was made for:

describe("use jest.replaceProperty() to override properties of global objects", () => {
    afterEach(() => {
        jest.restoreAllMocks();
    });
    it("works before the property is overridden", () => {
        expect(window.innerWidth).toBeGreaterThan(0);
    });
    it("works and is harmless", () => {
        jest.replaceProperty(window, "innerWidth", 0);
        expect(window.innerWidth).toBe(0);
    });
    it("does not affect the next test", () => {
        expect(window.innerWidth).toBeGreaterThan(0);
    });
});
Nach dem Login kopieren

Mocking Methods

Methods can be mocked similar to properties.

describe("override methods of local objects using jest.fn()", () => {
    it("works and is harmless", () => {
        const mySet = new Set([1]);
        mySet.has = jest.fn().mockReturnValue(false);
        expect(mySet.has(1)).toBeFalsy();
    });
    it("does not affect the next test", () => {
        const mySet = new Set([1]);
        expect(mySet.has(1)).toBeTruthy();
    });
});
Nach dem Login kopieren

If you use myObject.someFunction = jest.fn() on global objects, your tests may depend on each other and loose their meaning:

describe("don't override methods of global objects using jest.fn()", () => {
    it("works before the method is overridden", () => {
        expect(document.getElementById("foo")).toBeNull();
    });
    it("works, but is evil", () => {
        const el = document.createElement("div");
        document.getElementById = jest.fn().mockReturnValue(el);

        expect(document.getElementById("foo")).toBe(el);
    });
    it("fails in the test after the property was overridden", () => {
        expect(() => {
            expect(document.getElementById("foo")).toBeNull(); // <-- ERROR: expect(received).toBeNull()
        }).toThrow(Error);
    });
});
Nach dem Login kopieren

How should we mock methods in global objects? That is what jest.spyOn() is good for:

describe("use jest.spyOn() to override methods of global objects", () => {
    afterEach(() => {
        jest.restoreAllMocks();
    });
    it("works before the method is overridden", () => {
        expect(document.getElementById("foo")).toBeNull();
    });
    it("works and is harmless", () => {
        const el = document.createElement("div");
        jest.spyOn(document, "getElementById").mockReturnValue(el);

        expect(document.getElementById("foo")).toBe(el);
    });
    it("does not affect the next test", () => {
        expect(document.getElementById("foo")).toBeNull();
    });
});
Nach dem Login kopieren

You Must Clean up

If you want to be sure all tests find the system in the same (fresh, clean) state, you need to restore the state of mocks after each test.

The simplest solution is to set the restoreMocks configuration property.

The most straight forward option is to call jest.restoreAllMocks() in the afterEach()

How to Mock Something for all Tests

Sometimes you want to Mock things for all tests in a file. If you use jest.spyOn() and jest.replaceProperty() on the top-level or in a describe() block, all Mocks will be reset after the first test is executed.

On the top-level you can safely override properties and methods, without jest.spyOn() and jest.replaceProperty().

If you want to Mock things only for a describe() block, you need to make these calls in a beforeEach() hook.

以上是Jest Recap: Safely Mock Properties and Methods of Global Objects的详细内容。更多信息请关注PHP中文网其他相关文章!

Quelle:dev.to
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!