From b2db7f21ed15fbbd3a90b67ac96787e49eb58fe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Thu, 17 Sep 2020 10:52:20 +0200 Subject: [PATCH] [FIX] observer: does not proxify promises Promises are kind of special, and do not behave like usual javascript values. For this issue, the problem is that when the observer tries to observe a promise value, the code will crash with an error like this: Uncaught TypeError: Method Promise.prototype.then called on incompatible receiver [object Object] Also, note that it does not make much sense to proxify promise methods anyway, since they are not (supposed) to be modified. So, with this commit, we simply consider that promises should be treated like a primitive value: simply ignored when determining if it should be proxified Note that I actually believe that putting promises in a useState is not a good idea in general. closes #677 --- src/core/observer.ts | 7 ++++++- src/qweb/qweb.ts | 2 +- tests/core/observer.test.ts | 17 +++++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/core/observer.ts b/src/core/observer.ts index df642ad7..4f9b955b 100644 --- a/src/core/observer.ts +++ b/src/core/observer.ts @@ -25,7 +25,12 @@ export class Observer { notifyCB() {} observe(value: T, parent?: any): T { - if (value === null || typeof value !== "object" || value instanceof Date) { + if ( + value === null || + typeof value !== "object" || + value instanceof Date || + value instanceof Promise + ) { // fun fact: typeof null === 'object' return value; } diff --git a/src/qweb/qweb.ts b/src/qweb/qweb.ts index 7787673d..8cc81eb1 100644 --- a/src/qweb/qweb.ts +++ b/src/qweb/qweb.ts @@ -86,7 +86,7 @@ interface Utils { [key: string]: any; } -function isComponent(obj) { +function isComponent(obj): boolean { return obj && obj.hasOwnProperty("__owl__"); } diff --git a/tests/core/observer.test.ts b/tests/core/observer.test.ts index f416deec..25a5ac81 100644 --- a/tests/core/observer.test.ts +++ b/tests/core/observer.test.ts @@ -68,6 +68,23 @@ describe("observer", () => { expect(obj.date).not.toBe(date); }); + test("properly handle promises (i.e.: treat them like primitive values", async () => { + const observer = new Observer(); + let resolved = false; + const prom = new Promise((r) => r()); + const obj: any = observer.observe({ prom }); + expect(obj.prom).toBeInstanceOf(Promise); + + obj.prom.then(() => (resolved = true)); + + expect(observer.revNumber(obj)).toBe(1); + + expect(resolved).toBe(false); + await Promise.resolve(); + expect(resolved).toBe(true); + expect(observer.revNumber(obj)).toBe(1); + }); + test("can change values in array", () => { const observer = new Observer(); const obj: any = observer.observe({ arr: [1, 2] });