From 2e735d2832b73bfb7f43761e3ebb3368100176c2 Mon Sep 17 00:00:00 2001 From: FrancoisGe Date: Fri, 6 Oct 2023 11:34:08 +0200 Subject: [PATCH] [FIX] web: mockServer onChange should only return fields from view Before this commit, when calling onchange, the mockServer returned all the changes present in the onchanges functions defined on fields. The expected behaviour is to return only the changes required by the view. Part-of: odoo/odoo#137828 --- addons/web/static/tests/helpers/mock_server.js | 13 +++++++++---- addons/web/static/tests/mock_server_tests.js | 15 +++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/addons/web/static/tests/helpers/mock_server.js b/addons/web/static/tests/helpers/mock_server.js index e31d6f94239..2c3c7cf4eea 100644 --- a/addons/web/static/tests/helpers/mock_server.js +++ b/addons/web/static/tests/helpers/mock_server.js @@ -861,7 +861,7 @@ export class MockServer { const onchanges = this.models[modelName].onchanges || {}; const firstOnChange = !fields.length; - const fieldsFromView = Object.keys(specification); + const fieldsFromView = new Set(Object.keys(specification)); let serverValues = {}; const onchangeValues = {}; @@ -874,17 +874,17 @@ export class MockServer { } } if (resId) { - serverValues = this.mockRead(modelName, [args[0], fieldsFromView], kwargs)[0]; + serverValues = this.mockRead(modelName, [args[0], [...fieldsFromView]], kwargs)[0]; } else if (firstOnChange) { // It is the new semantics: no field in arguments means we are in // a default_get + onchange situation - fields = fieldsFromView; + fields = [...fieldsFromView]; fields .filter((fName) => !Object.keys(serverValues).includes(fName) && fName !== "id") .forEach((fName) => { onchangeValues[fName] = false; }); - const defaultValues = this.mockDefaultGet(modelName, [fieldsFromView], kwargs); + const defaultValues = this.mockDefaultGet(modelName, [[...fieldsFromView]], kwargs); for (const fieldName in defaultValues) { const fieldType = this.models[modelName].fields[fieldName].type; if (["one2many", "many2many"].includes(fieldType)) { @@ -913,6 +913,11 @@ export class MockServer { onchanges[field](new Proxy(target, handler)); } }); + for (const fieldName in onchangeValues) { + if (!fieldsFromView.has(fieldName)) { + delete onchangeValues[fieldName]; + } + } return { value: this.convertToOnChange(modelName, onchangeValues, specification), diff --git a/addons/web/static/tests/mock_server_tests.js b/addons/web/static/tests/mock_server_tests.js index 35f0da50a35..555f391ecdd 100644 --- a/addons/web/static/tests/mock_server_tests.js +++ b/addons/web/static/tests/mock_server_tests.js @@ -1425,4 +1425,19 @@ QUnit.module("MockServer", (hooks) => { assert.strictEqual(data.models.bar.records.find((r) => r.id === 7).foo, "A"); assert.strictEqual(data.models.bar.records.find((r) => r.id === 8).foo, "B"); }); + + QUnit.test("performRPC: trigger onchange for new record", async function (assert) { + data.models.bar.onchanges = { + foo: (obj) => { + obj.bool = true; + }, + }; + const server = new MockServer(data, {}); + const result = await server.performRPC("", { + model: "bar", + method: "onchange", + args: [[], {}, [], { foo: {} }], + }); + assert.deepEqual(result.value, { foo: 0 }); + }); });