summaryrefslogtreecommitdiff
path: root/addons/web/static/tests/widgets
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/web/static/tests/widgets
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/web/static/tests/widgets')
-rw-r--r--addons/web/static/tests/widgets/company_switcher_tests.js169
-rw-r--r--addons/web/static/tests/widgets/data_export_tests.js421
-rw-r--r--addons/web/static/tests/widgets/domain_selector_tests.js249
-rw-r--r--addons/web/static/tests/widgets/model_field_selector_tests.js325
-rw-r--r--addons/web/static/tests/widgets/rainbow_man_tests.js39
5 files changed, 1203 insertions, 0 deletions
diff --git a/addons/web/static/tests/widgets/company_switcher_tests.js b/addons/web/static/tests/widgets/company_switcher_tests.js
new file mode 100644
index 00000000..fe0fec5e
--- /dev/null
+++ b/addons/web/static/tests/widgets/company_switcher_tests.js
@@ -0,0 +1,169 @@
+odoo.define('web.SwitchCompanyMenu_tests', function (require) {
+"use strict";
+
+var SwitchCompanyMenu = require('web.SwitchCompanyMenu');
+var testUtils = require('web.test_utils');
+
+
+async function createSwitchCompanyMenu(params) {
+ params = params || {};
+ var target = params.debug ? document.body : $('#qunit-fixture');
+ var menu = new SwitchCompanyMenu();
+ await testUtils.mock.addMockEnvironment(menu, params);
+ await menu.appendTo(target)
+ return menu
+}
+
+
+async function initMockCompanyMenu(assert, params) {
+ var menu = await createSwitchCompanyMenu({
+ session: {
+ ...params.session,
+ setCompanies: function (mainCompanyId, companyIds) {
+ assert.equal(mainCompanyId, params.assertMainCompany[0], params.assertMainCompany[1]);
+ assert.equal(_.intersection(companyIds, params.asserCompanies[0]).length, params.asserCompanies[0].length, params.asserCompanies[1]);
+ },
+ }
+ })
+ await testUtils.dom.click(menu.$('.dropdown-toggle')); // open company switcher dropdown
+ return menu
+}
+
+async function testSwitchCompany(assert, params) {
+ assert.expect(2);
+ var menu = await initMockCompanyMenu(assert, params);
+ await testUtils.dom.click(menu.$(`div[data-company-id=${params.company}] div.log_into`));
+ menu.destroy();
+}
+
+async function testToggleCompany(assert, params) {
+ assert.expect(2);
+ var menu = await initMockCompanyMenu(assert, params);
+ await testUtils.dom.click(menu.$(`div[data-company-id=${params.company}] div.toggle_company`));
+ menu.destroy();
+}
+
+QUnit.module('widgets', {
+ beforeEach: async function () {
+ this.session_mock_multi = {
+ user_companies: {
+ current_company: [1, "Company 1"],
+ allowed_companies: [[1, "Company 1"], [2, "Company 2"], [3, "Company 3"]],
+ },
+ user_context: { allowed_company_ids: [1, 3] },
+ },
+ this.session_mock_single = {
+ user_companies: {
+ current_company: [1, "Company 1"],
+ allowed_companies: [[1, "Company 1"], [2, "Company 2"], [3, "Company 3"]],
+ },
+ user_context: { allowed_company_ids: [1] },
+ }
+ },
+
+}, function () {
+
+ QUnit.module('SwitchCompanyMenu', {}, function () {
+
+ QUnit.test("Company switcher basic rendering", async function (assert) {
+ assert.expect(6);
+ var menu = await createSwitchCompanyMenu({ session: this.session_mock_multi });
+ assert.equal(menu.$('.company_label:contains(Company 1)').length, 1, "it should display Company 1")
+ assert.equal(menu.$('.company_label:contains(Company 2)').length, 1, "it should display Company 2")
+ assert.equal(menu.$('.company_label:contains(Company 3)').length, 1, "it should display Company 3")
+
+ assert.equal(menu.$('div[data-company-id=1] .fa-check-square').length, 1, "Company 1 should be checked")
+ assert.equal(menu.$('div[data-company-id=2] .fa-square-o').length, 1, "Company 2 should not be checked")
+ assert.equal(menu.$('div[data-company-id=3] .fa-check-square').length, 1, "Company 3 should be checked")
+ menu.destroy();
+ });
+ });
+
+ QUnit.module('SwitchCompanyMenu', {}, function () {
+
+ QUnit.test("Toggle new company in multiple company mode", async function (assert) {
+ /**
+ * [x] **Company 1** [x] **Company 1**
+ * toggle->[ ] Company 2 ====> [x] Company 2
+ * [x] Company 3 [x] Company 3
+ */
+ await testToggleCompany(assert, {
+ company: 2,
+ session: this.session_mock_multi,
+ assertMainCompany: [1, "Main company should not have changed"],
+ asserCompanies: [[1, 2, 3], "All companies should be activated"],
+ });
+ });
+
+ QUnit.test("Toggle active company in mutliple company mode", async function (assert) {
+ /**
+ * [x] **Company 1** [x] **Company 1**
+ * [ ] Company 2 ====> [ ] Company 2
+ * toggle->[x] Company 3 [ ] Company 3
+ */
+ await testToggleCompany(assert, {
+ company: 3,
+ session: this.session_mock_multi,
+ assertMainCompany: [1, "Main company should not have changed"],
+ asserCompanies: [[1], "Companies 3 should be unactivated"],
+ });
+ });
+
+ QUnit.test("Switch main company in mutliple company mode", async function (assert) {
+ /**
+ * [x] **Company 1** [x] Company 1
+ * [ ] Company 2 ====> [ ] Company 2
+ * switch->[x] Company 3 [x] **Company 3**
+ */
+ await testSwitchCompany(assert, {
+ company: 3,
+ session: this.session_mock_multi,
+ assertMainCompany: [3, "Main company should switch to Company 3"],
+ asserCompanies: [[1, 3], "Companies 1 and 3 should still be active"],
+ });
+ });
+
+ QUnit.test("Switch new company in mutliple company mode", async function (assert) {
+ /**
+ * [x] **Company 1** [x] Company 1
+ * switch->[ ] Company 2 ====> [x] **Company 2**
+ * [x] Company 3 [x] Company 3
+ */
+ await testSwitchCompany(assert, {
+ company: 2,
+ session: this.session_mock_multi,
+ assertMainCompany: [2, "Company 2 should become the main company"],
+ asserCompanies: [[1, 2, 3], "Companies 1 and 3 should still be active"],
+ });
+ });
+
+ QUnit.test("Switch main company in single company mode", async function (assert) {
+ /**
+ * [x] **Company 1** [ ] Company 1
+ * [ ] Company 2 ====> [ ] Company 2
+ * switch->[ ] Company 3 [x] **Company 3**
+ */
+ await testSwitchCompany(assert, {
+ company: 3,
+ session: this.session_mock_single,
+ assertMainCompany: [3, "Main company should switch to Company 3"],
+ asserCompanies: [[3], "Companies 1 should no longer be active"],
+ });
+ });
+
+ QUnit.test("Toggle new company in single company mode", async function (assert) {
+ /**
+ * [x] **Company 1** [ ] **Company 1**
+ * [ ] Company 2 ====> [ ] Company 2
+ * toggle->[ ] Company 3 [x] Company 3
+ */
+ await testToggleCompany(assert, {
+ company: 3,
+ session: this.session_mock_single,
+ assertMainCompany: [1, "Company 1 should still be the main company"],
+ asserCompanies: [[1, 3], "Company 3 should be activated"],
+ });
+ });
+ });
+});
+});
diff --git a/addons/web/static/tests/widgets/data_export_tests.js b/addons/web/static/tests/widgets/data_export_tests.js
new file mode 100644
index 00000000..2e2cae1c
--- /dev/null
+++ b/addons/web/static/tests/widgets/data_export_tests.js
@@ -0,0 +1,421 @@
+odoo.define('web.data_export_tests', function (require) {
+"use strict";
+
+const data = require('web.data');
+const framework = require('web.framework');
+const ListView = require('web.ListView');
+const testUtils = require('web.test_utils');
+
+const cpHelpers = testUtils.controlPanel;
+const createView = testUtils.createView;
+
+QUnit.module('widgets', {
+ beforeEach: function () {
+ this.data = {
+ 'partner': {
+ fields: {
+ foo: {string: "Foo", type: "char"},
+ bar: {string: "Bar", type: "char"},
+ unexportable: {string: "Unexportable", type: "boolean", exportable: false},
+ },
+ records: [
+ {
+ id: 1,
+ foo: "yop",
+ bar: "bar-blup",
+ }, {
+ id: 2,
+ foo: "yop",
+ bar: "bar-yop",
+ }, {
+ id: 3,
+ foo: "blup",
+ bar: "bar-blup",
+ }
+ ]
+ },
+ 'ir.exports': {
+ fields: {
+ name: {string: "Name", type: "char"},
+ },
+ records: [],
+ },
+ };
+ this.mockSession = {
+ async user_has_group(g) { return g === 'base.group_allow_export'; }
+ }
+ this.mockDataExportRPCs = function (route) {
+ if (route === '/web/export/formats') {
+ return Promise.resolve([
+ {tag: 'csv', label: 'CSV'},
+ {tag: 'xls', label: 'Excel'},
+ ]);
+ }
+ if (route === '/web/export/get_fields') {
+ return Promise.resolve([
+ {
+ field_type: "one2many",
+ string: "Activities",
+ required: false,
+ value: "activity_ids/id",
+ id: "activity_ids",
+ params: {"model": "mail.activity", "prefix": "activity_ids", "name": "Activities"},
+ relation_field: "res_id",
+ children: true,
+ }, {
+ children: false,
+ field_type: 'char',
+ id: "foo",
+ relation_field: null,
+ required: false,
+ string: 'Foo',
+ value: "foo",
+ }
+ ]);
+ }
+ return this._super.apply(this, arguments);
+ };
+ }
+}, function () {
+
+ QUnit.module('Data Export');
+
+
+ QUnit.test('exporting all data in list view', async function (assert) {
+ assert.expect(8);
+
+ var blockUI = framework.blockUI;
+ var unblockUI = framework.unblockUI;
+ framework.blockUI = function () {
+ assert.step('block UI');
+ };
+ framework.unblockUI = function () {
+ assert.step('unblock UI');
+ };
+
+ var list = await createView({
+ View: ListView,
+ model: 'partner',
+ data: this.data,
+ arch: '<tree><field name="foo"/></tree>',
+ viewOptions: {
+ hasActionMenus: true,
+ },
+ mockRPC: this.mockDataExportRPCs,
+ session: {
+ ...this.mockSession,
+ get_file: function (params) {
+ assert.step(params.url);
+ params.complete();
+ },
+ },
+ });
+
+
+ await testUtils.dom.click(list.$('thead th.o_list_record_selector input'));
+
+ await cpHelpers.toggleActionMenu(list);
+ await cpHelpers.toggleMenuItem(list, 'Export');
+
+ assert.strictEqual($('.modal').length, 1, "a modal dialog should be open");
+ assert.strictEqual($('div.o_tree_column:contains(Activities)').length, 1,
+ "the Activities field should be in the list of exportable fields");
+ assert.strictEqual($('.modal .o_export_field').length, 1, "There should be only one export field");
+ assert.strictEqual($('.modal .o_export_field').data('field_id'), 'foo', "There should be only one export field");
+
+ // select the field Description, click on add, then export and close
+ await testUtils.dom.click($('.modal .o_tree_column:contains(Foo) .o_add_field'));
+ await testUtils.dom.click($('.modal span:contains(Export)'));
+ await testUtils.dom.click($('.modal span:contains(Close)'));
+ list.destroy();
+ framework.blockUI = blockUI;
+ framework.unblockUI = unblockUI;
+ assert.verifySteps([
+ 'block UI',
+ '/web/export/csv',
+ 'unblock UI',
+ ]);
+ });
+
+ QUnit.test('exporting data in list view (multi pages)', async function (assert) {
+ assert.expect(4);
+
+ let expectedData;
+ const list = await createView({
+ View: ListView,
+ model: 'partner',
+ data: this.data,
+ arch: '<tree limit="2"><field name="foo"/></tree>',
+ domain: [['id', '<', 1000]],
+ viewOptions: {
+ hasActionMenus: true,
+ },
+ mockRPC: this.mockDataExportRPCs,
+ session: {
+ ...this.mockSession,
+ get_file: function (params) {
+ const data = JSON.parse(params.data.data);
+ assert.deepEqual({ids: data.ids, domain: data.domain}, expectedData);
+ params.complete();
+ },
+ },
+ });
+
+ // select all records (first page) and export
+ expectedData = {
+ ids: [1, 2],
+ domain: [['id', '<', 1000]],
+ };
+ await testUtils.dom.click(list.$('thead th.o_list_record_selector input'));
+
+ await cpHelpers.toggleActionMenu(list);
+ await cpHelpers.toggleMenuItem(list, 'Export');
+
+ assert.containsOnce(document.body, '.modal');
+
+ await testUtils.dom.click($('.modal span:contains(Export)'));
+ await testUtils.dom.click($('.modal span:contains(Close)'));
+
+ // select all domain and export
+ expectedData = {
+ ids: false,
+ domain: [['id', '<', 1000]],
+ };
+ await testUtils.dom.click(list.$('.o_list_selection_box .o_list_select_domain'));
+
+ await cpHelpers.toggleActionMenu(list);
+ await cpHelpers.toggleMenuItem(list, 'Export');
+
+ assert.containsOnce(document.body, '.modal');
+
+ await testUtils.dom.click($('.modal span:contains(Export)'));
+ await testUtils.dom.click($('.modal span:contains(Close)'));
+
+ list.destroy();
+ });
+
+ QUnit.test('exporting view with non-exportable field', async function (assert) {
+ assert.expect(0);
+
+ var list = await createView({
+ View: ListView,
+ model: 'partner',
+ data: this.data,
+ arch: '<tree><field name="unexportable"/></tree>',
+ viewOptions: {
+ hasActionMenus: true,
+ },
+ mockRPC: this.mockDataExportRPCs,
+ session: {
+ ...this.mockSession,
+ get_file: function (params) {
+ assert.step(params.url);
+ params.complete();
+ },
+ },
+ });
+
+ await testUtils.dom.click(list.$('thead th.o_list_record_selector input'));
+
+ await cpHelpers.toggleActionMenu(list);
+ await cpHelpers.toggleMenuItem(list, 'Export');
+
+ list.destroy();
+ });
+
+ QUnit.test('saving fields list when exporting data', async function (assert) {
+ assert.expect(4);
+
+ var create = data.DataSet.prototype.create;
+
+ data.DataSet.prototype.create = function () {
+ assert.step('create');
+ return Promise.resolve([]);
+ };
+
+ var list = await createView({
+ View: ListView,
+ model: 'partner',
+ data: this.data,
+ arch: '<tree><field name="foo"/></tree>',
+ viewOptions: {
+ hasActionMenus: true,
+ },
+ session: this.mockSession,
+ mockRPC: this.mockDataExportRPCs,
+ });
+
+
+ // Open the export modal
+ await testUtils.dom.click(list.$('thead th.o_list_record_selector input'));
+ await cpHelpers.toggleActionMenu(list);
+ await cpHelpers.toggleMenuItem(list, 'Export');
+
+ assert.strictEqual($('.modal').length, 1,
+ "a modal dialog should be open");
+
+ // Select 'Activities' in fields to export
+ await testUtils.dom.click($('.modal .o_export_tree_item:contains(Activities) .o_add_field'));
+ assert.strictEqual($('.modal .o_fields_list .o_export_field').length, 2,
+ "there should be two items in the fields list");
+ // Save as template
+ await testUtils.fields.editAndTrigger($('.modal .o_exported_lists_select'), 'new_template', ['change']);
+ await testUtils.fields.editInput($('.modal .o_save_list .o_save_list_name'), 'fields list');
+ await testUtils.dom.click($('.modal .o_save_list .o_save_list_btn'));
+
+ assert.verifySteps(['create'],
+ "create should have been called");
+
+ // Close the modal and destroy list
+ await testUtils.dom.click($('.modal button span:contains(Close)'));
+ list.destroy();
+
+ // restore create function
+ data.DataSet.prototype.create = create;
+ });
+
+ QUnit.test('Export dialog UI test', async function (assert) {
+ assert.expect(5);
+ var list = await createView({
+ View: ListView,
+ model: 'partner',
+ data: this.data,
+ arch: '<tree><field name="foo"/></tree>',
+ viewOptions: {
+ hasActionMenus: true,
+ },
+ session: this.mockSession,
+ mockRPC: this.mockDataExportRPCs,
+ });
+
+
+ // Open the export modal
+ await testUtils.dom.click(list.$('thead th.o_list_record_selector input'));
+ await cpHelpers.toggleActionMenu(list);
+ await cpHelpers.toggleMenuItem(list, 'Export');
+
+ assert.strictEqual($('.modal .o_export_tree_item:visible').length, 2, "There should be only two items visible");
+ await testUtils.dom.click($('.modal .o_export_search_input'));
+ $('.modal .o_export_search_input').val('Activities').trigger($.Event('input', {
+ keyCode: 65,
+ }));
+ assert.strictEqual($('.modal .o_export_tree_item:visible').length, 1, "Only match item visible");
+ // Add field
+ await testUtils.dom.click($('.modal div:contains(Activities) .o_add_field'));
+ assert.strictEqual($('.modal .o_fields_list li').length, 2, "There should be two fields in export field list.");
+ assert.strictEqual($('.modal .o_fields_list li:eq(1)').text(), "Activities",
+ "string of second field in export list should be 'Activities'");
+ // Remove field
+ await testUtils.dom.click($('.modal .o_fields_list li:first .o_remove_field'));
+ assert.strictEqual($('.modal .o_fields_list li').length, 1, "There should be only one field in list");
+ list.destroy();
+ });
+
+ QUnit.test('Direct export button invisible', async function (assert) {
+ assert.expect(1)
+
+ let list = await createView({
+ View: ListView,
+ model: 'partner',
+ data: this.data,
+ arch: `<tree export_xlsx="0"><field name="foo"/></tree>`,
+ session: this.mockSession,
+ });
+ assert.containsNone(list, '.o_list_export_xlsx')
+ list.destroy();
+ });
+
+ QUnit.test('Direct export list ', async function (assert) {
+ assert.expect(2);
+
+ let list = await createView({
+ View: ListView,
+ model: 'partner',
+ data: this.data,
+ arch: `
+ <tree export_xlsx="1">
+ <field name="foo"/>
+ <field name="bar"/>
+ </tree>`,
+ domain: [['bar', '!=', 'glou']],
+ session: {
+ ...this.mockSession,
+ get_file(args) {
+ let data = JSON.parse(args.data.data);
+ assert.strictEqual(args.url, '/web/export/xlsx', "should call get_file with the correct url");
+ assert.deepEqual(data, {
+ context: {},
+ model: 'partner',
+ domain: [['bar', '!=', 'glou']],
+ groupby: [],
+ ids: false,
+ import_compat: false,
+ fields: [{
+ name: 'foo',
+ label: 'Foo',
+ type: 'char',
+ }, {
+ name: 'bar',
+ label: 'Bar',
+ type: 'char',
+ }]
+ }, "should be called with correct params");
+ args.complete();
+ },
+ },
+ });
+
+ // Download
+ await testUtils.dom.click(list.$buttons.find('.o_list_export_xlsx'));
+
+ list.destroy();
+ });
+
+ QUnit.test('Direct export grouped list ', async function (assert) {
+ assert.expect(2);
+
+ let list = await createView({
+ View: ListView,
+ model: 'partner',
+ data: this.data,
+ arch: `
+ <tree>
+ <field name="foo"/>
+ <field name="bar"/>
+ </tree>`,
+ groupBy: ['foo', 'bar'],
+ domain: [['bar', '!=', 'glou']],
+ session: {
+ ...this.mockSession,
+ get_file(args) {
+ let data = JSON.parse(args.data.data);
+ assert.strictEqual(args.url, '/web/export/xlsx', "should call get_file with the correct url");
+ assert.deepEqual(data, {
+ context: {},
+ model: 'partner',
+ domain: [['bar', '!=', 'glou']],
+ groupby: ['foo', 'bar'],
+ ids: false,
+ import_compat: false,
+ fields: [{
+ name: 'foo',
+ label: 'Foo',
+ type: 'char',
+ }, {
+ name: 'bar',
+ label: 'Bar',
+ type: 'char',
+ }]
+ }, "should be called with correct params");
+ args.complete();
+ },
+ },
+ });
+
+ await testUtils.dom.click(list.$buttons.find('.o_list_export_xlsx'));
+
+ list.destroy();
+ });
+});
+
+});
diff --git a/addons/web/static/tests/widgets/domain_selector_tests.js b/addons/web/static/tests/widgets/domain_selector_tests.js
new file mode 100644
index 00000000..a587117f
--- /dev/null
+++ b/addons/web/static/tests/widgets/domain_selector_tests.js
@@ -0,0 +1,249 @@
+odoo.define('web.domain_selector_tests', function (require) {
+"use strict";
+
+var DomainSelector = require("web.DomainSelector");
+var testUtils = require("web.test_utils");
+
+QUnit.module('widgets', {}, function () {
+
+QUnit.module('DomainSelector', {
+ beforeEach: function () {
+ this.data = {
+ partner: {
+ fields: {
+ foo: {string: "Foo", type: "char", searchable: true},
+ bar: {string: "Bar", type: "boolean", searchable: true},
+ nice_datetime: {string: "Datetime", type: "datetime", searchable: true},
+ product_id: {string: "Product", type: "many2one", relation: "product", searchable: true},
+ },
+ records: [{
+ id: 1,
+ foo: "yop",
+ bar: true,
+ product_id: 37,
+ }, {
+ id: 2,
+ foo: "blip",
+ bar: true,
+ product_id: false,
+ }, {
+ id: 4,
+ foo: "abc",
+ bar: false,
+ product_id: 41,
+ }],
+ onchanges: {},
+ },
+ product: {
+ fields: {
+ name: {string: "Product Name", type: "char", searchable: true}
+ },
+ records: [{
+ id: 37,
+ display_name: "xphone",
+ }, {
+ id: 41,
+ display_name: "xpad",
+ }]
+ },
+ };
+ },
+}, function () {
+
+ QUnit.test("creating a domain from scratch", async function (assert) {
+ assert.expect(13);
+
+ var $target = $("#qunit-fixture");
+
+ // Create the domain selector and its mock environment
+ var domainSelector = new DomainSelector(null, "partner", [], {
+ readonly: false,
+ debugMode: true,
+ });
+ await testUtils.mock.addMockEnvironment(domainSelector, {data: this.data});
+ await domainSelector.appendTo($target);
+
+ // As we gave an empty domain, there should be a visible button to add
+ // the first domain part
+ var $domainAddFirstNodeButton = domainSelector.$(".o_domain_add_first_node_button:visible");
+ assert.strictEqual($domainAddFirstNodeButton.length, 1,
+ "there should be a button to create first domain element");
+
+ // Clicking on the button should add a visible field selector in the
+ // widget so that the user can change the field chain
+ await testUtils.dom.click($domainAddFirstNodeButton);
+ var $fieldSelector = domainSelector.$(".o_field_selector:visible");
+ assert.strictEqual($fieldSelector.length, 1,
+ "there should be a field selector");
+
+ // Focusing the field selector input should open a field selector popover
+ $fieldSelector.trigger('focusin');
+ await testUtils.nextTick();
+ var $fieldSelectorPopover = $fieldSelector.find(".o_field_selector_popover:visible");
+ assert.strictEqual($fieldSelectorPopover.length, 1,
+ "field selector popover should be visible");
+
+ // The field selector popover should contain the list of "partner"
+ // fields. "Bar" should be among them.
+ var $lis = $fieldSelectorPopover.find("li");
+ var $barLi = $();
+ $lis.each(function () {
+ var $li = $(this);
+ if ($li.html().indexOf("Bar") >= 0) {
+ $barLi = $li;
+ }
+ });
+ assert.strictEqual($barLi.length, 1,
+ "field selector popover should contain the 'Bar' field");
+
+ // Clicking the "Bar" field should change the internal domain and this
+ // should be displayed in the debug input
+ await testUtils.dom.click($barLi);
+ assert.strictEqual(
+ domainSelector.$(".o_domain_debug_input").val(),
+ '[["bar","=",True]]',
+ "the domain input should contain a domain with 'bar'"
+ );
+
+ // There should be a "+" button to add a domain part; clicking on it
+ // should add the default "['id', '=', 1]" domain
+ var $plus = domainSelector.$(".fa-plus-circle");
+ assert.strictEqual($plus.length, 1, "there should be a '+' button");
+ await testUtils.dom.click($plus);
+ assert.strictEqual(
+ domainSelector.$(".o_domain_debug_input").val(),
+ '["&",["bar","=",True],["id","=",1]]',
+ "the domain input should contain a domain with 'bar' and 'id'");
+
+ // There should be two "..." buttons to add a domain group; clicking on
+ // the first one, should add this group with defaults "['id', '=', 1]"
+ // domains and the "|" operator
+ var $dots = domainSelector.$(".fa-ellipsis-h");
+ assert.strictEqual($dots.length, 2, "there should be two '...' buttons");
+ await testUtils.dom.click($dots.first());
+ assert.strictEqual(
+ domainSelector.$(".o_domain_debug_input").val(),
+ '["&","&",["bar","=",True],"|",["id","=",1],["id","=",1],["id","=",1]]',
+ "the domain input should contain a domain with 'bar', 'id' and a subgroup"
+ );
+
+ // Changing the domain input to update the subgroup to use the "foo"
+ // field instead of "id" should rerender the widget and adapt the
+ // widget suggestions
+ domainSelector.$(".o_domain_debug_input").val('["&","&",["bar","=",True],"|",["foo","=","hello"],["id","=",1],["id","=",1]]').change();
+ await testUtils.nextTick();
+ assert.strictEqual(domainSelector.$(".o_field_selector").eq(1).find("input.o_field_selector_debug").val(), "foo",
+ "the second field selector should now contain the 'foo' value");
+ assert.ok(domainSelector.$(".o_domain_leaf_operator_select").eq(1).html().indexOf("contains") >= 0,
+ "the second operator selector should now contain the 'contains' operator");
+
+ // There should be five "-" buttons to remove domain part; clicking on
+ // the two last ones, should leave a domain with only the "bar" and
+ // "foo" fields, with the initial "&" operator
+ var $minus = domainSelector.$(".o_domain_delete_node_button");
+ assert.strictEqual($minus.length, 5, "there should be five 'x' buttons");
+ await testUtils.dom.click($minus.last());
+ await testUtils.dom.click(domainSelector.$(".o_domain_delete_node_button").last());
+ assert.strictEqual(
+ domainSelector.$(".o_domain_debug_input").val(),
+ '["&",["bar","=",True],["foo","=","hello"]]',
+ "the domain input should contain a domain with 'bar' and 'foo'"
+ );
+ domainSelector.destroy();
+ });
+
+ QUnit.test("building a domain with a datetime", async function (assert) {
+ assert.expect(2);
+
+ var $target = $("#qunit-fixture");
+
+ // Create the domain selector and its mock environment
+ var domainSelector = new DomainSelector(null, "partner", [["nice_datetime", "=", "2017-03-27 15:42:00"]], {
+ readonly: false,
+ });
+ await testUtils.mock.addMockEnvironment(domainSelector, {data: this.data});
+ await domainSelector.appendTo($target);
+
+ // Check that there is a datepicker to choose the date
+ var $datepicker = domainSelector.$(".o_datepicker:visible");
+ assert.strictEqual($datepicker.length, 1,
+ "there should be a datepicker");
+
+ var val = $datepicker.find('input').val();
+ await testUtils.dom.openDatepicker($datepicker);
+ await testUtils.dom.clickFirst($('.bootstrap-datetimepicker-widget :not(.today)[data-action="selectDay"]'));
+ assert.notEqual(domainSelector.$(".o_datepicker:visible input").val(), val,
+ "datepicker value should have changed");
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget a[data-action=close]'));
+
+ domainSelector.destroy();
+ });
+
+ QUnit.test("building a domain with a m2o without following the relation", async function (assert) {
+ assert.expect(1);
+
+ var $target = $("#qunit-fixture");
+
+ // Create the domain selector and its mock environment
+ var domainSelector = new DomainSelector(null, "partner", [["product_id", "ilike", 1]], {
+ debugMode: true,
+ readonly: false,
+ });
+ await testUtils.mock.addMockEnvironment(domainSelector, {data: this.data});
+ await domainSelector.appendTo($target);
+
+ await testUtils.fields.editAndTrigger(domainSelector.$('.o_domain_leaf_value_input'),
+ 'pad', ['input', 'change']);
+ assert.strictEqual(domainSelector.$('.o_domain_debug_input').val(), '[["product_id","ilike","pad"]]',
+ "string should have been allowed as m2o value");
+
+ domainSelector.destroy();
+ });
+
+ QUnit.test("editing a domain with `parent` key", async function (assert) {
+ assert.expect(1);
+
+ var $target = $("#qunit-fixture");
+
+ // Create the domain selector and its mock environment
+ var domainSelector = new DomainSelector(null, "product", "[['name','=',parent.foo]]", {
+ debugMode: true,
+ readonly: false,
+ });
+ await testUtils.mock.addMockEnvironment(domainSelector, {data: this.data});
+ await domainSelector.appendTo($target);
+
+ assert.strictEqual(domainSelector.$el.text(), "This domain is not supported.",
+ "an error message should be displayed because of the `parent` key");
+
+ domainSelector.destroy();
+ });
+
+ QUnit.test("creating a domain with a default option", async function (assert) {
+ assert.expect(1);
+
+ var $target = $("#qunit-fixture");
+
+ // Create the domain selector and its mock environment
+ var domainSelector = new DomainSelector(null, "partner", [], {
+ readonly: false,
+ debugMode: true,
+ default: [["foo","=","kikou"]],
+ });
+ await testUtils.mock.addMockEnvironment(domainSelector, {data: this.data});
+ await domainSelector.appendTo($target);
+
+ // Clicking on the button should add a visible field selector in the
+ // widget so that the user can change the field chain
+ await testUtils.dom.click(domainSelector.$(".o_domain_add_first_node_button:visible"));
+
+ assert.strictEqual(
+ domainSelector.$(".o_domain_debug_input").val(),
+ '[["foo","=","kikou"]]',
+ "the domain input should contain the default domain");
+
+ domainSelector.destroy();
+ });
+});
+});
+});
diff --git a/addons/web/static/tests/widgets/model_field_selector_tests.js b/addons/web/static/tests/widgets/model_field_selector_tests.js
new file mode 100644
index 00000000..69bb1eb9
--- /dev/null
+++ b/addons/web/static/tests/widgets/model_field_selector_tests.js
@@ -0,0 +1,325 @@
+odoo.define('web.model_field_selector_tests', function (require) {
+"use strict";
+
+var ModelFieldSelector = require("web.ModelFieldSelector");
+var testUtils = require("web.test_utils");
+
+QUnit.module('widgets', {}, function () {
+
+QUnit.module('ModelFieldSelector', {
+ beforeEach: function () {
+ this.data = {
+ partner: {
+ fields: {
+ foo: {string: "Foo", type: "char", searchable: true},
+ bar: {string: "Bar", type: "boolean", searchable: true},
+ product_id: {string: "Product", type: "many2one", relation: "product", searchable: true},
+ },
+ records: [{
+ id: 1,
+ foo: "yop",
+ bar: true,
+ product_id: 37,
+ }, {
+ id: 2,
+ foo: "blip",
+ bar: true,
+ product_id: false,
+ }, {
+ id: 4,
+ foo: "abc",
+ bar: false,
+ product_id: 41,
+ }],
+ onchanges: {},
+ },
+ product: {
+ fields: {
+ name: {string: "Product Name", type: "char", searchable: true}
+ },
+ records: [{
+ id: 37,
+ display_name: "xphone",
+ }, {
+ id: 41,
+ display_name: "xpad",
+ }]
+ },
+ };
+ },
+}, function () {
+
+ QUnit.test("creating a field chain from scratch", async function (assert) {
+ assert.expect(14);
+
+ var $target = $("#qunit-fixture");
+
+ // Create the field selector and its mock environment
+ var fieldSelector = new ModelFieldSelector(null, "partner", [], {
+ readonly: false,
+ debugMode: true,
+ });
+ await testUtils.mock.addMockEnvironment(fieldSelector, {data: this.data});
+ await fieldSelector.appendTo($target);
+ var $value = fieldSelector.$("> .o_field_selector_value");
+
+ // Focusing the field selector input should open a field selector popover
+ fieldSelector.$el.trigger('focusin');
+ var $fieldSelectorPopover = fieldSelector.$(".o_field_selector_popover:visible");
+ assert.strictEqual($fieldSelectorPopover.length, 1,
+ "field selector popover should be visible");
+
+ // The field selector popover should contain the list of "partner"
+ // fields. "Bar" should be among them.
+ var $lis = $fieldSelectorPopover.find("li");
+ var $barLi = $();
+ $lis.each(function () {
+ var $li = $(this);
+ if ($li.html().indexOf("Bar") >= 0) {
+ $barLi = $li;
+ }
+ });
+ assert.strictEqual($barLi.length, 1,
+ "field selector popover should contain the 'Bar' field");
+
+ // Clicking the "Bar" field should close the popover and set the field
+ // chain to "bar" as it is a basic field
+ await testUtils.dom.click($barLi);
+ assert.notOk($fieldSelectorPopover.is("visible"),
+ "field selector popover should be closed now");
+ assert.strictEqual(getValueFromDOM($value), "Bar",
+ "field selector value should be displayed with a 'Bar' tag");
+
+ assert.deepEqual(fieldSelector.getSelectedField(), {
+ model: "partner",
+ name: "bar",
+ searchable: true,
+ string: "Bar",
+ type: "boolean",
+ }, "the selected field should be correctly set");
+
+ // Focusing the input again should open the same popover
+ fieldSelector.$el.trigger('focusin');
+ await testUtils.nextTick();
+ assert.ok($fieldSelectorPopover.is(":visible"),
+ "field selector popover should be visible");
+
+ // The field selector popover should contain the list of "partner"
+ // fields. "Product" should be among them.
+ $lis = $fieldSelectorPopover.find("li");
+ var $productLi = $();
+ $lis.each(function () {
+ var $li = $(this);
+ if ($li.html().indexOf("Product") >= 0) {
+ $productLi = $li;
+ }
+ });
+ assert.strictEqual($productLi.length, 1,
+ "field selector popover should contain the 'Product' field");
+
+ // Clicking on the "Product" field should update the popover to show
+ // the product fields (so only "Product Name" should be there)
+ await testUtils.dom.click($productLi);
+ $lis = $fieldSelectorPopover.find("li");
+ assert.strictEqual($lis.length, 1,
+ "there should be only one field proposition for 'product' model");
+ assert.ok($lis.first().html().indexOf("Product Name") >= 0,
+ "the name of the only suggestion should be 'Product Name'");
+
+ // Clicking on "Product Name" should close the popover and set the chain
+ // to "product_id.name"
+ await testUtils.dom.click($lis.first());
+ assert.notOk($fieldSelectorPopover.is("visible"),
+ "field selector popover should be closed now");
+ assert.strictEqual(getValueFromDOM($value), "Product -> Product Name",
+ "field selector value should be displayed with two tags: 'Product' and 'Product Name'");
+
+ // Remove the current selection and recreate it again
+ fieldSelector.$el.trigger('focusin');
+ await testUtils.nextTick();
+ await testUtils.dom.click(fieldSelector.$('.o_field_selector_prev_page'));
+ await testUtils.dom.click(fieldSelector.$('.o_field_selector_close'));
+
+ fieldSelector.$el.trigger('focusin');
+ await testUtils.nextTick();
+ $fieldSelectorPopover = fieldSelector.$(".o_field_selector_popover:visible");
+ $lis = $fieldSelectorPopover.find("li");
+ $productLi = $();
+ $lis.each(function () {
+ var $li = $(this);
+ if ($li.html().indexOf("Product") >= 0) {
+ $productLi = $li;
+ }
+ });
+ assert.strictEqual($productLi.length, 1,
+ "field selector popover should contain the 'Product' field");
+
+ await testUtils.dom.click($productLi);
+ $lis = $fieldSelectorPopover.find("li");
+ await testUtils.dom.click($lis.first());
+ assert.notOk($fieldSelectorPopover.is("visible"),
+ "field selector popover should be closed now");
+ assert.strictEqual(getValueFromDOM($value), "Product -> Product Name",
+ "field selector value should be displayed with two tags: 'Product' and 'Product Name'");
+
+ fieldSelector.destroy();
+
+ function getValueFromDOM($dom) {
+ return _.map($dom.find(".o_field_selector_chain_part"), function (part) {
+ return $(part).text().trim();
+ }).join(" -> ");
+ }
+ });
+
+ QUnit.test("default field chain should set the page data correctly", async function (assert) {
+ assert.expect(3);
+
+ var $target = $("#qunit-fixture");
+
+ // Create the field selector and its mock environment
+ // passing 'product_id' as a prefilled field-chain
+ var fieldSelector = new ModelFieldSelector(null, "partner", ['product_id'], {
+ readonly: false,
+ debugMode: true,
+ });
+ await testUtils.addMockEnvironment(fieldSelector, {data: this.data});
+ await fieldSelector.appendTo($target);
+
+ // Focusing the field selector input should open a field selector popover
+ fieldSelector.$el.trigger('focusin');
+ var $fieldSelectorPopover = fieldSelector.$(".o_field_selector_popover:visible");
+ assert.strictEqual($fieldSelectorPopover.length, 1,
+ "field selector popover should be visible");
+
+ // The field selector popover should contain the list of "product"
+ // fields. "Product Name" should be among them.
+ var $lis = $fieldSelectorPopover.find("li");
+ assert.strictEqual($lis.length, 1,
+ "there should be only one field proposition for 'product' model");
+ assert.ok($lis.first().html().indexOf("Product Name") >= 0,
+ "the name of the only suggestion should be 'Product Name'");
+
+
+ fieldSelector.destroy();
+ });
+
+ QUnit.test("use the filter option", async function (assert) {
+ assert.expect(2);
+
+ var $target = $("#qunit-fixture");
+
+ // Create the field selector and its mock environment
+ var fieldSelector = new ModelFieldSelector(null, "partner", [], {
+ readonly: false,
+ filter: function (field) {
+ return field.type === 'many2one';
+ },
+ });
+ await testUtils.mock.addMockEnvironment(fieldSelector, {data: this.data});
+ await fieldSelector.appendTo($target);
+
+ fieldSelector.$el.trigger('focusin');
+ await testUtils.nextTick();
+ var $fieldSelectorPopover = fieldSelector.$(".o_field_selector_popover:visible");
+ var $lis = $fieldSelectorPopover.find("li");
+ assert.strictEqual($lis.length, 1, "there should only be one element");
+ assert.strictEqual($lis.text().trim(), "Product", "the available field should be the many2one");
+
+ fieldSelector.destroy();
+ });
+
+ QUnit.test("default `showSearchInput` option", async function (assert) {
+ assert.expect(6);
+
+ var $target = $("#qunit-fixture");
+
+ // Create the field selector and its mock environment
+ var fieldSelector = new ModelFieldSelector(null, "partner", [], {
+ readonly: false,
+ });
+ await testUtils.mock.addMockEnvironment(fieldSelector, {data: this.data});
+ await fieldSelector.appendTo($target);
+
+ fieldSelector.$el.trigger('focusin');
+ await testUtils.nextTick();
+ var $fieldSelectorPopover = fieldSelector.$(".o_field_selector_popover:visible");
+ var $searchInput = $fieldSelectorPopover.find(".o_field_selector_search input");
+ assert.strictEqual($searchInput.length, 1, "there should be a search input");
+
+ // without search
+ assert.strictEqual($fieldSelectorPopover.find("li").length, 3, "there should be three available fields");
+ assert.strictEqual($fieldSelectorPopover.find("li").text().trim().replace(/\s+/g, ' '), "Bar Foo Product", "the available field should be correct");
+ await testUtils.fields.editAndTrigger($searchInput, 'xx', 'keyup');
+
+ assert.strictEqual($fieldSelectorPopover.find("li").length, 0, "there shouldn't be any element");
+ await testUtils.fields.editAndTrigger($searchInput, 'Pro', 'keyup');
+ assert.strictEqual($fieldSelectorPopover.find("li").length, 1, "there should only be one element");
+ assert.strictEqual($fieldSelectorPopover.find("li").text().trim().replace(/\s+/g, ' '), "Product", "the available field should be the Product");
+
+ fieldSelector.destroy();
+ });
+
+ QUnit.test("false `showSearchInput` option", async function (assert) {
+ assert.expect(1);
+
+ var $target = $("#qunit-fixture");
+
+ // Create the field selector and its mock environment
+ var fieldSelector = new ModelFieldSelector(null, "partner", [], {
+ readonly: false,
+ showSearchInput: false,
+ });
+ await testUtils.mock.addMockEnvironment(fieldSelector, { data: this.data });
+ await fieldSelector.appendTo($target);
+
+ fieldSelector.$el.trigger('focusin');
+ await testUtils.nextTick();
+ var $fieldSelectorPopover = fieldSelector.$(".o_field_selector_popover:visible");
+ var $searchInput = $fieldSelectorPopover.find(".o_field_selector_search input");
+ assert.strictEqual($searchInput.length, 0, "there should be no search input");
+
+ fieldSelector.destroy();
+ });
+
+ QUnit.test("create a field chain with value 1 i.e. TRUE_LEAF", async function (assert) {
+ assert.expect(1);
+
+ var $target = $("#qunit-fixture");
+
+ //create the field selector with domain value ["1"]
+ var fieldSelector = new ModelFieldSelector(null, "partner", ["1"], {
+ readonly: false,
+ showSearchInput: false,
+ });
+ await testUtils.mock.addMockEnvironment(fieldSelector, {data: this.data});
+ await fieldSelector.appendTo($target);
+
+ var $fieldName = fieldSelector.$('.o_field_selector_chain_part');
+ assert.strictEqual($fieldName.text().trim(), "1",
+ "field name value should be 1.");
+
+ fieldSelector.destroy();
+ });
+
+ QUnit.test("create a field chain with value 0 i.e. FALSE_LEAF", async function (assert) {
+ assert.expect(1);
+
+ var $target = $("#qunit-fixture");
+
+ //create the field selector with domain value ["0"]
+ var fieldSelector = new ModelFieldSelector(null, "partner", ["0"], {
+ readonly: false,
+ showSearchInput: false,
+ });
+ await testUtils.mock.addMockEnvironment(fieldSelector, {data: this.data});
+ await fieldSelector.appendTo($target);
+
+ var $fieldName = fieldSelector.$('.o_field_selector_chain_part');
+ assert.strictEqual($fieldName.text().trim(), "0",
+ "field name value should be 0.");
+
+ fieldSelector.destroy();
+ });
+});
+});
+});
diff --git a/addons/web/static/tests/widgets/rainbow_man_tests.js b/addons/web/static/tests/widgets/rainbow_man_tests.js
new file mode 100644
index 00000000..ad265416
--- /dev/null
+++ b/addons/web/static/tests/widgets/rainbow_man_tests.js
@@ -0,0 +1,39 @@
+odoo.define('web.RainbowMan_tests', function (require) {
+"use strict";
+
+var RainbowMan = require('web.RainbowMan');
+
+QUnit.module('widgets', {}, function () {
+
+QUnit.module('RainbowMan', {
+ beforeEach: function () {
+ this.data = {
+ message: 'Congrats!',
+ };
+ },
+}, function () {
+
+ QUnit.test("rendering a rainbowman", function (assert) {
+ var done = assert.async();
+ assert.expect(2);
+
+ var $target = $("#qunit-fixture");
+
+ // Create and display rainbowman
+ var rainbowman = new RainbowMan(this.data);
+ rainbowman.appendTo($target).then(function () {
+ var $rainbow = rainbowman.$(".o_reward_rainbow");
+ assert.strictEqual($rainbow.length, 1,
+ "Should have displayed rainbow effect");
+
+ assert.ok(rainbowman.$('.o_reward_msg_content').html() === 'Congrats!',
+ "Card on the rainbowman should display 'Congrats!' message");
+
+ rainbowman.destroy();
+ done();
+ });
+
+ });
+});
+});
+});