I have a local testing environment, where I want to temporary override querySelector. I know that monkeypatching is bad practice, but in this case this code will only be used locally on developer side. I have this snippet that I wrote (overrides querySelector to fetch all selectors with another substring in the selector called addonID):
function maybeOverrideForTestStart(partialIDOfWidget, fullIDOfWidget) {
if(!isLocal) return;
const addonID = fullIDOfWidget.replace(partialIDOfWidget, "");
Element.prototype.querySelectorTemp = Element.prototype.querySelector.bind(Element);
Element.prototype.querySelector = function(selector) {
const element = this.querySelectorTemp(selector);
if (element) return element;
if (addonID) {
return this.querySelectorTemp(selector + addonID) || null;
}
};
}
function maybeOverrideForTestEnd() {
if(!isLocal) return;
Element.prototype.querySelector = Element.querySelectorTemp;
}
I call maybeOverrideForTestStart in the beginning of my testing, and maybeOverrideForTestEnd in the end. But this doesn't work, and I'm not sure what I'm missing. I'm getting either someElement.querySelector is not a function or "Uncaught TypeError: Illegal invocation".
Note - I also cannot understand if this also overrides the document.querySelector and document.body.querySelector or just someElement.querySelector.
Help is appreciated, thanks.
I would change the naming of
maybeOverrideForTestStarttopatchQuerySelectorssince its implementation changes as well.In order to correctly redefine/patch the modified
querySelectorimplementations (one needs to do it for bothDocument.prototypeandElement.prototype) and also to exactly restore each default state, one should choose an approach which makes use of each prototypalquerySelector's property descriptor. The function does patch each modified version but also does return a function which restores each original setting, everything viaObject.defineProperty.