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.
2
Answers
I’m not sure if you need to
.bind()
the function, but you could keep a reference to the original function in a constant, for exampleI would change the naming of
maybeOverrideForTestStart
tomockQuerySelector
since its implementation changes as well.In order to correctly redefine/patch the modified
querySelector
implementation and also to exactly restore its default state one should choose an approach which makes use of the prototypalquerySelector
‘s property descriptor. The function would patch the modified version but also return a function which does restore the original setting, both viaObject.defineProperty
.