{"id":15541789,"url":"https://github.com/simonihmig/ember-window-mock","last_synced_at":"2025-05-16T18:05:38.290Z","repository":{"id":37601586,"uuid":"104937894","full_name":"simonihmig/ember-window-mock","owner":"simonihmig","description":"Mock window global in tests with test-friendly replacements for location, alert/confirm/prompt/ and more.","archived":false,"fork":false,"pushed_at":"2025-05-15T22:22:09.000Z","size":6367,"stargazers_count":64,"open_issues_count":16,"forks_count":16,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-16T18:04:12.166Z","etag":null,"topics":["ember","ember-addon"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/simonihmig.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-09-26T21:07:58.000Z","updated_at":"2025-04-21T01:30:10.000Z","dependencies_parsed_at":"2023-11-11T20:22:14.655Z","dependency_job_id":"70633c1d-230a-4205-9403-971f7531a513","html_url":"https://github.com/simonihmig/ember-window-mock","commit_stats":{"total_commits":837,"total_committers":19,"mean_commits":44.05263157894737,"dds":0.6224611708482677,"last_synced_commit":"b49d56c0094cef416048ff023e3ce60964594634"},"previous_names":["kaliber5/ember-window-mock"],"tags_count":31,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonihmig%2Fember-window-mock","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonihmig%2Fember-window-mock/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonihmig%2Fember-window-mock/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonihmig%2Fember-window-mock/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/simonihmig","download_url":"https://codeload.github.com/simonihmig/ember-window-mock/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254582903,"owners_count":22095518,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ember","ember-addon"],"created_at":"2024-10-02T12:19:39.759Z","updated_at":"2025-05-16T18:05:38.251Z","avatar_url":"https://github.com/simonihmig.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ember-window-mock\n\n[![CI](https://github.com/kaliber5/ember-window-mock/actions/workflows/ci.yml/badge.svg)](https://github.com/kaliber5/ember-window-mock/actions/workflows/ci.yml)\n[![Ember Observer Score](https://emberobserver.com/badges/ember-window-mock.svg)](https://emberobserver.com/addons/ember-window-mock)\n[![npm version](https://badge.fury.io/js/ember-window-mock.svg)](https://badge.fury.io/js/ember-window-mock)\n\nThis Ember CLI addon provides the `window` global as an ES6 module import that you can use in any component or controller where\nyou need `window`. But some of its properties and functions are prohibitive to be used\nin tests as they will break the test run:\n\n- you cannot set `window.location.href` to trigger a redirect, as that will leave your test page\n- `alert`, `confirm` and `prompt` are blocking calls, and cannot be closed without user interaction, so they will just\n  suspend your test run\n\nSo when running tests this import will be replaced with one that mocks these critical parts.\n\n## Compatibility\n\n- Ember.js v4.8 or above\n- Embroider or ember-auto-import v2\n\n## Installation\n\n```\nember install ember-window-mock\n```\n\n## Usage\n\n### How to use it in your app\n\nLet's say you want to redirect to an external URL. A simple controller could look like this:\n\n```js\nimport Controller from \"@ember/controller\";\nimport { action } from \"@ember/object\";\n\nexport default class IndexController extends Controller {\n  @action\n  redirect(url) {\n    window.location.href = url;\n  }\n}\n```\n\nWith this addon, you can just import `window` instead of using the global:\n\n```js\nimport Controller from \"@ember/controller\";\nimport { action } from \"@ember/object\";\nimport window from \"ember-window-mock\";\n\nexport default class IndexController extends Controller {\n  @action\n  redirect(url) {\n    window.location.href = url;\n  }\n}\n```\n\nEverything else works as you would expect, since the import is exactly the same as the global, when not running tests.\n\n### The window mock\n\nWhen running in the test environment, the import will be replaced with a mock. It is a proxy to `window`, so all of the\nnon-critical properties and functions just use the normal `window` global. But the critical parts are replaced suitable\nfor tests:\n\n- `window.location` is mocked with an object with the same API (members like `.href` or `.host`), but setting\n  `location.href` will just do nothing. Still reading from `location.href` will return the value that was previously set,\n  so you can run assertions against that value to check if you app tried to redirect to the expected URL.\n- `window.localStorage` is also mocked with an object with the same API (`getItem`, `setItem`, `removeItem`, `clear`, `key`, and `length`). Storage is not persistent and does not affect your browser's `localStorage` object.\n- `window.sessionStorage` is mocked similar to `window.localStorage`.\n- `alert`, `confirm` and `prompt` are replaced by simple noop functions (they do nothing). You can use a mocking library\n  like [Sinon.js](http://sinonjs.org/) to replace them with spies or stubs to assert that they have been called or to\n  return some predefined value (e.g. `true` for `confirm`).\n\nMoreover it allows you to set any (nested) properties, even if they are defined as read only. This way you can pretend\ndifferent environments in your tests. For example you can fake different devices by changing\n\n- `window.navigator.userAgent` when you do user agent detection in your app.\n- `window.screen.width` to test responsive layouts when your components render differently based on it.\n\nSee below for some examples.\n\n**Important:**\n\n- The window mock works by using an ES6 `Proxy`, so **your development environment and tests need to run in a browser like Chrome that\n  supports `Proxy` natively** (as it cannot be transpiled by Babel)\n- Note that this will only work when you use these function through the import, and not by using the global directly.\n\n### Resetting the state in tests\n\nIt is possible to leak some state on the window mock between tests. For example when your app sets `location.href` in a\ntest like this:\n\n```js\nwindow.location.href = \"http://www.example.com\";\n```\n\nFor the following test `window.location.href` will still be `'http://www.example.com'`, but instead it should have a\nfresh instance of the window mock. Therefore this addon exports a `setupWindowMock` function to kill all changed state on `window`:\n\n```js\nimport { setupWindowMock } from 'ember-window-mock/test-support';\n\nmodule('SidebarController', function(hooks) {\n  setupWindowMock(hooks);\n\n  test(...);\n});\n```\n\nIf you want to reset the state within a test, you can explicitly call `reset`:\n\n```js\nimport window from 'ember-window-mock';\nimport { setupWindowMock, reset } from 'ember-window-mock/test-support';\n\nmodule('SidebarController', function(hooks) {\n  setupWindowMock(hooks);\n\n  test('some test', function(assert) {\n    window.location.href = 'https://example.com';\n    assert.strictEqual(window.location.hostname, 'example.com');\n\n    reset();\n\n    assert.strictEqual(window.location.hostname, 'localhost');\n  });\n});\n```\n\n### createMockedWindow()\n\nWhen all you need is mocking the global `window` object, the guide above has you covered. But there can be cases where you want to create a new mocked window object from scratch, for example to mock `window.parent` with a different window instance. This you can use the `createMockedWindow()` test helper for:\n\n```js\nimport window from 'ember-window-mock/test-support';\nimport { createMockedWindow, setupWindowMock } from 'ember-window-mock/test-support';\n\nmodule('SidebarController', function(hooks) {\n  setupWindowMock(hooks);\n\n  test('app is running in iframe', function(assert) {\n    window.location.href = 'https://myapp.com';\n    window.parent = createMockedWindow();\n    window.parent.location.href = 'https://example.com';\n\n    // ...\n  });\n});\n```\n\n`setupWindowMock()` will _not_ reset the state of any explicitly created mocked windows, but in most cases this is not needed, since as soon as the reference to that mocked window is not used anymore, it will not have any effects and regular garbage collection will dispose the object. However, if you need to reset the state explicitly _within_ a test, you can do so by passing the mocked window object to `reset()`:\n\n```js\nimport { createMockedWindow, reset } from 'ember-window-mock/test-support';\n\nconst mockedWindow = createMockedWindow();\nmockedWindow.localStorage.set('foo', 'bar');\n// do something\nreset(mockedWindow);\n// now mockedWindow is back to its original state again\n```\n\n### Test examples\n\n#### Mocking `window.location`\n\nGiven a controller like the one above, that redirects to some URL when a button is clicked, an application test could like this:\n\n```js\nimport { module, test } from \"qunit\";\nimport { click, visit } from \"@ember/test-helpers\";\nimport { setupApplicationTest } from \"ember-qunit\";\nimport window from \"ember-window-mock\";\nimport { setupWindowMock } from \"ember-window-mock/test-support\";\n\nmodule(\"Acceptance | redirect\", function (hooks) {\n  setupApplicationTest(hooks);\n  setupWindowMock(hooks);\n\n  test(\"it redirects when clicking the button\", async function (assert) {\n    await visit(\"/\");\n    await click(\"button\");\n\n    assert.equal(window.location.href, \"http://www.example.com\");\n  });\n});\n```\n\n#### Mocking `confirm()`\n\nHere is an example that uses [ember-sinon-qunit](https://github.com/elwayman02/ember-sinon-qunit) to replace `confirm`,\nso you can easily check if it has been called, and to return some defined value:\n\n```js\nimport { module, test } from \"qunit\";\nimport { click, visit } from \"@ember/test-helpers\";\nimport { setupApplicationTest } from \"ember-qunit\";\nimport window from \"ember-window-mock\";\nimport { setupWindowMock } from \"ember-window-mock/test-support\";\nimport sinon from \"sinon\";\n\nmodule(\"Acceptance | redirect\", function (hooks) {\n  setupApplicationTest(hooks);\n  setupWindowMock(hooks);\n\n  test(\"it deletes an item\", async function (assert) {\n    let stub = sinon.stub(window, \"confirm\");\n    stub.returns(true);\n\n    await visit(\"/\");\n    await click(\"[data-test-delete]\");\n\n    assert.ok(stub.calledOnce);\n    assert.ok(stub.calledWith(\"Are you sure?\"));\n  });\n});\n```\n\n#### Mocking `open()`\n\nHere is an example that assigns a new function to replace `open`.\nYou can check if the function has been called as well as the value of its parameters.\n\n```js\nimport { module, test } from \"qunit\";\nimport { click, visit } from \"@ember/test-helpers\";\nimport { setupApplicationTest } from \"ember-qunit\";\nimport window from \"ember-window-mock\";\nimport { setupWindowMock } from \"ember-window-mock/test-support\";\n\nmodule(\"Acceptance | new window\", function (hooks) {\n  setupApplicationTest(hooks);\n  setupWindowMock(hooks);\n\n  test(\"it opens a new window when clicking the button\", async function (assert) {\n    await visit(\"/\");\n    window.open = (urlToOpen) =\u003e {\n      assert.equal(urlToOpen, \"http://www.example.com/some-file.jpg\");\n    };\n    await click(\"button\");\n  });\n});\n```\n\n## Contributing\n\nSee the [Contributing](CONTRIBUTING.md) guide for details.\n\n## License\n\nThis project is licensed under the [MIT License](LICENSE.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimonihmig%2Fember-window-mock","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsimonihmig%2Fember-window-mock","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimonihmig%2Fember-window-mock/lists"}