Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jest - Testing Module Multiple Times in One Test Suite

I have a TypeScript module (should be irrelevant, as I think this affect JS too) and I'm trying to test a module I have. The module imports lots of data from external files and chooses which data should be returned based on the a variable.

I'm attempting to run some tests where I update that variable, re-require the module and run further tests in one file. But my issue is that the require of the file only runs once. I guess it's being cached. Is it possible to tell Jest's require function not to cache or to clear the cache between tests?

Here's some stripped back code of what I'm trying to achieve:

module.ts

import { getLanguage } from "utils/functions";

import * as messagesEn from "resources/translations/en";
import * as messagesFr from "resources/translations/fr";

// Determine the user's default language.
const language: string = getLanguage();

// Set messages based on the language.
let messages: LocaleMessages = messagesEn.default;
if (languageWithoutRegionCode === "fr") {
    messages = messagesFr.default;
}

export { messages, language };

test.ts

import "jest";

// Mock the modules
const messagesEn = { "translation1": "English", "translation2": "Words" };
const messagesFr = { "translation1": "Francais", "translation2": "Mots" };
const getLangTest = jest.fn(() => "te-ST");
const getLangEn = jest.fn(() => "en-GB");
const getLangFr = jest.fn(() => "fr-FR");
jest.mock("resources/translations/en", () => ({"default": messagesEn}));
jest.mock("resources/translations/fr", () => ({"default": messagesFr}));
jest.mock("utils/functions", () => ({
        getLanguage: getLangTest
    })
);

describe("Localisation initialisation", () => {
    it("Sets language", () => {
        const localisation = require("./localisation");
        expect(getLangTest).toHaveBeenCalled();
        expect(localisation.language).toEqual("te-ST");
        expect(localisation.messages).toEqual(messagesEn);
    });

    it("Sets english messages", () => {
        // THIS GETS THE MODULE FROM THE CACHE
        const localisation = require("./localisation");
        expect(getLangEn).toHaveBeenCalled();
        expect(localisation.language).toEqual("en-GB");
        expect(localisation.messages).toEqual(messagesEn);
    });

    it("Sets french messages", () => {
        // THIS GETS THE MODULE FROM THE CACHE
        const localisation = require("./localisation");
        expect(getLangFr).toHaveBeenCalled();
        expect(localisation.language).toEqual("fr-FR");
        expect(localisation.messages).toEqual(messagesFr);
    });
});

I'm aware the second and third tests won't work anyway as I'd need to update the "utils/functions" mock. The issue is that the code in module.ts only runs once.

like image 645
Simon Avatar asked Jan 11 '17 18:01

Simon


People also ask

Does Jest run tests concurrently?

Jest will execute different test files potentially in parallel, potentially in a different order from run to run. Per file, it will run all describe blocks first and then run tests in sequence, in the order it encountered them while executing the describe blocks.

Is Jest enough for testing?

Jest is a JavaScript test runner that lets you access the DOM via jsdom . While jsdom is only an approximation of how the browser works, it is often good enough for testing React components.

What is auto mocking Jest?

Jest offers many features out of the box. One that is very powerful and commonly used in unit tests is the auto mock feature, which is when Jest automatically mocks everything exported by a module that is imported as a dependency by any module we are testing.

Does Jest mock get hoisted?

Using with ES module imports​ But often you need to instruct Jest to use a mock before modules use it. For this reason, Jest will automatically hoist jest. mock calls to the top of the module (before any imports).


1 Answers

So, many thanks to the Jest folks on Discord. It's possible to actually clear the modules from the cache with the jest.resetModules() function.

So my test.ts file will look as follows:

describe("Localisation initialisation", () => {
    beforeEach(() => {
        jest.resetModules();
    });

    it("Sets language", () => {
        const localisation = require("./localisation");
        // Perform the tests
    });

    it("Sets english messages", () => {
        const localisation = require("./localisation");
        // Perform the tests
    });

    it("Sets french messages", () => {
        const localisation = require("./localisation");
        // Perform the tests
    });
});

The beforeEach() call to jest.resetModules() ensures we're re-running the code in the module.

like image 198
Simon Avatar answered Sep 27 '22 20:09

Simon