We use cookies on this site to enhance your user experience

By clicking the Accept button, you agree to us doing so. More info on our cookie policy

Testing window.open() in JavaScript with Jest

Published: Dec 1, 2024 by C.S. Rhymes

I recently had to write a test for a React component that opened a new browser window. To open the new window I made use of window.open() in my code. This made the component easy to write, but I had to think a bit differently about how to write the test for this.

More information on the window.open() method is available on mdn web docs.

To set a bit or background, I had a React component that had a simple form with a couple of inputs. When the user completed the inputs and submitted the form it opened a new window to a specified URL with the inputs as URL parameters.

The component to test

Here is a very simplified version of the component as a demonstration. I’d recommend using something like react-hook-form to add validation to your form.

// MyForm.js
import React, { useState } from "react";

const MyForm = ({ baseURL }) => {
  const [name, setName] = useState("");
  const [subject, setSubject] = useState("");

  const onSubmit = () => {
    window.open(
      `${baseURL}?name=${encodeURIComponent(name)}&subject=${encodeURIComponent(
        subject
      )}`,
      "_blank"
    );
  };

  return (
    <form onSubmit={onSubmit}>
      <label htmlFor="name">Name</label>
      <input name="name" id="name" onChange={(e) => setName(e.target.value)} />
      <label htmlFor="subject">Subject</label>
      <input
        name="subject"
        id="subject"
        onChange={(e) => setSubject(e.target.value)}
      />
      <input type="submit" value="Submit (opens in new window)" />
    </form>
  );
};

export default MyForm;

Now we have our component, lets think about the test for it.

What I’d normally test

Normally I would test what has been rendered in my component, using assertions such as expect the component to have text content or assert the url is what is expected (using window.location.href), but I quickly realised that approach won’t work in jest for this example.

Window.open opens a new browser window, so it doesn’t affect the component we are testing. We can’t see what is inside the new window or what its url is as it is outside of the scope of the component we are testing.

So how do we test something that is outside of what we can see? We don’t actually need to test that a new window is opened as that would be testing the window interface’s functionality and not our code. Instead, we just need to test that the window.open method is called.

Mocking window.open()

Therefore we need to mock window.open() and test that it was called inside our code.

// Mock window.open
global.open = jest.fn();

Now we can set the values in the inputs, submit our form and then test that the window.open was called. We can use fireEvent to set the values of the inputs and pressing the submit button.

fireEvent.input(screen.getByLabelText("Name"), {
  target: {
    value: "Test Name",
  },
});
fireEvent.input(screen.getByLabelText("Subject"), {
  target: {
    value: "An example subject",
  },
});
fireEvent.submit(
  screen.getByRole("button", { name: "Submit (opens in new window)" })
);

It’s worth having a read through the documentation for the considerations for fireEvent. You may want to use user-event instead depending on your use case.

We want to await for the method to run. We can do that using waitFor().

await waitFor(() => {
  expect(global.open).toHaveBeenCalled();
});

To ensure we are not opening loads of new windows, we can check that we only call window.open once.

await waitFor(() => {
  expect(global.open).toHaveBeenCalledTimes(1);
});

We can also check what arguments the method is called with, passing in the URL we expect as the first argument and the target as the second.

await waitFor(() => {
  expect(global.open).toHaveBeenCalledWith(
    "http://example.com?name=Test%20Name&subject=An%20example%20subject",
    "_blank"
  );
});

The complete test file

Here is the complete test file for your reference.

// MyForm.test.js
import React from "react";
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import MyForm from "./MyForm";

describe("MyForm test", () => {
  beforeEach(() => {
    // Mock window.open
    global.open = jest.fn();
  });

  it("opens a new window with the correct url", async () => {
    render(<MyForm baseURL="http://example.com" />);

    fireEvent.input(screen.getByLabelText("Name"), {
      target: {
        value: "Test Name",
      },
    });
    fireEvent.input(screen.getByLabelText("Subject"), {
      target: {
        value: "An example subject",
      },
    });
    fireEvent.submit(
      screen.getByRole("button", { name: "Submit (opens in new window)" })
    );

    await waitFor(() => {
      expect(global.open).toHaveBeenCalled();
      expect(global.open).toHaveBeenCalledTimes(1);
      expect(global.open).toHaveBeenCalledWith(
        "http://example.com?name=Test%20Name&subject=An%20example%20subject",
        "_blank"
      );
    });
  });
});

Photo by energepic.com on StockSnap

webdev javascript testing

Latest Posts

Testing window.open() in JavaScript with Jest
Testing window.open() in JavaScript with Jest

I recently had to write a test for a React component that opened a new browser window. To open the new window I made use of window.open() in my code. This made the component easy to write, but I had to think a bit differently about how to write the test for this.

Why did I become a writer?
Why did I become a writer?

There has been a lot of discussion on Threads recently about becoming a writer, but don’t give up your day job. I have seen a lot of arguments from all sides, some people saying they became a successful full time writer, others saying they would never give up their job, then there are others who became writers full time then went back to another job. Writing has always been a hobby for me, but this discussion has made me think more about why I write.

Adding social icons to the Bulma Clean Theme footer
Adding social icons to the Bulma Clean Theme footer

Version 1.1.0 of Bulma clean theme has been released. It has a small update that allows you to easily add social media links to the footer of your site.

How NOT to make a website

How NOT to make a Website

By C.S. Rhymes

From £1.99 or read for free on Kindle Unlimited!

Nigel's Intranet Adventure

Nigel's Intranet Adventure

By C.S. Rhymes

From £1.99 or read for free on Kindle Unlimited!