[IMP] web, *: optimize save record from webclient

This commit, adds a new python method (`web_save`) to save a record, and
optionally read-it again in one rpc call. This optimizes the current
behavior that is to save a record in one rpc, and read-it in a second
rpc.

web_save, will receive the list of IDs of the records to save (if this
list is empty it will create the records, if not, it will write on the
existing records), the list of changed fields, and the unity
specification as optional argument to read the created/modified records
(if the specification is not set, the function will return a list of IDs
of the created/modified records).

closes odoo/odoo#133021

Task-id: 3453184
Related: odoo/enterprise#46559
Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
Jorge Pinna Puissant
2023-09-04 09:19:06 +00:00
parent b28265dbb2
commit ebd538a194
64 changed files with 783 additions and 716 deletions
@@ -32,7 +32,7 @@ QUnit.module("Views", {}, function () {
account_move: accountMoveService,
},
async mockRPC(route) {
if (route === "/web/dataset/call_kw/account.move/write") {
if (route === "/web/dataset/call_kw/account.move/web_save") {
assert.step("tab saved");
def.resolve();
}
@@ -141,7 +141,7 @@ QUnit.module("Barcodes", (hooks) => {
serverData,
arch: '<form><field name="display_name"/></form>',
mockRPC: function (route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
assert.step("save");
}
},
@@ -209,7 +209,7 @@ QUnit.module('Crm Kanban Progressbar', {
</templates>
</kanban>`,
async mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
await def;
}
}
@@ -194,7 +194,7 @@ QUnit.module('favorite filter widget', (hooks) => {
mockRPC: function (route, args) {
if (args.method === 'unlink' && args.model === 'mailing.filter') {
assert.deepEqual(args.args[0], [1], "should pass correct filter ID for deletion");
} else if (args.method === 'write' && args.model === 'mailing.mailing') {
} else if (args.method === 'web_save' && args.model === 'mailing.mailing') {
assert.strictEqual(args.args[1].mailing_filter_id,
false, "filter id should be");
assert.strictEqual(args.args[1].mailing_domain,
@@ -109,8 +109,7 @@ QUnit.module('Subtask Kanban List tests', {
assert.containsOnce(subtaskEl, ".o_field_widget.o_field_project_task_state_selection.subtask_state_widget_col .fa-check-circle.text-success", "The state of the subtask should be Done");
assert.verifySteps([
"project.task/search_read",
"project.task/write",
"project.task/web_read",
"project.task/web_save",
"project.task/search_read",
"project.task/web_read", // read the parent task to recompute the subtask count
]);
@@ -19,9 +19,9 @@ const arch =
const setup_date = DateTime.fromISO('2022-01-03T08:03:44+00:00').toSQL();
function mockRPC(route, { args }) {
if (route === '/web/dataset/call_kw/person/create') {
if (route === '/web/dataset/call_kw/person/web_save' && args[0].length === 0) {
// simulate 'stock.quant' create function which can return existing record
const [values] = args[0];
const values = args[1];
values.create_date = DateTime.now().toSQL();
values.write_date = values.create_date;
var name = values.name;
@@ -32,7 +32,7 @@ function mockRPC(route, { args }) {
d.age = age;
d.job = job;
d.write_date = values.write_date;
return Promise.resolve([d.id]);
return Promise.resolve([{ id: d.id, name: d.name, age: d.age, job: d.job, create_date: d.create_date, write_date: d.write_date }]);
}
}
}
@@ -158,7 +158,7 @@ QUnit.module("QuestionPageOneToManyField", (hooks) => {
</form>
`,
mockRPC(route, args) {
if (args.method === "write" && args.model === "survey") {
if (args.method === "web_save" && args.model === "survey") {
assert.step("save parent form");
}
},
@@ -196,7 +196,7 @@ QUnit.module("QuestionPageOneToManyField", (hooks) => {
</form>
`,
mockRPC(route, args) {
if (args.method === "write" && args.model === "survey") {
if (args.method === "web_save" && args.model === "survey") {
assert.step("save parent form");
throw makeServerError({
description: "This isn't right!",
+7
View File
@@ -66,6 +66,13 @@ class Base(models.AbstractModel):
'records': records,
}
def web_save(self, vals, specification: Dict[str, Dict]) -> List[Dict]:
if self:
self.write(vals)
else:
self = self.create(vals)
return self.with_context(bin_size=True).web_read(specification)
def web_read(self, specification: Dict[str, Dict]) -> List[Dict]:
fields_to_read = list(specification) or ['id']
+23 -1
View File
@@ -84,7 +84,14 @@ function validateArray(name, array) {
}
}
export const UPDATE_METHODS = ["unlink", "create", "write", "action_archive", "action_unarchive"];
export const UPDATE_METHODS = [
"unlink",
"create",
"write",
"web_save",
"action_archive",
"action_unarchive",
];
export class ORM {
constructor(rpc, user) {
@@ -292,6 +299,21 @@ export class ORM {
validateObject("data", data);
return this.call(model, "write", [ids, data], kwargs);
}
/**
* @param {string} model
* @param {number[]} ids
* @param {any} data
* @param {any} [kwargs={}]
* @param {Object} [kwargs.specification]
* @param {Object} [kwargs.context]
* @returns {Promise<any[]>}
*/
webSave(model, ids, data, kwargs = {}) {
validatePrimitiveList("ids", "number", ids);
validateObject("data", data);
return this.call(model, "web_save", [ids, data], kwargs);
}
}
/**
@@ -79,6 +79,10 @@ export class DataPoint extends Reactive {
return this.config.context;
}
get currentCompanyId() {
return this.config.currentCompanyId;
}
// -------------------------------------------------------------------------
// Public
// -------------------------------------------------------------------------
@@ -124,6 +124,7 @@ export class DynamicRecordList extends DynamicList {
resId: data.id || false,
resIds: data.id ? [data.id] : [],
isMonoRecord: true,
currentCompanyId: this.currentCompanyId,
mode,
},
data,
@@ -10,7 +10,13 @@ import { x2ManyCommands } from "@web/core/orm_service";
import { pick } from "@web/core/utils/objects";
import { escape } from "@web/core/utils/strings";
import { DataPoint } from "./datapoint";
import { getFieldContext, parseServerValue } from "./utils";
import {
FetchRecordError,
getBasicEvalContext,
getFieldContext,
getFieldsSpec,
parseServerValue,
} from "./utils";
export class Record extends DataPoint {
static type = "Record";
@@ -439,6 +445,7 @@ export class Record extends DataPoint {
resIds: data.map((r) => r.id),
orderBy: defaultOrderBy || [],
limit: limit || Number.MAX_SAFE_INTEGER,
currentCompanyId: this.currentCompanyId,
context: {}, // will be set afterwards, see "_updateContext" in "_setEvalContext"
};
const options = {
@@ -838,39 +845,56 @@ export class Record extends DataPoint {
if (canProceed === false) {
return false;
}
const kwargs = { context: this.context };
let resId = this.resId;
let fieldSpec = {};
if (!noReload) {
fieldSpec = getFieldsSpec(
this.activeFields,
this.fields,
getBasicEvalContext(this.config)
);
}
const kwargs = {
context: this.context,
specification: fieldSpec,
};
let records = [];
try {
if (creation) {
[resId] = await this.model.orm.create(this.resModel, [changes], kwargs);
} else {
await this.model.orm.write(this.resModel, [resId], changes, kwargs);
}
records = await this.model.orm.webSave(
this.resModel,
this.resId ? [this.resId] : [],
changes,
kwargs
);
} catch (e) {
if (onError) {
return onError(e, { discard: () => this._discard() });
}
if (!this.isInEdition) {
const nextConfig = {};
if (creation) {
nextConfig.resId = resId;
}
await this._load(nextConfig);
await this._load({});
}
throw e;
}
if (creation && records.length) {
const resId = records[0].id;
const resIds = this.resIds.concat([resId]);
this.model._updateConfig(this.config, { resId, resIds }, { noReload: true });
}
if (!noReload) {
const nextConfig = {};
if (creation) {
nextConfig.resId = resId;
nextConfig.resIds = this.resIds.concat([resId]);
if (!records.length) {
throw new FetchRecordError(records.map((r) => r.id));
}
await this._load(nextConfig);
this.model._applyProperties(records, this.config);
if (this.resId) {
this.model._updateSimilarRecords(this, records[0]);
}
if (this.config.isRoot) {
this.model.hooks.onWillLoadRoot(this.config);
}
this._setData(records[0]);
} else {
this.model._updateConfig(this.config, { resId }, { noReload: true });
this._values = { ...this._values, ...this._changes };
if ("id" in this.activeFields) {
this._values.id = resId;
this._values.id = records[0].id;
}
this._changes = {};
this.data = { ...this._values };
@@ -887,13 +911,7 @@ export class Record extends DataPoint {
* be uselessly re-rendered if we replace it by a brand new object.
*/
_setEvalContext() {
const evalContext = {
...this.context,
active_id: this.resId || false,
active_ids: this.resId ? [this.resId] : [],
active_model: this.resModel,
current_company_id: this.model.company.currentCompany.id,
};
const evalContext = getBasicEvalContext(this.config);
const dataContext = this._computeDataContext();
Object.assign(this.evalContext, evalContext, dataContext.withoutVirtualIds);
Object.assign(this.evalContextWithVirtualIds, evalContext, dataContext.withVirtualIds);
@@ -20,6 +20,8 @@ import {
createPropertyActiveField,
extractInfoFromGroupData,
isRelational,
FetchRecordError,
getBasicEvalContext,
} from "./utils";
/**
@@ -44,6 +46,7 @@ import {
* @property {Object} activeFields
* @property {object} context
* @property {boolean} isMonoRecord
* @property {number} currentCompanyId
* @property {boolean} isRoot
* @property {Array} [domain]
* @property {Array} [groupBy]
@@ -86,12 +89,6 @@ const DEFAULT_HOOKS = {
onRecordChanged: () => {},
};
export class FetchRecordError extends Error {
constructor(resIds) {
super(`Can't fetch record(s) ${resIds}. They might have been deleted.`);
}
}
export function fetchRecordErrorHandler(env, error, originalError) {
if (originalError instanceof FetchRecordError) {
env.services.notification.add(originalError.message, { sticky: true, type: "danger" });
@@ -119,7 +116,6 @@ export class RelationalModel extends Model {
*/
setup(params, { action, company, dialog, notification, rpc, user }) {
this.action = action;
this.company = company;
this.dialog = dialog;
this.notification = notification;
this.rpc = rpc;
@@ -133,6 +129,7 @@ export class RelationalModel extends Model {
/** @type {Config} */
this.config = {
isMonoRecord: false,
currentCompanyId: company.currentCompany.id,
...params.config,
isRoot: true,
};
@@ -257,6 +254,9 @@ export class RelationalModel extends Model {
if (currentConfig.isMonoRecord) {
config.resId = "resId" in params ? params.resId : config.resId;
config.resIds = "resIds" in params ? params.resIds : config.resIds;
if (!config.resIds) {
config.resIds = config.resId ? [config.resId] : [];
}
if (!config.resId && config.mode !== "edit") {
config.mode = "edit";
}
@@ -308,13 +308,7 @@ export class RelationalModel extends Model {
this.hooks.onWillLoadRoot(config);
}
if (config.isMonoRecord) {
const evalContext = {
...config.context,
active_id: config.resId,
active_ids: [config.resId],
active_model: config.resModel,
current_company_id: this.company.currentCompany.id,
};
const evalContext = getBasicEvalContext(config);
if (!config.resId) {
return this._loadNewRecord(config, { evalContext });
}
@@ -348,7 +342,7 @@ export class RelationalModel extends Model {
...config,
context: {
...config.context,
current_company_id: this.company.currentCompany.id,
current_company_id: config.currentCompanyId,
},
});
}
@@ -675,6 +675,7 @@ export class StaticList extends DataPoint {
resIds: resId ? [resId] : [],
mode: params.mode || "readonly",
isMonoRecord: true,
currentCompanyId: this.currentCompanyId,
};
const { CREATE, UPDATE } = x2ManyCommands;
const options = {
@@ -48,6 +48,12 @@ export function makeActiveField({
const AGGREGATABLE_FIELD_TYPES = ["float", "integer", "monetary"]; // types that can be aggregated in grouped views
export class FetchRecordError extends Error {
constructor(resIds) {
super(`Can't fetch record(s) ${resIds}. They might have been deleted.`);
}
}
export function addFieldDependencies(activeFields, fields, fieldDependencies = []) {
for (const field of fieldDependencies) {
if (!("readonly" in field)) {
@@ -274,6 +280,16 @@ export function getFieldContext(
};
}
export function getBasicEvalContext(config) {
return {
...config.context,
active_id: config.resId || false,
active_ids: config.resId ? [config.resId] : [],
active_model: config.resModel,
current_company_id: config.currentCompanyId,
};
}
export function getFieldsSpec(
activeFields,
fields,
@@ -627,6 +627,8 @@ export class MockServer {
return this.mockUnlink(args.model, args.args);
case "web_read":
return this.mockWebRead(args.model, args.args, args.kwargs);
case "web_save":
return this.mockWebSave(args.model, args.args, args.kwargs);
case "read_group":
return this.mockReadGroup(args.model, args.kwargs);
case "web_read_group":
@@ -1905,6 +1907,16 @@ export class MockServer {
return this.mockRead(modelName, [records.map((r) => r.id), fieldNames]);
}
mockWebSave(modelName, args, kwargs) {
const ids = args[0];
if (ids.length === 0) {
args[0] = this.mockCreate(modelName, args[1], kwargs);
} else {
this.mockWrite(modelName, args);
}
return this.mockWebRead(modelName, args, kwargs);
}
mockWebRead(modelName, args, kwargs) {
const ids = args[0];
let fieldNames = Object.keys(kwargs.specification);
@@ -10,7 +10,6 @@ import * as BarcodeScanner from "@web/webclient/barcode/barcode_scanner";
let serverData;
let target;
const CREATE = "create";
const NAME_SEARCH = "name_search";
const PRODUCT_PRODUCT = "product.product";
const SALE_ORDER_LINE = "sale_order_line";
@@ -123,8 +122,8 @@ QUnit.module("Fields", (hooks) => {
<field name="${PRODUCT_FIELD_NAME}" options="{'can_scan_barcode': True}"/>
</form>`,
async mockRPC(route, args, performRPC) {
if (args.method === CREATE && args.model === SALE_ORDER_LINE) {
const selectedId = args.args[0][0][PRODUCT_FIELD_NAME];
if (args.method === "web_save" && args.model === SALE_ORDER_LINE) {
const selectedId = args.args[1][PRODUCT_FIELD_NAME];
assert.equal(
selectedId,
selectedRecordTest.id,
@@ -76,8 +76,8 @@ QUnit.module("ViewDialogs", (hooks) => {
<field name="linked_sale_order_line" widget="many2many_tags"/>
</form>`,
async mockRPC(route, args) {
if (args.method === "create" && args.model === "sale_order_line") {
const { product_id: selectedId } = args.args[0][0];
if (args.method === "web_save" && args.model === "sale_order_line") {
const { product_id: selectedId } = args.args[1];
assert.strictEqual(selectedId, false, `there should be no product selected`);
}
},
@@ -132,8 +132,8 @@ QUnit.module("ViewDialogs", (hooks) => {
<field name="linked_sale_order_line" widget="many2many_tags"/>
</form>`,
async mockRPC(route, args) {
if (args.method === "create" && args.model === "sale_order_line") {
const { product_id: selectedId } = args.args[0][0];
if (args.method === "web_save" && args.model === "sale_order_line") {
const { product_id: selectedId } = args.args[1];
assert.strictEqual(selectedId, 111, `the product should be selected`);
}
if (args.method === "some_action") {
@@ -791,7 +791,7 @@ QUnit.module("Views", ({ beforeEach }) => {
<calendar event_open_popup="1" date_start="start" date_stop="stop" all_day="allday" mode="month" />
`,
mockRPC(route, { args, method }) {
if (method === "write") {
if (method === "web_save" && args[0].length !== 0) {
assert.deepEqual(
args[1],
{ name: "event 4 modified" },
@@ -1528,7 +1528,7 @@ QUnit.module("Views", ({ beforeEach }) => {
</calendar>
`,
mockRPC(route, { args, kwargs, method }) {
if (method === "create") {
if (method === "web_save") {
assert.deepEqual(
kwargs.context,
{
@@ -1730,7 +1730,7 @@ QUnit.module("Views", ({ beforeEach }) => {
</calendar>
`,
mockRPC(route, { args, kwargs, method }) {
if (method === "create") {
if (method === "web_save") {
assert.deepEqual(
kwargs.context,
{
@@ -4223,7 +4223,7 @@ QUnit.module("Views", ({ beforeEach }) => {
<calendar event_open_popup="1" create="0" date_start="start" date_stop="stop" mode="month" />
`,
mockRPC(route, { args, method }) {
if (method === "write") {
if (method === "web_save") {
assert.deepEqual(
args[1],
{ name: "event 4 modified" },
@@ -107,6 +107,7 @@ QUnit.module("Fields", (hooks) => {
});
QUnit.test("AceEditorField on html fields works", async function (assert) {
assert.expect(8);
serverData.models.partner.fields.htmlField = {
string: "HTML Field",
type: "html",
@@ -129,7 +130,7 @@ QUnit.module("Fields", (hooks) => {
mockRPC(route, args) {
if (args.method) {
assert.step(args.method);
if (args.method === "write") {
if (args.method === "web_save") {
assert.deepEqual(args.args[1], { foo: "DEF" });
}
if (args.method === "onchange") {
@@ -154,7 +155,7 @@ QUnit.module("Fields", (hooks) => {
await editInput(target, ".o_field_widget[name=foo] textarea", "DEF");
await clickSave(target);
assert.verifySteps(["get_views", "web_read", "write", "web_read"]);
assert.verifySteps(["get_views", "web_read", "web_save"]);
});
QUnit.test("AceEditorField doesn't crash when editing", async (assert) => {
@@ -259,6 +260,6 @@ QUnit.module("Fields", (hooks) => {
await triggerEvents(textArea, null, ["blur"]);
assert.verifySteps(['onchange: [[1],{"foo":"a"},["foo"],{"display_name":{},"foo":{}}]']);
await click(target, ".o_form_button_save");
assert.verifySteps(['write: [[1],{"foo":"a"}]', "web_read: [[1]]"]);
assert.verifySteps(['web_save: [[1],{"foo":"a"}]']);
});
});
@@ -90,7 +90,7 @@ QUnit.module("Fields", (hooks) => {
</templates>
</kanban>`,
mockRPC(route, args) {
if (args.method === "write" && args.model === "partner") {
if (args.method === "web_save" && args.model === "partner") {
assert.step("save");
assert.deepEqual(args.args, [[1], { bar: false }]);
}
@@ -114,12 +114,14 @@ QUnit.module("Fields", (hooks) => {
assert.verifySteps(["save"]);
});
QUnit.test("FavoriteField does not save if autosave option is set to false", async function (assert) {
await makeView({
type: "kanban",
resModel: "partner",
serverData,
arch: `
QUnit.test(
"FavoriteField does not save if autosave option is set to false",
async function (assert) {
await makeView({
type: "kanban",
resModel: "partner",
serverData,
arch: `
<kanban>
<templates>
<t t-name="kanban-box">
@@ -129,29 +131,31 @@ QUnit.module("Fields", (hooks) => {
</t>
</templates>
</kanban>`,
mockRPC(route, args) {
if (args.method === "write" && args.model === "partner") {
assert.step("save");
}
},
domain: [["id", "=", 1]],
});
mockRPC(route, args) {
if (args.method === "web_save" && args.model === "partner") {
assert.step("save");
}
},
domain: [["id", "=", 1]],
});
// click on favorite
await click(target, ".o_field_widget .o_favorite");
assert.containsNone(
target,
".o_kanban_record .o_field_widget .o_favorite > a i.fa.fa-star",
"should not be favorite"
);
assert.strictEqual(
target.querySelector(".o_kanban_record .o_field_widget .o_favorite > a").textContent,
" Add to Favorites",
'the label should say "Add to Favorites"'
);
// click on favorite
await click(target, ".o_field_widget .o_favorite");
assert.containsNone(
target,
".o_kanban_record .o_field_widget .o_favorite > a i.fa.fa-star",
"should not be favorite"
);
assert.strictEqual(
target.querySelector(".o_kanban_record .o_field_widget .o_favorite > a")
.textContent,
" Add to Favorites",
'the label should say "Add to Favorites"'
);
assert.verifySteps([]);
});
assert.verifySteps([]);
}
);
QUnit.test("FavoriteField in form view", async function (assert) {
await makeView({
@@ -249,13 +249,13 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(_route, { method }) {
if (method === "write") {
assert.step("write");
if (method === "web_save") {
assert.step("web_save");
}
},
});
await click(target, ".o_field_widget[name='bar'] input");
assert.verifySteps(["write"]);
assert.verifySteps(["web_save"]);
});
QUnit.test("BooleanToggleField - autosave option set to false", async function (assert) {
@@ -269,8 +269,8 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(_route, { method }) {
if (method === "write") {
assert.step("write");
if (method === "web_save") {
assert.step("web_save");
}
},
});
@@ -190,7 +190,7 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, { args, method }) {
if (method === "write") {
if (method === "web_save") {
assert.strictEqual(args[1].foo, false, "the foo value should be false");
}
},
@@ -223,7 +223,7 @@ QUnit.module("Fields", (hooks) => {
serverData,
arch: '<form><field name="date"/></form>',
mockRPC(route, { args }) {
if (route === "/web/dataset/call_kw/partner/write") {
if (route === "/web/dataset/call_kw/partner/web_save") {
assert.strictEqual(
args[1].date,
"2017-02-22",
@@ -374,7 +374,7 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
assert.deepEqual(args.args[1], { datetime: "2017-02-08 06:00:00" });
}
},
@@ -364,7 +364,7 @@ QUnit.module("Fields", (hooks) => {
serverData,
arch: '<form><field name="datetime"/></form>',
mockRPC(route, { args }) {
if (route === "/web/dataset/call_kw/partner/write") {
if (route === "/web/dataset/call_kw/partner/web_save") {
assert.strictEqual(
args[1].datetime,
false,
@@ -738,7 +738,7 @@ QUnit.module("Fields", (hooks) => {
const webClient = await createWebClient({
serverData,
mockRPC(route, { method, args }) {
if (method === "write") {
if (method === "web_save") {
assert.strictEqual(args[1].foo, rawDomain);
}
if (route === "/web/domain/validate") {
@@ -827,7 +827,7 @@ QUnit.module("Fields", (hooks) => {
// Save
await clickSave(target);
assert.verifySteps(["write", "web_read", "search_count"]);
assert.verifySteps(["web_save", "search_count"]);
assert.strictEqual(target.querySelector(".o_domain_debug_input").value, rawDomain);
});
@@ -39,7 +39,7 @@ QUnit.module("Fields", (hooks) => {
</sheet>
</form>`,
mockRPC(route, { args }) {
if (route === "/web/dataset/call_kw/partner/write") {
if (route === "/web/dataset/call_kw/partner/web_save") {
// 2.3 / 0.5 = 4.6
assert.strictEqual(args[1].qux, 4.6, "the correct float value should be saved");
}
@@ -39,7 +39,7 @@ QUnit.module("Fields", (hooks) => {
</sheet>
</form>`,
mockRPC(route, args) {
if (route === "/web/dataset/call_kw/partner/write") {
if (route === "/web/dataset/call_kw/partner/web_save") {
// 48 / 60 = 0.8
assert.strictEqual(
args.args[1].qux,
@@ -89,7 +89,7 @@ QUnit.module("Fields", (hooks) => {
<field name="qux" widget="float_time"/>
</form>`,
mockRPC(route, args) {
if (route === "/web/dataset/call_kw/partner/write") {
if (route === "/web/dataset/call_kw/partner/web_save") {
assert.strictEqual(
args.args[1].qux,
9.5,
@@ -35,7 +35,7 @@ QUnit.module("Fields", (hooks) => {
<field name="float_field" widget="float_toggle" options="{'factor': 0.125, 'range': [0, 1, 0.75, 0.5, 0.25]}" digits="[5,3]"/>
</form>`,
mockRPC(route, { args }) {
if (route === "/web/dataset/call_kw/partner/write") {
if (route === "/web/dataset/call_kw/partner/web_save") {
// 1.000 / 0.125 = 8
assert.step(args[1].float_field.toString());
}
@@ -317,7 +317,7 @@ QUnit.module("Fields", ({ beforeEach }) => {
</form>`,
resId: 1,
mockRPC(route, { args, method }) {
if (method === "write") {
if (method === "web_save") {
assert.strictEqual(args[1].txt, false, "the txt value should be false");
}
},
@@ -313,7 +313,7 @@ QUnit.module("Fields", (hooks) => {
<field name="document" widget="image" />
</form>`,
mockRPC(_route, { method, args }) {
if (method === "write") {
if (method === "web_save") {
args[1].write_date = lastUpdates[index];
args[1].document = "4 kb";
index++;
@@ -51,7 +51,7 @@ QUnit.module("Fields", (hooks) => {
QUnit.module("Many2ManyBinaryField");
QUnit.test("widget many2many_binary", async function (assert) {
assert.expect(22);
assert.expect(21);
const fakeHTTPService = {
start() {
@@ -106,6 +106,17 @@ QUnit.module("Fields", (hooks) => {
},
});
}
if (args.method === "web_save" && args.model === "turtle") {
assert.deepEqual(args.kwargs.specification, {
display_name: {},
picture_ids: {
fields: {
mimetype: {},
name: {},
},
},
});
}
if (args.method === "web_read" && args.model === "ir.attachment") {
assert.deepEqual(args.kwargs.specification, {
mimetype: {},
@@ -193,8 +204,7 @@ QUnit.module("Fields", (hooks) => {
);
assert.verifySteps([
"/web/dataset/call_kw/ir.attachment/web_read",
"/web/dataset/call_kw/turtle/write",
"/web/dataset/call_kw/turtle/web_read",
"/web/dataset/call_kw/turtle/web_save",
]);
});
@@ -63,8 +63,8 @@ QUnit.module("Fields", (hooks) => {
</group>
</form>`,
mockRPC(route, args) {
if (args.method === "write") {
assert.step("write");
if (args.method === "web_save") {
assert.step("web_save");
assert.deepEqual(args.args[1].timmy, commands.shift());
}
},
@@ -91,7 +91,7 @@ QUnit.module("Fields", (hooks) => {
assert.notOk(checkboxes[0].checked);
assert.ok(checkboxes[1].checked);
assert.verifySteps(["write", "write"]);
assert.verifySteps(["web_save", "web_save"]);
});
QUnit.test("Many2ManyCheckBoxesField (readonly)", async function (assert) {
@@ -175,7 +175,7 @@ QUnit.module("Fields", (hooks) => {
);
assert.containsOnce(target, "div.o_field_widget div.form-check input:checked");
assert.verifySteps(["get_views", "web_read", "name_search", "write", "web_read"]);
assert.verifySteps(["get_views", "web_read", "name_search", "web_save"]);
});
QUnit.test(
@@ -272,7 +272,7 @@ QUnit.module("Fields", (hooks) => {
<field name="timmy" widget="many2many_checkboxes" />
</form>`,
mockRPC(route, { args, method }) {
if (method === "write") {
if (method === "web_save") {
const expectedIds = records.map((r) => r.id);
expectedIds.pop();
assert.deepEqual(args[1].timmy, [[6, false, expectedIds]]);
@@ -327,11 +327,11 @@ QUnit.module("Fields", (hooks) => {
<field name="timmy" widget="many2many_checkboxes" />
</form>`,
async mockRPC(route, { args, method }) {
if (method === "write") {
if (method === "web_save") {
const expectedIds = records.map((r) => r.id);
expectedIds.shift();
assert.deepEqual(args[1].timmy, [[6, false, expectedIds]]);
assert.step("write");
assert.step("web_save");
}
if (method === "name_search") {
assert.step("name_search");
@@ -356,7 +356,7 @@ QUnit.module("Fields", (hooks) => {
assert.notOk(
target.querySelector(".o_field_widget[name='timmy'] input[type='checkbox']").checked
);
assert.verifySteps(["name_search", "write"]);
assert.verifySteps(["name_search", "web_save"]);
});
QUnit.test("Many2ManyCheckBoxesField in a one2many", async function (assert) {
@@ -379,7 +379,7 @@ QUnit.module("Fields", (hooks) => {
</field>
</form>`,
mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
assert.deepEqual(args.args[1], {
p: [[1, 1, { timmy: [[6, false, [15, 12]]] }]],
});
@@ -418,9 +418,9 @@ QUnit.module("Fields", (hooks) => {
<field name="timmy" widget="many2many_checkboxes"/>
</form>`,
mockRPC: function (route, args) {
if (args.method === "create") {
if (args.method === "web_save") {
assert.deepEqual(
args.args[0][0].timmy,
args.args[1].timmy,
[[6, false, [12]]],
"correct values should have been sent to create"
);
@@ -541,7 +541,7 @@ QUnit.module("Fields", (hooks) => {
assert.verifySteps(["get_views", "web_read", "name_search"]);
// save
await clickSave(target);
assert.verifySteps(["onchange", "write", "web_read"]);
assert.verifySteps(["onchange", "web_save"]);
});
QUnit.test("Many2ManyCheckBoxesField in a notebook tab", async function (assert) {
@@ -586,6 +586,6 @@ QUnit.module("Fields", (hooks) => {
assert.containsOnce(target, "div.o_field_widget[name=int_field]");
// save
await clickSave(target);
assert.verifySteps(["get_views", "web_read", "name_search", "write", "web_read"]);
assert.verifySteps(["get_views", "web_read", "name_search", "web_save"]);
});
});
@@ -258,21 +258,30 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, args) {
if (route === "/web/dataset/call_kw/partner_type/write") {
if (
route === "/web/dataset/call_kw/partner_type/web_save" &&
args.args[0].length !== 0
) {
assert.strictEqual(
args.args[1].display_name,
"new name",
"should write 'new_name'"
);
}
if (route === "/web/dataset/call_kw/partner_type/create") {
if (
route === "/web/dataset/call_kw/partner_type/web_save" &&
args.args[0].length === 0
) {
assert.strictEqual(
args.args[0][0].display_name,
args.args[1].display_name,
"A new type",
"should create 'A new type'"
);
}
if (route === "/web/dataset/call_kw/partner/write") {
if (
route === "/web/dataset/call_kw/partner/web_save" &&
args.args[0].length !== 0
) {
const commands = args.args[1].timmy;
// get the created type's id
const createdType = serverData.models.partner_type.records.find((record) => {
@@ -620,7 +629,7 @@ QUnit.module("Fields", (hooks) => {
});
QUnit.test(
"many2many list (non editable): create a new record and click on action button",
"many2many list (non editable): create a new record and click on action button 1",
async function (assert) {
serverData.views = {
"partner_type,false,list": '<tree><field name="display_name"/></tree>',
@@ -647,8 +656,8 @@ QUnit.module("Fields", (hooks) => {
resId: 1,
mockRPC: async (route, args) => {
assert.step(args.method);
if (args.method === "create") {
assert.deepEqual(args.args[0][0], { display_name: "Hello" });
if (args.method === "web_save") {
assert.deepEqual(args.args[1], { display_name: "Hello" });
}
},
});
@@ -674,12 +683,12 @@ QUnit.module("Fields", (hooks) => {
await click(modal, ".o_statusbar_buttons [name='myaction']");
assert.strictEqual(modal.querySelector("[name='display_name'] input").value, "Hello");
assert.verifySteps(["create", "web_read", "action: myaction"]);
assert.verifySteps(["web_save", "action: myaction"]);
}
);
QUnit.test(
"many2many list (non editable): create a new record and click on action button",
"many2many list (non editable): create a new record and click on action button 2",
async function (assert) {
serverData.views = {
"partner_type,false,list": '<tree><field name="display_name"/></tree>',
@@ -706,8 +715,8 @@ QUnit.module("Fields", (hooks) => {
resId: 1,
mockRPC: async (route, args) => {
assert.step(args.method);
if (args.method === "create") {
assert.deepEqual(args.args[0][0], { display_name: "Hello" });
if (args.method === "web_save" && args.args[0].length === 0) {
assert.deepEqual(args.args[1], { display_name: "Hello" });
}
},
});
@@ -752,14 +761,7 @@ QUnit.module("Fields", (hooks) => {
["Hello (edited)"]
);
assert.verifySteps([
"create",
"web_read",
"action: myaction",
"write",
"web_read",
"web_read",
]);
assert.verifySteps(["web_save", "action: myaction", "web_save", "web_read"]);
}
);
@@ -948,8 +950,7 @@ QUnit.module("Fields", (hooks) => {
"get_views", // list view in dialog
"web_search_read", // list view in dialog
"web_read", // relational field (updated)
"write", // save main record
"web_read", // main record
"web_save", // save main record
]);
});
@@ -1055,10 +1056,16 @@ QUnit.module("Fields", (hooks) => {
<field name="timmy" widget="many2many" can_create="false" can_write="false"/>
</form>`,
mockRPC(route, args) {
if (route === "/web/dataset/call_kw/partner/create") {
assert.deepEqual(args.args[0][0], { timmy: [[6, false, [12]]] });
if (
route === "/web/dataset/call_kw/partner/web_save" &&
args.args[0].length === 0
) {
assert.deepEqual(args.args[1], { timmy: [[6, false, [12]]] });
}
if (route === "/web/dataset/call_kw/partner/write") {
if (
route === "/web/dataset/call_kw/partner/web_save" &&
args.args[0].length !== 0
) {
assert.deepEqual(args.args[1], { timmy: [[3, 12]] });
}
},
@@ -1581,7 +1588,7 @@ QUnit.module("Fields", (hooks) => {
await click(target.querySelector(".modal-body input[type=checkbox]"));
await click(target.querySelector(".modal .modal-footer .btn-primary"));
assert.verifySteps(["write", "web_read"]);
assert.verifySteps(["web_save"]);
// there is nothing left to save -> should not do a 'write' RPC
await clickSave(target);
@@ -1649,7 +1656,7 @@ QUnit.module("Fields", (hooks) => {
QUnit.test("onchange with 40+ commands for a many2many", async function (assert) {
// this test ensures that the basic_model correctly handles more LINK_TO
// commands than the limit of the dataPoint (40 for x2many kanban)
assert.expect(21);
assert.expect(20);
// create a lot of partner_types that will be linked by the onchange
const commands = [];
@@ -1685,7 +1692,7 @@ QUnit.module("Fields", (hooks) => {
resId: 1,
mockRPC(route, args) {
assert.step(args.method);
if (args.method === "write") {
if (args.method === "web_save") {
assert.deepEqual(
args.args[1].timmy,
commands.map((c) => [c[0], c[1]]),
@@ -1761,7 +1768,7 @@ QUnit.module("Fields", (hooks) => {
"there should be 40 records displayed on page 1"
);
assert.verifySteps(["write", "web_read", "web_read"]);
assert.verifySteps(["web_save", "web_read"]);
});
QUnit.test("default_get, onchange, onchange on m2m", async function (assert) {
@@ -476,8 +476,8 @@ QUnit.module("Fields", (hooks) => {
</templates>
</kanban>`,
async mockRPC(route, { method, args }) {
if (method === "write") {
assert.step(`write: ${args[1].partner_ids[0][2]}`);
if (method === "web_save") {
assert.step(`web_save: ${args[1].partner_ids[0][2]}`);
}
},
});
@@ -485,7 +485,7 @@ QUnit.module("Fields", (hooks) => {
// add and directly remove an item
await click(target, ".o_popover .o-autocomplete--dropdown-item:first-child");
await click(target, ".o_popover .o_tag .o_delete");
assert.verifySteps(["write: 1", "write: "]);
assert.verifySteps(["web_save: 1", "web_save: "]);
}
);
@@ -198,7 +198,7 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC: (route, { args, method, model, kwargs }) => {
if (route === "/web/dataset/call_kw/partner/write") {
if (route === "/web/dataset/call_kw/partner/web_save") {
var commands = args[1].timmy;
assert.strictEqual(commands.length, 1, "should have generated one command");
assert.strictEqual(
@@ -208,7 +208,7 @@ QUnit.module("Fields", (hooks) => {
);
assert.deepEqual(commands[0][2], [12, 13], "new value should be [12, 13]");
}
if (method === "web_read" && model === "partner_type") {
if ((method === "web_read" || method === "web_save") && model === "partner_type") {
assert.deepEqual(
kwargs.specification,
{ display_name: {}, color: {} },
@@ -585,8 +585,8 @@ QUnit.module("Fields", (hooks) => {
serverData,
arch: '<form><field name="timmy" widget="many2many_tags"/></form>',
mockRPC: (route, { args }) => {
if (route === "/web/dataset/call_kw/partner/create") {
const commands = args[0][0].timmy;
if (route === "/web/dataset/call_kw/partner/web_save") {
const commands = args[1].timmy;
assert.strictEqual(commands.length, 1, "should have generated one command");
assert.strictEqual(
commands[0][0],
@@ -639,7 +639,7 @@ QUnit.module("Fields", (hooks) => {
<field name="timmy" widget="many2many_tags" options="{'color_field': 'color'}"/>
</form>`,
mockRPC: (route, { args, method }) => {
if (method === "write") {
if (method === "web_save") {
assert.step(JSON.stringify(args[1]));
}
},
@@ -1570,8 +1570,8 @@ QUnit.module("Fields", (hooks) => {
if (args.method === "name_create") {
throw makeServerError({ type: "ValidationError" });
}
if (args.method === "create") {
assert.deepEqual(args.args[0][0], {
if (args.method === "web_save") {
assert.deepEqual(args.args[1], {
color: 8,
name: "new partner",
});
@@ -1770,16 +1770,13 @@ QUnit.module("Fields", (hooks) => {
if (args.method === "web_read") {
await def;
}
}
},
});
patchWithCleanup(form.env.services.notification, {
add: () => assert.step("notification"),
});
assert.verifySteps([
"get_views",
"onchange",
]);
assert.verifySteps(["get_views", "onchange"]);
assert.containsNone(target, ".o_tag");
@@ -1788,10 +1785,7 @@ QUnit.module("Fields", (hooks) => {
await clickOpenedDropdownItem(target, "timmy", "gold");
assert.containsNone(target, ".o_tag");
assert.verifySteps([
"name_search",
"web_read",
]);
assert.verifySteps(["name_search", "web_read"]);
await clickSave(target);
assert.doesNotHaveClass(target, "[name='timmy']", "o_field_invalid");
@@ -1801,10 +1795,7 @@ QUnit.module("Fields", (hooks) => {
def.resolve();
await nextTick();
assert.verifySteps([
"create",
"web_read",
]);
assert.verifySteps(["web_save"]);
});
QUnit.test("Many2ManyTagsField with option 'no_quick_create' set to true", async (assert) => {
@@ -10,7 +10,6 @@ import * as BarcodeScanner from "@web/webclient/barcode/barcode_scanner";
let serverData;
let target;
const CREATE = "create";
const NAME_SEARCH = "name_search";
const PRODUCT_PRODUCT = "product.product";
const SALE_ORDER_LINE = "sale_order_line";
@@ -133,8 +132,8 @@ QUnit.module("Fields", (hooks) => {
</form>
`,
async mockRPC(route, args, performRPC) {
if (args.method === CREATE && args.model === SALE_ORDER_LINE) {
const selectedId = args.args[0][0][PRODUCT_FIELD_NAME];
if (args.method === "web_save" && args.model === SALE_ORDER_LINE) {
const selectedId = args.args[1][PRODUCT_FIELD_NAME];
assert.equal(
selectedId,
selectedRecordTest.id,
@@ -172,8 +171,8 @@ QUnit.module("Fields", (hooks) => {
<field name="${PRODUCT_FIELD_NAME}" options="{'can_scan_barcode': True}"/>
</form>`,
async mockRPC(route, args, performRPC) {
if (args.method === CREATE && args.model === SALE_ORDER_LINE) {
const selectedId = args.args[0][0][PRODUCT_FIELD_NAME];
if (args.method === "web_save" && args.model === SALE_ORDER_LINE) {
const selectedId = args.args[1][PRODUCT_FIELD_NAME];
assert.equal(
selectedId,
selectedRecordTest.id,
@@ -317,7 +317,7 @@ QUnit.module("Fields", (hooks) => {
assert.deepEqual(args[0], [4], "should call get_formview_id with correct id");
return Promise.resolve(false);
}
if (method === "write") {
if (method === "web_save") {
throw new Error("should not call write");
}
},
@@ -385,8 +385,8 @@ QUnit.module("Fields", (hooks) => {
if (method === "get_formview_id") {
return Promise.resolve(false);
}
if (method === "write") {
assert.step("write");
if (method === "web_save") {
assert.step("web_save");
}
},
});
@@ -402,7 +402,7 @@ QUnit.module("Fields", (hooks) => {
// save and close modal
await clickSave(target.querySelectorAll(".modal")[1]);
assert.verifySteps(["write"]);
assert.verifySteps(["web_save"]);
// save form
await clickSave(target);
assert.verifySteps([]);
@@ -682,7 +682,7 @@ QUnit.module("Fields", (hooks) => {
<field name="trululu" />
</tree>`,
mockRPC(route, args) {
if (args.method === "create" || args.method === "write") {
if (args.method === "web_save") {
assert.step(`${args.method}: ${JSON.stringify(args.args)}`);
}
},
@@ -696,14 +696,14 @@ QUnit.module("Fields", (hooks) => {
await selectDropdownItem(target, "trululu", "Create and edit...");
await clickSave(target.querySelector(".modal"));
assert.verifySteps([`create: [[{"name":"yy"}]]`]);
assert.verifySteps([`web_save: [[],{"name":"yy"}]`]);
assert.strictEqual(
target.querySelector(".o_field_widget[name=trululu] input").value,
"yy"
);
await click(target);
assert.verifySteps([`write: [[1],{"trululu":5}]`]);
assert.verifySteps([`web_save: [[1],{"trululu":5}]`]);
assert.strictEqual(
target.querySelector(".o_data_cell[name=trululu]").textContent,
"yy"
@@ -827,7 +827,7 @@ QUnit.module("Fields", (hooks) => {
"get_formview_id",
"get_views",
"web_read",
"write",
"web_save",
"read",
"onchange",
]);
@@ -907,7 +907,7 @@ QUnit.module("Fields", (hooks) => {
<field name="trululu"/>
</tree>`,
mockRPC(route, { method, args }) {
if (method === "write") {
if (method === "web_save") {
assert.step(method);
assert.deepEqual(args[1], { trululu: false });
}
@@ -924,7 +924,7 @@ QUnit.module("Fields", (hooks) => {
await click(target, ".o_list_view");
assert.strictEqual(target.querySelector(".o_data_row").textContent, "");
assert.verifySteps(["write"]);
assert.verifySteps(["web_save"]);
});
QUnit.test("focus tracking on a many2one in a list", async function (assert) {
@@ -1117,7 +1117,7 @@ QUnit.module("Fields", (hooks) => {
</sheet>
</form>`,
mockRPC(route, { args }) {
if (route === "/web/dataset/call_kw/partner/write") {
if (route === "/web/dataset/call_kw/partner/web_save") {
assert.strictEqual(args[1].trululu, 20, "should write the correct id");
}
},
@@ -1372,7 +1372,7 @@ QUnit.module("Fields", (hooks) => {
assert.step(method);
return Object.keys(namegets).map((id) => [parseInt(id), namegets[id]]);
}
if (method === "write") {
if (method === "web_save") {
assert.step(method);
assert.deepEqual(args[1], {
trululu: 2,
@@ -1411,7 +1411,7 @@ QUnit.module("Fields", (hooks) => {
);
await clickSave(target);
assert.verifySteps(["write", "web_read"]);
assert.verifySteps(["web_save"]);
});
QUnit.test("many2one search with trailing and leading spaces", async function (assert) {
@@ -1603,10 +1603,10 @@ QUnit.module("Fields", (hooks) => {
assert.step("name_create");
await def;
}
if (method === "create") {
assert.step("create");
if (method === "web_save") {
assert.step("web_save");
assert.strictEqual(
args[0][0].trululu,
args[1].trululu,
newRecordId,
"should create with the correct m2o id"
);
@@ -1626,7 +1626,7 @@ QUnit.module("Fields", (hooks) => {
def.resolve();
await nextTick();
assert.verifySteps(["create"]);
assert.verifySteps(["web_save"]);
});
QUnit.test(
@@ -1675,9 +1675,9 @@ QUnit.module("Fields", (hooks) => {
assert.step("name_create");
await def;
}
if (method === "create") {
assert.step("create");
const [values] = args[0];
if (method === "web_save") {
assert.step("web_save");
const values = args[1];
assert.strictEqual(values.trululu, newRecordId);
}
},
@@ -1706,7 +1706,7 @@ QUnit.module("Fields", (hooks) => {
def.resolve();
await nextTick();
assert.verifySteps(["create"]);
assert.verifySteps(["web_save"]);
assert.containsN(target, ".o_data_row", 4);
assert.strictEqual(target.querySelector(".o_data_row .o_data_cell").textContent, "b");
});
@@ -1736,10 +1736,10 @@ QUnit.module("Fields", (hooks) => {
assert.step("name_create");
await def;
}
if (method === "create") {
assert.step("create");
if (method === "web_save") {
assert.step("web_save");
assert.strictEqual(
args[0][0].p[0][2].trululu,
args[1].p[0][2].trululu,
newRecordId,
"should create with the correct m2o id"
);
@@ -1762,7 +1762,7 @@ QUnit.module("Fields", (hooks) => {
await def.resolve();
await nextTick();
assert.verifySteps(["create"]);
assert.verifySteps(["web_save"]);
assert.strictEqual(
target.querySelector(".o_data_row .o_data_cell").textContent,
"b",
@@ -1836,8 +1836,8 @@ QUnit.module("Fields", (hooks) => {
if (method === "name_create") {
await def;
}
if (method === "create") {
assert.deepEqual(args[0][0].p[0][2].trululu, newRecordId);
if (method === "web_save") {
assert.deepEqual(args[1].p[0][2].trululu, newRecordId);
}
},
});
@@ -2419,12 +2419,12 @@ QUnit.module("Fields", (hooks) => {
</sheet>
</form>`,
mockRPC(route, { args, method }) {
if (method === "create") {
if (method === "web_save") {
assert.deepEqual(
args[0][0],
args[1],
{
int_field: 1,
timmy: [[0, args[0][0].timmy[0][1], { display_name: "new value" }]],
timmy: [[0, args[1].timmy[0][1], { display_name: "new value" }]],
},
"should send the correct values to create"
);
@@ -2477,9 +2477,9 @@ QUnit.module("Fields", (hooks) => {
</sheet>
</form>`,
mockRPC(route, { args, method }) {
if (method === "create") {
if (method === "web_save") {
assert.deepEqual(
args[0][0].turtles,
args[1].turtles,
[
[4, 2],
[4, 3],
@@ -2647,8 +2647,8 @@ QUnit.module("Fields", (hooks) => {
if (route === "/web/dataset/call_kw/partner_type/get_formview_id") {
return false;
}
if (route === "/web/dataset/call_kw/partner_type/write") {
assert.step("partner_type write");
if (route === "/web/dataset/call_kw/partner_type/web_save") {
assert.step("partner_type web_save");
}
},
});
@@ -2676,7 +2676,7 @@ QUnit.module("Fields", (hooks) => {
await clickSave(target.querySelectorAll(".modal")[1]);
await clickSave(target);
assert.verifySteps(["onchange sequence", "partner_type write"]);
assert.verifySteps(["onchange sequence", "partner_type web_save"]);
});
QUnit.test("autocompletion in a many2one, in form view with a domain", async function (assert) {
@@ -2932,8 +2932,8 @@ QUnit.module("Fields", (hooks) => {
if (method === "name_create") {
throw makeServerError({ type: "ValidationError" });
}
if (method === "create") {
assert.deepEqual(args[0][0], { name: "xyz" });
if (method === "web_save") {
assert.deepEqual(args[1], { name: "xyz" });
}
},
});
@@ -2984,7 +2984,7 @@ QUnit.module("Fields", (hooks) => {
});
QUnit.test(
"failing quick create on a many2one inside a one2many because ValidationError",
"failing quick create on a many2one inside a one2many because ValidationError",
async function (assert) {
assert.expect(4);
@@ -3005,8 +3005,8 @@ QUnit.module("Fields", (hooks) => {
if (method === "name_create") {
throw makeServerError({ type: "ValidationError" });
}
if (method === "create") {
assert.deepEqual(args[0][0], { name: "xyz" });
if (method === "web_save") {
assert.deepEqual(args[1], { name: "xyz" });
}
},
});
@@ -3590,8 +3590,7 @@ QUnit.module("Fields", (hooks) => {
"web_search_read", // to display results in the dialog
"name_search",
"onchange",
"write",
"web_read",
"web_save",
]);
}
);
@@ -3640,8 +3639,7 @@ QUnit.module("Fields", (hooks) => {
"web_search_read", // to display results in the dialog
"name_search",
"onchange",
"write",
"web_read",
"web_save",
]);
}
);
@@ -4394,8 +4392,8 @@ QUnit.module("Fields", (hooks) => {
if (method === "get_formview_id") {
return 98;
}
if (method === "write") {
assert.step("write");
if (method === "web_save") {
assert.step("web_save");
}
},
});
@@ -4416,7 +4414,7 @@ QUnit.module("Fields", (hooks) => {
target.querySelector(".o_field_widget[name=foo] input").value,
"some value"
);
assert.verifySteps(["write"]);
assert.verifySteps(["web_save"]);
});
QUnit.test("create and edit, save and then discard", async function (assert) {
@@ -535,7 +535,7 @@ QUnit.module("Fields", (hooks) => {
</field>
</form>`,
async mockRPC(route, args) {
if (args.method === "create") {
if (args.method === "web_save") {
await def;
}
},
@@ -632,7 +632,7 @@ QUnit.module("Fields", (hooks) => {
await clickSave(target.querySelector(".modal"));
await clickSave(target);
assert.verifySteps(["write", "web_read"]);
assert.verifySteps(["web_save"]);
});
QUnit.test("one2many list editable with cell readonly modifier", async function (assert) {
@@ -656,7 +656,7 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, args) {
if (route === "/web/dataset/call_kw/partner/write") {
if (route === "/web/dataset/call_kw/partner/web_save") {
assert.deepEqual(
args.args[1].p[0][2],
{ foo: "ff", qux: 99, turtles: [] },
@@ -732,8 +732,8 @@ QUnit.module("Fields", (hooks) => {
await def;
assert.step("onchange");
}
if (args.method === "write") {
assert.step("write");
if (args.method === "web_save") {
assert.step("web_save");
assert.deepEqual(args.args[1].p, [
[1, 1, { int_field: 9 }],
[1, 2, { int_field: 10, qux: 99 }],
@@ -748,7 +748,7 @@ QUnit.module("Fields", (hooks) => {
// resolve the onchange promise
def.resolve();
await nextTick();
assert.verifySteps(["onchange", "write"]);
assert.verifySteps(["onchange", "web_save"]);
}
);
@@ -1122,7 +1122,7 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
const expectedResultTurtles = [
[1, 1, { turtle_foo: "hop", partner_ids: [[4, 2]] }],
];
@@ -1191,7 +1191,7 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
const expectedResultTurtles = [
[1, 1, { turtle_foo: "hop", partner_ids: [[4, 2]] }],
[
@@ -1259,7 +1259,7 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, args) {
if (route === "/web/dataset/call_kw/partner/write") {
if (route === "/web/dataset/call_kw/partner/web_save") {
var expectedResultTurtles = [
[
1,
@@ -2546,7 +2546,7 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
assert.step(args.method);
assert.deepEqual(args.args[1].p, [
[1, 2, { int_field: 0 }],
@@ -2584,7 +2584,7 @@ QUnit.module("Fields", (hooks) => {
await clickSave(target);
assert.verifySteps(["write"]);
assert.verifySteps(["web_save"]);
assert.deepEqual(getNodesTextContent(target.querySelectorAll(".o_data_cell.o_list_char")), [
"blip",
"My little Foo Value",
@@ -2734,8 +2734,8 @@ QUnit.module("Fields", (hooks) => {
readIDs = args.args[0];
checkRead = false;
}
if (args.method === "write") {
assert.step("write");
if (args.method === "web_save") {
assert.step("web_save");
saveCount++;
const commands = args.args[1].p;
switch (saveCount) {
@@ -2896,7 +2896,7 @@ QUnit.module("Fields", (hooks) => {
// save
await clickSave(target);
assert.verifySteps(["write", "write", "write"]);
assert.verifySteps(["web_save", "web_save", "web_save"]);
});
QUnit.test(
@@ -3729,7 +3729,7 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, args) {
if (route === "/web/dataset/call_kw/partner/write") {
if (route === "/web/dataset/call_kw/partner/web_save") {
const commands = args.args[1].p;
assert.deepEqual(commands, [[3, 1]], "should send a command 3 (unlink)");
}
@@ -3770,7 +3770,7 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, args) {
if (route === "/web/dataset/call_kw/partner/write") {
if (route === "/web/dataset/call_kw/partner/web_save") {
const commands = args.args[1].p;
assert.deepEqual(commands, [[2, 1]]);
}
@@ -3823,7 +3823,7 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, args) {
if (route === "/web/dataset/call_kw/partner/write") {
if (route === "/web/dataset/call_kw/partner/web_save") {
const commands = args.args[1].p;
assert.deepEqual(commands, [
[
@@ -4120,7 +4120,7 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC: function (route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
nbWrite++;
assert.deepEqual(args.args[1], {
p: [
@@ -4185,7 +4185,7 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
// Would be nice to assert this way, but we don't control the virtual ids index
// assert.deepEqual(args.args[1].p, [
// [0, "virtual_2", { foo: "gemuse" }],
@@ -4361,7 +4361,7 @@ QUnit.module("Fields", (hooks) => {
await clickSave(target);
assert.containsNone(target, "tr.o_data_row");
assert.verifySteps(["get_views", "web_read", "onchange", "onchange", "write", "web_read"]);
assert.verifySteps(["get_views", "web_read", "onchange", "onchange", "web_save"]);
});
QUnit.test("discard O2M field with close button", async function (assert) {
@@ -4816,7 +4816,7 @@ QUnit.module("Fields", (hooks) => {
"9"
);
assert.verifySteps(["get_views", "web_read", "onchange", "onchange", "write", "web_read"]);
assert.verifySteps(["get_views", "web_read", "onchange", "onchange", "web_save"]);
});
QUnit.test("editable o2m, pressing ESC discard current changes", async function (assert) {
@@ -5118,7 +5118,7 @@ QUnit.module("Fields", (hooks) => {
await click(getPickerCell("1").at(0));
await clickSave(target);
assert.verifySteps(["get_views", "web_read", "onchange", "write", "web_read"]);
assert.verifySteps(["get_views", "web_read", "onchange", "web_save"]);
});
QUnit.test("one2many and onchange only write modified field", async function (assert) {
@@ -5162,7 +5162,7 @@ QUnit.module("Fields", (hooks) => {
</field>
</form>`,
mockRPC: function (method, args) {
if (args.method === "write") {
if (args.method === "web_save") {
assert.deepEqual(
args.args[1].turtles,
[
@@ -5494,7 +5494,7 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
assert.deepEqual(args.args[1].p, [
[
0,
@@ -5936,10 +5936,10 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, args) {
if (route === "/web/dataset/call_kw/turtle/create") {
if (route === "/web/dataset/call_kw/turtle/web_save") {
assert.ok(args.args, "should write on the turtle record");
}
if (route === "/web/dataset/call_kw/partner/write") {
if (route === "/web/dataset/call_kw/partner/web_save") {
assert.strictEqual(args.args[0][0], 1, "should write on the partner record 1");
assert.deepEqual(
args.args[1].turtles,
@@ -6037,7 +6037,7 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, args) {
if (route === "/web/dataset/call_kw/turtle/write") {
if (route === "/web/dataset/call_kw/turtle/web_save") {
assert.strictEqual(args.args[0].length, 1, "should write on the turtle record");
assert.deepEqual(
args.args[1],
@@ -6045,7 +6045,7 @@ QUnit.module("Fields", (hooks) => {
"should write only the product_id on the turtle record"
);
}
if (route === "/web/dataset/call_kw/partner/write") {
if (route === "/web/dataset/call_kw/partner/web_save") {
assert.strictEqual(args.args[0][0], 1, "should write on the partner record 1");
assert.strictEqual(
args.args[1].turtles[0][0],
@@ -6301,10 +6301,10 @@ QUnit.module("Fields", (hooks) => {
</field>
</form>`,
mockRPC(route, args) {
if (args.method === "create") {
const virtualID = args.args[0][0].turtles[0][1];
if (args.method === "web_save") {
const virtualID = args.args[1].turtles[0][1];
assert.deepEqual(
args.args[0][0].turtles,
args.args[1].turtles,
[[0, virtualID, { turtle_foo: "cat" }]],
"should send proper commands"
);
@@ -6478,7 +6478,7 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
assert.deepEqual(
args.args[1].turtles,
[
@@ -6872,7 +6872,7 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
assert.deepEqual(args.args[1].turtles, [
[
1,
@@ -6926,7 +6926,7 @@ QUnit.module("Fields", (hooks) => {
if (route === "/web/dataset/call_kw/partner/get_formview_id") {
return Promise.resolve(false);
}
if (args.method === "write") {
if (args.method === "web_save") {
assert.deepEqual(
args.args[1].timmy,
[[6, false, [12]]],
@@ -7330,7 +7330,7 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
assert.step(args.method);
assert.strictEqual(args.args[1].p.length, 1);
const command = args.args[1].p[0];
@@ -7424,7 +7424,7 @@ QUnit.module("Fields", (hooks) => {
// click all buttons
await click(target, btn1Disabled);
assert.verifySteps(["write", "button_disabled_partner_4"]);
assert.verifySteps(["web_save", "button_disabled_partner_4"]);
await click(target, btn1Warn);
await click(target, btn2Disabled);
await click(target, btn2Warn);
@@ -7504,7 +7504,7 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
const commands = args.args[1].turtles;
assert.deepEqual(commands, [
[0, commands[0][1], { turtle_foo: "default foo turtle" }],
@@ -7551,7 +7551,7 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
const commands = args.args[1].turtles;
assert.deepEqual(commands, [
[0, commands[0][1], { turtle_foo: "default foo turtle" }],
@@ -8133,7 +8133,7 @@ QUnit.module("Fields", (hooks) => {
});
QUnit.test("editable list: contexts are correctly sent", async function (assert) {
assert.expect(5);
assert.expect(4);
serverData.models.partner.records[0].timmy = [12];
@@ -8166,7 +8166,7 @@ QUnit.module("Fields", (hooks) => {
);
assert.deepEqual(args.kwargs.specification.timmy.context, { key2: "hello" });
}
if (args.method === "write") {
if (args.method === "web_save") {
assert.deepEqual(
args.kwargs.context,
{
@@ -8174,8 +8174,9 @@ QUnit.module("Fields", (hooks) => {
someKey: "some value",
uid: 7,
},
"write context"
"read partner context"
);
assert.deepEqual(args.kwargs.specification.timmy.context, { key2: "hello" });
}
},
resId: 1,
@@ -8406,7 +8407,7 @@ QUnit.module("Fields", (hooks) => {
</field>
</form>`,
mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
assert.deepEqual(args.args[1].p[0][2], {
p: [[1, 1, { display_name: "new name" }]],
});
@@ -8534,7 +8535,7 @@ QUnit.module("Fields", (hooks) => {
});
QUnit.test("editing tabbed one2many (editable=bottom)", async function (assert) {
assert.expect(11);
assert.expect(10);
serverData.models.partner.records[0].turtles = [];
for (let i = 0; i < 42; i++) {
@@ -8560,7 +8561,7 @@ QUnit.module("Fields", (hooks) => {
resId: 1,
mockRPC(route, args) {
assert.step(args.method);
if (args.method === "write") {
if (args.method === "web_save") {
assert.strictEqual(
args.args[1].turtles[0][0],
0,
@@ -8578,7 +8579,7 @@ QUnit.module("Fields", (hooks) => {
await clickSave(target);
assert.containsN(target, "tr.o_data_row", 40);
assert.verifySteps(["get_views", "web_read", "onchange", "write", "web_read"]);
assert.verifySteps(["get_views", "web_read", "onchange", "web_save"]);
});
QUnit.test("editing tabbed one2many (editable=bottom), again...", async function (assert) {
@@ -8612,7 +8613,7 @@ QUnit.module("Fields", (hooks) => {
});
QUnit.test("editing tabbed one2many (editable=top)", async function (assert) {
assert.expect(14);
assert.expect(13);
serverData.models.partner.records[0].turtles = [];
serverData.models.turtle.fields.turtle_foo.default = "default foo";
@@ -8639,7 +8640,7 @@ QUnit.module("Fields", (hooks) => {
resId: 1,
mockRPC(route, args) {
assert.step(args.method);
if (args.method === "write") {
if (args.method === "web_save") {
assert.strictEqual(args.args[1].turtles[0][0], 0);
assert.deepEqual(args.args[1].turtles[0][2], { turtle_foo: "rainbow dash" });
}
@@ -8657,7 +8658,7 @@ QUnit.module("Fields", (hooks) => {
await clickSave(target);
assert.containsN(target, "tr.o_data_row", 40);
assert.verifySteps(["get_views", "web_read", "web_read", "onchange", "write", "web_read"]);
assert.verifySteps(["get_views", "web_read", "web_read", "onchange", "web_save"]);
});
QUnit.test(
@@ -8897,14 +8898,14 @@ QUnit.module("Fields", (hooks) => {
</sheet>
</form>`,
mockRPC(route, args) {
if (args.method === "create") {
if (args.method === "web_save") {
assert.strictEqual(
args.args[0][0].p[0][0],
args.args[1].p[0][0],
0,
"should send a command 0 (CREATE) for p"
);
assert.deepEqual(
args.args[0][0].p[0][2],
args.args[1].p[0][2],
{ turtles: [[4, 1]] },
"should send the correct values"
);
@@ -8978,7 +8979,7 @@ QUnit.module("Fields", (hooks) => {
throw makeServerError({ type: "ValidationError" });
}
}
if (args.method === "write") {
if (args.method === "web_save") {
assert.deepEqual(
args.args[1].turtles[0],
[1, 2, { turtle_foo: "foo" }],
@@ -9008,7 +9009,7 @@ QUnit.module("Fields", (hooks) => {
});
QUnit.test("propagate context to sub views without default_* keys", async function (assert) {
assert.expect(7);
assert.expect(6);
await makeView({
type: "form",
@@ -9138,8 +9139,8 @@ QUnit.module("Fields", (hooks) => {
</sheet>
</form>`,
mockRPC(route, args) {
if (args.method === "create") {
const commands = args.args[0][0].p;
if (args.method === "web_save") {
const commands = args.args[1].p;
assert.deepEqual(commands, [
[
0,
@@ -10595,8 +10596,7 @@ QUnit.module("Fields", (hooks) => {
"onchange", // main record
"onchange", // line 1
"onchange", // line 2
"create",
"web_read", // main record
"web_save",
]);
}
);
@@ -10620,7 +10620,7 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, args) {
if (route === "/web/dataset/call_kw/partner/write") {
if (route === "/web/dataset/call_kw/partner/web_save") {
args.args[1].p[0][2].datetime = "2018-04-05 12:00:00";
}
},
@@ -13033,8 +13033,8 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, args) {
if (args.method === "write") {
assert.step("write"); // should not happen
if (args.method === "web_save") {
assert.step("web_save"); // should not happen
}
},
});
@@ -13051,7 +13051,7 @@ QUnit.module("Fields", (hooks) => {
assert.containsNone(target, ".o_kanban_record:not(.o_kanban_ghost)");
await clickSave(target);
assert.verifySteps(["write"]);
assert.verifySteps(["web_save"]);
});
QUnit.test("toggle boolean in o2m with the formView in edition", async function (assert) {
@@ -13082,7 +13082,7 @@ QUnit.module("Fields", (hooks) => {
assert.verifySteps(["get_views partner", "web_read partner"]);
await click(target, ".o_boolean_toggle");
assert.verifySteps(["onchange partner", "write turtle", "web_read turtle"]);
assert.verifySteps(["onchange partner", "web_save turtle"]);
});
QUnit.test("create a new record with an x2m invisible", async function (assert) {
@@ -13132,11 +13132,9 @@ QUnit.module("Fields", (hooks) => {
},
};
}
if (args.method === "create") {
const commands = args.args[0][0].p;
if (args.method === "web_save") {
const commands = args.args[1].p;
assert.deepEqual(commands, [[0, commands[0][1], { int_field: 4, trululu: 1 }]]);
}
if (args.method === "web_read") {
assert.deepEqual(args.kwargs.specification, {
display_name: {},
p: {},
@@ -13149,7 +13147,7 @@ QUnit.module("Fields", (hooks) => {
assert.verifySteps(["get_views", "onchange"]);
await click(target, ".o_form_button_save");
assert.verifySteps(["create", "web_read"]);
assert.verifySteps(["web_save"]);
});
QUnit.test("edit a record with an x2m invisible", async function (assert) {
@@ -13176,10 +13174,15 @@ QUnit.module("Fields", (hooks) => {
turtles: {},
});
}
if (args.method === "write") {
if (args.method === "web_save") {
assert.deepEqual(args.args[1], {
foo: "plop",
});
assert.deepEqual(args.kwargs.specification, {
display_name: {},
foo: {},
turtles: {},
});
}
},
resId: 1,
@@ -13190,7 +13193,7 @@ QUnit.module("Fields", (hooks) => {
await editInput(target, "[name='foo'] input", "plop");
await clickSave(target);
assert.verifySteps(["write partner", "web_read partner"]);
assert.verifySteps(["web_save partner"]);
});
QUnit.test("can't select a record in a one2many", async function (assert) {
@@ -13682,7 +13685,7 @@ QUnit.module("Fields", (hooks) => {
await click(target.querySelector(".modal .o_form_button_save"));
assert.strictEqual(target.querySelector(".o_data_row").textContent, "changed5");
await click(target, ".o_form_button_save");
assert.verifySteps(["create: partner", "web_read: partner"]);
assert.verifySteps(["web_save: partner"]);
assert.strictEqual(target.querySelector(".o_data_row").textContent, "changed5");
});
@@ -13768,8 +13771,8 @@ QUnit.module("Fields", (hooks) => {
};
const mockRPC = async (route, args) => {
if (args.method === "write") {
assert.step("write");
if (args.method === "web_save") {
assert.step("web_save");
assert.deepEqual(args.args[1], {
p: [[0, args.args[1].p[0][1], { display_name: "a name" }]],
});
@@ -13792,7 +13795,7 @@ QUnit.module("Fields", (hooks) => {
await nextTick();
doAction(webClient, 2);
await nextTick();
assert.verifySteps(["write"]);
assert.verifySteps(["web_save"]);
def.resolve();
await nextTick();
@@ -13979,7 +13982,7 @@ QUnit.module("Fields", (hooks) => {
</group>
</form>`,
mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
assert.deepEqual(args.args[1], {
int_field: 16,
p: [
@@ -83,8 +83,8 @@ QUnit.module("Fields", (hooks) => {
serverData,
arch: '<form><field name="document" widget="pdf_viewer"/></form>',
async mockRPC(_route, { method, args }) {
if (method === "create") {
assert.deepEqual(args[0], [{ document: btoa("test") }]);
if (method === "web_save") {
assert.deepEqual(args[1], { document: btoa("test") });
}
},
});
@@ -41,7 +41,7 @@ QUnit.module("Fields", (hooks) => {
<field name="float_field" widget="percentage"/>
</form>`,
mockRPC(route, { args, method }) {
if (method === "write") {
if (method === "web_save") {
assert.strictEqual(
args[1].float_field,
0.24,
@@ -333,14 +333,14 @@ QUnit.module("Fields", (hooks) => {
</templates>
</kanban>`,
mockRPC(route, args) {
if (args.method === "write") {
assert.step(`write ${JSON.stringify(args.args)}`);
if (args.method === "web_save") {
assert.step(`web_save ${JSON.stringify(args.args)}`);
}
},
});
assert.containsNone(target, ".o_kanban_record .fa-star");
await click(target.querySelector(".o_priority a.o_priority_star.fa-star-o"), null, true);
assert.verifySteps(['write [[1],{"selection":"1"}]']);
assert.verifySteps(['web_save [[1],{"selection":"1"}]']);
assert.containsOnce(target, ".o_kanban_record .fa-star");
await click(
@@ -349,7 +349,7 @@ QUnit.module("Fields", (hooks) => {
);
await click(target, ".o_kanban_quick_create .o_kanban_add");
await click(target.querySelector(".o_priority a.o_priority_star.fa-star-o"), null, true);
assert.verifySteps(['write [[6],{"selection":"1"}]']);
assert.verifySteps(['web_save [[6],{"selection":"1"}]']);
assert.containsN(target, ".o_kanban_record .fa-star", 2);
});
@@ -636,8 +636,8 @@ QUnit.module("Fields", (hooks) => {
</sheet>
</form>`,
mockRPC(_route, { method }) {
if (method === "write") {
assert.step("write");
if (method === "web_save") {
assert.step("web_save");
}
},
});
@@ -646,7 +646,7 @@ QUnit.module("Fields", (hooks) => {
".o_field_widget .o_priority a.o_priority_star.fa-star-o"
);
await click(stars[stars.length - 1]);
assert.verifySteps(["write"]);
assert.verifySteps(["web_save"]);
});
QUnit.test("PriorityField - prevent auto save with autosave option", async function (assert) {
@@ -84,7 +84,7 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, { method, args }) {
if (method === "write") {
if (method === "web_save") {
assert.deepEqual(
args[1],
{ int_field: 999, float_field: 5, display_name: "new name" },
@@ -126,7 +126,7 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, { method, args }) {
if (method === "write") {
if (method === "web_save") {
assert.strictEqual(
args[1].int_field,
69,
@@ -178,7 +178,7 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, { method, args }) {
if (method === "write") {
if (method === "web_save") {
assert.strictEqual(
args[1].int_field,
69,
@@ -225,7 +225,7 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, { method, args }) {
if (method === "write") {
if (method === "web_save") {
assert.strictEqual(
args[1].float_field,
69,
@@ -319,7 +319,7 @@ QUnit.module("Fields", (hooks) => {
</kanban>`,
resId: 1,
mockRPC(route, { method, args }) {
if (method === "write") {
if (method === "web_save") {
assert.strictEqual(args[1].int_field, 69, "New value of progress bar saved");
}
},
@@ -378,7 +378,7 @@ QUnit.module("Fields", (hooks) => {
</kanban>`,
resId: 1,
mockRPC(route, { method, args }) {
if (method === "write") {
if (method === "web_save") {
throw new Error("Not supposed to write");
}
},
@@ -462,7 +462,7 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC: function (route, { method, args }) {
if (method === "write") {
if (method === "web_save") {
assert.strictEqual(
args[1].int_field,
1037,
@@ -1296,7 +1296,7 @@ QUnit.module("Fields", (hooks) => {
if (method === "check_access_rights") {
return true;
}
if (method === "write") {
if (method === "web_save") {
assert.deepEqual(args[1].properties, [
{
name: "property_1",
@@ -1345,7 +1345,7 @@ QUnit.module("Fields", (hooks) => {
// save
assert.verifySteps([]);
await clickSave(target);
assert.verifySteps(["write", "web_read"]);
assert.verifySteps(["web_save"]);
});
/**
@@ -1875,7 +1875,7 @@ QUnit.module("Fields", (hooks) => {
// We open the property popover
await click(target, ".o_property_field:first-child .o_field_property_open_popover");
assert.containsOnce(target,".o_field_property_definition");
assert.containsOnce(target, ".o_field_property_definition");
// Trying to delete the property should have closed its definition popover
// We click on delete button
@@ -315,7 +315,7 @@ QUnit.module("Fields", (hooks) => {
serverData,
arch: '<form><field name="selection" widget="radio"/></form>',
mockRPC: function (route, { args, method, model }) {
if (model === "partner" && method === "write") {
if (model === "partner" && method === "web_save") {
assert.strictEqual(args[1].selection, "1", "should write correct value");
}
},
@@ -252,8 +252,7 @@ QUnit.module("Fields", (hooks) => {
"name_search", // for the select
"name_search", // for the spawned many2one
"name_create",
"create",
"web_read",
"web_save",
],
"The name_create method should have been called"
);
@@ -437,7 +436,7 @@ QUnit.module("Fields", (hooks) => {
"the name_search should be done on the newly set model"
);
}
if (method === "write") {
if (method === "web_save") {
assert.strictEqual(model, "partner", "should write on the current model");
assert.deepEqual(
args,
@@ -527,13 +526,11 @@ QUnit.module("Fields", (hooks) => {
<field name="reference_char" widget="reference"/>
</form>`,
mockRPC(route, { args, method }) {
if (method === "create") {
assert.deepEqual(args[0], [
{
bar: false,
reference_char: "False,0",
},
]);
if (method === "web_save") {
assert.deepEqual(args[1], {
bar: false,
reference_char: "False,0",
});
}
},
});
@@ -566,13 +563,11 @@ QUnit.module("Fields", (hooks) => {
<field name="reference"/>
</form>`,
mockRPC(route, { args, method }) {
if (method === "create") {
assert.deepEqual(args[0], [
{
bar: false,
reference: "partner,4",
},
]);
if (method === "web_save") {
assert.deepEqual(args[1], {
bar: false,
reference: "partner,4",
});
}
},
});
@@ -849,7 +844,7 @@ QUnit.module("Fields", (hooks) => {
);
QUnit.test("Reference field with default value in list view", async function (assert) {
assert.expect(2);
assert.expect(1);
await makeView({
type: "list",
@@ -870,9 +865,8 @@ QUnit.module("Fields", (hooks) => {
},
},
};
} else if (method === "create") {
assert.strictEqual(args.length, 1);
assert.strictEqual(args[0][0].reference, "partner,2");
} else if (method === "web_save") {
assert.strictEqual(args[1].reference, "partner,2");
}
},
});
@@ -225,7 +225,7 @@ QUnit.module("Fields", (hooks) => {
serverData,
arch: '<form><field name="trululu" widget="selection" /></form>',
mockRPC(route, { args, method }) {
if (method === "write") {
if (method === "web_save") {
assert.strictEqual(
args[1].trululu,
false,
@@ -554,8 +554,8 @@ QUnit.module("Fields", (hooks) => {
</templates>
</kanban>`,
mockRPC: (route, args, performRPC) => {
if (route === "/web/dataset/call_kw/partner/write") {
assert.step("write");
if (route === "/web/dataset/call_kw/partner/web_save") {
assert.step("web_save");
}
return performRPC(route, args);
},
@@ -566,7 +566,7 @@ QUnit.module("Fields", (hooks) => {
const doneItem = target.querySelectorAll(".dropdown-item")[2]; // item "done";
await click(doneItem);
assert.verifySteps(["write"]);
assert.verifySteps(["web_save"]);
assert.hasClass(target.querySelector(".o_field_state_selection span"), "o_status_green");
});
@@ -587,15 +587,15 @@ QUnit.module("Fields", (hooks) => {
</form>`,
resId: 1,
mockRPC(_route, { method }) {
if (method === "write") {
assert.step("write");
if (method === "web_save") {
assert.step("web_save");
}
},
});
await click(target, ".o_field_widget.o_field_state_selection .o_status");
await click(target, ".dropdown-menu .dropdown-item:last-child");
assert.verifySteps(["write"]);
assert.verifySteps(["web_save"]);
}
);
@@ -611,8 +611,8 @@ QUnit.module("Fields", (hooks) => {
</header>
</form>`,
mockRPC(_route, { method }) {
if (method === "write") {
assert.step("write");
if (method === "web_save") {
assert.step("web_save");
}
},
});
@@ -620,7 +620,7 @@ QUnit.module("Fields", (hooks) => {
".o_statusbar_status button.btn:not(.dropdown-toggle):not(:disabled):not(.o_arrow_button_current)"
);
await click(clickableButtons[clickableButtons.length - 1]);
assert.verifySteps(["write"]);
assert.verifySteps(["web_save"]);
});
QUnit.test(
@@ -775,9 +775,9 @@ QUnit.module("Views", (hooks) => {
<field name="int_field" readonly="1"/>
</form>`,
mockRPC(route, args) {
if (args.method === "create") {
if (args.method === "web_save") {
assert.deepEqual(
args.args[0][0],
args.args[1],
{
display_name: "plop",
foo: "My little Foo Value",
@@ -785,14 +785,14 @@ QUnit.module("Views", (hooks) => {
},
" 'int_field' and 'bar' shouldn't be present"
);
assert.step("create");
assert.step("web_save");
}
},
});
await editInput(target, "[name='display_name'] input", "plop");
await clickSave(target);
assert.verifySteps(["create"]);
assert.verifySteps(["web_save"]);
});
QUnit.test("decoration-bf works on fields", async function (assert) {
@@ -2464,8 +2464,8 @@ QUnit.module("Views", (hooks) => {
</group>
</form>`,
mockRPC(route, args) {
if (args.method === "create") {
assert.deepEqual(args.args[0][0], {
if (args.method === "web_save") {
assert.deepEqual(args.args[1], {
bar: true,
int_field: 0,
foo: "some value",
@@ -3078,7 +3078,7 @@ QUnit.module("Views", (hooks) => {
"qux input is properly formatted"
);
assert.verifySteps(["get_views", "onchange", "create", "web_read", "write", "web_read"]);
assert.verifySteps(["get_views", "onchange", "web_save", "web_save"]);
});
QUnit.test("separators", async function (assert) {
@@ -3478,7 +3478,7 @@ QUnit.module("Views", (hooks) => {
QUnit.test("buttons in form view, new record", async function (assert) {
// this test simulates a situation similar to the settings forms.
assert.expect(9);
assert.expect(8);
serverData.models.partner.records = []; // such that we know the created record will be id 1
const mockedActionService = {
@@ -3523,11 +3523,11 @@ QUnit.module("Views", (hooks) => {
await click(target.querySelector(".o_form_statusbar button.p"));
assert.verifySteps(["create", "web_read", "execute_action", "web_read"]);
assert.verifySteps(["web_save", "execute_action", "web_read"]);
});
QUnit.test("buttons in form view, new record, with field id in view", async function (assert) {
assert.expect(8);
assert.expect(7);
// buttons in form view are one of the rare example of situation when we
// save a record without reloading it immediately, because we only care
// about its id for the next step. But at some point, if the field id
@@ -3574,14 +3574,7 @@ QUnit.module("Views", (hooks) => {
await click(target.querySelector(".o_form_statusbar button.p"));
assert.verifySteps([
"get_views",
"onchange",
"create",
"web_read",
"execute_action",
"web_read",
]);
assert.verifySteps(["get_views", "onchange", "web_save", "execute_action", "web_read"]);
});
QUnit.test("buttons with data-hotkey attribute", async function (assert) {
@@ -3622,8 +3615,8 @@ QUnit.module("Views", (hooks) => {
serverData,
arch: '<form><group><field name="foo"/></group></form>',
mockRPC(route, args) {
if (args.method === "write") {
assert.ok(true, "should call the /write route");
if (args.method === "web_save") {
assert.ok(true, "should call the web_save route");
assert.strictEqual(args.args[1].foo, "tralala");
}
},
@@ -3642,7 +3635,7 @@ QUnit.module("Views", (hooks) => {
serverData,
arch: '<form><group><field name="foo"/></group></form>',
mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
args.args[1].foo = "apple";
}
},
@@ -3662,9 +3655,8 @@ QUnit.module("Views", (hooks) => {
serverData,
arch: '<form><group><field name="foo"/></group></form>',
async mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
args.args[1].foo = "apple";
} else if (args.method === "web_read") {
// Block the 'read' call
await Promise.resolve(def);
}
@@ -3921,7 +3913,7 @@ QUnit.module("Views", (hooks) => {
resId: 1,
context: { active_field: 2 },
mockRPC(route, args) {
if (args.method === "create") {
if (args.method === "web_save") {
assert.strictEqual(
args.kwargs.context.active_field,
2,
@@ -4476,12 +4468,7 @@ QUnit.module("Views", (hooks) => {
await click(document.body.querySelector(".modal-footer .btn-primary"));
assert.verifySteps(["action_archive: partner", "get_views: product", "onchange: product"]);
await click(target, ".modal footer .myButton");
assert.verifySteps([
"create: product",
"web_read: product",
"do_archive: product",
"web_read: partner",
]);
assert.verifySteps(["web_save: product", "do_archive: product", "web_read: partner"]);
assert.containsNone(target, ".modal");
assert.strictEqual(target.querySelector("[name='active'] input").value, "archived");
});
@@ -4612,8 +4599,8 @@ QUnit.module("Views", (hooks) => {
arch: '<form><field name="foo"/></form>',
actionMenus: {},
async mockRPC(route, args) {
if (args.method === "create") {
assert.step("create");
if (args.method === "web_save") {
assert.step("web_save");
throw makeServerError();
}
if (args.method === "copy") {
@@ -4628,7 +4615,7 @@ QUnit.module("Views", (hooks) => {
// Discard changes don't trigger Duplicate action
await click(target, ".modal .btn-secondary");
assert.verifySteps(["create"]);
assert.verifySteps(["web_save"]);
});
QUnit.test("clicking on stat buttons in edit mode", async function (assert) {
@@ -4663,7 +4650,7 @@ QUnit.module("Views", (hooks) => {
</form>`,
resId: 2,
mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
assert.strictEqual(
args.args[1].foo,
"tralala",
@@ -4683,7 +4670,7 @@ QUnit.module("Views", (hooks) => {
assert.containsOnce(target, ".o_form_editable", "form view should be in edit mode");
assert.strictEqual(count, 2, "should have triggered a execute action");
assert.verifySteps(["get_views", "web_read", "write", "web_read"]);
assert.verifySteps(["get_views", "web_read", "web_save"]);
});
QUnit.test("clicking on stat buttons save and reload in edit mode", async function (assert) {
@@ -4715,7 +4702,7 @@ QUnit.module("Views", (hooks) => {
</form>`,
resId: 2,
mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
// simulate an override of the model...
args.args[1].display_name = "GOLDORAK";
args.args[1].name = "GOLDORAK";
@@ -4763,7 +4750,7 @@ QUnit.module("Views", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
writeCount++;
}
},
@@ -4811,7 +4798,7 @@ QUnit.module("Views", (hooks) => {
await editInput(target, ".o_field_widget[name=foo] input", "tralala");
await click(target.querySelector(".o_content button.btn-primary"));
assert.verifySteps(["get_views", "web_read", "write", "web_read", "execute_action"]);
assert.verifySteps(["get_views", "web_read", "web_save", "execute_action"]);
});
QUnit.test('buttons with attr "special" in dialog close the dialog', async function (assert) {
@@ -4844,10 +4831,10 @@ QUnit.module("Views", (hooks) => {
if (route === "/web/dataset/call_kw/product/get_formview_id") {
return false;
}
if (route === "/web/dataset/call_kw/product/create") {
if (route === "/web/dataset/call_kw/product/web_save") {
assert.step("create RPC");
}
if (route === "/web/dataset/call_kw/partner/write") {
if (route === "/web/dataset/call_kw/partner/web_save") {
assert.step("write RPC");
}
},
@@ -5414,7 +5401,7 @@ QUnit.module("Views", (hooks) => {
resIds: [1, 2],
resId: 1,
mockRPC(route) {
if (route === "/web/dataset/call_kw/partner/write") {
if (route === "/web/dataset/call_kw/partner/web_save") {
nbWrite++;
}
},
@@ -5497,7 +5484,7 @@ QUnit.module("Views", (hooks) => {
await click(target.querySelector(".o_pager_next"));
assert.strictEqual(target.querySelector(".o_pager_value").textContent, "2");
assert.verifySteps(["get_views", "web_read", "write", "web_read"]);
assert.verifySteps(["get_views", "web_read", "web_save", "web_read"]);
});
QUnit.test("switching to another record from an invalid one", async function (assert) {
@@ -5512,8 +5499,8 @@ QUnit.module("Views", (hooks) => {
resIds: [1, 2],
resId: 1,
mockRPC(route) {
if (route === "/web/dataset/call_kw/partner/write") {
assert.step("write");
if (route === "/web/dataset/call_kw/partner/web_save") {
assert.step("web_save");
}
},
});
@@ -5546,8 +5533,8 @@ QUnit.module("Views", (hooks) => {
resIds: [1, 2],
resId: 1,
mockRPC(route) {
if (route === "/web/dataset/call_kw/partner/write") {
assert.step("write");
if (route === "/web/dataset/call_kw/partner/web_save") {
assert.step("web_save");
}
},
});
@@ -5614,7 +5601,7 @@ QUnit.module("Views", (hooks) => {
resIds: [1, 2],
resId: 1,
mockRPC(route) {
if (route === "/web/dataset/call_kw/partner/write") {
if (route === "/web/dataset/call_kw/partner/web_save") {
nbWrite++;
}
},
@@ -6514,7 +6501,7 @@ QUnit.module("Views", (hooks) => {
});
QUnit.test("properly apply onchange on many2many fields", async function (assert) {
assert.expect(11);
assert.expect(10);
serverData.models.partner.onchanges = {
foo: function (obj) {
@@ -6537,7 +6524,7 @@ QUnit.module("Views", (hooks) => {
</form>`,
mockRPC(route, args) {
assert.step(args.method);
if (args.method === "write") {
if (args.method === "web_save") {
assert.deepEqual(
args.args[1].timmy,
[
@@ -6572,7 +6559,7 @@ QUnit.module("Views", (hooks) => {
await clickSave(target);
assert.verifySteps(["get_views", "web_read", "onchange", "write", "web_read"]);
assert.verifySteps(["get_views", "web_read", "onchange", "web_save"]);
});
QUnit.test(
@@ -6923,7 +6910,7 @@ QUnit.module("Views", (hooks) => {
arch: `<form><field name="foo"/></form>`,
resId: 2,
async mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
await def;
}
},
@@ -7028,7 +7015,7 @@ QUnit.module("Views", (hooks) => {
},
});
}
if (args.method === "write") {
if (args.method === "web_save") {
assert.deepEqual(
args.args[1].p,
[
@@ -7538,8 +7525,8 @@ QUnit.module("Views", (hooks) => {
</field>
</form>`,
mockRPC(route, args) {
if (args.method === "create") {
const command = args.args[0][0].p;
if (args.method === "web_save") {
const command = args.args[1].p;
assert.deepEqual(
command,
[
@@ -7586,18 +7573,18 @@ QUnit.module("Views", (hooks) => {
</field>
</form>`,
mockRPC(route, args) {
if (args.method === "create") {
if (args.method === "web_save") {
assert.deepEqual(
args.args[0][0].p,
args.args[1].p,
[
[
0,
args.args[0][0].p[0][1],
args.args[1].p[0][1],
{
p: [
[
0,
args.args[0][0].p[0][2].p[0][1],
args.args[1].p[0][2].p[0][1],
{ display_name: "xtv" },
],
],
@@ -7707,7 +7694,7 @@ QUnit.module("Views", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
assert.deepEqual(args.args[1], { foo: "New foo value" });
}
},
@@ -7751,11 +7738,11 @@ QUnit.module("Views", (hooks) => {
</field>
</form>`,
mockRPC(route, args) {
if (args.method === "create") {
if (args.method === "web_save") {
// foo should be saved because of the "force_save" attribute
// qux should be saved because it isn't readonly
// int_field should not be saved as it is readonly
const commands = args.args[0][0].p;
const commands = args.args[1].p;
assert.deepEqual(commands, [
[0, commands[0][1], { foo: "some value", qux: 6.5 }],
]);
@@ -8301,8 +8288,8 @@ QUnit.module("Views", (hooks) => {
serverData,
arch: `<form><field name="bar"/></form>`,
mockRPC(route, { method, args }) {
if (method === "create") {
assert.deepEqual(args[0][0].bar, false);
if (method === "web_save") {
assert.deepEqual(args[1].bar, false);
}
},
});
@@ -8526,8 +8513,7 @@ QUnit.module("Views", (hooks) => {
assert.verifySteps([
"get_views",
"onchange",
"create",
"web_read",
"web_save",
`{"action_id":29,"context":{"lang":"en","uid":7,"tz":"taht","active_id":6,"active_ids":[6],"active_model":"partner","active_domain":[]}}`,
"web_read",
]);
@@ -8593,7 +8579,7 @@ QUnit.module("Views", (hooks) => {
mockRPC(route, args) {
if (route === "/web/dataset/call_kw/product/get_formview_id") {
return false;
} else if (args.method === "write") {
} else if (args.method === "web_save") {
assert.strictEqual(args.model, "product");
assert.strictEqual(args.args[1].product_ids[0][2].display_name, "xtv");
}
@@ -9402,7 +9388,7 @@ QUnit.module("Views", (hooks) => {
assert.verifySteps(["get_views", "onchange"]);
assert.containsOnce(target, ".o_form_editable");
await click(target, ".o_field_translate.btn-link");
assert.verifySteps(["create", "web_read", "get_installed", "get_field_translations"]);
assert.verifySteps(["web_save", "get_installed", "get_field_translations"]);
assert.containsOnce(target, ".modal");
assert.strictEqual(target.querySelector(".modal-title").textContent, "Translate: foo");
});
@@ -9730,7 +9716,7 @@ QUnit.module("Views", (hooks) => {
await click(target.querySelector(".o_statusbar_buttons button"));
assert.verifySteps([]);
await click(target.querySelector(".modal-footer button.btn-primary"));
assert.verifySteps(["create", "web_read", "execute_action"]);
assert.verifySteps(["web_save", "execute_action"]);
}
);
@@ -9808,7 +9794,7 @@ QUnit.module("Views", (hooks) => {
await Promise.resolve();
assert.ok(target.querySelector(".modal-footer button.btn-primary").disabled);
await nextTick();
assert.verifySteps(["create", "web_read", "execute_action"]);
assert.verifySteps(["web_save", "execute_action"]);
});
QUnit.test(
@@ -9877,7 +9863,7 @@ QUnit.module("Views", (hooks) => {
resId: 1,
mockRPC(route, args) {
assert.step(args.method);
if (args.method === "write") {
if (args.method === "web_save") {
return def;
}
},
@@ -9892,8 +9878,7 @@ QUnit.module("Views", (hooks) => {
assert.verifySteps([
"get_views",
"web_read", // initial read to render the view
"write", // write on save
"web_read", // read on reload
"web_save", // write on save
]);
});
@@ -9921,7 +9906,7 @@ QUnit.module("Views", (hooks) => {
resId: 1,
mockRPC(route, args) {
assert.step(args.method);
if (args.method === "write" && args.args[1].foo === "incorrect value") {
if (args.method === "web_save" && args.args[1].foo === "incorrect value") {
return Promise.reject(new Error("Odoo Server Error"));
}
},
@@ -9938,9 +9923,8 @@ QUnit.module("Views", (hooks) => {
assert.verifySteps([
"get_views",
"web_read", // initial read to render the view
"write", // write on save (it fails, does not trigger a read)
"write", // write on save (it works)
"web_read", // read on reload
"web_save", // write on save (it fails, does not trigger a read)
"web_save", // write on save (it works)
]);
});
@@ -9975,8 +9959,8 @@ QUnit.module("Views", (hooks) => {
mode: "readonly",
resId: 1,
mockRPC(route, args) {
if (args.method === "write") {
assert.step("write");
if (args.method === "web_save") {
assert.step("web_save");
if (failFlag) {
return Promise.reject(new Error("Odoo Server Error"));
}
@@ -10010,10 +9994,9 @@ QUnit.module("Views", (hooks) => {
assert.verifySteps([
"web_read",
"write", // fails
"web_save", // fails
"web_read", // must reload when saving fails
"write", // works
"web_read", // must reload when saving works
"web_save", // works
]);
}
);
@@ -10104,11 +10087,11 @@ QUnit.module("Views", (hooks) => {
);
}
}
if (args.method === "create") {
if (args.method === "web_save") {
assert.deepEqual(
args.args[0][0],
args.args[1],
{
p: [[0, args.args[0][0].p[0][1], { display_name: "readonly" }]],
p: [[0, args.args[1].p[0][1], { display_name: "readonly" }]],
},
"should not have sent the value of the readonly field"
);
@@ -10357,7 +10340,7 @@ QUnit.module("Views", (hooks) => {
"web_read", // first dialog
"get_formview_id", // id of second form view opened in a dialog
"web_read", // second dialog
"write", // save second dialog
"web_save", // save second dialog
"read", // reload the display_name (first dialog)
]);
});
@@ -10851,7 +10834,7 @@ QUnit.module("Views", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
assert.deepEqual(args.args[1].p[0][2], values);
}
},
@@ -10916,7 +10899,7 @@ QUnit.module("Views", (hooks) => {
"some foo value",
"foo field should have correct value"
);
assert.verifySteps(["get_views", "onchange", "create", "web_read"]);
assert.verifySteps(["get_views", "onchange", "web_save"]);
});
QUnit.test("saving with invalid uncommitted changes", async function (assert) {
@@ -10981,10 +10964,10 @@ QUnit.module("Views", (hooks) => {
if (args.method === "onchange") {
await onchangeDef;
}
if (args.method === "create") {
assert.step("create");
if (args.method === "web_save") {
assert.step("web_save");
assert.strictEqual(
args.args[0][0].p[0][2].foo,
args.args[1].p[0][2].foo,
"foo value",
"should have wait for the onchange to return before saving"
);
@@ -11015,7 +10998,7 @@ QUnit.module("Views", (hooks) => {
onchangeDef.resolve();
await nextTick();
assert.verifySteps(["resolve", "create"]);
assert.verifySteps(["resolve", "web_save"]);
}
);
@@ -11058,7 +11041,7 @@ QUnit.module("Views", (hooks) => {
if (args.method === "onchange") {
await onchangeDef;
}
if (args.method === "create") {
if (args.method === "web_save") {
await createDef;
}
};
@@ -11150,7 +11133,7 @@ QUnit.module("Views", (hooks) => {
const writeDef = makeDeferred();
const mockRPC = async (route, args) => {
if (args.method === "write") {
if (args.method === "web_save") {
writeCalls += 1;
await writeDef;
}
@@ -11573,7 +11556,7 @@ QUnit.module("Views", (hooks) => {
await editInput(target, '.o_field_widget[name="name"] input', "Test Company");
await clickSave(target);
assert.verifySteps(["get_views", "onchange", "create", "reload company", "web_read"]);
assert.verifySteps(["get_views", "onchange", "web_save", "reload company"]);
}
);
@@ -11619,7 +11602,7 @@ QUnit.module("Views", (hooks) => {
await editInput(target, '.o_field_widget[name="name"] input', "Test Company2");
await clickSave(target);
assert.verifySteps(["get_views", "web_read", "write", "reload company", "web_read"]);
assert.verifySteps(["get_views", "web_read", "web_save", "reload company"]);
}
);
@@ -11733,7 +11716,7 @@ QUnit.module("Views", (hooks) => {
};
const mockRPC = (route, args) => {
if (args.method === "write") {
if (args.method === "web_save") {
assert.deepEqual(args.args, [[1], { name: "aaa" }]);
}
};
@@ -11809,7 +11792,7 @@ QUnit.module("Views", (hooks) => {
};
const mockRPC = (route, args) => {
if (args.method === "write") {
if (args.method === "web_save") {
assert.deepEqual(args.args, [[1], { name: "aaa" }]);
}
};
@@ -11887,8 +11870,8 @@ QUnit.module("Views", (hooks) => {
const webClient = await createWebClient({
serverData,
mockRPC(route, { method }) {
if (method === "write") {
assert.step("write");
if (method === "web_save") {
assert.step("web_save");
throw makeServerError();
}
},
@@ -11898,7 +11881,7 @@ QUnit.module("Views", (hooks) => {
await editInput(target, ".o_field_widget[name='name'] input", "aaa");
await click(target.querySelector(".breadcrumb-item.o_back_button"));
assert.verifySteps(["write"]);
assert.verifySteps(["web_save"]);
await nextTick();
assert.containsOnce(target, ".o_error_dialog");
});
@@ -11949,7 +11932,7 @@ QUnit.module("Views", (hooks) => {
};
const mockRPC = (route, args) => {
if (args.method === "write") {
if (args.method === "web_save") {
assert.deepEqual(args.args, [[1], { name: "aaa" }]);
}
};
@@ -11996,7 +11979,7 @@ QUnit.module("Views", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, { args, method, model }) {
if (method === "write" && model === "partner") {
if (method === "web_save" && model === "partner") {
assert.step("save"); // should be called
assert.deepEqual(args, [[1], { display_name: "test" }]);
}
@@ -12031,7 +12014,7 @@ QUnit.module("Views", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, { args, method, model }) {
if (method === "write" && model === "partner") {
if (method === "web_save" && model === "partner") {
assert.step("save"); // should not be called
}
},
@@ -12059,7 +12042,7 @@ QUnit.module("Views", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, { args, method, model }) {
if (method === "write" && model === "partner") {
if (method === "web_save" && model === "partner") {
assert.step("save"); // should not be called
}
},
@@ -12121,7 +12104,7 @@ QUnit.module("Views", (hooks) => {
</form>`,
resId: 1,
mockRPC(route, { args, method, model }) {
if (method === "write" && model === "partner") {
if (method === "web_save" && model === "partner") {
assert.step("save"); // should not be called
}
},
@@ -12167,7 +12150,7 @@ QUnit.module("Views", (hooks) => {
};
const mockRPC = (route, args) => {
if (args.method === "write") {
if (args.method === "web_save") {
assert.step("save");
}
};
@@ -12222,7 +12205,7 @@ QUnit.module("Views", (hooks) => {
if (method === "onchange" && model === "partner") {
return def;
}
if (method === "write" && model === "partner") {
if (method === "web_save" && model === "partner") {
assert.deepEqual(args, [[1], { display_name: "test" }]);
}
},
@@ -12258,7 +12241,7 @@ QUnit.module("Views", (hooks) => {
if (method === "onchange") {
return def;
}
if (method === "write") {
if (method === "web_save") {
assert.deepEqual(args, [[1], { display_name: "test1", name: "test2" }]);
}
},
@@ -12282,7 +12265,7 @@ QUnit.module("Views", (hooks) => {
resId: 1,
mockRPC(route, { args, method }) {
assert.step(method);
if (method === "write") {
if (method === "web_save") {
assert.deepEqual(args, [[1], { foo: "test" }]);
}
},
@@ -12297,7 +12280,7 @@ QUnit.module("Views", (hooks) => {
window.dispatchEvent(new Event("beforeunload"));
await nextTick();
assert.verifySteps(["get_views", "web_read", "write"]);
assert.verifySteps(["get_views", "web_read", "web_save"]);
});
QUnit.test(
@@ -12328,7 +12311,7 @@ QUnit.module("Views", (hooks) => {
if (method === "onchange") {
return def;
}
if (method === "write") {
if (method === "web_save") {
assert.deepEqual(args, [
[1],
{ display_name: "test", name: "test", foo: "test" },
@@ -12353,7 +12336,7 @@ QUnit.module("Views", (hooks) => {
window.dispatchEvent(new Event("beforeunload"));
await nextTick();
assert.verifySteps(["get_views", "web_read", "onchange", "write"]);
assert.verifySteps(["get_views", "web_read", "onchange", "web_save"]);
}
);
@@ -12370,7 +12353,7 @@ QUnit.module("Views", (hooks) => {
resId: 1,
mockRPC(route, { method }) {
assert.step(method);
if (method === "write") {
if (method === "web_save") {
assert.notOk(true, "should not call the /write route");
}
},
@@ -12438,8 +12421,8 @@ QUnit.module("Views", (hooks) => {
actionMenus: {},
resId: 1,
mockRPC(route, { method }) {
if (method === "write") {
assert.step("write");
if (method === "web_save") {
assert.step("web_save");
}
},
});
@@ -12452,7 +12435,7 @@ QUnit.module("Views", (hooks) => {
await click(target, ".o_cp_action_menus button");
await click(target.querySelector(".o_cp_action_menus .dropdown-menu .dropdown-item"));
assert.verifySteps(["write"]);
assert.verifySteps(["web_save"]);
assert.strictEqual(target.querySelector(".o_pager_counter").textContent, "2 / 2");
assert.strictEqual(target.querySelector(".o_field_widget[name='foo'] input").value, "test");
@@ -12488,8 +12471,8 @@ QUnit.module("Views", (hooks) => {
actionMenus: {},
resId: 1,
mockRPC(route, { method }) {
if (method === "write") {
assert.step("write");
if (method === "web_save") {
assert.step("web_save");
throw makeServerError();
}
},
@@ -12498,7 +12481,7 @@ QUnit.module("Views", (hooks) => {
await editInput(target, ".o_field_widget[name='foo'] input", "test");
await click(target, ".o_cp_action_menus button");
await click(target.querySelector(".o_cp_action_menus .dropdown-menu .dropdown-item"));
assert.verifySteps(["write"]);
assert.verifySteps(["web_save"]);
await nextTick();
assert.containsOnce(target, ".o_error_dialog");
});
@@ -12511,8 +12494,8 @@ QUnit.module("Views", (hooks) => {
arch: `<form><field name="foo"/></form>`,
resId: 1,
mockRPC(route, { method }) {
if (method === "write") {
assert.step("write");
if (method === "web_save") {
assert.step("web_save");
}
},
});
@@ -12524,7 +12507,7 @@ QUnit.module("Views", (hooks) => {
target,
".o_control_panel_main_buttons .d-none.d-xl-inline-flex .o_form_button_create"
);
assert.verifySteps(["write"]);
assert.verifySteps(["web_save"]);
assert.strictEqual(
target.querySelector(".o_field_widget[name='foo'] input").value,
"My little Foo Value"
@@ -12559,8 +12542,8 @@ QUnit.module("Views", (hooks) => {
actionMenus: {},
resId: 1,
mockRPC(route, { method }) {
if (method === "write") {
assert.step("write");
if (method === "web_save") {
assert.step("web_save");
throw makeServerError();
}
},
@@ -12568,7 +12551,7 @@ QUnit.module("Views", (hooks) => {
await editInput(target, ".o_field_widget[name='foo'] input", "test");
await createRecord();
assert.verifySteps(["write"]);
assert.verifySteps(["web_save"]);
await nextTick();
assert.containsOnce(target, ".o_error_dialog");
});
@@ -12599,8 +12582,8 @@ QUnit.module("Views", (hooks) => {
const webClient = await createWebClient({
serverData,
mockRPC(route, { method }) {
if (method === "create") {
assert.step("create");
if (method === "web_save") {
assert.step("web_save");
throw makeServerError({ message: "Some business message" });
}
},
@@ -12616,7 +12599,7 @@ QUnit.module("Views", (hooks) => {
await editInput(target, ".o_field_widget[name='foo'] input", "test");
await click(target.querySelector(".modal footer .myButton"));
assert.verifySteps(["create"]);
assert.verifySteps(["web_save"]);
await nextTick();
assert.containsOnce(target, ".o_error_dialog");
assert.containsN(target, ".modal", 2);
@@ -12681,14 +12664,14 @@ QUnit.module("Views", (hooks) => {
</field>
</form>`,
mockRPC(route, args) {
if (args.method === "create") {
if (args.method === "web_save") {
assert.deepEqual(
args.args[0][0],
args.args[1],
{
p: [
[
0,
args.args[0][0].p[0][1],
args.args[1].p[0][1],
{ length: 0, display_name: "readonly" },
],
],
@@ -12869,19 +12852,17 @@ QUnit.module("Views", (hooks) => {
</form>`,
mockRPC(route, args) {
assert.step(args.method);
if (args.method === "create") {
assert.deepEqual(args.args[0], [
{
int_field: 0,
text: false,
},
]);
if (args.method === "web_save") {
assert.deepEqual(args.args[1], {
int_field: 0,
text: false,
});
}
},
});
await clickSave(target);
assert.verifySteps(["get_views", "onchange", "create", "web_read"]);
assert.verifySteps(["get_views", "onchange", "web_save"]);
});
QUnit.test(
@@ -12930,8 +12911,8 @@ QUnit.module("Views", (hooks) => {
</form>`,
mockRPC(route, args) {
assert.step(args.method);
if (args.method === "create") {
assert.deepEqual(args.args[0][0].p[0][2], { int_field: 1, text: false });
if (args.method === "web_save") {
assert.deepEqual(args.args[1].p[0][2], { int_field: 1, text: false });
}
},
});
@@ -12947,7 +12928,7 @@ QUnit.module("Views", (hooks) => {
target.querySelector(".o_list_renderer .o_data_row [name='int_field']").textContent,
"1"
);
assert.verifySteps(["get_views", "onchange", "onchange", "create", "web_read"]);
assert.verifySteps(["get_views", "onchange", "onchange", "web_save"]);
}
);
@@ -13174,7 +13155,7 @@ QUnit.module("Views", (hooks) => {
serverData,
arch: `<form><field name="foo" required="1"/></form>`,
mockRPC(route, { method }) {
if (method === "write") {
if (method === "web_save") {
return Promise.reject(false);
}
},
@@ -13215,7 +13196,7 @@ QUnit.module("Views", (hooks) => {
serverData,
arch: `<form js_class="custom_form"><field name="foo" required="1"/></form>`,
mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
assert.step(`write ${args.args[0]}`);
}
},
@@ -13257,8 +13238,8 @@ QUnit.module("Views", (hooks) => {
serverData,
arch: `<form js_class="custom_form"><field name="foo" required="1"/></form>`,
mockRPC(route, args) {
if (args.method === "write") {
assert.step("write");
if (args.method === "web_save") {
assert.step("web_save");
}
},
});
@@ -13548,7 +13529,7 @@ QUnit.module("Views", (hooks) => {
const mockRPC = async (route, args) => {
if (
(args.method === "web_read" || args.method === "write") &&
(args.method === "web_read" || args.method === "web_save") &&
args.args[0][0] === 1
) {
assert.step(args.method);
@@ -13566,12 +13547,12 @@ QUnit.module("Views", (hooks) => {
// Close ErrorDialog
await click(target, ".o_dialog .btn-close");
assert.deepEqual(target.querySelectorAll("[name='p'] .o_data_row").length, 1);
assert.verifySteps(["write", "web_read"]);
assert.verifySteps(["web_save", "web_read"]);
await editInput(target, "[name=foo] input", "new value");
await clickSave(target);
assert.deepEqual(target.querySelectorAll("[name='p'] .o_data_row").length, 1);
assert.verifySteps(["write", "web_read"]);
assert.verifySteps(["web_save"]);
}
);
@@ -13637,9 +13618,9 @@ QUnit.module("Views", (hooks) => {
if (args.method === "web_read") {
assert.step(args.method);
assert.deepEqual(args.args[0], [6]);
} else if (args.method === "create") {
} else if (args.method === "web_save") {
assert.step(args.method);
assert.deepEqual(args.args[0][0], {
assert.deepEqual(args.args[1], {
foo: "new value",
});
}
@@ -13655,7 +13636,7 @@ QUnit.module("Views", (hooks) => {
// Close ErrorDialog
await click(target, ".o_dialog .btn-close");
assert.strictEqual(target.querySelector("[name=foo] input").value, "new value");
assert.verifySteps(["create", "web_read"]);
assert.verifySteps(["web_save", "web_read"]);
}
);
@@ -13875,7 +13856,7 @@ QUnit.module("Views", (hooks) => {
await def;
}
if (args.method === "write") {
if (args.method === "web_save") {
assert.deepEqual(args.args[1], {
p: [[1, 1, { foo: "new foo" }]],
});
@@ -1880,7 +1880,7 @@ QUnit.module("Views", (hooks) => {
});
QUnit.test("quick create record with quick_create_view", async (assert) => {
assert.expect(20);
assert.expect(19);
serverData.views["partner,some_view_ref,form"] =
"<form>" +
@@ -1902,16 +1902,14 @@ QUnit.module("Views", (hooks) => {
groupBy: ["bar"],
async mockRPC(route, args) {
assert.step(args.method || route);
if (args.method === "create") {
if (args.method === "web_save") {
assert.deepEqual(
args.args[0],
[
{
foo: "new partner",
int_field: 4,
state: "def",
},
],
args.args[1],
{
foo: "new partner",
int_field: 4,
state: "def",
},
"should send the correct values"
);
}
@@ -1952,8 +1950,7 @@ QUnit.module("Views", (hooks) => {
"web_search_read", // initial search_read (second column)
"get_views", // form view in quick create
"onchange", // quick create
"create", // should perform a create to create the record
"web_read",
"web_save", // should perform a web_save to create the record
"web_read", // read the created record
"onchange", // new quick create
]);
@@ -1985,16 +1982,14 @@ QUnit.module("Views", (hooks) => {
</kanban>`,
groupBy: ["bar"],
async mockRPC(route, args) {
if (args.method === "create") {
if (args.method === "web_save") {
assert.deepEqual(
args.args[0],
[
{
foo: "new partner",
int_field: 4,
state: "def",
},
],
args.args[1],
{
foo: "new partner",
int_field: 4,
state: "def",
},
"should send the correct values"
);
}
@@ -2233,7 +2228,7 @@ QUnit.module("Views", (hooks) => {
});
QUnit.test("quick create record in grouped on m2o (with quick_create_view)", async (assert) => {
assert.expect(16);
assert.expect(15);
serverData.views["partner,some_view_ref,form"] =
"<form>" +
@@ -2255,16 +2250,15 @@ QUnit.module("Views", (hooks) => {
groupBy: ["product_id"],
async mockRPC(route, { method, args, kwargs }) {
assert.step(method || route);
if (method === "create") {
if (method === "web_save") {
assert.deepEqual(
args[0],
[
{
foo: "new partner",
int_field: 4,
state: "def",
},
],
args[1],
{
foo: "new partner",
int_field: 4,
state: "def",
},
"should send the correct values"
);
const { default_product_id, default_qux } = kwargs.context;
@@ -2296,8 +2290,7 @@ QUnit.module("Views", (hooks) => {
"web_search_read", // initial search_read (second column)
"get_views", // form view in quick create
"onchange", // quick create
"create", // should perform a create to create the record
"web_read",
"web_save", // should perform a web_save to create the record
"web_read", // read the created record
"onchange", // reopen the quick create automatically
]);
@@ -2437,15 +2430,13 @@ QUnit.module("Views", (hooks) => {
groupBy: ["category_ids"],
async mockRPC(route, { method, args, kwargs }) {
assert.step(method || route);
if (method === "create") {
assert.deepEqual(args[0], [
{
foo: "new partner",
},
]);
if (method === "web_save") {
assert.deepEqual(args[1], {
foo: "new partner",
});
const { default_category_ids } = kwargs.context;
assert.deepEqual(default_category_ids, [6]);
return [5];
return [{ id: 5 }];
}
if (method === "web_read" && args[0][0] === 5) {
return [{ id: 5, foo: "new partner", category_ids: [6] }];
@@ -2478,7 +2469,7 @@ QUnit.module("Views", (hooks) => {
"web_search_read", // initial search_read (second column)
"get_views", // get form view
"onchange", // quick create
"create", // should perform a create to create the record
"web_save", // should perform a web_save to create the record
"web_read", // read the created record
"onchange", // reopen the quick create automatically
]);
@@ -2506,13 +2497,11 @@ QUnit.module("Views", (hooks) => {
groupBy: ["category_ids"],
async mockRPC(route, { method, args, kwargs }) {
assert.step(method || route);
if (method === "create") {
assert.deepEqual(args[0], [
{
category_ids: [[4, 6]],
foo: "new partner",
},
]);
if (method === "web_save") {
assert.deepEqual(args[1], {
category_ids: [[4, 6]],
foo: "new partner",
});
const { default_category_ids } = kwargs.context;
assert.deepEqual(default_category_ids, [6]);
}
@@ -2552,7 +2541,7 @@ QUnit.module("Views", (hooks) => {
"web_search_read", // initial search_read (second column)
"get_views", // get form view
"onchange", // quick create
"create", // should perform a create to create the record
"web_save", // should perform a web_save to create the record
"web_read",
"onchange",
]);
@@ -2725,9 +2714,9 @@ QUnit.module("Views", (hooks) => {
</kanban>`,
groupBy: ["bar"],
async mockRPC(route, { method, args }) {
if (method === "create") {
if (method === "web_save") {
assert.notOk(
"int_field" in args[0],
"int_field" in args[1],
"readonly field shouldn't be sent in create"
);
}
@@ -2749,7 +2738,7 @@ QUnit.module("Views", (hooks) => {
await editQuickCreateInput("foo", "new partner");
assert.verifySteps(["onchange"]);
await validateRecord();
assert.verifySteps(["create", "web_read", "onchange"]);
assert.verifySteps(["web_save", "web_read", "onchange"]);
});
QUnit.test("quick create record and change state in grouped mode", async (assert) => {
@@ -2957,8 +2946,8 @@ QUnit.module("Views", (hooks) => {
"</t></templates></kanban>",
groupBy: ["bar"],
async mockRPC(route, args) {
if (args.method === "create") {
assert.step("create");
if (args.method === "web_save") {
assert.step("web_save");
await prom;
}
},
@@ -3005,7 +2994,7 @@ QUnit.module("Views", (hooks) => {
"quick create should be enabled"
);
assert.verifySteps(["create"]);
assert.verifySteps(["web_save"]);
});
QUnit.test("quick create record: prevent multiple adds with Add clicked", async (assert) => {
@@ -3025,8 +3014,8 @@ QUnit.module("Views", (hooks) => {
"</t></templates></kanban>",
groupBy: ["bar"],
async mockRPC(route, { method }) {
if (method === "create") {
assert.step("create");
if (method === "web_save") {
assert.step("web_save");
await prom;
}
},
@@ -3067,7 +3056,7 @@ QUnit.module("Views", (hooks) => {
"quick create should be enabled"
);
assert.verifySteps(["create"]);
assert.verifySteps(["web_save"]);
});
QUnit.test(
@@ -3200,9 +3189,9 @@ QUnit.module("Views", (hooks) => {
}
break;
}
case "create": {
case "web_save": {
assert.step(method);
const values = args[0][0];
const values = args[1];
assert.strictEqual(values.foo, "new partner");
assert.strictEqual(values.int_field, 3);
break;
@@ -3268,7 +3257,7 @@ QUnit.module("Views", (hooks) => {
assert.verifySteps([
"onchange", // default_get
"onchange", // new partner
"create",
"web_save",
"onchange", // default_get
]);
}
@@ -3307,9 +3296,9 @@ QUnit.module("Views", (hooks) => {
await prom;
}
}
if (args.method === "create") {
assert.step("create");
assert.deepEqual(args.args[0][0], {
if (args.method === "web_save") {
assert.step("web_save");
assert.deepEqual(args.args[1], {
foo: "new partner",
int_field: 3,
});
@@ -3367,7 +3356,7 @@ QUnit.module("Views", (hooks) => {
assert.verifySteps([
"onchange", // default_get
"onchange", // new partner
"create",
"web_save",
"onchange", // default_get
]);
}
@@ -3934,8 +3923,8 @@ QUnit.module("Views", (hooks) => {
if (args.method === "name_create") {
throw makeServerError({ message: "This is a user error" });
}
if (args.method === "create") {
assert.deepEqual(args.args[0][0], { foo: "blip" });
if (args.method === "web_save") {
assert.deepEqual(args.args[1], { foo: "blip" });
assert.deepEqual(args.kwargs.context, {
default_foo: "blip",
default_name: "test",
@@ -3984,8 +3973,8 @@ QUnit.module("Views", (hooks) => {
if (args.method === "name_create") {
throw makeServerError({ message: "This is a user error" });
}
if (args.method === "create") {
assert.deepEqual(args.args[0][0], { state: "abc" });
if (args.method === "web_save") {
assert.deepEqual(args.args[1], { state: "abc" });
assert.deepEqual(args.kwargs.context, {
default_state: "abc",
default_name: "test",
@@ -4283,8 +4272,8 @@ QUnit.module("Views", (hooks) => {
"</kanban>",
groupBy: ["foo"],
async mockRPC(route, { method, args, kwargs }) {
if (method === "create") {
assert.deepEqual(args[0], [{ foo: "blip" }]);
if (method === "web_save") {
assert.deepEqual(args[1], { foo: "blip" });
assert.strictEqual(kwargs.context.default_foo, "blip");
}
},
@@ -4325,8 +4314,8 @@ QUnit.module("Views", (hooks) => {
"</kanban>",
groupBy: ["bar"],
async mockRPC(route, { method, args, kwargs }) {
if (method === "create") {
assert.deepEqual(args[0], [{ bar: true }]);
if (method === "web_save") {
assert.deepEqual(args[1], { bar: true });
assert.strictEqual(kwargs.context.default_bar, true);
}
},
@@ -4371,8 +4360,8 @@ QUnit.module("Views", (hooks) => {
"</kanban>",
groupBy: ["state"],
async mockRPC(route, { method, args, kwargs }) {
if (method === "create") {
assert.deepEqual(args[0], [{ state: "abc" }]);
if (method === "web_save") {
assert.deepEqual(args[1], { state: "abc" });
assert.strictEqual(kwargs.context.default_state, "abc");
}
},
@@ -4619,10 +4608,7 @@ QUnit.module("Views", (hooks) => {
// Write on the record using the priority widget to trigger a re-render in readonly
await click(target, ".o_kanban_record:first-child .o_priority_star:first-child");
assert.verifySteps([
"/web/dataset/call_kw/partner/write",
"/web/dataset/call_kw/partner/web_read",
]);
assert.verifySteps(["/web/dataset/call_kw/partner/web_save"]);
assert.containsN(
target,
".o_kanban_record:first-child .o_field_many2many_tags .o_tag",
@@ -4993,7 +4979,7 @@ QUnit.module("Views", (hooks) => {
assert.step("resequence");
return true;
}
if (args.model === "partner" && args.method === "write") {
if (args.model === "partner" && args.method === "web_save") {
assert.deepEqual(args.args[1], { state: "abc" });
}
},
@@ -5443,7 +5429,7 @@ QUnit.module("Views", (hooks) => {
"</kanban>",
groupBy: ["product_id"],
async mockRPC(route, { model, method }) {
if (model === "partner" && method === "write") {
if (model === "partner" && method === "web_save") {
return Promise.reject({});
}
},
@@ -8683,7 +8669,7 @@ QUnit.module("Views", (hooks) => {
</templates>
</kanban>`,
async mockRPC(route, { method, args }) {
if (method === "write") {
if (method === "web_save") {
assert.step(`write-color-${args[1].color}`);
}
},
@@ -9918,18 +9904,15 @@ QUnit.module("Views", (hooks) => {
"web_search_read",
"web_search_read",
"web_search_read",
"write",
"web_read",
"web_save",
"read_progress_bar",
"/web/dataset/resequence",
"read",
"write",
"web_read",
"web_save",
"read_progress_bar",
"/web/dataset/resequence",
"read",
"write",
"web_read",
"web_save",
"read_progress_bar",
"/web/dataset/resequence",
"read",
@@ -9989,8 +9972,7 @@ QUnit.module("Views", (hooks) => {
"read_progress_bar",
"web_search_read",
"web_search_read",
"write",
"web_read",
"web_save",
"read_progress_bar",
"web_read_group",
"/web/dataset/resequence",
@@ -10071,8 +10053,7 @@ QUnit.module("Views", (hooks) => {
"read_progress_bar",
"web_search_read",
"web_search_read",
"write",
"web_read",
"web_save",
"read_progress_bar",
"/web/dataset/resequence",
"read",
@@ -10289,7 +10270,7 @@ QUnit.module("Views", (hooks) => {
"web_search_read",
"get_views",
"onchange",
"create",
"web_save",
"web_read",
"read_progress_bar",
"web_read_group",
@@ -10364,13 +10345,13 @@ QUnit.module("Views", (hooks) => {
"web_search_read",
"get_views",
"onchange",
"create",
"web_save",
"web_read",
"read_progress_bar",
"web_read_group",
"web_read_group",
"onchange",
"create",
"web_save",
"web_read",
"read_progress_bar",
"web_read_group",
@@ -10953,7 +10934,7 @@ QUnit.module("Views", (hooks) => {
</templates>
</kanban>`,
async mockRPC(_route, { model, method, args }) {
if (model === "partner" && method === "write") {
if (model === "partner" && method === "web_save") {
assert.step(String(args[0][0]));
}
},
@@ -11539,8 +11520,7 @@ QUnit.module("Views", (hooks) => {
"web_search_read",
"web_search_read",
"web_search_read",
"write",
"web_read",
"web_save",
"read_progress_bar",
"/web/dataset/resequence",
"read",
@@ -11625,8 +11605,7 @@ QUnit.module("Views", (hooks) => {
assert.deepEqual(getTooltips(1), ["1 blip", "1 Other"]);
assert.deepEqual(getCardTexts(1), ["2blip", "3gnap"]);
assert.verifySteps([
"write",
"web_read",
"web_save",
"read_progress_bar",
"web_search_read",
"/web/dataset/resequence",
@@ -12482,8 +12461,7 @@ QUnit.module("Views", (hooks) => {
"web_search_read",
"web_search_read",
"web_search_read",
"write",
"web_read",
"web_save",
"read_progress_bar",
"web_search_read",
"web_search_read",
@@ -13086,8 +13064,7 @@ QUnit.module("Views", (hooks) => {
"read_progress_bar",
"web_search_read",
"web_search_read",
"write",
"web_read",
"web_save",
"read_progress_bar",
"web_read_group",
]);
@@ -13176,7 +13153,7 @@ QUnit.module("Views", (hooks) => {
"name_create", // should perform a name_create to create the record
"get_views", // load views for form view dialog
"onchange", // load of a virtual record in form view dialog
"create", // save virtual record
"web_save", // save virtual record
"web_read", // read the created record to get foo value
"onchange", // reopen the quick create automatically
]);
@@ -13455,7 +13432,7 @@ QUnit.module("Views", (hooks) => {
prom.resolve();
await nextTick();
assert.verifySteps(["write", "web_read", "/web/dataset/resequence", "read"]);
assert.verifySteps(["web_save", "/web/dataset/resequence", "read"]);
assert.deepEqual(
[...target.querySelectorAll(".o_kanban_record")].map((el) => el.innerText),
["hello", "hello", "hello", "xmo"]
@@ -13521,7 +13498,7 @@ QUnit.module("Views", (hooks) => {
</kanban>`,
groupBy: ["product_id"],
mockRPC: async (route, { method }) => {
if (method === "write") {
if (method === "web_save") {
await def;
}
},
@@ -1186,8 +1186,7 @@ QUnit.module("Views", (hooks) => {
assert.verifySteps([
"get_views",
"web_search_read",
"write",
"web_read",
"web_save",
"toDo",
"web_search_read",
]);
@@ -1575,8 +1574,8 @@ QUnit.module("Views", (hooks) => {
</tree>`,
mockRPC(_, { args, method }) {
assert.step(method);
if (method === "create") {
assert.deepEqual(args[0], [{ int_field: 1, foo: false }]);
if (method === "web_save") {
assert.deepEqual(args[1], { int_field: 1, foo: false });
}
},
});
@@ -1588,7 +1587,7 @@ QUnit.module("Views", (hooks) => {
await click(target, ".o_list_view");
assert.containsN(target, ".o_data_row", 5);
assert.strictEqual(target.querySelector(".o_data_row [name='int_field']").textContent, "1");
assert.verifySteps(["onchange", "create", "web_read"]);
assert.verifySteps(["onchange", "web_save"]);
});
QUnit.test("multi_edit: edit a required field with an invalid value", async function (assert) {
@@ -2405,7 +2404,7 @@ QUnit.module("Views", (hooks) => {
groupBy: ["m2m"],
domain: [["m2o", "=", 1]],
mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
assert.deepEqual(args.args[0], [1], "should write on the correct record");
assert.deepEqual(
args.args[1],
@@ -2636,8 +2635,8 @@ QUnit.module("Views", (hooks) => {
serverData,
arch: '<tree js_class="custom_list" editable="top"><field name="foo" required="1"/></tree>',
mockRPC: async (route, args) => {
if (args.method === "write") {
assert.step(`write ${args.args[0]}`);
if (args.method === "web_save") {
assert.step(`web_save ${args.args[0]}`);
}
},
});
@@ -2649,7 +2648,7 @@ QUnit.module("Views", (hooks) => {
await editInput(target, "[name='foo'] input", "YOLO");
await click(target, ".o_list_view");
assert.verifySteps(["onWillSaveRecord 1", "write 1", "onRecordSaved 1"]);
assert.verifySteps(["onWillSaveRecord 1", "web_save 1", "onRecordSaved 1"]);
}
);
@@ -2678,8 +2677,8 @@ QUnit.module("Views", (hooks) => {
arch: '<tree js_class="custom_list" editable="top" expand="1"><field name="foo" required="1"/></tree>',
groupBy: ["bar"],
mockRPC: async (route, args) => {
if (args.method === "write") {
assert.step(`write ${args.args[0]}`);
if (args.method === "web_save") {
assert.step(`web_save ${args.args[0]}`);
}
},
});
@@ -2691,7 +2690,7 @@ QUnit.module("Views", (hooks) => {
await editInput(target, "[name='foo'] input", "YOLO");
await click(target, ".o_list_view");
assert.verifySteps(["onWillSaveRecord 4", "write 4", "onRecordSaved 4"]);
assert.verifySteps(["onWillSaveRecord 4", "web_save 4", "onRecordSaved 4"]);
}
);
@@ -2856,7 +2855,7 @@ QUnit.module("Views", (hooks) => {
</field>
</form>`,
mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
assert.deepEqual(args.args[1], { grosminet: false });
}
},
@@ -2927,8 +2926,8 @@ QUnit.module("Views", (hooks) => {
<field name="bar" widget="boolean_toggle"/>
</tree>`,
mockRPC(route, args) {
if (args.method === "write") {
assert.step("write: " + args.args[1].bar);
if (args.method === "web_save") {
assert.step("web_save: " + args.args[1].bar);
}
},
});
@@ -2939,14 +2938,14 @@ QUnit.module("Views", (hooks) => {
await click(target.querySelector(".o_data_row .o_boolean_toggle input"));
assert.notOk(target.querySelector(".o_data_row .o_boolean_toggle input").checked);
assert.containsNone(target, ".o_selected_row");
assert.verifySteps(["write: false"]);
assert.verifySteps(["web_save: false"]);
// toggle the boolean value after switching the row in edition
assert.containsNone(target, ".o_selected_row");
await click(target.querySelector(".o_data_row .o_data_cell .o_field_boolean_toggle div"));
assert.containsOnce(target, ".o_selected_row");
await click(target.querySelector(".o_selected_row .o_field_boolean_toggle div"));
assert.verifySteps(["write: true"]);
assert.verifySteps(["web_save: true"]);
});
QUnit.test("basic operations for editable list renderer", async function (assert) {
@@ -3086,7 +3085,7 @@ QUnit.module("Views", (hooks) => {
serverData,
arch: '<tree editable="bottom"><field name="foo"/></tree>',
mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
assert.deepEqual(
args.args,
[[1], { foo: "xyz" }],
@@ -8270,8 +8269,8 @@ QUnit.module("Views", (hooks) => {
</tree>`,
noContentHelp: "click to add a partner",
mockRPC(route, args) {
if (args.method === "create") {
assert.step("create");
if (args.method === "web_save") {
assert.step("web_save");
}
},
});
@@ -8322,7 +8321,7 @@ QUnit.module("Views", (hooks) => {
false,
"buttons should not be disabled once the record is created"
);
assert.verifySteps(["create"]);
assert.verifySteps(["web_save"]);
});
QUnit.test("list view, editable, with a button", async function (assert) {
@@ -8337,8 +8336,8 @@ QUnit.module("Views", (hooks) => {
<button string="abc" icon="fa-phone" type="object" name="schedule_another_phonecall"/>
</tree>`,
mockRPC(route, { method }) {
if (method === "create") {
assert.step("create");
if (method === "web_save") {
assert.step("web_save");
} else if (route === "/web/dataset/call_button") {
assert.step("call_button");
return true;
@@ -8360,7 +8359,7 @@ QUnit.module("Views", (hooks) => {
await click(target, "table button");
assert.verifySteps(
["create", "call_button"],
["web_save", "call_button"],
"clicking the button should save the record and then execute the action"
);
});
@@ -8436,8 +8435,8 @@ QUnit.module("Views", (hooks) => {
<field name="int_field" sum="Sum"/>
</tree>`,
mockRPC(route, args) {
if (args.method === "create") {
assert.step("create");
if (args.method === "web_save") {
assert.step("web_save");
}
},
});
@@ -8445,17 +8444,17 @@ QUnit.module("Views", (hooks) => {
await click($(".o_list_button_add:visible").get(0));
await editInput(target, ".o_field_widget[name=foo] input", "new value");
await click(target.querySelector(".o_list_renderer"));
assert.verifySteps(["create"]);
assert.verifySteps(["web_save"]);
await click($(".o_list_button_add:visible").get(0));
await editInput(target, ".o_field_widget[name=foo] input", "new value");
await click(target.querySelector("tfoot"));
assert.verifySteps(["create"]);
assert.verifySteps(["web_save"]);
await click($(".o_list_button_add:visible").get(0));
await editInput(target, ".o_field_widget[name=foo] input", "new value");
await click(target.querySelectorAll("tbody tr")[2].querySelector(".o_data_cell"));
assert.verifySteps(["create"]);
assert.verifySteps(["web_save"]);
});
QUnit.test("editable list view, should refocus date field", async (assert) => {
@@ -9424,8 +9423,7 @@ QUnit.module("Views", (hooks) => {
assert.verifySteps([
"/web/dataset/call_kw/foo/get_views",
"/web/dataset/call_kw/foo/web_search_read",
"/web/dataset/call_kw/foo/write",
"/web/dataset/call_kw/foo/web_read",
"/web/dataset/call_kw/foo/web_save",
"/web/dataset/call_kw/foo/onchange",
]);
});
@@ -9442,7 +9440,7 @@ QUnit.module("Views", (hooks) => {
mockRPC(route, args, performRPC) {
assert.step(args.method);
const result = performRPC(route, args);
if (args.method === "web_read") {
if (args.method === "web_save") {
return readPromise.then(function () {
return result;
});
@@ -9486,7 +9484,7 @@ QUnit.module("Views", (hooks) => {
"5th row should be selected"
);
assert.verifySteps(["get_views", "web_search_read", "write", "web_read", "onchange"]);
assert.verifySteps(["get_views", "web_search_read", "web_save", "onchange"]);
});
QUnit.test("display toolbar", async function (assert) {
@@ -10097,7 +10095,7 @@ QUnit.module("Views", (hooks) => {
1,
"should have the new value visible in dom"
);
assert.verifySteps(["get_views", "web_search_read", "write", "web_read"]);
assert.verifySteps(["get_views", "web_search_read", "web_save"]);
}
);
@@ -11626,7 +11624,7 @@ QUnit.module("Views", (hooks) => {
assert.containsNone(document.body, ".modal");
await clickSave(target);
assert.verifySteps(["create", "web_read"]);
assert.verifySteps(["web_save"]);
// edit a field
await click(rows[0].querySelector("[name=int_field]"));
@@ -12063,7 +12061,7 @@ QUnit.module("Views", (hooks) => {
"gnap",
"blip",
]);
assert.verifySteps(["get_views", "web_search_read", "write", "web_read"]);
assert.verifySteps(["get_views", "web_search_read", "web_save"]);
}
);
@@ -14280,11 +14278,9 @@ QUnit.module("Views", (hooks) => {
"web_read_group",
"web_search_read",
"web_search_read",
"write",
"web_read",
"web_save",
"onchange",
"create",
"web_read",
"web_save",
"onchange",
]);
});
@@ -14331,8 +14327,7 @@ QUnit.module("Views", (hooks) => {
"get_views",
"web_read_group",
"web_search_read",
"write",
"web_read",
"web_save",
]);
}
);
@@ -17110,7 +17105,7 @@ QUnit.module("Views", (hooks) => {
<field name="foo"/>
</tree>`,
mockRPC(route, { args, method, model }) {
if (model === "foo" && method === "write") {
if (model === "foo" && method === "web_save") {
assert.step("save"); // should be called
assert.deepEqual(args, [[1], { foo: "test" }]);
}
@@ -17138,7 +17133,7 @@ QUnit.module("Views", (hooks) => {
<field name="foo"/>
</tree>`,
mockRPC(route, { args, method, model }) {
if (model === "foo" && method === "write") {
if (model === "foo" && method === "web_save") {
assert.deepEqual(args, [[1], { foo: "test" }]);
}
},
@@ -17206,7 +17201,7 @@ QUnit.module("Views", (hooks) => {
if (model === "foo" && method === "onchange") {
return def;
}
if (model === "foo" && method === "write") {
if (model === "foo" && method === "web_save") {
assert.deepEqual(args, [[1], { int_field: 2021 }]);
}
},
@@ -17242,7 +17237,7 @@ QUnit.module("Views", (hooks) => {
if (model === "foo" && method === "onchange") {
return def;
}
if (model === "foo" && method === "write") {
if (model === "foo" && method === "web_save") {
assert.deepEqual(args, [[1], { foo: "test", int_field: 2021 }]);
}
},
@@ -17680,8 +17675,8 @@ QUnit.module("Views", (hooks) => {
</list>`,
serverData,
mockRPC(route, args) {
if (args.method === "write") {
assert.step("write");
if (args.method === "web_save") {
assert.step("web_save");
assert.deepEqual(args.args, [[1], { display_name: "test" }]);
}
},
@@ -17694,7 +17689,7 @@ QUnit.module("Views", (hooks) => {
triggerHotkey("Tab");
await nextTick();
assert.verifySteps(["write"]);
assert.verifySteps(["web_save"]);
});
QUnit.test("edit a field with a slow onchange in a new row", async function (assert) {
@@ -17747,7 +17742,7 @@ QUnit.module("Views", (hooks) => {
// check the current line is added with the correct content
assert.strictEqual(target.querySelector(".o_data_row [name=int_field]").innerText, value);
assert.verifySteps(["create", "web_read"]);
assert.verifySteps(["web_save"]);
});
QUnit.test("create a record with the correct context", async (assert) => {
@@ -17763,8 +17758,8 @@ QUnit.module("Views", (hooks) => {
</list>`,
serverData,
mockRPC(route, args) {
if (args.method === "create") {
assert.step("create");
if (args.method === "web_save") {
assert.step("web_save");
const { context } = args.kwargs;
assert.strictEqual(context.default_text, "yop");
assert.strictEqual(context.test, true);
@@ -17788,7 +17783,7 @@ QUnit.module("Views", (hooks) => {
]
);
assert.verifySteps(["create"]);
assert.verifySteps(["web_save"]);
});
QUnit.test("create a record with the correct context in a group", async (assert) => {
@@ -17804,8 +17799,8 @@ QUnit.module("Views", (hooks) => {
groupBy: ["bar"],
serverData,
mockRPC(route, args) {
if (args.method === "create") {
assert.step("create");
if (args.method === "web_save") {
assert.step("web_save");
const { context } = args.kwargs;
assert.strictEqual(context.default_bar, true);
assert.strictEqual(context.default_text, "yop");
@@ -17832,7 +17827,7 @@ QUnit.module("Views", (hooks) => {
]
);
assert.verifySteps(["create"]);
assert.verifySteps(["web_save"]);
});
QUnit.test(
@@ -18185,7 +18180,7 @@ QUnit.module("Views", (hooks) => {
<field name="foo"/>
</tree>`,
mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
throw new Error("Can't write");
}
},
@@ -18274,6 +18269,8 @@ QUnit.module("Views", (hooks) => {
mockRPC(_, args) {
if (args.method === "web_read") {
assert.step(`web_read ${args.args[0]}`);
} else if (args.method === "web_save") {
assert.step(`web_save ${args.args[0]}`);
}
},
});
@@ -18298,7 +18295,7 @@ QUnit.module("Views", (hooks) => {
[...target.querySelectorAll(".o_data_row td[name=m2o]")].map((el) => el.innerText),
["Value 3", "Value 2", "Value 1", "Value 1"]
);
assert.verifySteps(["web_read 1"]);
assert.verifySteps(["web_save 1"]);
});
QUnit.test("view's context is passed down as evalContext", async (assert) => {
@@ -273,8 +273,7 @@ QUnit.module("Record Component", (hooks) => {
"fields_get",
"web_read",
"onWillSaveRecord",
"write",
"web_read",
"web_save",
"onRecordSaved",
]);
});
@@ -299,7 +299,7 @@ QUnit.module("ViewDialogs", (hooks) => {
};
let reject = true;
function mockRPC(route, args) {
if (args.method === "create" && reject) {
if (args.method === "web_save" && reject) {
return Promise.reject();
}
}
@@ -357,7 +357,7 @@ QUnit.module("ViewDialogs", (hooks) => {
};
const def = makeDeferred();
async function mockRPC(route, args) {
if (args.method === "write") {
if (args.method === "web_save") {
await def;
}
}
@@ -305,13 +305,13 @@ QUnit.module("ViewDialogs", (hooks) => {
if (route === "/web/dataset/call_kw/instrument/get_formview_id") {
return Promise.resolve(false);
}
if (route === "/web/dataset/call_kw/instrument/create") {
if (route === "/web/dataset/call_kw/instrument/web_save") {
assert.deepEqual(
args.args[0],
[{ badassery: [[6, false, [1]]], name: "ABC" }],
args.args[1],
{ badassery: [[6, false, [1]]], name: "ABC" },
"The method create should have been called with the right arguments"
);
return Promise.resolve([90]);
return [{ id: 90 }];
}
},
});
@@ -75,7 +75,7 @@ QUnit.module("Widgets", (hooks) => {
assert.deepEqual(args.kwargs.attachment_ids, [5, 2]);
return true;
}
if (args.method === "write") {
if (args.method === "web_save") {
assert.deepEqual(args.args[1], { display_name: "yop" });
}
if (args.method === "web_read") {
@@ -94,7 +94,7 @@ QUnit.module("Widgets", (hooks) => {
await click(target, ".o_attach_document");
fileInput.dispatchEvent(new Event("change"));
await nextTick();
assert.verifySteps(["write", "web_read", "post", "my_action", "web_read"]);
assert.verifySteps(["web_save", "post", "my_action", "web_read"]);
});
QUnit.test(
@@ -132,8 +132,8 @@ QUnit.module("Widgets", (hooks) => {
assert.deepEqual(args.kwargs.attachment_ids, [5, 2]);
return true;
}
if (args.method === "create") {
assert.deepEqual(args.args[0], [{ display_name: "yop" }]);
if (args.method === "web_save") {
assert.deepEqual(args.args[1], { display_name: "yop" });
}
if (args.method === "web_read") {
assert.deepEqual(args.args[0], [2]);
@@ -151,7 +151,7 @@ QUnit.module("Widgets", (hooks) => {
await click(target, ".o_attach_document");
fileInput.dispatchEvent(new Event("change"));
await nextTick();
assert.verifySteps(["create", "web_read", "post", "my_action", "web_read"]);
assert.verifySteps(["web_save", "post", "my_action", "web_read"]);
}
);
});
@@ -66,7 +66,7 @@ QUnit.module("Widgets", ({ beforeEach }) => {
</form>
`,
mockRPC(route, { args, method }) {
if (method === "write") {
if (method === "web_save") {
writeCall++;
if (writeCall === 1) {
assert.ok(args[1].sun, "value of sunday should be true");
@@ -147,8 +147,7 @@ QUnit.module("ActionManager", (hooks) => {
]);
await testUtils.dom.click(`button[name="5"]`);
assert.verifySteps([
"/web/dataset/call_kw/partner/create",
"/web/dataset/call_kw/partner/web_read",
"/web/dataset/call_kw/partner/web_save",
"/web/action/load",
"/web/dataset/call_kw/partner/get_views",
"/web/dataset/call_kw/partner/onchange",
@@ -156,7 +155,7 @@ QUnit.module("ActionManager", (hooks) => {
assert.containsOnce(document.body, ".modal");
await testUtils.dom.click(`button[name="some_method"]`);
assert.verifySteps([
"/web/dataset/call_kw/partner/create",
"/web/dataset/call_kw/partner/web_save",
"/web/dataset/call_button",
"/web/dataset/call_kw/partner/web_read",
]);
@@ -1202,7 +1202,7 @@ QUnit.module("ActionManager", (hooks) => {
QUnit.test('save when leaving a "dirty" view', async function (assert) {
assert.expect(4);
const mockRPC = async (route, { args, method, model }) => {
if (model === "partner" && method === "write") {
if (model === "partner" && method === "web_save") {
assert.deepEqual(args, [[1], { foo: "pinkypie" }]);
}
};
@@ -1665,7 +1665,7 @@ QUnit.module("ActionManager", (hooks) => {
"web_search_read",
"onchange",
"get_formview_action",
"create", // FIXME: to check with mcm
"web_save", // FIXME: to check with mcm
"get_views",
"web_read",
"web_read",
@@ -1923,7 +1923,7 @@ QUnit.module("ActionManager", (hooks) => {
assert.expect(4);
let writeCalls = 0;
const mockRPC = async (route, { method }) => {
if (method === "write") {
if (method === "web_save") {
writeCalls += 1;
}
};
@@ -357,7 +357,7 @@ QUnit.module("SettingsFormView", (hooks) => {
QUnit.test(
"settings views does not read existing id when coming back in breadcrumbs",
async function (assert) {
assert.expect(11);
assert.expect(10);
serverData.actions = {
1: {
@@ -413,8 +413,7 @@ QUnit.module("SettingsFormView", (hooks) => {
assert.verifySteps([
"get_views", // initial setting action
"onchange", // this is a setting view => new record transient record
"create", // create the record before doing the action
"web_read", // read the created record
"web_save", // create the record before doing the action
"get_views", // for other action in breadcrumb,
"web_search_read", // with a searchread
"onchange", // when we come back, we want to restart from scratch
@@ -556,16 +555,14 @@ QUnit.module("SettingsFormView", (hooks) => {
await click(target.querySelector("button[name='4']"));
assert.verifySteps([
"create", // settings: create the record before doing the action
"web_read", // settings: read the created record
"web_save", // settings: create the record before doing the action
"get_views", // dialog: get views
"onchange", // dialog: onchange
]);
await click(target, ".modal button.btn.btn-primary.o_form_button_save");
assert.verifySteps([
"create", // dialog: create the record before doing back to the settings
"web_read", // dialog: read the created record
"web_save", // dialog: create the record before doing back to the settings
"onchange", // settings: when we come back, we want to restart from scratch
]);
});
@@ -970,9 +967,9 @@ QUnit.module("SettingsFormView", (hooks) => {
};
const mockRPC = (route, args) => {
if (args.method === "create") {
if (args.method === "web_save") {
assert.deepEqual(
args.args[0][0],
args.args[1],
{ foo: true },
"should create a record with foo=true"
);
@@ -1039,8 +1036,7 @@ QUnit.module("SettingsFormView", (hooks) => {
await click(target, ".myBtn");
await click(target, ".modal .btn-primary");
assert.verifySteps([
"create",
"web_read",
"web_save",
'action executed {"name":"execute","type":"object","resModel":"res.config.settings","resId":1,"resIds":[1],"context":{"lang":"en","uid":7,"tz":"taht"},"buttonContext":{}}',
]);
});
@@ -1080,8 +1076,7 @@ QUnit.module("SettingsFormView", (hooks) => {
await click(target, ".myBtn");
await click(target.querySelectorAll(".modal .btn-secondary")[1]);
assert.verifySteps([
"create",
"web_read",
"web_save",
'action executed {"context":{"lang":"en","uid":7,"tz":"taht"},"type":"object","name":"mymethod","resModel":"res.config.settings","resId":1,"resIds":[1],"buttonContext":{}}',
]);
});
@@ -1228,7 +1223,7 @@ QUnit.module("SettingsFormView", (hooks) => {
resModel: "res.config.settings",
serverData,
mockRPC: function (route, args) {
if (args.method === "create" && !self.alreadySavedOnce) {
if (args.method === "web_save" && !self.alreadySavedOnce) {
self.alreadySavedOnce = true;
//fail on first create
return Promise.reject({});
@@ -1308,7 +1303,7 @@ QUnit.module("SettingsFormView", (hooks) => {
let def;
const mockRPC = async (route, args) => {
if (args.method === "web_read") {
if (args.method === "web_save") {
await def; // slow down reload of settings view
}
};
@@ -1406,8 +1401,8 @@ QUnit.module("SettingsFormView", (hooks) => {
if (route === "/web/dataset/call_button" && args.method === "execute") {
assert.step("execute");
return true;
} else if (args.method === "create") {
assert.step("create");
} else if (args.method === "web_save") {
assert.step("web_save");
}
};
@@ -1432,7 +1427,7 @@ QUnit.module("SettingsFormView", (hooks) => {
await click(target.querySelector(".modal-footer .btn-primary"));
assert.verifySteps([
"create", // saveRecord from modal
"web_save", // saveRecord from modal
"execute", // execute_action
]);
}
@@ -173,7 +173,7 @@ QUnit.module("WebEditor.HtmlField", ({ beforeEach }) => {
</sheet>
</form>`,
mockRPC(route, args) {
if (args.method === "write" && args.model === 'partner') {
if (args.method === "web_save" && args.model === 'partner') {
assert.equal(args.args[1].txt, htmlDocumentTextTemplate('Hi', 'blue'));
writePromise.resolve();
}
@@ -355,7 +355,7 @@ QUnit.module("WebEditor.HtmlField", ({ beforeEach }) => {
const newImageSrc = "/web/image/1234/cropped_transparent.png";
const mockRPC = async function (route, args) {
if (
route === '/web/dataset/call_kw/partner/write' &&
route === '/web/dataset/call_kw/partner/web_save' &&
args.model === 'partner'
) {
if (writeCount === 0) {
@@ -17,3 +17,4 @@ from . import test_company_checks
from . import test_unity_read
from . import test_views
from . import test_web_read_group
from . import test_web_save
@@ -0,0 +1,38 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.tests.common import TransactionCase
class TestWebSave(TransactionCase):
def test_web_save_create(self):
''' Test the web_save method on a new record. '''
# Create a new record, without unity specification (it should return only the id)
self.env['test_new_api.person'].search([]).unlink()
result = self.env['test_new_api.person'].web_save({'name': 'ged'}, {})
person = self.env['test_new_api.person'].search([])
self.assertTrue(person.exists())
self.assertEqual(person.name, 'ged')
self.assertEqual(len(result), 1)
self.assertEqual(result, [{'id': person.id}])
# Create a new record, with unity specification
result = self.env['test_new_api.person'].web_save({'name': 'ged'}, {'display_name': {}})
person = self.env['test_new_api.person'].browse(result[0]['id'])
self.assertTrue(person.exists())
self.assertEqual(result, [{'id': person.id, 'display_name': 'ged'}])
def test_web_save_write(self):
''' Test the web_save method on an existing record. '''
person = self.env['test_new_api.person'].create({'name': 'ged'})
# Modify an existing record, without unity specification (it should return only the id)
result = person.web_save({'name': 'aab'}, {})
self.assertEqual(person.name, 'aab')
self.assertEqual(len(result), 1)
self.assertEqual(result, [{'id': person.id}])
# Modify an existing record, with unity specification
result = person.web_save({'name': 'lpe'}, {'display_name': {}})
self.assertEqual(result, [{'id': person.id, 'display_name': 'lpe'}])