如何修复错误:未实现:导航(哈希更改除外)

Hoa*_*Son 5 unit-testing jestjs vuejs2

我正在为包含的文件实施单元测试,window.location.href需要对其进行检查。

我开玩笑的版本是22.0.4。在节点版本> = 10上运行测试时,一切都很好

但是我在运行它时收到此错误 v8.9.3

console.error node_modules/jsdom/lib/jsdom/virtual-console.js:29
      Error: Not implemented: navigation (except hash changes)
Run Code Online (Sandbox Code Playgroud)

我对此一无所知。我在许多页面上进行了搜索,以找出解决方案或有关此问题的任何提示,以了解此处发生的情况。

[更新]-我对源代码进行了深入研究,我认为此错误来自jsdom。

at module.exports (webapp/node_modules/jsdom/lib/jsdom/browser/not-implemented.js:9:17)
at navigateFetch (webapp/node_modules/jsdom/lib/jsdom/living/window/navigation.js:74:3)
Run Code Online (Sandbox Code Playgroud)

navigation.js文件

exports.evaluateJavaScriptURL = (window, urlRecord) => {
  const urlString = whatwgURL.serializeURL(urlRecord);
  const scriptSource = whatwgURL.percentDecode(Buffer.from(urlString)).toString();
  if (window._runScripts === "dangerously") {
    try {
      return window.eval(scriptSource);
    } catch (e) {
      reportException(window, e, urlString);
    }
  }
  return undefined;
};
exports.navigate = (window, newURL, flags) => {
  // This is NOT a spec-compliant implementation of navigation in any way. It implements a few selective steps that
  // are nice for jsdom users, regarding hash changes and JavaScript URLs. Full navigation support is being worked on
  // and will likely require some additional hooks to be implemented.

  const document = idlUtils.implForWrapper(window._document);
  const currentURL = document._URL;

  if (!flags.reloadTriggered && urlEquals(currentURL, newURL, { excludeFragments: true })) {
    if (newURL.fragment !== currentURL.fragment) {
      navigateToFragment(window, newURL, flags);
    }
    return;
  }

  // NOT IMPLEMENTED: Prompt to unload the active document of browsingContext.

  // NOT IMPLEMENTED: form submission algorithm
  // const navigationType = 'other';

  // NOT IMPLEMENTED: if resource is a response...
  if (newURL.scheme === "javascript") {
    window.setTimeout(() => {
      const result = exports.evaluateJavaScriptURL(window, newURL);
      if (typeof result === "string") {
        notImplemented("string results from 'javascript:' URLs", window);
      }
    }, 0);
    return;
  }
  navigateFetch(window);
};
Run Code Online (Sandbox Code Playgroud)

not-implemented.js

module.exports = function (nameForErrorMessage, window) {
  if (!window) {
    // Do nothing for window-less documents.
    return;
  }

  const error = new Error(`Not implemented: ${nameForErrorMessage}`);
  error.type = "not implemented";

  window._virtualConsole.emit("jsdomError", error);
};
Run Code Online (Sandbox Code Playgroud)

我在这些文件中看到了一些奇怪的逻辑。

  1. const scriptSource = whatwgURL.percentDecode(Buffer.from(urlString)).toString();
  2. 然后检查字符串并返回错误

小智 28

jest仅适用于我的替代版本:

let assignMock = jest.fn();

delete window.location;
window.location = { assign: assignMock };

afterEach(() => {
  assignMock.mockClear();
});
Run Code Online (Sandbox Code Playgroud)

参考:https : //remarkablemark.org/blog/2018/11/17/mock-window-location/

  • 对于 Typescript:`window.location = ({ allocate: allocateMock as any }) as Location;` (9认同)
  • 只是为了补充这一点,我个人必须包含 window.location 对象的所有键才能使其工作,将所有函数分配给 allocateMock 并将其他所有内容分配给一个字符串,除了祖先起源,我刚刚将其设置为无效的。这可能是因为我的 eslint 设置让我生气,所以这可能不是每个人都需要的。除此之外,这对 2021 年的我有用! (2认同)

小智 18

替代解决方案:您可以模拟位置对象

const mockResponse = jest.fn();
    Object.defineProperty(window, "location", {
      value: {
        hash: {
          endsWith: mockResponse,
          includes: mockResponse
        },
        assign: mockResponse
      },
      writable: true
    });
Run Code Online (Sandbox Code Playgroud)

  • 对于 **Ionic React** 用户。您可以将此代码放入 *setupTests.ts* 文件中。 (2认同)

Mih*_*ale 12

我在一项单元测试中遇到了类似的问题。这是我为解决此问题所做的工作。

  • 替换window.location.hrefwindow.location.assign(url)OR window.location.replace(url)

  • JSDOM 仍然会抱怨window.location.assign未实现。

    Error: Not implemented: navigation (except hash changes)

  • 然后,在您的一个单元测试中,上述组件/功能包含window.assign(url)window.replace(url)定义以下内容

    • sinon.stub(window.location, 'assign');
    • sinon.stub(window.location, 'replace');
    • 确保您导入sinon import sinon from 'sinon';


希望这可以像为我那样为您解决问题。


究其原因JSDOM埋怨Error: Not implemented: navigation (except hash changes)是因为JSDOM没有实现类似的方法window.alertwindow.location.assign等等。


参考文献:

  • 在打字稿中出现此错误 TypeError: 属性分配的描述符不可配置且不可写 9 | > 10 | sinon.stub(window.location, '分配'); | ^ 11 | sinon.stub(window.location, '替换'); (5认同)

Yus*_*bek 9

您可以使用jest-location-mock

CRA 的使用示例 (create-react-app)

// src/setupTests.ts
import "jest-location-mock";
Run Code Online (Sandbox Code Playgroud)

  • 这根本不起作用 (5认同)
  • 这对我来说也不起作用,使用反应路由器。 (3认同)

小智 8

我找到了一个很好的参考来解释和解决问题:https://remarkablemark.org/blog/2018/11/17/mock-window-location/

因为测试是在 Node 下运行的,所以它无法理解 window.location,所以我们需要模拟该函数:

前任:

delete window.location;
window.location = { reload: jest.fn() }
Run Code Online (Sandbox Code Playgroud)