Jest: I found `window` is `global` in jest from StackOverflow, but not mention in docs?

Created on 30 May 2017  ·  7Comments  ·  Source: facebook/jest

Do you want to request a feature or report a bug?

feature

What is the current behavior?

At the beginning, I searched window through jest document, but got nothing...
So I was using window from 'jsdom' like this:

import { JSDOM } from 'jsdom'
const { window } = new JSDOM()
global.window = window

But, my module didn't use this window.

After that, I found global is what I want from StackOverflow

I used that and it worked~

But...It's kind of weird.
I can't find anything mention that in docs.
And I'm thinking maybe jest can change the window that module used to global.window.
So we can use window instantly rather than global...

Most helpful comment

For any future googlers: global is window. So if you want to use the window object, don't use global.window — just use global.

All 7 comments

jsdom is used automatically. Don't import it in your test.

Yeah, I already know that...
I just thought jest document should mention that global is window...

I met same issue.

test("should not defined global.window", function() {
    console.log(typeof global.window !== "undefined" ? "global.window is defined" : "No window");
    expect(global.window).toBeUndefined();
});
// It fail on Node.js + Jest.

Reproduce repository: azu/jest-expose-global-window

I notice that some library doesn't work on Node.js + Jest default env.
For example, https://github.com/alizain/ulid doen't work.

I've avoided this issue by setting "testEnvironment": "node".

For any future googlers: global is window. So if you want to use the window object, don't use global.window — just use global.

I had some tests where I needed to see if window.print was called and also if document.title was used somewhere. However, if you set anything global, it will also be present in other tests. I used the following shared helpers to temporarily set some global properties.

export async function withGlobalProperty(
  propertyName,
  tempValue,
  handler = () => {}
) {
  const original = global[propertyName];
  global[propertyName] = tempValue;
  await handler();
  global[propertyName] = original;
}

export async function withGlobalDocumentProperty(propertyName, tempValue, handler = () => {}) {
  const original = global.document[propertyName];
  global.document[propertyName] = tempValue;
  await handler();
  global.document[propertyName] = original;
}

Then in a test:

import { withGlobalProperty, withGlobalDocumentProperty } from "./shared.js";

test("should trigger `window.print()` when clicked", () => {
  const mockPrint = jest.fn();
  withGlobalProperty("print", mockPrint, () => {
    const wrapper = mount(<Component />);
    wrapper.simulate("click");

    expect(mockPrint).toHaveBeenCalledTimes(1);
  });
});

test("should default the `text` to `document.title`", () => {
  const title = "My Title";
  withGlobalDocumentProperty("title", title, () => {
    const wrapper = mount(<AnotherComponent />);

    expect(
      wrapper.find(`a[href*="text=${encodeURIComponent(title)}"]`)
    ).toHaveLength(1);
  });
});

There may be a cleaner/safer way to do all this :)

@robertwbradford Your test will not fail if there is an error. The promise needs to complete before the result is returned to it, so your test will always pass if written without async/await. That's if you use async/await in your withGlobalProperty. If you remove all async/await, then no problem.

❌ Example of a test which should fail but pass anyway with your example. It throws an error which is swallowed UnhandledPromiseRejectionWarning: Unhandled promise rejection.

export async function withGlobalProperty(
  propertyName,
  tempValue,
  handler = () => {}
) {
  const original = global[propertyName];
  global[propertyName] = tempValue;
  await handler();
  global[propertyName] = original;
}

  test('returns the same value for a string defined in window', () => {
    withGlobalProperty('acme', { value: true }, () => {
      expect(window.acme.value).toBe(false)
    })
  })

✔️The test should be rewritten adding async/await:

export async function withGlobalProperty(
  propertyName,
  tempValue,
  handler = () => {}
) {
  const original = global[propertyName];
  global[propertyName] = tempValue;
  await handler();
  global[propertyName] = original;
}

  test('returns the same value for a string defined in window', async () => {
    await withGlobalProperty('acme', { value: true }, () => {
      expect(window.acme.value).toBe(false)
    })
  })

✔️... or no async/await should be used at all:

export function withGlobalProperty(
  propertyName,
  tempValue,
  handler = () => {}
) {
  const original = global[propertyName];
  global[propertyName] = tempValue;
  handler();
  global[propertyName] = original;
}

  test('returns the same value for a string defined in window', () => {
    withGlobalProperty('acme', { value: true }, () => {
      expect(window.acme.value).toBe(false)
    })
  })

Good catch, @sebastienfi . Thanks.

Was this page helpful?
0 / 5 - 0 ratings