Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Manipulation with window location is no longer possible #3492

Open
avlapeto opened this issue Jan 9, 2023 · 5 comments
Open

Manipulation with window location is no longer possible #3492

avlapeto opened this issue Jan 9, 2023 · 5 comments

Comments

@avlapeto
Copy link

avlapeto commented Jan 9, 2023

Basic info:

  • Node.js version: 18.12.0
  • jsdom version: 21.0.0

Minimal reproduction case

We have a page that performs a redirect to an external page based on query string parameters:

...
<script>
const redirectUrl = 'https://github.com/'
window.location.href = redirectUrl;
// window.location.assign(redirectUrl);
</script>
...

and integration test that expects that location.href will be changed (or location.assing will be invoked with some params).

    const windowLocation = {};
    const { window } = new JSDOM(response.text, {
      beforeParse(window) {
        delete window.location;
        window.location = windowLocation;
      },
      runScripts: 'dangerously',
    });
   expect(windowLocation.href).toBe('https://github.com/');

Previously (jsdom 20.0.3) we changed the original location object to a syntetic one and ran an expectation on it. But since window.location became non-configurable, it's no longer possible. 
Any advice about options to spy on location object?

Right now, we are getting:

Error: Not implemented: navigation (except hash changes).

Thanks in advance!

@jenseng
Copy link
Contributor

jenseng commented May 6, 2023

So this won't work for all cases, but if you can control which "window" is used by your code under test, you can inject a more test-friendly version (as in this react-router PR to upgrade jsdom).

e.g. given some app code we want to test:

function goSomewhere({ redirectUrl }) {
  window.location.assign(redirectUrl);
}

If we change it like so:

function goSomewhere({ redirectUrl, window: w = window }) {
  w.location.assign(redirectUrl);
}

Existing callers callers will still default to the real window. But in our test code we can then do something like this:

const testWindow = { ...window, location: { ...window.location, assign: jest.fn() } };
goSomewhere({ redirectUrl: "https://github.com", window: testWindow });
expect(testWindow.location.assign).toHaveBeenCalledWith("https://github.com");

@avlapeto
Copy link
Author

avlapeto commented May 9, 2023

@jenseng
Thanks much for your suggestion! Based on it I improved my tests to work with the newest version of jest. Unfortunately it's not possible in our case to extract function declaration to a js file and easily test it.

My solution is:

...
<script>
// ... Business logic start
// ... Business logic end

const redirectUrl = 'https://github.com/'
window.redirect = window.redirect || function (redirectUrl, win) {
    win.location.href = redirectUrl;
  }
redirect(redirectUrl, window);
</script>
...

And test it in a way:

const { window } = new JSDOM(response.text, {
  beforeParse(window) {
    window.redirect = jest.fn();
  },
  runScripts: 'dangerously',
});
expect(window.redirect).toHaveBeenCalledWith(redirectParam, window);;

It's note actually check that redirect is happening, but it test business logic before redirect should happen.

From my point of view this issue could be closed, since with propper decomposition you could test window object.

@uladzimirdev
Copy link

great solution @jenseng, unfortunately if you do not use window directly, it can be tricky to override window. Solution which worked in my case I found here.

/**
 * Changes the URL used by the global JSDOM instance in the current window.
 *
 * NOTE: This does not change the origin which would result in a security exception.
 */
function changeJSDOMURL(url) {
  const newURL = new URL(url);
  const href = `${window.origin}${newURL.pathname}${newURL.search}${newURL.hash}`;
  history.replaceState(history.state, null, href);
}

@donaldpipowitch
Copy link

My strategy now: we moved all location.href assignments to a setLocationHref call that is imported from a module, so we can easily mock it in Jest. Not nice, but works.

dgdavid added a commit to openSUSE/agama that referenced this issue Oct 25, 2023
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
dgdavid added a commit to openSUSE/agama that referenced this issue Oct 25, 2023
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
dgdavid added a commit to openSUSE/agama that referenced this issue Oct 25, 2023
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
dgdavid added a commit to openSUSE/agama that referenced this issue Oct 30, 2023
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
dgdavid added a commit to openSUSE/agama that referenced this issue Oct 30, 2023
Because 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
dgdavid added a commit to openSUSE/agama that referenced this issue Oct 31, 2023
Because 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
dgdavid added a commit to openSUSE/agama that referenced this issue Oct 31, 2023
Because 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
@tkrotoff
Copy link

tkrotoff commented Dec 7, 2023

FYI The commit that did this change: 0c8eb3a

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants