合并企业版代码(未测试,先提交到测试分支)
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
odoo.define('web_studio.ReportEditorAction_tests', function (require) {
|
||||
"use strict";
|
||||
|
||||
const { controlPanel } = require('web.test_utils');
|
||||
const { getPagerValue, pagerNext } = controlPanel;
|
||||
|
||||
const { getFixture } = require("@web/../tests/helpers/utils");
|
||||
const { doAction } = require("@web/../tests/webclient/helpers");
|
||||
const { openStudio, registerStudioDependencies,getReportServerData } = require("@web_studio/../tests/helpers");
|
||||
const { createEnterpriseWebClient } = require("@web_enterprise/../tests/helpers");
|
||||
|
||||
let serverData;
|
||||
let target;
|
||||
QUnit.module('Studio', {
|
||||
beforeEach: function () {
|
||||
this.data = {
|
||||
foo: {
|
||||
fields: {},
|
||||
records: [{ id: 22 }, { id: 23 }],
|
||||
},
|
||||
"ir.actions.report": {
|
||||
fields: { model: { type: "char" }, report_name: { type: "char" }, report_type:{ type: "char" }},
|
||||
records: [{ id: 11, model: "foo", report_name: "foo_report", report_type: "pdf" }],
|
||||
},
|
||||
"ir.model": {
|
||||
fields: {},
|
||||
},
|
||||
};
|
||||
const reportServerData = getReportServerData();
|
||||
const actions = {
|
||||
1: {
|
||||
id: 1,
|
||||
xml_id: "kikou.action",
|
||||
name: 'Kikou Action',
|
||||
res_model: 'foo',
|
||||
type: 'ir.actions.act_window',
|
||||
view_mode: 'list,form',
|
||||
views: [[1, 'form']],
|
||||
}
|
||||
};
|
||||
const views = Object.assign({
|
||||
"foo,2,form": `<form><field name="display_name" /></form>`,
|
||||
"foo,false,search": `<search />`,
|
||||
}, reportServerData.views);
|
||||
serverData = {actions, models: this.data, views};
|
||||
Object.assign(serverData.models, reportServerData.models);
|
||||
registerStudioDependencies();
|
||||
target = getFixture();
|
||||
},
|
||||
}, function () {
|
||||
QUnit.module('ReportEditorAction');
|
||||
|
||||
QUnit.test('use pager', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
const reportHTML = `
|
||||
<html>
|
||||
<head/>
|
||||
<body>
|
||||
<div id="wrapwrap">
|
||||
<main>
|
||||
<div class="page"/>
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
const mockRPC = (route, args) => {
|
||||
switch (route) {
|
||||
case "/web_studio/get_report_views":
|
||||
return { report_html: reportHTML };
|
||||
case "/web_studio/get_widgets_available_options":
|
||||
case "/web_studio/read_paperformat":
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
const webClient = await createEnterpriseWebClient({ serverData, mockRPC });
|
||||
await doAction(webClient, 1);
|
||||
await openStudio(target, {report: 11});
|
||||
|
||||
assert.strictEqual(getPagerValue(target), "1");
|
||||
await pagerNext(target);
|
||||
assert.strictEqual(getPagerValue(target), "2");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,800 @@
|
||||
odoo.define('web_studio.ReportEditorComponents_tests', function (require) {
|
||||
"use strict";
|
||||
|
||||
var testUtils = require('web.test_utils');
|
||||
var studioTestUtils = require('web_studio.testUtils');
|
||||
var Widget = require('web.Widget');
|
||||
|
||||
var studioTestUtils = require('web_studio.testUtils');
|
||||
var editComponentsRegistry = require('web_studio.reportEditComponentsRegistry');
|
||||
var reportNewComponentsRegistry = require('web_studio.reportNewComponentsRegistry');
|
||||
|
||||
|
||||
QUnit.module('Studio', {}, function () {
|
||||
|
||||
QUnit.module('ReportComponents', {
|
||||
before: function() {
|
||||
return new Promise(function (resolve, reject) {
|
||||
studioTestUtils.createSidebar({}).then(function (sidebar) {
|
||||
sidebar.destroy();
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
},
|
||||
beforeEach: function () {
|
||||
this.widgetsOptions = {
|
||||
monetary: {
|
||||
company_id: {
|
||||
type: "model",
|
||||
string: "Company",
|
||||
description: "Company used for the original currency (only used for t-esc)",
|
||||
default_value: "Company used to render the template",
|
||||
params: "res.company"
|
||||
},
|
||||
date: {
|
||||
type: "date",
|
||||
string: "Date",
|
||||
description: "Date used for the original currency (only used for t-esc)",
|
||||
default_value: "Current date"
|
||||
},
|
||||
from_currency: {
|
||||
type: "model",
|
||||
string: "Original currency",
|
||||
params: "res.currency"
|
||||
},
|
||||
display_currency: {
|
||||
type: "model",
|
||||
string: "Display currency",
|
||||
required: "value_to_html",
|
||||
params: "res.currency"
|
||||
}
|
||||
},
|
||||
relative: {
|
||||
now: {
|
||||
type: "datetime",
|
||||
string: "Reference date",
|
||||
description: "Date to compare with the field value.",
|
||||
default_value: "Current date"
|
||||
}
|
||||
},
|
||||
image: {},
|
||||
text: {},
|
||||
html: {},
|
||||
many2many: {},
|
||||
date: {
|
||||
format: {
|
||||
type: "string",
|
||||
string: "Date format"
|
||||
}
|
||||
},
|
||||
datetime: {
|
||||
time_only: {
|
||||
type: "boolean",
|
||||
string: "Display only the time"
|
||||
},
|
||||
hide_seconds: {
|
||||
type: "boolean",
|
||||
string: "Hide seconds"
|
||||
},
|
||||
format: {
|
||||
type: "string",
|
||||
string: "Pattern to format"
|
||||
}
|
||||
},
|
||||
qweb: {},
|
||||
many2one: {},
|
||||
integer: {},
|
||||
float_time: {},
|
||||
contact: {
|
||||
separator: {
|
||||
type: "selection",
|
||||
params : {
|
||||
type: "selection",
|
||||
selection: [
|
||||
[" ", "Space"],
|
||||
[",", "Comma"],
|
||||
["-", "Dash"],
|
||||
["|", "Vertical bar"],
|
||||
["/", "Slash"]
|
||||
],
|
||||
placeholder: 'Linebreak',
|
||||
},
|
||||
string: "Address separator",
|
||||
description: "Separator use to split the addresse from the display_name.",
|
||||
default_value: false,
|
||||
},
|
||||
no_marker: {
|
||||
type: "boolean",
|
||||
string: "Hide marker",
|
||||
description: "Don't display the font awsome marker"
|
||||
},
|
||||
country_image: {
|
||||
type: "boolean",
|
||||
string: "Displayed contry image",
|
||||
description: "Display the country image if the field is present on the record"
|
||||
},
|
||||
fields: {
|
||||
type: "array",
|
||||
string: "Displayed fields",
|
||||
description: "List of contact fields to display in the widget",
|
||||
default_value: [
|
||||
"name",
|
||||
"address",
|
||||
"phone",
|
||||
"mobile",
|
||||
"email"
|
||||
],
|
||||
params: {
|
||||
type: "selection",
|
||||
params: [
|
||||
{'field_name': 'name', 'label': 'Name'},
|
||||
{'field_name': 'address', 'label': 'Address'},
|
||||
{'field_name': 'phone', 'label': 'Phone'},
|
||||
{'field_name': 'mobile', 'label': 'Mobile'},
|
||||
{'field_name': 'email', 'label': 'Email'},
|
||||
{'field_name': 'vat', 'label': 'VAT'},
|
||||
]
|
||||
}
|
||||
},
|
||||
no_tag_br: {
|
||||
type: "boolean",
|
||||
string: "Use comma",
|
||||
description: "Use comma instead of the <br> tag to display the address"
|
||||
},
|
||||
phone_icons: {
|
||||
type: "boolean",
|
||||
string: "Displayed phone icons",
|
||||
description: "Display the phone icons even if no_marker is True"
|
||||
}
|
||||
},
|
||||
duration: {
|
||||
unit: {
|
||||
type: "select",
|
||||
string: "Date unit",
|
||||
description: "Date unit used for comparison and formatting",
|
||||
default_value: "hour",
|
||||
params: [
|
||||
[ "year", "year" ],
|
||||
[ "month", "month" ],
|
||||
[ "week", "week" ],
|
||||
[ "day", "day" ],
|
||||
[ "hour", "hour" ],
|
||||
[ "minute", "minute" ],
|
||||
[ "second", "second" ]
|
||||
]
|
||||
},
|
||||
round: {
|
||||
type: "select",
|
||||
string: "Rounding unit",
|
||||
description: "Date unit used for the rounding. If the value is given, this must be smaller than the unit",
|
||||
default_value: "Same unit as \"unit\" option",
|
||||
params: [
|
||||
[ "year", "year" ],
|
||||
[ "month", "month" ],
|
||||
[ "week", "week" ],
|
||||
[ "day", "day" ],
|
||||
[ "hour", "hour" ],
|
||||
[ "minute", "minute" ],
|
||||
[ "second", "second" ]
|
||||
]
|
||||
}
|
||||
},
|
||||
selection: {
|
||||
selection: {
|
||||
type: "selection",
|
||||
string: "Selection",
|
||||
default_value: "Use the field information",
|
||||
required: true
|
||||
}
|
||||
},
|
||||
barcode: {
|
||||
type: {
|
||||
type: "string",
|
||||
string: "Barcode type",
|
||||
description: "Barcode type, eg: UPCA, EAN13, Code128",
|
||||
default_value: "Code128"
|
||||
},
|
||||
width: {
|
||||
type: "integer",
|
||||
string: "Width",
|
||||
default_value: 600
|
||||
},
|
||||
height: {
|
||||
type: "integer",
|
||||
string: "Height",
|
||||
default_value: 100
|
||||
},
|
||||
humanreadable: {
|
||||
type: "integer",
|
||||
string: "Human Readable",
|
||||
default_value: 0
|
||||
}
|
||||
},
|
||||
float: {
|
||||
precision: {
|
||||
type: "integer",
|
||||
string: "Rounding precision"
|
||||
}
|
||||
}
|
||||
};
|
||||
this.data = studioTestUtils.getData({
|
||||
'model.test': {
|
||||
fields: {
|
||||
name: {string: "Name", type: "char"},
|
||||
image: {string: "Image", type: "binary"},
|
||||
child: {string: "Child", type: 'many2one', relation: 'model.test.child', searchable: true},
|
||||
child_bis: {string: "Child Bis", type: 'many2one', relation: 'model.test.child', searchable: true},
|
||||
children: {string: "Children", type: 'many2many', relation: 'model.test.child', searchable: true},
|
||||
},
|
||||
records: [],
|
||||
},
|
||||
'model.test.child': {
|
||||
fields: {
|
||||
name: { string: "Name", type: "char" },
|
||||
company_id: { string: "Company", type: "many2one", relation: 'res.company', searchable: true },
|
||||
currency_id: { string: "Currency", type: "many2one", relation: 'res.currency', searchable: true },
|
||||
date: { string: "Date", type: "datetime", searchable: true },
|
||||
},
|
||||
records: [],
|
||||
},
|
||||
'res.company': {
|
||||
fields: {
|
||||
name: { string: "Name", type: "char" },
|
||||
},
|
||||
records: [],
|
||||
},
|
||||
'res.currency': {
|
||||
fields: {
|
||||
name: { string: "Name", type: "char" },
|
||||
},
|
||||
records: [],
|
||||
},
|
||||
});
|
||||
studioTestUtils.patch();
|
||||
},
|
||||
afterEach: function () {
|
||||
studioTestUtils.unpatch();
|
||||
},
|
||||
}, function () {
|
||||
QUnit.module('New');
|
||||
|
||||
QUnit.test('field', async function (assert) {
|
||||
assert.expect(2);
|
||||
var parent = new Widget();
|
||||
await testUtils.mock.addMockEnvironment(parent, {
|
||||
data: this.data,
|
||||
});
|
||||
await parent.appendTo($('#qunit-fixture'));
|
||||
var InlineField = reportNewComponentsRegistry.get('Inline')[1];
|
||||
|
||||
var tOptions = new InlineField(parent, {
|
||||
models: {
|
||||
'model.test': 'Toto',
|
||||
},
|
||||
});
|
||||
|
||||
tOptions.add({
|
||||
targets: [{
|
||||
data: {},
|
||||
node: {
|
||||
attrs: {
|
||||
'data-oe-id': 99,
|
||||
'data-oe-xpath': '/my/node/path/',
|
||||
},
|
||||
contextOrder: ['toto'],
|
||||
context: {
|
||||
toto: 'model.test',
|
||||
},
|
||||
parent: {
|
||||
children: [],
|
||||
attrs: {},
|
||||
}
|
||||
},
|
||||
}]
|
||||
}).then(function (res) {
|
||||
assert.deepEqual(res.inheritance,
|
||||
[{content: '<span t-field="toto.child"></span>', xpath: '/my/node/path/', view_id: 99, position: undefined}],
|
||||
"Should send the operation");
|
||||
});
|
||||
await testUtils.nextTick();
|
||||
|
||||
await testUtils.dom.triggerEvents($('.o_web_studio_field_modal .o_field_selector'), ['focus']);
|
||||
await testUtils.dom.click($('.o_web_studio_field_modal .o_field_selector_close'));
|
||||
await testUtils.dom.click($('.o_web_studio_field_modal .btn-primary'));
|
||||
|
||||
assert.strictEqual($('.modal main[role="alert"]').length, 1,
|
||||
"Should display an alert because the field name of the record is wrong");
|
||||
await testUtils.dom.click($('.modal:has(main[role="alert"]) .btn-primary'));
|
||||
|
||||
await testUtils.dom.triggerEvents($('.o_web_studio_field_modal .o_field_selector'), ['focus']);
|
||||
await testUtils.dom.click($('.o_web_studio_field_modal .o_field_selector_item[data-name="child"]'));
|
||||
await testUtils.dom.click($('.o_web_studio_field_modal .btn-primary'));
|
||||
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('add a binary field', async function (assert) {
|
||||
assert.expect(1);
|
||||
var parent = new Widget();
|
||||
await testUtils.mock.addMockEnvironment(parent, {
|
||||
data: this.data,
|
||||
});
|
||||
await parent.appendTo($('#qunit-fixture'));
|
||||
var InlineField = reportNewComponentsRegistry.get('Inline')[1];
|
||||
var tOptions = new InlineField(parent, {
|
||||
models: {
|
||||
'model.test': 'Kikou',
|
||||
},
|
||||
});
|
||||
|
||||
tOptions.add({
|
||||
targets: [{
|
||||
data: {},
|
||||
node: {
|
||||
attrs: {
|
||||
'data-oe-id': 99,
|
||||
'data-oe-xpath': '/my/node/path/',
|
||||
},
|
||||
contextOrder: ['toto'],
|
||||
context: {
|
||||
toto: 'model.test',
|
||||
},
|
||||
parent: {
|
||||
children: [],
|
||||
attrs: {},
|
||||
}
|
||||
},
|
||||
}]
|
||||
}).then(function (res) {
|
||||
assert.deepEqual(res.inheritance,
|
||||
[{content: '<span t-field="toto.image" t-options-widget=""image""></span>', xpath: '/my/node/path/', view_id: 99, position: undefined}],
|
||||
"image widget should be set");
|
||||
});
|
||||
await testUtils.nextTick();
|
||||
|
||||
await testUtils.dom.triggerEvents($('.o_web_studio_field_modal .o_field_selector'), ['focus']);
|
||||
await testUtils.dom.click($('.o_web_studio_field_modal .o_field_selector_item[data-name="image"]'));
|
||||
await testUtils.dom.click($('.o_web_studio_field_modal .btn-primary'));
|
||||
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
QUnit.module('Edit');
|
||||
|
||||
QUnit.test('column component with valid classes', async function (assert) {
|
||||
assert.expect(2);
|
||||
var parent = new Widget();
|
||||
await parent.appendTo($('#qunit-fixture'));
|
||||
var column = new (editComponentsRegistry.get('column'))(parent, {
|
||||
node: {
|
||||
attrs: {
|
||||
class: 'col-5 offset-3',
|
||||
},
|
||||
},
|
||||
});
|
||||
await column.appendTo(parent.$el);
|
||||
|
||||
assert.strictEqual(column.$('input[name="size"]').val(), "5",
|
||||
"the size should be correctly set");
|
||||
assert.strictEqual(column.$('input[name="offset"]').val(), "3",
|
||||
"the offset should be correctly set");
|
||||
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('column component with invalid classes', async function (assert) {
|
||||
assert.expect(2);
|
||||
var parent = new Widget();
|
||||
await parent.appendTo($('#qunit-fixture'));
|
||||
var column = new (editComponentsRegistry.get('column'))(parent, {
|
||||
node: {
|
||||
attrs: {
|
||||
class: 'col- offset-kikou',
|
||||
},
|
||||
},
|
||||
});
|
||||
await column.appendTo(parent.$el);
|
||||
|
||||
assert.strictEqual(column.$('input[name="size"]').val(), "",
|
||||
"the size should be unkown");
|
||||
assert.strictEqual(column.$('input[name="offset"]').val(), "",
|
||||
"the offset should be unkown");
|
||||
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('hidden "width" for layout component with col nodes', async function (assert) {
|
||||
assert.expect(1);
|
||||
var parent = new Widget();
|
||||
await testUtils.mock.addMockEnvironment(parent, this);
|
||||
await parent.appendTo($('#qunit-fixture'));
|
||||
var layout = new (editComponentsRegistry.get('layout'))(parent, {
|
||||
node: {
|
||||
tag: 'div',
|
||||
attrs: {
|
||||
class: 'col- offset-kikou',
|
||||
},
|
||||
$nodes: $(),
|
||||
},
|
||||
});
|
||||
await layout.appendTo(parent.$el);
|
||||
|
||||
assert.containsNone(layout.$('.o_web_studio_width'),
|
||||
"the width attribute shouldn't be displayed for div.col nodes");
|
||||
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('tOptions component', async function (assert) {
|
||||
assert.expect(3);
|
||||
var parent = new Widget();
|
||||
await parent.appendTo($('#qunit-fixture'));
|
||||
var tOptions = new (editComponentsRegistry.get('tOptions'))(parent, {
|
||||
widgetsOptions: this.widgetsOptions,
|
||||
node: {
|
||||
attrs: {
|
||||
't-options': '{"widget": "text"}',
|
||||
't-options-widget': '"image"',
|
||||
't-options-other-options': 'True',
|
||||
'data-oe-id': 99,
|
||||
'data-oe-xpath': '/my/node/path/',
|
||||
},
|
||||
},
|
||||
context: {},
|
||||
state: null,
|
||||
models: null,
|
||||
});
|
||||
await tOptions.appendTo(parent.$el);
|
||||
assert.strictEqual(tOptions.$('select').val(), 'image',
|
||||
"Should select the image widget");
|
||||
assert.containsNone(tOptions, '.o_web_studio_toption_option',
|
||||
"there should be no available option");
|
||||
|
||||
// unset the `widget`
|
||||
await testUtils.mock.addMockEnvironment(parent, {
|
||||
intercepts: {
|
||||
view_change: function (ev) {
|
||||
assert.deepEqual(ev.data.operation.new_attrs, {'t-options-widget': '""'},
|
||||
"should correctly delete the group");
|
||||
},
|
||||
},
|
||||
});
|
||||
tOptions.$('select').val('').trigger('change');
|
||||
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('tOptions component parse expression', async function (assert) {
|
||||
assert.expect(5);
|
||||
var parent = new Widget();
|
||||
await parent.appendTo($('#qunit-fixture'));
|
||||
|
||||
var fields = this.data['model.test.child'].fields;
|
||||
fields.company_id = {string: "Company", type: "many2one", relation: 'res.company', searchable: true};
|
||||
fields.currency_id = {string: "Currency", type: "many2one", relation: 'res.currency', searchable: true};
|
||||
fields.date = {string: "Date", type: "datetime", searchable: true};
|
||||
await testUtils.mock.addMockEnvironment(parent, {
|
||||
data: this.data,
|
||||
});
|
||||
|
||||
var tOptions = new (editComponentsRegistry.get('tOptions'))(parent, {
|
||||
widgetsOptions: this.widgetsOptions,
|
||||
node: {
|
||||
attrs: {
|
||||
't-options': 'dict(from_currency=o.child.currency_id, date=o.child.date)',
|
||||
't-options-widget': '"monetary"',
|
||||
't-options-company_id': 'o.child.company_id',
|
||||
'data-oe-id': 99,
|
||||
'data-oe-xpath': '/my/node/path/',
|
||||
},
|
||||
context: {"o": "model.test"},
|
||||
},
|
||||
context: {},
|
||||
state: null,
|
||||
models: {"model.test": "Model Test"},
|
||||
});
|
||||
|
||||
await tOptions.appendTo(parent.$el);
|
||||
assert.strictEqual(tOptions.$('select').val(), 'monetary',
|
||||
"Should select the image widget");
|
||||
assert.containsN(tOptions, '.o_web_studio_toption_option', 4,
|
||||
"there should be 4 available options for the monetary widget");
|
||||
assert.strictEqual(tOptions.$('.o_web_studio_toption_option_monetary_from_currency .o_field_selector_value').text().replace(/\s+/g, ''),
|
||||
"o(ModelTest)ChildCurrency",
|
||||
"Should display the currency field");
|
||||
assert.strictEqual(tOptions.$('.o_web_studio_toption_option_monetary_date .o_field_selector_value').text().replace(/\s+/g, ''),
|
||||
"o(ModelTest)ChildDate",
|
||||
"Should display the data field");
|
||||
assert.strictEqual(tOptions.$('.o_web_studio_toption_option_monetary_company_id .o_field_selector_value').text().replace(/\s+/g, ''),
|
||||
"o(ModelTest)ChildCompany",
|
||||
"Should display the company field");
|
||||
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('tEsc component with parsable expression', async function (assert) {
|
||||
assert.expect(1);
|
||||
var parent = new Widget();
|
||||
await parent.appendTo($('#qunit-fixture'));
|
||||
|
||||
await testUtils.mock.addMockEnvironment(parent, {
|
||||
data: this.data,
|
||||
});
|
||||
|
||||
var tOptions = new (editComponentsRegistry.get('tEsc'))(parent, {
|
||||
node: {
|
||||
attrs: {
|
||||
't-esc': 'o.child.company_id',
|
||||
'data-oe-id': 99,
|
||||
'data-oe-xpath': '/my/node/path/',
|
||||
},
|
||||
context: {"o": "model.test"},
|
||||
},
|
||||
context: {},
|
||||
state: null,
|
||||
models: {"model.test": "Model Test"},
|
||||
});
|
||||
await tOptions.appendTo(parent.$el);
|
||||
await testUtils.nextTick();
|
||||
// the component value is parsable so we display it with ModelFieldSelector
|
||||
assert.strictEqual(tOptions.$('.o_field_selector_value').text().replace(/\s+/g, ''),
|
||||
"o(ModelTest)ChildCompany",
|
||||
"Should display the company field");
|
||||
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('tEsc component with non-parsable expression', async function (assert) {
|
||||
assert.expect(1);
|
||||
var parent = new Widget();
|
||||
await parent.appendTo($('#qunit-fixture'));
|
||||
|
||||
await testUtils.mock.addMockEnvironment(parent, {
|
||||
data: this.data,
|
||||
});
|
||||
|
||||
var tOptions = new (editComponentsRegistry.get('tEsc'))(parent, {
|
||||
node: {
|
||||
attrs: {
|
||||
't-esc': 'o.child.getCompany()',
|
||||
'data-oe-id': 99,
|
||||
'data-oe-xpath': '/my/node/path/',
|
||||
},
|
||||
context: {"o": "model.test"},
|
||||
},
|
||||
context: {},
|
||||
state: null,
|
||||
models: {"model.test": "Model Test"},
|
||||
});
|
||||
await tOptions.appendTo(parent.$el);
|
||||
await testUtils.nextTick();
|
||||
// the component can not parse the value so we display a simple input
|
||||
assert.strictEqual(tOptions.$('input[name="t-esc"]').val(),
|
||||
"o.child.getCompany()",
|
||||
"Should display the company field");
|
||||
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('contact: many2many_select', async function (assert) {
|
||||
assert.expect(11);
|
||||
var parent = new Widget();
|
||||
|
||||
$('ul.ui-autocomplete').remove(); // clean the body to avoid errors due to another test
|
||||
|
||||
var optionsFields;
|
||||
await testUtils.mock.addMockEnvironment(parent, {
|
||||
intercepts: {
|
||||
view_change: function (ev) {
|
||||
assert.deepEqual(ev.data.operation.new_attrs['t-options-fields'], optionsFields,
|
||||
'Should save the contact options');
|
||||
|
||||
params.node.attrs['t-options-fields'] = JSON.stringify(ev.data.operation.new_attrs['t-options-fields']);
|
||||
},
|
||||
},
|
||||
});
|
||||
await parent.appendTo($('#qunit-fixture'));
|
||||
|
||||
var params = {
|
||||
widgetsOptions: this.widgetsOptions,
|
||||
node: {
|
||||
attrs: {
|
||||
't-options': '{"widget": "contact"}',
|
||||
't-options-no_marker': 'True',
|
||||
'data-oe-id': 99,
|
||||
'data-oe-xpath': '/my/node/path/',
|
||||
},
|
||||
},
|
||||
context: {},
|
||||
state: null,
|
||||
models: null,
|
||||
};
|
||||
|
||||
var tOptions = new (editComponentsRegistry.get('tOptions'))(parent, params);
|
||||
await tOptions.appendTo(parent.$el);
|
||||
assert.containsN(tOptions, '.o_web_studio_toption_option', 3,
|
||||
"there should be 3 available options for the contact widget (they are filtered)");
|
||||
assert.strictEqual(tOptions.$('.o_badge_text').text(), 'NameAddressPhoneMobileEmail', 'Should display default value');
|
||||
await testUtils.dom.click(tOptions.$('.o_input_dropdown input'));
|
||||
assert.strictEqual($('ul.ui-autocomplete .ui-menu-item').length, 1, 'Should not display the unselected items');
|
||||
assert.strictEqual($('ul.ui-autocomplete .o_m2o_dropdown_option').length, 0, 'Should not display create button');
|
||||
|
||||
optionsFields = ["name", "address", "phone", "mobile", "email", "vat"];
|
||||
await testUtils.dom.click($('ul.ui-autocomplete .ui-menu-item:contains(VAT)'));
|
||||
tOptions.destroy();
|
||||
|
||||
tOptions = new (editComponentsRegistry.get('tOptions'))(parent, params);
|
||||
await tOptions.appendTo(parent.$el);
|
||||
assert.strictEqual(tOptions.$('.o_badge_text').text(), 'NameAddressPhoneMobileEmailVAT', 'Should display the new value');
|
||||
await testUtils.dom.click(tOptions.$('.o_input_dropdown input'));
|
||||
assert.strictEqual($('ul.ui-autocomplete .ui-menu-item').length, 0, 'Should not display the unselected items');
|
||||
await testUtils.dom.click(tOptions.$('.o_input_dropdown input'));
|
||||
|
||||
optionsFields = ["address", "phone", "mobile", "email", "vat"];
|
||||
await testUtils.dom.click(tOptions.$('.o_field_many2manytags .o_delete:first'));
|
||||
assert.strictEqual(tOptions.$('.o_badge_text').text(), 'AddressPhoneMobileEmailVAT', 'Should display the new value without "name"');
|
||||
|
||||
optionsFields = ["phone", "mobile", "email", "vat"];
|
||||
await testUtils.dom.click(tOptions.$('.o_field_many2manytags .o_delete:first'));
|
||||
assert.strictEqual(tOptions.$('.o_badge_text').text(), 'PhoneMobileEmailVAT', 'Should display the new value without "address"');
|
||||
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('contact: address separator', async function (assert) {
|
||||
assert.expect(3);
|
||||
var parent = new Widget();
|
||||
|
||||
var addressSeparator;
|
||||
await testUtils.mock.addMockEnvironment(parent, {
|
||||
intercepts: {
|
||||
view_change: function (ev) {
|
||||
assert.strictEqual(ev.data.operation.new_attrs['t-options-separator'], addressSeparator,
|
||||
'Should save the selected address separator');
|
||||
},
|
||||
},
|
||||
});
|
||||
await parent.appendTo($('#qunit-fixture'));
|
||||
|
||||
var params = {
|
||||
widgetsOptions: this.widgetsOptions,
|
||||
node: {
|
||||
attrs: {
|
||||
't-options': '{"widget": "contact"}',
|
||||
't-options-no_marker': 'True',
|
||||
'data-oe-id': 99,
|
||||
'data-oe-xpath': '/my/node/path/',
|
||||
},
|
||||
},
|
||||
context: {},
|
||||
state: null,
|
||||
models: null,
|
||||
};
|
||||
|
||||
var tOptions = new (editComponentsRegistry.get('tOptions'))(parent, params);
|
||||
await tOptions.appendTo(parent.$el);
|
||||
var separators = _.map(tOptions.$('.o_web_studio_toption_option_contact_separator .o_field_widget option'), function (option) {
|
||||
return JSON.parse($(option).val());
|
||||
});
|
||||
assert.deepEqual(separators, [false, " ", ",", "-", "|", "/"], 'There should be a selection field with proper values');
|
||||
assert.strictEqual(tOptions.$('.o_web_studio_toption_option_contact_separator .o_field_widget option:selected').text(), 'Linebreak',
|
||||
'Default value should be "LineBrak"');
|
||||
addressSeparator = '","';
|
||||
await testUtils.fields.editSelect(tOptions.$('.o_web_studio_toption_option_contact_separator .o_field_widget'), addressSeparator);
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('contact: no_marker boolean field', async function (assert) {
|
||||
assert.expect(2);
|
||||
var parent = new Widget();
|
||||
|
||||
await testUtils.mock.addMockEnvironment(parent, {
|
||||
intercepts: {
|
||||
view_change: function (ev) {
|
||||
assert.strictEqual(ev.data.operation.new_attrs["t-options-no_marker"], false,
|
||||
'Toggling no_marker checkbox should change the option value');
|
||||
},
|
||||
},
|
||||
});
|
||||
await parent.appendTo($('#qunit-fixture'));
|
||||
|
||||
var params = {
|
||||
widgetsOptions: this.widgetsOptions,
|
||||
node: {
|
||||
attrs: {
|
||||
't-options': '{"widget": "contact"}',
|
||||
't-options-no_marker': 'True',
|
||||
'data-oe-id': 99,
|
||||
'data-oe-xpath': '/my/node/path/',
|
||||
},
|
||||
},
|
||||
context: {},
|
||||
state: null,
|
||||
models: null,
|
||||
};
|
||||
var tOptions = new (editComponentsRegistry.get('tOptions'))(parent, params);
|
||||
await tOptions.appendTo(parent.$el);
|
||||
|
||||
assert.containsOnce(tOptions, '.o_web_studio_toption_option_contact_no_marker input:checked',
|
||||
"no_marker checkbox is checked initially");
|
||||
await testUtils.dom.click(tOptions.$('.o_web_studio_toption_option_contact_no_marker input'));
|
||||
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('no search more in many2many_select', async function (assert) {
|
||||
assert.expect(3);
|
||||
var parent = new Widget();
|
||||
|
||||
$('ul.ui-autocomplete').remove(); // clean the body to avoid errors due to another test
|
||||
|
||||
await parent.appendTo($('#qunit-fixture'));
|
||||
|
||||
// to display more options in the many2many_select
|
||||
this.widgetsOptions.contact.fields.default_value = [];
|
||||
|
||||
var tOptions = new (editComponentsRegistry.get('tOptions'))(parent, {
|
||||
widgetsOptions: this.widgetsOptions,
|
||||
node: {
|
||||
attrs: {
|
||||
't-options': '{"widget": "contact"}',
|
||||
't-options-no_marker': 'True',
|
||||
'data-oe-id': 99,
|
||||
'data-oe-xpath': '/my/node/path/',
|
||||
},
|
||||
},
|
||||
context: {},
|
||||
state: null,
|
||||
models: null,
|
||||
});
|
||||
await tOptions.appendTo(parent.$el);
|
||||
|
||||
assert.strictEqual(tOptions.$('.o_badge_text').text(), '', 'Should display default value');
|
||||
await testUtils.dom.click(tOptions.$('.o_input_dropdown input'));
|
||||
assert.strictEqual($('ul.ui-autocomplete .ui-menu-item').length, 6 , 'Should not display the unselected items');
|
||||
assert.strictEqual($('ul.ui-autocomplete .o_m2o_dropdown_option').length, 0, 'Should not display create button nor the search more');
|
||||
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('groups component', async function (assert) {
|
||||
assert.expect(3);
|
||||
var parent = new Widget();
|
||||
await parent.appendTo($('#qunit-fixture'));
|
||||
var groups = new (editComponentsRegistry.get('groups'))(parent, {
|
||||
widgets: this.widgets,
|
||||
node: {
|
||||
tag: 'span',
|
||||
attrs: {
|
||||
studio_groups: "[" +
|
||||
"{\"name\": \"group_A\", \"display_name\": \"My Awesome Group\", \"id\": 42}," +
|
||||
"{\"name\": \"group_13\", \"display_name\": \"Kikou\", \"id\": 13}" +
|
||||
"]",
|
||||
},
|
||||
},
|
||||
});
|
||||
await groups.appendTo(parent.$el);
|
||||
|
||||
assert.containsN(groups, '.o_field_many2manytags .o_badge_text', 2,
|
||||
"there should be displayed two groups");
|
||||
assert.strictEqual(groups.$('.o_field_many2manytags').text().replace(/\s/g, ''), "MyAwesomeGroupKikou",
|
||||
"the groups should be correctly set");
|
||||
|
||||
// delete a group
|
||||
await testUtils.mock.addMockEnvironment(parent, {
|
||||
intercepts: {
|
||||
view_change: function (ev) {
|
||||
assert.deepEqual(ev.data.operation.new_attrs, {groups: [13]},
|
||||
"should correctly delete the group");
|
||||
},
|
||||
},
|
||||
});
|
||||
await testUtils.dom.click(groups.$('.o_field_many2manytags .o_delete:first'));
|
||||
|
||||
parent.destroy();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,914 @@
|
||||
odoo.define('web_studio.ReportEditorSidebar_tests', function (require) {
|
||||
"use strict";
|
||||
|
||||
const { nextTick } = require("@web/../tests/helpers/utils");
|
||||
|
||||
var testUtils = require('web.test_utils');
|
||||
|
||||
var studioTestUtils = require('web_studio.testUtils');
|
||||
|
||||
QUnit.module('Studio', {}, function () {
|
||||
|
||||
QUnit.module('ReportEditorSidebar', {
|
||||
beforeEach: function () {
|
||||
this.data = {
|
||||
'report.paperformat': {
|
||||
fields: {
|
||||
display_name: {string: "Name", type: "char"},
|
||||
},
|
||||
records: [{
|
||||
id: 42,
|
||||
display_name: 'My Awesome Format',
|
||||
}],
|
||||
},
|
||||
'res.groups': {
|
||||
fields: {
|
||||
display_name: {string: "Name", type: "char"},
|
||||
},
|
||||
records: [{
|
||||
id: 6,
|
||||
display_name: 'Group6',
|
||||
}, {
|
||||
id: 7,
|
||||
display_name: 'Group7',
|
||||
}],
|
||||
},
|
||||
'x_mymodel': {
|
||||
fields: {
|
||||
display_name: {string: "Name", type: "char"},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
this.widgetsOptions = {
|
||||
image: {},
|
||||
integer: {},
|
||||
text: {},
|
||||
};
|
||||
},
|
||||
}, function () {
|
||||
QUnit.test("basic rendering", async function (assert) {
|
||||
var done = assert.async();
|
||||
assert.expect(5);
|
||||
|
||||
studioTestUtils.createSidebar({
|
||||
state: { mode: 'report' },
|
||||
report: {},
|
||||
}).then(async function (sidebar) {
|
||||
|
||||
assert.hasClass(sidebar.$('.o_web_studio_sidebar_header [name="report"]'),'active',
|
||||
"the report tab should be active");
|
||||
assert.hasClass(sidebar.$('.o_web_studio_sidebar_header [name="options"]'),'inactive',
|
||||
"the options tab should be inactive");
|
||||
|
||||
testUtils.mock.intercept(sidebar, 'sidebar_tab_changed', function (ev) {
|
||||
assert.step(ev.data.mode);
|
||||
});
|
||||
testUtils.dom.click(sidebar.$('.o_web_studio_sidebar_header [name="new"]'));
|
||||
assert.verifySteps(['new'], "the sidebar should be updated");
|
||||
|
||||
await testUtils.dom.click(sidebar.$('.o_web_studio_sidebar_header [name="options"]'));
|
||||
assert.verifySteps([], "one should not be able to select options");
|
||||
|
||||
sidebar.destroy();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test("'Report' tab behaviour", async function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
return studioTestUtils.createSidebar({
|
||||
data: this.data,
|
||||
state: { mode: 'report' },
|
||||
report: {
|
||||
name: 'Kikou',
|
||||
},
|
||||
}).then(async function (sidebar) {
|
||||
|
||||
assert.hasAttrValue(sidebar.$('.o_web_studio_sidebar_header > .active'), 'name', "report",
|
||||
"the 'Report' tab should be active");
|
||||
assert.strictEqual(sidebar.$('input[name="name"]').val(), "Kikou",
|
||||
"the report name should be displayed");
|
||||
|
||||
testUtils.mock.intercept(sidebar, 'studio_edit_report', function (ev) {
|
||||
if (ev.data.name) {
|
||||
assert.deepEqual(ev.data, { name: "wow_report" });
|
||||
} else if ('paperformat_id' in ev.data) {
|
||||
paperformatValues.push(ev.data);
|
||||
} else if (ev.data.groups_id) {
|
||||
assert.deepEqual(ev.data, { groups_id: [7] });
|
||||
}
|
||||
});
|
||||
// edit report name
|
||||
sidebar.$('input[name="name"]').val("wow_report").trigger('change');
|
||||
|
||||
// edit the report paperformat
|
||||
var paperformatValues = [];
|
||||
await testUtils.fields.many2one.clickOpenDropdown('paperformat_id');
|
||||
await testUtils.fields.many2one.clickHighlightedItem('paperformat_id');
|
||||
assert.deepEqual(paperformatValues, [{ paperformat_id: 42 }]);
|
||||
|
||||
// remove the report paperformat
|
||||
sidebar.$('[name="paperformat_id"] input').val('').trigger('keyup').trigger('focusout');
|
||||
await testUtils.nextTick();
|
||||
assert.deepEqual(paperformatValues, [{ paperformat_id: 42 }, { paperformat_id: false }]);
|
||||
|
||||
// edit groups
|
||||
await testUtils.fields.many2one.clickOpenDropdown('groups_id');
|
||||
await testUtils.fields.many2one.clickItem('groups_id', 'Group7');
|
||||
|
||||
sidebar.destroy();
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test("'Add' tab behaviour", function (assert) {
|
||||
var done = assert.async();
|
||||
assert.expect(2);
|
||||
|
||||
studioTestUtils.createSidebar({
|
||||
state: { mode: 'new' },
|
||||
}).then(function (sidebar) {
|
||||
|
||||
assert.hasAttrValue(sidebar.$('.o_web_studio_sidebar_header > .active'), 'name', "new",
|
||||
"the 'Add' tab should be active");
|
||||
assert.ok(sidebar.$('.ui-draggable').length,
|
||||
"there should be draggable components");
|
||||
|
||||
sidebar.destroy();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test("basic 'Options' tab behaviour", function (assert) {
|
||||
var done = assert.async();
|
||||
assert.expect(4);
|
||||
|
||||
var node = {
|
||||
node: {
|
||||
attrs: {
|
||||
'data-oe-id': '42',
|
||||
'data-oe-xpath': '/t/t/div',
|
||||
},
|
||||
tag: 'span',
|
||||
$nodes: $(),
|
||||
},
|
||||
};
|
||||
studioTestUtils.createSidebar({
|
||||
state: {
|
||||
mode: 'properties',
|
||||
nodes: [node],
|
||||
},
|
||||
}).then(function (sidebar) {
|
||||
|
||||
assert.hasAttrValue(sidebar.$('.o_web_studio_sidebar_header > .active'), 'name', "options",
|
||||
"the 'Options' tab should be active");
|
||||
assert.containsOnce(sidebar, '.o_web_studio_sidebar_content .collapse',
|
||||
"there should be one node in the accordion");
|
||||
assert.hasClass(sidebar.$('.o_web_studio_sidebar_content .collapse'),'show',
|
||||
"the node should be expanded by default");
|
||||
|
||||
// remove the element
|
||||
testUtils.mock.intercept(sidebar, 'element_removed', function (ev) {
|
||||
assert.deepEqual(ev.data.node, node.node);
|
||||
});
|
||||
testUtils.dom.click(sidebar.$('.o_web_studio_sidebar_content .collapse .o_web_studio_remove'));
|
||||
|
||||
sidebar.destroy();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test("'Options' tab with multiple nodes", async function (assert) {
|
||||
assert.expect(9);
|
||||
|
||||
var node1 = {
|
||||
node: {
|
||||
attrs: {
|
||||
'data-oe-id': '42',
|
||||
'data-oe-xpath': '/t/t/div',
|
||||
},
|
||||
tag: 'span',
|
||||
$nodes: $(),
|
||||
},
|
||||
};
|
||||
|
||||
var node2 = {
|
||||
node: {
|
||||
attrs: {
|
||||
'data-oe-id': '40',
|
||||
'data-oe-xpath': '/t/t',
|
||||
},
|
||||
tag: 'div',
|
||||
$nodes: $(),
|
||||
},
|
||||
};
|
||||
const sidebar = await studioTestUtils.createSidebar({
|
||||
state: {
|
||||
mode: 'properties',
|
||||
nodes: [node1, node2],
|
||||
},
|
||||
});
|
||||
|
||||
assert.hasAttrValue(sidebar.$('.o_web_studio_sidebar_header > .active'), 'name', "options",
|
||||
"the 'Options' tab should be active");
|
||||
assert.containsN(sidebar, '.o_web_studio_sidebar_content .card', 2,
|
||||
"there should be one node in the accordion");
|
||||
assert.hasClass(sidebar.$('.o_web_studio_sidebar_content .card:has(.o_text:contains(span)) .collapse'),'show',
|
||||
"the 'span' node should be expanded by default");
|
||||
assert.doesNotHaveClass(sidebar.$('.o_web_studio_sidebar_content .card:has(.o_text:contains(div)) .collapse'), 'show',
|
||||
"the 'div' node shouldn't be expanded");
|
||||
assert.strictEqual(sidebar.$('.o_web_studio_sidebar_content .o_web_studio_accordion > .card:last .card-header:first').text().trim(), "span",
|
||||
"the last node should be the span");
|
||||
|
||||
// expand the first node
|
||||
// BS4 collapsing is asynchronous
|
||||
await new Promise((resolve) => {
|
||||
$(document.body).one("hidden.bs.collapse", () => {
|
||||
resolve();
|
||||
});
|
||||
testUtils.dom.click(sidebar.$('.o_web_studio_sidebar_content .o_web_studio_accordion > .card:first [data-bs-toggle="collapse"]:first'));
|
||||
})
|
||||
// await end of transitions: https://getbootstrap.com/docs/5.0/components/collapse/#example
|
||||
await nextTick()
|
||||
assert.doesNotHaveClass(sidebar.$('.o_web_studio_sidebar_content .card:has(.o_text:contains(span)) .collapse:first'), 'show',
|
||||
"the 'span' node should have been closed");
|
||||
assert.hasClass(sidebar.$('.o_web_studio_sidebar_content .card:has(.o_text:contains(div)) .collapse:first'),'show',
|
||||
"the 'div' node should be expanded");
|
||||
|
||||
// reexpand the second node
|
||||
await new Promise((resolve) => {
|
||||
$(document.body).one("shown.bs.collapse", () => {
|
||||
resolve();
|
||||
});
|
||||
testUtils.dom.click(sidebar.$('.o_web_studio_sidebar_content .o_web_studio_accordion > .card:last [data-bs-toggle="collapse"]:first'));
|
||||
})
|
||||
await nextTick();
|
||||
assert.hasClass(sidebar.$('.o_web_studio_sidebar_content .card:has(.o_text:contains(span)) .collapse:first'),'show',
|
||||
"the 'span' node should be expanded again");
|
||||
assert.doesNotHaveClass(sidebar.$('.o_web_studio_sidebar_content .card:has(.o_text:contains(div)) .collapse:first'), 'show',
|
||||
"the 'div' node shouldn't be expanded anymore");
|
||||
|
||||
sidebar.destroy();
|
||||
});
|
||||
|
||||
QUnit.test("'Options' tab with layout component can be expanded", function (assert) {
|
||||
var done = assert.async();
|
||||
assert.expect(3);
|
||||
|
||||
var node = {
|
||||
node: {
|
||||
attrs: {
|
||||
'data-oe-id': '42',
|
||||
'data-oe-xpath': '/t/t/div',
|
||||
},
|
||||
tag: 'span',
|
||||
$nodes: $(),
|
||||
},
|
||||
};
|
||||
studioTestUtils.createSidebar({
|
||||
state: {
|
||||
mode: 'properties',
|
||||
nodes: [node],
|
||||
},
|
||||
}).then(function (sidebar) {
|
||||
|
||||
assert.containsOnce(sidebar, '.o_web_studio_sidebar_content .collapse',
|
||||
"there should be one node in the accordion");
|
||||
assert.containsOnce(sidebar, '.o_web_studio_sidebar_content .o_web_studio_layout',
|
||||
"there should be a layout component");
|
||||
assert.containsOnce(sidebar, '.o_web_studio_sidebar_content .o_web_studio_layout .o_web_studio_margin',
|
||||
"there should be a margin section in the layout component");
|
||||
|
||||
sidebar.destroy();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test("'Options' tab with layout component can be expanded on open ", function (assert) {
|
||||
var done = assert.async();
|
||||
assert.expect(1);
|
||||
|
||||
var node = {
|
||||
node: {
|
||||
attrs: {
|
||||
'data-oe-id': '42',
|
||||
'data-oe-xpath': '/t/t/div',
|
||||
},
|
||||
tag: 'span',
|
||||
$nodes: $(),
|
||||
},
|
||||
};
|
||||
studioTestUtils.createSidebar({
|
||||
state: {
|
||||
mode: 'properties',
|
||||
nodes: [node],
|
||||
},
|
||||
previousState: {
|
||||
"42/t/t/div": { 'layout': { showAll: true } }, // opens the layout expanded
|
||||
},
|
||||
}).then(function (sidebar) {
|
||||
|
||||
assert.equal(sidebar.$('.o_web_studio_width:visible').length, 1);
|
||||
|
||||
sidebar.destroy();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test("'Options' tab with layout component can be expanded on open with hierarchy", function (assert) {
|
||||
var done = assert.async();
|
||||
assert.expect(2);
|
||||
|
||||
var nodes = [
|
||||
{
|
||||
context: {'rec': 'int'},
|
||||
node: {
|
||||
attrs: {
|
||||
'data-oe-id': '42',
|
||||
'data-oe-xpath': '/t/t/t/t/div',
|
||||
't-esc': 'rec',
|
||||
},
|
||||
tag: 'span',
|
||||
$nodes: $(),
|
||||
}
|
||||
},
|
||||
{
|
||||
context: {'rec': 'int'},
|
||||
node: {
|
||||
attrs: {
|
||||
'data-oe-id': '42',
|
||||
'data-oe-xpath': '/t/t/t/t',
|
||||
't-if': 'o.is_ok',
|
||||
},
|
||||
tag: 'div',
|
||||
$nodes: $(),
|
||||
},
|
||||
},
|
||||
{
|
||||
context: {'rec': 'int'},
|
||||
node: {
|
||||
attrs: {
|
||||
'data-oe-id': '42',
|
||||
'data-oe-xpath': '/t/t/t',
|
||||
't-else': '',
|
||||
},
|
||||
tag: 't',
|
||||
$nodes: $(),
|
||||
},
|
||||
},
|
||||
{
|
||||
context: {},
|
||||
node: {
|
||||
attrs: {
|
||||
'data-oe-id': '42',
|
||||
'data-oe-xpath': '/t/t',
|
||||
't-foreach': '5',
|
||||
't-as': 'rec',
|
||||
},
|
||||
tag: 't',
|
||||
$nodes: $(),
|
||||
},
|
||||
},
|
||||
{
|
||||
context: {},
|
||||
node: {
|
||||
attrs: {
|
||||
'data-oe-id': '42',
|
||||
'data-oe-xpath': '/t',
|
||||
't-name': 'my.template',
|
||||
},
|
||||
tag: 't',
|
||||
$nodes: $(),
|
||||
},
|
||||
},
|
||||
];
|
||||
nodes[0].node.parent = nodes[1].node;
|
||||
nodes[1].node.children = [nodes[0].node]
|
||||
nodes[1].node.parent = nodes[2].node;
|
||||
nodes[2].node.children = [nodes[1].node]
|
||||
nodes[2].node.parent = nodes[3].node;
|
||||
nodes[3].node.children = [{tag: 'span', attrs: {'t-if': 'false'}, $nodes: $(), parent: nodes[3].node}, nodes[2].node]
|
||||
nodes[3].node.parent = nodes[4].node;
|
||||
nodes[4].node.children = [nodes[3].node]
|
||||
nodes[4].node.parent = null;
|
||||
|
||||
studioTestUtils.createSidebar({
|
||||
state: {
|
||||
mode: 'properties',
|
||||
nodes: nodes,
|
||||
},
|
||||
previousState: {
|
||||
"42/t/t/t/t/div": { 'layout': { showAll: true } }, // opens the layout expanded
|
||||
},
|
||||
}).then(function (sidebar) {
|
||||
|
||||
assert.equal(sidebar.$('.card').length, 5, 'Should have 5 item');
|
||||
assert.equal(sidebar.$('.card h5 > button').get().map(el => el.textContent.replace(/[\s\n]+/g, ' ').trim()).join(' > '), 't > t [foreach="5"] > t > div > span [rec]', 'Should have all ordered parents');
|
||||
|
||||
sidebar.destroy();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test("'Options' tab with widget selection (tOptions) component", function (assert) {
|
||||
var done = assert.async();
|
||||
assert.expect(4);
|
||||
|
||||
var node = {
|
||||
context: {
|
||||
'doc': 'x_mymodel',
|
||||
},
|
||||
node: {
|
||||
attrs: {
|
||||
'data-oe-id': '42',
|
||||
'data-oe-xpath': '/t/t/div',
|
||||
't-field': 'doc.id',
|
||||
't-options-widget': '"text"',
|
||||
},
|
||||
tag: 'span',
|
||||
$nodes: $(),
|
||||
},
|
||||
};
|
||||
studioTestUtils.createSidebar({
|
||||
state: {
|
||||
mode: 'properties',
|
||||
nodes: [node],
|
||||
},
|
||||
widgetsOptions: this.widgetsOptions,
|
||||
}).then(function (sidebar) {
|
||||
|
||||
assert.containsOnce(sidebar, '.o_web_studio_tfield_fieldexpression',
|
||||
"the t-field component should be displayed");
|
||||
assert.containsOnce(sidebar, '.o_web_studio_toption_widget',
|
||||
"the t-options component should be displayed");
|
||||
assert.strictEqual(sidebar.$('.o_web_studio_toption_widget select').text().replace(/\s/g, ''), "imageintegertext",
|
||||
"all widgets should be selectable");
|
||||
assert.strictEqual(sidebar.$('.o_web_studio_toption_widget select').val(), "text",
|
||||
"the correct widget should be selected");
|
||||
|
||||
sidebar.destroy();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test("'Options' tab with FieldSelector does not flicker", async function (assert) {
|
||||
assert.expect(3);
|
||||
var def = testUtils.makeTestPromise();
|
||||
|
||||
var node = {
|
||||
context: {
|
||||
'doc': 'x_mymodel',
|
||||
},
|
||||
node: {
|
||||
attrs: {
|
||||
'data-oe-id': '42',
|
||||
'data-oe-xpath': '/t/t/div',
|
||||
't-field': 'doc.id',
|
||||
't-options-widget': '"text"',
|
||||
},
|
||||
context: {
|
||||
'doc': 'x_mymodel',
|
||||
},
|
||||
tag: 'span',
|
||||
$nodes: $(),
|
||||
},
|
||||
};
|
||||
var sidebarDef = studioTestUtils.createSidebar({
|
||||
data: this.data,
|
||||
models: {
|
||||
'x_mymodel': 'My Model',
|
||||
},
|
||||
state: {
|
||||
mode: 'properties',
|
||||
nodes: [node],
|
||||
},
|
||||
widgetsOptions: this.widgetsOptions,
|
||||
mockRPC: function (route, args) {
|
||||
if (args.model === 'x_mymodel' && args.method === 'fields_get') {
|
||||
// Block the 'read' call
|
||||
var result = this._super.apply(this, arguments);
|
||||
return Promise.resolve(def).then(_.constant(result));
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
await testUtils.nextTick();
|
||||
assert.strictEqual($('.o_web_studio_tfield_fieldexpression').length, 0,
|
||||
"the sidebar should wait its components to be rendered before its insertion");
|
||||
|
||||
// release the fields_get
|
||||
def.resolve();
|
||||
var sidebar = await sidebarDef;
|
||||
await testUtils.nextTick();
|
||||
assert.strictEqual($('.o_web_studio_tfield_fieldexpression').length, 1,
|
||||
"the t-field component should be displayed");
|
||||
assert.strictEqual(sidebar.$('.o_web_studio_tfield_fieldexpression .o_field_selector_value').text().replace(/\s/g, ''),
|
||||
"doc(MyModel)ID",
|
||||
"the field chain should be correctly displayed");
|
||||
|
||||
sidebar.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('Various layout changes', function (assert) {
|
||||
var done = assert.async();
|
||||
// this test is a combinaison of multiple tests, to avoid copy
|
||||
// pasting multiple times de sidebar create/intercept/destroy
|
||||
|
||||
var layoutChangeNode = {
|
||||
attrs: {
|
||||
'data-oe-id': '99',
|
||||
'data-oe-xpath': '/t/t/div',
|
||||
},
|
||||
tag: 'div',
|
||||
$nodes: $(),
|
||||
};
|
||||
var layoutChangeTextNode = {
|
||||
attrs: {
|
||||
'data-oe-id': '99',
|
||||
'data-oe-xpath': '/t/t/span',
|
||||
},
|
||||
tag: 'span',
|
||||
$nodes: $(),
|
||||
};
|
||||
var nodeWithAllLayoutPropertiesSet = {
|
||||
tag: "div",
|
||||
attrs: {
|
||||
//width: "1",
|
||||
style: "margin-top:2px;width:1px;margin-right:3px;margin-bottom:4px;margin-left:5px;",
|
||||
class: "o_bold o_italic h3 bg-o-color-3 text-o-color-2 o_underline",
|
||||
'data-oe-id': '99',
|
||||
'data-oe-xpath': '/t/t/div',
|
||||
},
|
||||
$nodes: $(),
|
||||
};
|
||||
|
||||
var nodeWithAllLayoutPropertiesFontAndBackgroundSet = {
|
||||
tag: "div",
|
||||
attrs: {
|
||||
//width: "1",
|
||||
style: "margin-top:2px;margin-right:3px;width:1px;margin-bottom:4px;margin-left:5px;background-color:#00FF00;color:#00FF00",
|
||||
class: "o_bold o_italic h3 o_underline",
|
||||
'data-oe-id': '99',
|
||||
'data-oe-xpath': '/t/t/div',
|
||||
},
|
||||
$nodes: $(),
|
||||
};
|
||||
var layoutChangesOperations = [
|
||||
{
|
||||
testName: "add a margin top in pixels",
|
||||
nodeToUse: layoutChangeNode,
|
||||
eventToTrigger: "change",
|
||||
sidebarOperationInputSelector: '.o_web_studio_margin [data-margin="margin-top"]',
|
||||
valueToPut: "42",
|
||||
expectedRPC: {
|
||||
inheritance: [{
|
||||
content: "<attribute name=\"style\" separator=\";\" add=\"margin-top:42px\"/>",
|
||||
position: "attributes",
|
||||
view_id: 99,
|
||||
xpath: "/t/t/div"
|
||||
}]
|
||||
}
|
||||
}, {
|
||||
testName: "add a margin bottom in pixels",
|
||||
nodeToUse: layoutChangeNode,
|
||||
eventToTrigger: "change",
|
||||
sidebarOperationInputSelector: '.o_web_studio_margin [data-margin="margin-bottom"]',
|
||||
valueToPut: "42",
|
||||
expectedRPC: {
|
||||
inheritance: [{
|
||||
content: "<attribute name=\"style\" separator=\";\" add=\"margin-bottom:42px\"/>",
|
||||
position: "attributes",
|
||||
view_id: 99,
|
||||
xpath: "/t/t/div"
|
||||
}]
|
||||
}
|
||||
}, {
|
||||
testName: "add a margin left in pixels",
|
||||
nodeToUse: layoutChangeNode,
|
||||
eventToTrigger: "change",
|
||||
sidebarOperationInputSelector: '.o_web_studio_margin [data-margin="margin-left"]',
|
||||
valueToPut: "42",
|
||||
expectedRPC: {
|
||||
inheritance: [{
|
||||
content: "<attribute name=\"style\" separator=\";\" add=\"margin-left:42px\"/>",
|
||||
position: "attributes",
|
||||
view_id: 99,
|
||||
xpath: "/t/t/div"
|
||||
}]
|
||||
}
|
||||
}, {
|
||||
testName: "add a margin right in pixels",
|
||||
nodeToUse: layoutChangeNode,
|
||||
eventToTrigger: "change",
|
||||
sidebarOperationInputSelector: '.o_web_studio_margin [data-margin="margin-right"]',
|
||||
valueToPut: "42",
|
||||
expectedRPC: {
|
||||
inheritance: [{
|
||||
content: "<attribute name=\"style\" separator=\";\" add=\"margin-right:42px\"/>",
|
||||
position: "attributes",
|
||||
view_id: 99,
|
||||
xpath: "/t/t/div"
|
||||
}]
|
||||
}
|
||||
}, {
|
||||
testName: "add a width",
|
||||
nodeToUse: layoutChangeNode,
|
||||
eventToTrigger: "change",
|
||||
sidebarOperationInputSelector: '.o_web_studio_width input',
|
||||
valueToPut: "42",
|
||||
expectedRPC: {
|
||||
inheritance: [{
|
||||
content: "<attribute name=\"style\" separator=\";\" add=\"width:42px\"/>",
|
||||
position: "attributes",
|
||||
view_id: 99,
|
||||
xpath: "/t/t/div"
|
||||
}]
|
||||
}
|
||||
}, {
|
||||
testName: "add a width on a text",
|
||||
nodeToUse: layoutChangeTextNode,
|
||||
eventToTrigger: "change",
|
||||
sidebarOperationInputSelector: '.o_web_studio_width input',
|
||||
valueToPut: "42",
|
||||
expectedRPC: {
|
||||
inheritance: [{
|
||||
content: "<attribute name=\"style\" separator=\";\" add=\"width:42px;display:inline-block\"/>",
|
||||
position: "attributes",
|
||||
view_id: 99,
|
||||
xpath: "/t/t/span"
|
||||
}]
|
||||
}
|
||||
}, {
|
||||
testName: "add a class",
|
||||
nodeToUse: layoutChangeNode,
|
||||
eventToTrigger: "change",
|
||||
sidebarOperationInputSelector: '.o_web_studio_classes input',
|
||||
valueToPut: "new_class",
|
||||
expectedRPC: {
|
||||
new_attrs: {
|
||||
class: "new_class"
|
||||
},
|
||||
type: "attributes",
|
||||
},
|
||||
}, {
|
||||
testName: "set the heading level",
|
||||
nodeToUse: layoutChangeNode,
|
||||
eventToTrigger: "click",
|
||||
sidebarOperationInputSelector: '.o_web_studio_font_size .dropdown-item-text[data-value="h3"]',
|
||||
expectedRPC: {
|
||||
inheritance: [{
|
||||
content: "<attribute name=\"class\" separator=\" \" add=\"h3\"/>",
|
||||
position: "attributes",
|
||||
view_id: 99,
|
||||
xpath: "/t/t/div"
|
||||
}]
|
||||
},
|
||||
}, {
|
||||
testName: "set the background color to a theme color",
|
||||
nodeToUse: layoutChangeNode,
|
||||
eventToTrigger: "mousedown",
|
||||
sidebarOperationInputSelector: '.o_web_studio_colors .o_web_studio_background_colorpicker button[data-color="o-color-3"]',
|
||||
expectedRPC: {
|
||||
inheritance: [{
|
||||
content: "<attribute name=\"class\" separator=\" \" add=\"bg-o-color-3\"/>",
|
||||
position: "attributes",
|
||||
view_id: 99,
|
||||
xpath: "/t/t/div"
|
||||
}]
|
||||
},
|
||||
}, {
|
||||
testName: "set the background color to a standard color",
|
||||
nodeToUse: layoutChangeNode,
|
||||
eventToTrigger: "mousedown",
|
||||
sidebarOperationInputSelector: '.o_web_studio_colors .o_web_studio_background_colorpicker button[data-value="#00FF00"]',
|
||||
valueToPut: "h3",
|
||||
expectedRPC: {
|
||||
inheritance: [{
|
||||
content: "<attribute name=\"style\" separator=\";\" add=\"background-color:#00FF00\"/>",
|
||||
position: "attributes",
|
||||
view_id: 99,
|
||||
xpath: "/t/t/div"
|
||||
}]
|
||||
},
|
||||
}, {
|
||||
testName: "set the font color to a theme color",
|
||||
nodeToUse: layoutChangeNode,
|
||||
eventToTrigger: "mousedown",
|
||||
sidebarOperationInputSelector: '.o_web_studio_colors .o_web_studio_font_colorpicker button[data-color="o-color-3"]',
|
||||
expectedRPC: {
|
||||
inheritance: [{
|
||||
content: "<attribute name=\"class\" separator=\" \" add=\"text-o-color-3\"/>",
|
||||
position: "attributes",
|
||||
view_id: 99,
|
||||
xpath: "/t/t/div"
|
||||
}]
|
||||
},
|
||||
}, {
|
||||
testName: "set the font color to a standard color",
|
||||
nodeToUse: layoutChangeNode,
|
||||
eventToTrigger: "mousedown",
|
||||
sidebarOperationInputSelector: '.o_web_studio_colors .o_web_studio_font_colorpicker button[data-value="#00FF00"]',
|
||||
valueToPut: "h3",
|
||||
expectedRPC: {
|
||||
inheritance: [{
|
||||
content: "<attribute name=\"style\" separator=\";\" add=\"color:#00FF00\"/>",
|
||||
position: "attributes",
|
||||
view_id: 99,
|
||||
xpath: "/t/t/div"
|
||||
}]
|
||||
},
|
||||
}, {
|
||||
testName: "set the alignment",
|
||||
nodeToUse: layoutChangeNode,
|
||||
eventToTrigger: "click",
|
||||
sidebarOperationInputSelector: '.o_web_studio_text_alignment button[title="end"]',
|
||||
expectedRPC: {
|
||||
inheritance: [{
|
||||
content: "<attribute name=\"class\" separator=\" \" add=\"text-end\"/>",
|
||||
position: "attributes",
|
||||
view_id: 99,
|
||||
xpath: "/t/t/div"
|
||||
}]
|
||||
},
|
||||
}, {
|
||||
testName: "remove margin top in pixels",
|
||||
nodeToUse: nodeWithAllLayoutPropertiesSet,
|
||||
eventToTrigger: "change",
|
||||
sidebarOperationInputSelector: '.o_web_studio_margin [data-margin="margin-top"]',
|
||||
valueToPut: "",
|
||||
expectedRPC: {
|
||||
inheritance: [{
|
||||
content: "<attribute name=\"style\" separator=\";\" remove=\"margin-top:2px\"/>",
|
||||
position: "attributes",
|
||||
view_id: 99,
|
||||
xpath: "/t/t/div"
|
||||
}]
|
||||
}
|
||||
}, {
|
||||
testName: "remove a margin bottom in pixels",
|
||||
nodeToUse: nodeWithAllLayoutPropertiesSet,
|
||||
eventToTrigger: "change",
|
||||
sidebarOperationInputSelector: '.o_web_studio_margin [data-margin="margin-bottom"]',
|
||||
valueToPut: "",
|
||||
expectedRPC: {
|
||||
inheritance: [{
|
||||
content: "<attribute name=\"style\" separator=\";\" remove=\"margin-bottom:4px\"/>",
|
||||
position: "attributes",
|
||||
view_id: 99,
|
||||
xpath: "/t/t/div"
|
||||
}]
|
||||
}
|
||||
}, {
|
||||
testName: "remove a margin left in pixels",
|
||||
nodeToUse: nodeWithAllLayoutPropertiesSet,
|
||||
eventToTrigger: "change",
|
||||
sidebarOperationInputSelector: '.o_web_studio_margin [data-margin="margin-left"]',
|
||||
valueToPut: "",
|
||||
expectedRPC: {
|
||||
inheritance: [{
|
||||
content: "<attribute name=\"style\" separator=\";\" remove=\"margin-left:5px\"/>",
|
||||
position: "attributes",
|
||||
view_id: 99,
|
||||
xpath: "/t/t/div"
|
||||
}]
|
||||
}
|
||||
}, {
|
||||
testName: "remove a margin right in pixels",
|
||||
nodeToUse: nodeWithAllLayoutPropertiesSet,
|
||||
eventToTrigger: "change",
|
||||
sidebarOperationInputSelector: '.o_web_studio_margin [data-margin="margin-right"]',
|
||||
valueToPut: "",
|
||||
expectedRPC: {
|
||||
inheritance: [{
|
||||
content: "<attribute name=\"style\" separator=\";\" remove=\"margin-right:3px\"/>",
|
||||
position: "attributes",
|
||||
view_id: 99,
|
||||
xpath: "/t/t/div"
|
||||
}]
|
||||
}
|
||||
}, {
|
||||
testName: "remove the width",
|
||||
nodeToUse: nodeWithAllLayoutPropertiesSet,
|
||||
eventToTrigger: "change",
|
||||
sidebarOperationInputSelector: '.o_web_studio_width input',
|
||||
valueToPut: "",
|
||||
expectedRPC: {
|
||||
inheritance: [{
|
||||
content: "<attribute name=\"style\" separator=\";\" remove=\"width:1px\"/>",
|
||||
position: "attributes",
|
||||
view_id: 99,
|
||||
xpath: "/t/t/div"
|
||||
}]
|
||||
}
|
||||
}, {
|
||||
testName: "remove a class",
|
||||
nodeToUse: nodeWithAllLayoutPropertiesSet,
|
||||
eventToTrigger: "change",
|
||||
sidebarOperationInputSelector: '.o_web_studio_classes input',
|
||||
valueToPut: "o_bold o_italic bg-o-color-3 text-o-color-2 o_underline",
|
||||
expectedRPC: {
|
||||
new_attrs: {
|
||||
class: "o_bold o_italic bg-o-color-3 text-o-color-2 o_underline"
|
||||
},
|
||||
type: "attributes",
|
||||
},
|
||||
}, {
|
||||
testName: "unset the background color to a theme color",
|
||||
nodeToUse: nodeWithAllLayoutPropertiesSet,
|
||||
eventToTrigger: "click",
|
||||
sidebarOperationInputSelector: '.o_web_studio_colors .o_web_studio_background_colorpicker .o_web_studio_reset_color',
|
||||
expectedRPC: {
|
||||
inheritance: [{
|
||||
content: "<attribute name=\"class\" separator=\" \" remove=\"bg-o-color-3\"/>",
|
||||
position: "attributes",
|
||||
view_id: 99,
|
||||
xpath: "/t/t/div"
|
||||
}]
|
||||
},
|
||||
},{
|
||||
testName: "unset the background color to a standard color",
|
||||
nodeToUse: nodeWithAllLayoutPropertiesFontAndBackgroundSet,
|
||||
eventToTrigger: "click",
|
||||
sidebarOperationInputSelector: '.o_web_studio_colors .o_web_studio_background_colorpicker .o_web_studio_reset_color',
|
||||
expectedRPC: {
|
||||
inheritance: [{
|
||||
content: "<attribute name=\"style\" separator=\";\" remove=\"background-color:#00FF00\"/>",
|
||||
position: "attributes",
|
||||
view_id: 99,
|
||||
xpath: "/t/t/div"
|
||||
}]
|
||||
},
|
||||
}, {
|
||||
testName: "unset the font color to a theme color",
|
||||
nodeToUse: nodeWithAllLayoutPropertiesSet,
|
||||
eventToTrigger: "click",
|
||||
sidebarOperationInputSelector: '.o_web_studio_colors .o_web_studio_font_colorpicker .o_web_studio_reset_color',
|
||||
expectedRPC: {
|
||||
inheritance: [{
|
||||
content: "<attribute name=\"class\" separator=\" \" remove=\"text-o-color-2\"/>",
|
||||
position: "attributes",
|
||||
view_id: 99,
|
||||
xpath: "/t/t/div"
|
||||
}]
|
||||
},
|
||||
}, {
|
||||
testName: "unset the font color to a standard color",
|
||||
nodeToUse: nodeWithAllLayoutPropertiesFontAndBackgroundSet,
|
||||
eventToTrigger: "click",
|
||||
sidebarOperationInputSelector: '.o_web_studio_colors .o_web_studio_font_colorpicker button.o_web_studio_reset_color',
|
||||
expectedRPC: {
|
||||
inheritance: [{
|
||||
content: "<attribute name=\"style\" separator=\";\" remove=\"color:#00FF00\"/>",
|
||||
position: "attributes",
|
||||
view_id: 99,
|
||||
xpath: "/t/t/div"
|
||||
}]
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
// there is one assert by operation
|
||||
assert.expect(layoutChangesOperations.length);
|
||||
|
||||
var initialDebugMode = odoo.debug;
|
||||
// show 'class' in the sidebar
|
||||
odoo.debug = true;
|
||||
|
||||
function poll (changeOperation) {
|
||||
var node = {
|
||||
node: changeOperation.nodeToUse,
|
||||
};
|
||||
studioTestUtils.createSidebar({
|
||||
state: {
|
||||
mode: 'properties',
|
||||
nodes: [node],
|
||||
},
|
||||
previousState: {
|
||||
"99/t/t/div": { 'layout': { showAll: true } }, // opens the layout expanded
|
||||
},
|
||||
}).then(function (sidebar) {
|
||||
testUtils.mock.intercept(sidebar, 'view_change', function (ev) {
|
||||
assert.deepEqual(ev.data.operation, changeOperation.expectedRPC, changeOperation.testName);
|
||||
});
|
||||
sidebar.$(changeOperation.sidebarOperationInputSelector)
|
||||
.val(changeOperation.valueToPut)
|
||||
.trigger(changeOperation.eventToTrigger);
|
||||
sidebar.destroy();
|
||||
}).then(function () {
|
||||
if (layoutChangesOperations.length) {
|
||||
poll(layoutChangesOperations.shift());
|
||||
} else {
|
||||
odoo.debug = initialDebugMode;
|
||||
done();
|
||||
}
|
||||
});
|
||||
}
|
||||
poll(layoutChangesOperations.shift());
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
odoo.define('web_studio.ReportEditor_tests', function (require) {
|
||||
"use strict";
|
||||
|
||||
var studioTestUtils = require('web_studio.testUtils');
|
||||
|
||||
QUnit.module('Studio', {}, function () {
|
||||
|
||||
QUnit.module('ReportEditor', {
|
||||
beforeEach: function () {
|
||||
},
|
||||
}, function () {
|
||||
QUnit.test('basic report rendering', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
var nodesArchs = {
|
||||
42: {
|
||||
attrs: {
|
||||
'data-oe-id': '42',
|
||||
'data-oe-xpath': '/t',
|
||||
name: "Layout",
|
||||
't-name': '42',
|
||||
},
|
||||
},
|
||||
id: 42,
|
||||
key: 'report.layout',
|
||||
parent: null,
|
||||
tag: 't',
|
||||
};
|
||||
var reportHTML = "<html><body><t/></body></html>";
|
||||
var editor = await studioTestUtils.createReportEditor({
|
||||
nodesArchs: nodesArchs,
|
||||
reportHTML: reportHTML,
|
||||
});
|
||||
|
||||
assert.containsOnce(editor, 'iframe',
|
||||
"an iframe should be rendered");
|
||||
assert.hasAttrValue(editor.$('iframe'), 'src', "about:blank",
|
||||
"the source should be correctly set");
|
||||
|
||||
editor.destroy();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user