Cómo corregir Error: No implementado: navegación (excepto cambios hash)

4 minutos de lectura

Avatar de usuario de Tran Son Hoang
Tran Son Hoang

Estoy implementando una prueba unitaria para un archivo que contiene window.location.href y necesito comprobarlo.

Mi versión de broma es 22.0.4. Todo está bien cuando ejecuto mi prueba en la versión del nodo> = 10

Pero me sale este error cuando lo ejecuto v8.9.3

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

No tengo idea al respecto. He buscado en muchas páginas para encontrar la solución o cualquier pista sobre esto para descubrir qué sucedió aquí.

[UPDATE] – Eché un vistazo profundo al código fuente y creo que este error es de 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)

archivo de navegación.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);
};

no implementado.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);
};

Veo algunas lógicas extrañas en estos archivos.

  1. const scriptSource = whatwgURL.percentDecode(Buffer.from(urlString)).toString();
  2. luego verifique la cadena y devuelva el error

Versión alternativa que funcionó para mí con jest solo:

let assignMock = jest.fn();

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

afterEach(() => {
  assignMock.mockClear();
});

Referencia:
https://remarkablemark.org/blog/2018/11/17/simulacro-de-ubicacion-de-ventana/

  • solo para agregar a esto, personalmente tuve que incluir todas las claves del objeto window.location para que esto funcionara, asignando todas las funciones a AssignMock y todo lo demás a una cadena, excepto ancestorOrigins, que acabo de configurar en nulo. Esto puede deberse a que mi configuración de eslint se enojó conmigo, por lo que podría no ser necesario para todos. Aparte de eso, ¡esto funcionó para mí en 2021!

    – Jabinator1

    24 de agosto de 2021 a las 22:38

  • Para mecanografiado: window.location = ({ assign: assignMock as any }) as Location;

    –Logan Cundiff

    17 de marzo de 2022 a las 16:11


Avatar de usuario de Akhilesh.tiwari
Akhilesh.tiwari

Solución alternativa: puede burlarse del objeto de ubicación

const mockResponse = jest.fn();
Object.defineProperty(window, 'location', {
  value: {
    hash: {
      endsWith: mockResponse,
      includes: mockResponse,
    },
    assign: mockResponse,
  },
  writable: true,
});

  • Para reacción iónica usuarios Puede colocar este código en su setupTests.ts expediente.

    – oso benny

    12 de julio de 2020 a las 16:12

Enfrenté un problema similar en una de mis pruebas unitarias. Esto es lo que hice para resolverlo.

  • Reemplazar window.location.href con window.location.assign(url) O
    window.location.replace(url)
  • JSDOM lo hará todavía quejarse window.location.assign no se ha implementado.

    Error: Not implemented: navigation (except hash changes)

  • Luego, en una de sus pruebas unitarias para el componente / función anterior que contiene window.assign(url) o window.replace(url) defina lo siguiente

    • sinon.stub(window.location, 'assign');
    • sinon.stub(window.location, 'replace');
    • Asegúrate de importar sinon import sinon from 'sinon';

Con suerte, esto debería solucionar el problema para usted como lo hizo para mí.

La razón por la que JSDOM se queja de la Error: Not implemented: navigation (except hash changes) es porque JSDOM no implementa métodos como window.alert, window.location.assignetc.

Referencias:

  • Sí. Apliqué esta solución reemplazando href por assign y funciona bien

    – Tran Son Hoang

    8 de febrero de 2019 a las 13:22

  • Obtener este error en TypeScript TypeError: el descriptor para la asignación de propiedades no es configurable ni escribible 9 | > 10 | sinon.stub(ventana.ubicación, ‘asignar’); | ^ 11 | sinon.stub(ventana.ubicación, ‘reemplazar’);

    –Viraj Singh

    2 de febrero de 2022 a las 6:55

Puedes usar broma-ubicación-simulacro paquete para eso

Ejemplo de uso con CRA (create-react-app)

// src/setupTests.ts
import "jest-location-mock";

Encontré una buena referencia que explica y resuelve el problema: https://remarkablemark.org/blog/2018/11/17/simulacro-de-ubicacion-de-ventana/

Debido a que las pruebas se ejecutan en Node, no puede entender window.location, por lo que debemos simular la función:

Ex:

delete window.location;
window.location = { reload: jest.fn() }

Avatar de usuario de Majid Eltayeb
majid eltayeb

 it('test', () => {
    const { open } = window;
    delete window.open;
    window.open = jest.fn();
    jest.spyOn(window, 'open');
    // then call the function that's calling the window
    expect(window.open).toHaveBeenCalled();
    window.open = open;
  });

Avatar de usuario de Luckylooke
Afortunado

Lo siguiente funcionó para mí:

  const originalHref = window.location.href;
  afterEach(() => {
    window.history.replaceState({}, "", decodeURIComponent(originalHref));
  });

feliz codificación 🙂

¿Ha sido útil esta solución?