Skip to content

Commit

Permalink
[web] Fix tests mocking window.location
Browse files Browse the repository at this point in the history
Beause it's no longer possible to mock some window properties since
jsdom 21.0.0 and it was updated to version 22.1.0 in previous commits.

See https://github.com/jsdom/jsdom/blob/master/Changelog.md#2100 and
jsdom/jsdom#3492
  • Loading branch information
dgdavid committed Oct 25, 2023
1 parent 877cd1a commit e921c01
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 32 deletions.
8 changes: 4 additions & 4 deletions web/src/context/l10n.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
// @ts-check

import React, { useCallback, useEffect, useState } from "react";
import { useCancellablePromise } from "~/utils";
import { useCancellablePromise, locationReload, setLocationSearch } from "~/utils";
import cockpit from "../lib/cockpit";
import { useInstallerClient } from "./installer";

Expand Down Expand Up @@ -174,11 +174,11 @@ function reload(newLanguage) {
const query = new URLSearchParams(window.location.search);
if (query.has("lang") && query.get("lang") !== newLanguage) {
query.set("lang", newLanguage);
// Calling search() with a different value makes the browser to navigate
// Setting location search with a different value makes the browser to navigate
// to the new URL.
window.location.search = query.toString();
setLocationSearch(query.toString());
} else {
window.location.reload();
locationReload();
}
}

Expand Down
50 changes: 23 additions & 27 deletions web/src/context/l10n.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { render, waitFor, screen } from "@testing-library/react";

import { L10nProvider } from "~/context/l10n";
import { InstallerClientProvider } from "./installer";
import * as utils from "~/utils";

const getUILanguageFn = jest.fn().mockResolvedValue();
const setUILanguageFn = jest.fn().mockResolvedValue();
Expand Down Expand Up @@ -72,24 +73,14 @@ const TranslatedContent = () => {
};

describe("L10nProvider", () => {
// remember the original object, we need to temporarily replace it with a mock
const origLocation = window.location;
const origNavigator = window.navigator;

// mock window.location.reload and search
beforeAll(() => {
delete window.location;
window.location = { reload: jest.fn(), search: "" };
jest.spyOn(utils, "locationReload").mockImplementation(utils.noop);
jest.spyOn(utils, "setLocationSearch");

delete window.navigator;
window.navigator = { languages: ["es-es", "cs-cz"] };
});

afterAll(() => {
window.location = origLocation;
window.navigator = origNavigator;
});

// remove the Cockpit language cookie after each test
afterEach(() => {
// setting a cookie with already expired date removes it
Expand Down Expand Up @@ -117,8 +108,7 @@ describe("L10nProvider", () => {
// children are displayed
await screen.findByText("hello");

expect(window.location.search).toEqual("");
expect(window.location.reload).not.toHaveBeenCalled();
expect(utils.locationReload).not.toHaveBeenCalled();
});
});

Expand All @@ -136,16 +126,16 @@ describe("L10nProvider", () => {
</InstallerClientProvider>
);

await waitFor(() => expect(window.location.reload).toHaveBeenCalled());
await waitFor(() => expect(utils.locationReload).toHaveBeenCalled());

// reload the component
// renders again after reloading
render(
<InstallerClientProvider client={client}>
<L10nProvider><TranslatedContent /></L10nProvider>
</InstallerClientProvider>
);
await waitFor(() => screen.getByText("hola"));

await waitFor(() => screen.getByText("hola"));
expect(setUILanguageFn).toHaveBeenCalledWith("es_ES");
});
});
Expand All @@ -164,8 +154,10 @@ describe("L10nProvider", () => {
<L10nProvider><TranslatedContent /></L10nProvider>
</InstallerClientProvider>
);
await waitFor(() => expect(window.location.reload).toHaveBeenCalled());

await waitFor(() => expect(utils.locationReload).toHaveBeenCalled());

// renders again after reloading
render(
<InstallerClientProvider client={client}>
<L10nProvider><TranslatedContent /></L10nProvider>
Expand All @@ -185,8 +177,10 @@ describe("L10nProvider", () => {
<L10nProvider><TranslatedContent /></L10nProvider>
</InstallerClientProvider>
);
await waitFor(() => expect(window.location.reload).toHaveBeenCalled());

await waitFor(() => expect(utils.locationReload).toHaveBeenCalled());

// renders again after reloading
render(
<InstallerClientProvider client={client}>
<L10nProvider><TranslatedContent /></L10nProvider>
Expand All @@ -200,7 +194,7 @@ describe("L10nProvider", () => {

describe("when the URL query parameter is set to '?lang=cs-CZ'", () => {
beforeEach(() => {
window.location.search = "?lang=cs-CZ";
history.replaceState(history.state, null, `http://localhost/?lang=cs-CZ`);
});

describe("when the Cockpit language is already set to 'cs-cz'", () => {
Expand All @@ -221,8 +215,8 @@ describe("L10nProvider", () => {
expect(setUILanguageFn).not.toHaveBeenCalled();

expect(document.cookie).toEqual("CockpitLang=cs-cz");
expect(window.location.reload).not.toHaveBeenCalled();
expect(window.location.search).toEqual("?lang=cs-CZ");
expect(utils.locationReload).not.toHaveBeenCalled();
expect(utils.setLocationSearch).not.toHaveBeenCalled();
});
});

Expand All @@ -240,16 +234,17 @@ describe("L10nProvider", () => {
<L10nProvider><TranslatedContent /></L10nProvider>
</InstallerClientProvider>
);
await waitFor(() => expect(window.location.search).toEqual("lang=cs-cz"));

// reload the component
await waitFor(() => expect(utils.setLocationSearch).toHaveBeenCalledWith("lang=cs-cz"));

// renders again after reloading
render(
<InstallerClientProvider client={client}>
<L10nProvider><TranslatedContent /></L10nProvider>
</InstallerClientProvider>
);
await waitFor(() => screen.getByText("ahoj"));

await waitFor(() => screen.getByText("ahoj"));
expect(setUILanguageFn).toHaveBeenCalledWith("cs_CZ");
});
});
Expand All @@ -267,16 +262,17 @@ describe("L10nProvider", () => {
<L10nProvider><TranslatedContent /></L10nProvider>
</InstallerClientProvider>
);
await waitFor(() => expect(window.location.search).toEqual("lang=cs-cz"));

await waitFor(() => expect(utils.setLocationSearch).toHaveBeenCalledWith("lang=cs-cz"));

// reload the component
render(
<InstallerClientProvider client={client}>
<L10nProvider><TranslatedContent /></L10nProvider>
</InstallerClientProvider>
);
await waitFor(() => screen.getByText("ahoj"));

await waitFor(() => screen.getByText("ahoj"));
expect(setUILanguageFn).toHaveBeenCalledWith("cs_CZ");
});
});
Expand Down
34 changes: 33 additions & 1 deletion web/src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,12 +178,44 @@ const hex = (value) => {
*/
const toValidationError = (issue) => ({ message: issue.description });

/**
* Wrapper around window.location.reload
* @function
*
* It's needed mainly to ease testing because we can't override window in jest with jsdom anymore
*
* See below links
* - https://github.com/jsdom/jsdom/blob/master/Changelog.md#2100
* - https://github.com/jsdom/jsdom/issues/3492
*/
const locationReload = () => {
window.location.reload();
};

/**
* Wrapper around window.location.search setter
* @function
*
* It's needed mainly to ease testing as we can't override window in jest with jsdom anymore
*
* See below links
* - https://github.com/jsdom/jsdom/blob/master/Changelog.md#2100
* - https://github.com/jsdom/jsdom/issues/3492
*
* @param {string} query
*/
const setLocationSearch = (query) => {
window.location.search = query;
};

export {
noop,
partition,
classNames,
useCancellablePromise,
useLocalStorage,
hex,
toValidationError
toValidationError,
locationReload,
setLocationSearch
};

0 comments on commit e921c01

Please sign in to comment.