From f9594fba3f537bb1241996e5b8515c00435d809c Mon Sep 17 00:00:00 2001 From: Aaron Bohy Date: Wed, 20 Oct 2021 09:18:59 +0000 Subject: [PATCH] [FIX] web: patch: can call a not bound patched function Before this commit, it wasn't possible to patch some functions (e.g. setTimeout) on window, because of the way we call them. Indeed, we typically do `setTimeout(...)`, because this function doesn't need to be bound to the window object. X-original-commit: 476dbf75bb88dc2ddfdd47c1f229ce53cf7fadb7 Part-of: odoo/odoo#78698 --- addons/web/static/src/core/utils/patch.js | 11 ++++++--- .../static/tests/core/utils/patch_tests.js | 24 +++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/addons/web/static/src/core/utils/patch.js b/addons/web/static/src/core/utils/patch.js index 0c4431960c5..e2ce1fa8867 100644 --- a/addons/web/static/src/core/utils/patch.js +++ b/addons/web/static/src/core/utils/patch.js @@ -77,10 +77,15 @@ export function patch(obj, patchName, patchValue, options = {}) { } else { newDesc[key] = { [patchedFnName](...args) { - const prevSuper = this._super; - this._super = _superFn.bind(this); + let prevSuper; + if (this) { + prevSuper = this._super; + this._super = _superFn.bind(this); + } const result = patchFn.call(this, ...args); - this._super = prevSuper; + if (this) { + this._super = prevSuper; + } return result; }, }[patchedFnName]; diff --git a/addons/web/static/tests/core/utils/patch_tests.js b/addons/web/static/tests/core/utils/patch_tests.js index 345d78c9fd6..f8c29f3107e 100644 --- a/addons/web/static/tests/core/utils/patch_tests.js +++ b/addons/web/static/tests/core/utils/patch_tests.js @@ -1084,6 +1084,30 @@ QUnit.module("utils", () => { assert.verifySteps(["obj"]); }); + QUnit.test("can call a non bound patched method", async function (assert) { + // use case: patching a function on window (e.g. setTimeout) + assert.expect(3); + + const obj = { + fn() { + assert.step("original"); + }, + }; + + const originalFn = obj.fn; + patch(obj, "patch", { + fn() { + assert.step("patched"); + originalFn(); + }, + }); + + const fn = obj.fn; // purposely not bound + fn(); + + assert.verifySteps(["patched", "original"]); + }); + QUnit.module("patch 'pure' option"); QUnit.test("function objects are preserved with 'pure' patch", async function (assert) {