[FIX] web: fix widget wrapper and weekdays widget

Before this commit, `WidgetWrapper` tried to redirect the call to
`updateState` on its wrapped component but it can happen that the
wrapper is not mounted yet and thus calling a function on its wrapped
component will crash.

This commit changes the implementation of `WidgetWrapper.updateState`
to redirect the call to `this.update` which will update the props of
the wrapped component and not directly its state.

task 2504521

closes odoo/odoo#69421

X-original-commit: 67f09b9a9df248fec26f53758e76070ab3171435
Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
Michael Mattiello (mcm)
2021-04-16 16:04:00 +00:00
parent a7e221ae62
commit 3036fc05b8
3 changed files with 77 additions and 5 deletions
@@ -9,10 +9,15 @@ odoo.define('web.WidgetWrapper', function (require) {
// Public
//----------------------------------------------------------------------
/**
* This function should be used to update the "widget" Component's props,
* not its state!
*
* @param {any} state
* @returns Promise
*/
updateState(state) {
if (this.componentRef.comp.updateState) {
this.componentRef.comp.updateState(state);
}
return this.update(Object.assign({}, this.props, { record: state }));
}
}
return WidgetWrapper;
@@ -19,9 +19,12 @@ odoo.define('web.WeekDays', function (require) {
/**
* @override
* @param {Object} nextProps
* @param {Object} nextProps.record
*/
updateState(state) {
this.state.days = this._prepareData(state.data);
async willUpdateProps(nextProps) {
this.state.days = this._prepareData(nextProps.record.data);
this.mode = nextProps.options.mode;
}
//--------------------------------------------------------------------------
@@ -1,6 +1,11 @@
odoo.define('web.OwlCompatibilityTests', function (require) {
"use strict";
const AbstractField = require('web.AbstractField');
const fieldRegistry = require('web.field_registry');
const widgetRegistry = require('web.widgetRegistry');
const FormView = require('web.FormView');
const { ComponentAdapter, ComponentWrapper, WidgetAdapterMixin } = require('web.OwlCompatibility');
const testUtils = require('web.test_utils');
const Widget = require('web.Widget');
@@ -1301,5 +1306,64 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
parent.destroy();
});
QUnit.module("WidgetWrapper");
QUnit.test("correctly update widget component during mounting", async function (assert) {
// It comes with a fix for a bug that occurred because in some circonstances,
// a widget component can be updated twice.
// Specifically, this occurs when there is 'pad' widget in the form view, because this
// widget does a 'setValue' in its 'renderEdit', which thus resets the widget component.
assert.expect(4);
const PadLikeWidget = fieldRegistry.get('char').extend({
_renderEdit() {
assert.step("setValue");
this._setValue("some value");
}
});
fieldRegistry.add('pad_like', PadLikeWidget);
class WidgetComponent extends Component {}
WidgetComponent.template = xml`<div>Widget</div>`;
widgetRegistry.add("widget_comp", WidgetComponent);
const form = await testUtils.createView({
View: FormView,
model: 'partner',
res_id: 1,
data: {
partner: {
fields: {
id: {string: "id", type:"integer"},
foo: {string: "Foo", type: "char"},
},
records: [{
id: 1,
foo: "value",
}],
},
},
arch: `
<form><sheet><group>
<field name="foo" widget="pad_like" />
<widget name="widget_comp" />
</group></sheet></form>
`,
});
assert.containsOnce(form, ".o_form_view.o_form_readonly");
await testUtils.dom.click(form.$(".o_form_label")[0]);
await testUtils.nextTick(); // wait for quick edit
assert.containsOnce(form, ".o_form_view.o_form_editable");
assert.verifySteps(["setValue"]);
form.destroy();
delete fieldRegistry.map.pad_like;
delete widgetRegistry.map.widget_comp;
});
});
});