Odoo18-Base/addons/web/static/tests/_framework/mock_browser.hoot.js
2025-01-06 10:57:38 +07:00

93 lines
3.0 KiB
JavaScript

// ! WARNING: this module cannot depend on modules not ending with ".hoot" (except libs) !
import { beforeEach } from "@odoo/hoot";
import { on } from "@odoo/hoot-dom";
import { mockLocation } from "@odoo/hoot-mock";
//-----------------------------------------------------------------------------
// Internal
//-----------------------------------------------------------------------------
/**
* List of properties that should not be mocked on the browser object.
*
* This is because they are already handled by HOOT and tampering with them could
* lead to unexpected behavior.
*/
const READONLY_PROPERTIES = [
"cancelAnimationFrame",
"clearInterval",
"clearTimeout",
"requestAnimationFrame",
"setInterval",
"setTimeout",
];
const anchorHrefDescriptor = Object.getOwnPropertyDescriptor(HTMLAnchorElement.prototype, "href");
//-----------------------------------------------------------------------------
// Exports
//-----------------------------------------------------------------------------
/**
* Browser module needs to be mocked to patch the `location` global object since
* it can't be directly mocked on the window object.
*
* @param {string} name
* @param {OdooModuleFactory} factory
*/
export function mockBrowserFactory(name, { fn }) {
return (...args) => {
const browserModule = fn(...args);
const properties = {
location: {
get: () => mockLocation,
set: (value) => (mockLocation.href = value),
},
};
for (const property of READONLY_PROPERTIES) {
const originalValue = browserModule.browser[property];
properties[property] = {
configurable: false,
get: () => originalValue,
};
}
Object.defineProperties(browserModule.browser, properties);
beforeEach(function mockAnchorHref() {
Object.defineProperty(HTMLAnchorElement.prototype, "href", {
...anchorHrefDescriptor,
get() {
return this.hasAttribute("href") ? new URL(this.getAttribute("href")).href : "";
},
});
const offHrefClick = on(window, "click", (ev) => {
const href = ev.target.closest("a[href]")?.href;
if (!href || ev.defaultPrevented) {
return;
}
ev.preventDefault();
// Assign href to mock location instead of actual location
mockLocation.href = href;
// Scroll to the target element if the href is/has a hash
const hash = href.startsWith("#") ? href : new URL(href).hash;
if (hash) {
document.getElementById(hash.slice(1))?.scrollIntoView();
}
});
return function restoreAnchorHref() {
offHrefClick();
Object.defineProperty(HTMLAnchorElement.prototype, "href", anchorHrefDescriptor);
};
});
return browserModule;
};
}