[FIX] web: field service: protect async methods

The async methods of field service were not declared in its key async.
This would allow destroyed components to process the results of those
methods (despite an initial call to useService). We fix that.

closes odoo/odoo#135950

X-original-commit: 7955def19c7d4a8c49be472413423bbf3beec2e5
Signed-off-by: Géry Debongnie <ged@odoo.com>
This commit is contained in:
Mathieu Duckerts-Antoine
2023-09-25 07:53:58 +00:00
parent 16179c9399
commit 1995f21d42
2 changed files with 66 additions and 0 deletions
@@ -12,6 +12,7 @@ import { registry } from "@web/core/registry";
export const fieldService = {
dependencies: ["orm"],
async: ["loadFields", "loadPath", "loadPropertyDefinitions"],
start(env, { orm }) {
const cache = new Cache(
(resModel, options) => {
@@ -3,6 +3,9 @@
import { fieldService } from "@web/core/field_service";
import { makeTestEnv } from "@web/../tests/helpers/mock_env";
import { registry } from "@web/core/registry";
import { Component, useState, xml } from "@odoo/owl";
import { useService } from "@web/core/utils/hooks";
import { getFixture, makeDeferred, mount, nextTick } from "@web/../tests/helpers/utils";
const serviceRegistry = registry.category("services");
@@ -270,3 +273,65 @@ QUnit.test("does not store loadFields calls in cache when failed", async (assert
assert.verifySteps(["fields_get", "fields_get"]);
});
QUnit.test("async method loadFields is protected", async (assert) => {
assert.expect(7);
let callFieldService;
class Child extends Component {
static template = xml`
<div class="o_child_component" />
`;
setup() {
this.fieldService = useService("field");
callFieldService = async () => {
assert.step("loadFields called");
await this.fieldService.loadFields("tortoise");
assert.step("loadFields result get");
};
}
}
class Parent extends Component {
static components = { Child };
static template = xml`
<t t-if="state.displayChild">
<Child />
</t>
`;
setup() {
this.state = useState({ displayChild: true });
}
}
const target = getFixture();
const def = makeDeferred();
const env = await makeTestEnv({
serverData,
async mockRPC() {
await def;
},
});
const parent = await mount(Parent, target, { env });
assert.containsOnce(target, ".o_child_component");
callFieldService();
assert.verifySteps(["loadFields called"]);
parent.state.displayChild = false;
await nextTick();
def.resolve();
await nextTick();
assert.verifySteps([]);
try {
await callFieldService();
} catch (e) {
assert.step(e.message);
}
assert.verifySteps(["loadFields called", "Component is destroyed"]);
});