summaryrefslogtreecommitdiff
path: root/addons/web/static/tests/views/view_dialogs_tests.js
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/views/view_dialogs_tests.js
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/web/static/tests/views/view_dialogs_tests.js')
-rw-r--r--addons/web/static/tests/views/view_dialogs_tests.js615
1 files changed, 615 insertions, 0 deletions
diff --git a/addons/web/static/tests/views/view_dialogs_tests.js b/addons/web/static/tests/views/view_dialogs_tests.js
new file mode 100644
index 00000000..046fb873
--- /dev/null
+++ b/addons/web/static/tests/views/view_dialogs_tests.js
@@ -0,0 +1,615 @@
+odoo.define('web.view_dialogs_tests', function (require) {
+"use strict";
+
+var dialogs = require('web.view_dialogs');
+var ListController = require('web.ListController');
+var testUtils = require('web.test_utils');
+var Widget = require('web.Widget');
+var FormView = require('web.FormView');
+
+const cpHelpers = testUtils.controlPanel;
+var createView = testUtils.createView;
+
+async function createParent(params) {
+ var widget = new Widget();
+ params.server = await testUtils.mock.addMockEnvironment(widget, params);
+ return widget;
+}
+
+QUnit.module('Views', {
+ beforeEach: function () {
+ this.data = {
+ partner: {
+ fields: {
+ display_name: { string: "Displayed name", type: "char" },
+ foo: {string: "Foo", type: 'char'},
+ bar: {string: "Bar", type: "boolean"},
+ instrument: {string: 'Instruments', type: 'many2one', relation: 'instrument'},
+ },
+ records: [
+ {id: 1, foo: 'blip', display_name: 'blipblip', bar: true},
+ {id: 2, foo: 'ta tata ta ta', display_name: 'macgyver', bar: false},
+ {id: 3, foo: 'piou piou', display_name: "Jack O'Neill", bar: true},
+ ],
+ },
+ instrument: {
+ fields: {
+ name: {string: "name", type: "char"},
+ badassery: {string: 'level', type: 'many2many', relation: 'badassery', domain: [['level', '=', 'Awsome']]},
+ },
+ },
+
+ badassery: {
+ fields: {
+ level: {string: 'level', type: "char"},
+ },
+ records: [
+ {id: 1, level: 'Awsome'},
+ ],
+ },
+
+ product: {
+ fields : {
+ name: {string: "name", type: "char" },
+ partner : {string: 'Doors', type: 'one2many', relation: 'partner'},
+ },
+ records: [
+ {id: 1, name: 'The end'},
+ ],
+ },
+ };
+ },
+}, function () {
+
+ QUnit.module('view_dialogs');
+
+ QUnit.test('formviewdialog buttons in footer are positioned properly', async function (assert) {
+ assert.expect(2);
+
+ var parent = await createParent({
+ data: this.data,
+ archs: {
+ 'partner,false,form':
+ '<form string="Partner">' +
+ '<sheet>' +
+ '<group><field name="foo"/></group>' +
+ '<footer><button string="Custom Button" type="object" class="btn-primary"/></footer>' +
+ '</sheet>' +
+ '</form>',
+ },
+ });
+
+ new dialogs.FormViewDialog(parent, {
+ res_model: 'partner',
+ res_id: 1,
+ }).open();
+ await testUtils.nextTick();
+
+ assert.notOk($('.modal-body button').length,
+ "should not have any button in body");
+ assert.strictEqual($('.modal-footer button').length, 1,
+ "should have only one button in footer");
+ parent.destroy();
+ });
+
+ QUnit.test('formviewdialog buttons in footer are not duplicated', async function (assert) {
+ assert.expect(2);
+ this.data.partner.fields.poney_ids = {string: "Poneys", type: "one2many", relation: 'partner'};
+ this.data.partner.records[0].poney_ids = [];
+
+ var parent = await createParent({
+ data: this.data,
+ archs: {
+ 'partner,false,form':
+ '<form string="Partner">' +
+ '<field name="poney_ids"><tree editable="top"><field name="display_name"/></tree></field>' +
+ '<footer><button string="Custom Button" type="object" class="btn-primary"/></footer>' +
+ '</form>',
+ },
+ });
+
+ new dialogs.FormViewDialog(parent, {
+ res_model: 'partner',
+ res_id: 1,
+ }).open();
+ await testUtils.nextTick();
+
+ assert.strictEqual($('.modal button.btn-primary').length, 1,
+ "should have 1 buttons in modal");
+
+ await testUtils.dom.click($('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.triggerKeydown($('input.o_input'), 'escape');
+
+ assert.strictEqual($('.modal button.btn-primary').length, 1,
+ "should still have 1 buttons in modal");
+ parent.destroy();
+ });
+
+ QUnit.test('SelectCreateDialog use domain, group_by and search default', async function (assert) {
+ assert.expect(3);
+
+ var search = 0;
+ var parent = await createParent({
+ data: this.data,
+ archs: {
+ 'partner,false,list':
+ '<tree string="Partner">' +
+ '<field name="display_name"/>' +
+ '<field name="foo"/>' +
+ '</tree>',
+ 'partner,false,search':
+ '<search>' +
+ '<field name="foo" filter_domain="[(\'display_name\',\'ilike\',self), (\'foo\',\'ilike\',self)]"/>' +
+ '<group expand="0" string="Group By">' +
+ '<filter name="groupby_bar" context="{\'group_by\' : \'bar\'}"/>' +
+ '</group>' +
+ '</search>',
+ },
+ mockRPC: function (route, args) {
+ if (args.method === 'web_read_group') {
+ assert.deepEqual(args.kwargs, {
+ context: {
+ search_default_foo: "piou",
+ search_default_groupby_bar: true,
+ },
+ domain: ["&", ["display_name", "like", "a"], "&", ["display_name", "ilike", "piou"], ["foo", "ilike", "piou"]],
+ fields: ["display_name", "foo", "bar"],
+ groupby: ["bar"],
+ orderby: '',
+ lazy: true,
+ limit: 80,
+ }, "should search with the complete domain (domain + search), and group by 'bar'");
+ }
+ if (search === 0 && route === '/web/dataset/search_read') {
+ search++;
+ assert.deepEqual(args, {
+ context: {
+ search_default_foo: "piou",
+ search_default_groupby_bar: true,
+ bin_size: true
+ }, // not part of the test, may change
+ domain: ["&", ["display_name", "like", "a"], "&", ["display_name", "ilike", "piou"], ["foo", "ilike", "piou"]],
+ fields: ["display_name", "foo"],
+ model: "partner",
+ limit: 80,
+ sort: ""
+ }, "should search with the complete domain (domain + search)");
+ } else if (search === 1 && route === '/web/dataset/search_read') {
+ assert.deepEqual(args, {
+ context: {
+ search_default_foo: "piou",
+ search_default_groupby_bar: true,
+ bin_size: true
+ }, // not part of the test, may change
+ domain: [["display_name", "like", "a"]],
+ fields: ["display_name", "foo"],
+ model: "partner",
+ limit: 80,
+ sort: ""
+ }, "should search with the domain");
+ }
+
+ return this._super.apply(this, arguments);
+ },
+ });
+
+ var dialog;
+ new dialogs.SelectCreateDialog(parent, {
+ no_create: true,
+ readonly: true,
+ res_model: 'partner',
+ domain: [['display_name', 'like', 'a']],
+ context: {
+ search_default_groupby_bar: true,
+ search_default_foo: 'piou',
+ },
+ }).open().then(function (result) {
+ dialog = result;
+ });
+ await testUtils.nextTick();
+ await cpHelpers.removeFacet('.modal', "Bar");
+ await cpHelpers.removeFacet('.modal');
+
+ parent.destroy();
+ });
+
+ QUnit.test('SelectCreateDialog correctly evaluates domains', async function (assert) {
+ assert.expect(1);
+
+ var parent = await createParent({
+ data: this.data,
+ archs: {
+ 'partner,false,list':
+ '<tree string="Partner">' +
+ '<field name="display_name"/>' +
+ '<field name="foo"/>' +
+ '</tree>',
+ 'partner,false,search':
+ '<search>' +
+ '<field name="foo"/>' +
+ '</search>',
+ },
+ mockRPC: function (route, args) {
+ if (route === '/web/dataset/search_read') {
+ assert.deepEqual(args.domain, [['id', '=', 2]],
+ "should have correctly evaluated the domain");
+ }
+ return this._super.apply(this, arguments);
+ },
+ session: {
+ user_context: {uid: 2},
+ },
+ });
+
+ new dialogs.SelectCreateDialog(parent, {
+ no_create: true,
+ readonly: true,
+ res_model: 'partner',
+ domain: "[['id', '=', uid]]",
+ }).open();
+ await testUtils.nextTick();
+
+ parent.destroy();
+ });
+
+ QUnit.test('SelectCreateDialog list view in readonly', async function (assert) {
+ assert.expect(1);
+
+ var parent = await createParent({
+ data: this.data,
+ archs: {
+ 'partner,false,list':
+ '<tree string="Partner" editable="bottom">' +
+ '<field name="display_name"/>' +
+ '<field name="foo"/>' +
+ '</tree>',
+ 'partner,false,search':
+ '<search/>'
+ },
+ });
+
+ var dialog;
+ new dialogs.SelectCreateDialog(parent, {
+ res_model: 'partner',
+ }).open().then(function (result) {
+ dialog = result;
+ });
+ await testUtils.nextTick();
+
+ // click on the first row to see if the list is editable
+ await testUtils.dom.click(dialog.$('.o_list_view tbody tr:first td:not(.o_list_record_selector):first'));
+
+ assert.equal(dialog.$('.o_list_view tbody tr:first td:not(.o_list_record_selector):first input').length, 0,
+ "list view should not be editable in a SelectCreateDialog");
+
+ parent.destroy();
+ });
+
+ QUnit.test('SelectCreateDialog cascade x2many in create mode', async function (assert) {
+ assert.expect(5);
+
+ var form = await createView({
+ View: FormView,
+ model: 'product',
+ data: this.data,
+ arch: '<form>' +
+ '<field name="name"/>' +
+ '<field name="partner" widget="one2many" >' +
+ '<tree editable="top">' +
+ '<field name="display_name"/>' +
+ '<field name="instrument"/>' +
+ '</tree>' +
+ '</field>' +
+ '</form>',
+ res_id: 1,
+ archs: {
+ 'partner,false,form': '<form>' +
+ '<field name="name"/>' +
+ '<field name="instrument" widget="one2many" mode="tree"/>' +
+ '</form>',
+
+ 'instrument,false,form': '<form>'+
+ '<field name="name"/>'+
+ '<field name="badassery">' +
+ '<tree>'+
+ '<field name="level"/>'+
+ '</tree>' +
+ '</field>' +
+ '</form>',
+
+ 'badassery,false,list': '<tree>'+
+ '<field name="level"/>'+
+ '</tree>',
+
+ 'badassery,false,search': '<search>'+
+ '<field name="level"/>'+
+ '</search>',
+ },
+
+ mockRPC: function(route, args) {
+ if (route === '/web/dataset/call_kw/partner/get_formview_id') {
+ return Promise.resolve(false);
+ }
+ if (route === '/web/dataset/call_kw/instrument/get_formview_id') {
+ return Promise.resolve(false);
+ }
+ if (route === '/web/dataset/call_kw/instrument/create') {
+ assert.deepEqual(args.args, [{badassery: [[6, false, [1]]], name: "ABC"}],
+ 'The method create should have been called with the right arguments');
+ return Promise.resolve(false);
+ }
+ return this._super(route, args);
+ },
+ });
+
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.many2one.createAndEdit("instrument");
+
+ var $modal = $('.modal-lg');
+
+ assert.equal($modal.length, 1,
+ 'There should be one modal');
+
+ await testUtils.dom.click($modal.find('.o_field_x2many_list_row_add a'));
+
+ var $modals = $('.modal-lg');
+
+ assert.equal($modals.length, 2,
+ 'There should be two modals');
+
+ var $second_modal = $modals.not($modal);
+ await testUtils.dom.click($second_modal.find('.o_list_table.table.table-sm.table-striped.o_list_table_ungrouped .o_data_row input[type=checkbox]'));
+
+ await testUtils.dom.click($second_modal.find('.o_select_button'));
+
+ $modal = $('.modal-lg');
+
+ assert.equal($modal.length, 1,
+ 'There should be one modal');
+
+ assert.equal($modal.find('.o_data_cell').text(), 'Awsome',
+ 'There should be one item in the list of the modal');
+
+ await testUtils.dom.click($modal.find('.btn.btn-primary'));
+
+ form.destroy();
+ });
+
+ QUnit.test('Form dialog and subview with _view_ref contexts', async function (assert) {
+ assert.expect(2);
+
+ this.data.instrument.records = [{id: 1, name: 'Tromblon', badassery: [1]}];
+ this.data.partner.records[0].instrument = 1;
+
+ var form = await createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch: '<form>' +
+ '<field name="name"/>' +
+ '<field name="instrument" context="{\'tree_view_ref\': \'some_tree_view\'}"/>' +
+ '</form>',
+ res_id: 1,
+ archs: {
+ 'instrument,false,form': '<form>'+
+ '<field name="name"/>'+
+ '<field name="badassery" context="{\'tree_view_ref\': \'some_other_tree_view\'}"/>' +
+ '</form>',
+
+ 'badassery,false,list': '<tree>'+
+ '<field name="level"/>'+
+ '</tree>',
+ },
+ viewOptions: {
+ mode: 'edit',
+ },
+
+ mockRPC: function(route, args) {
+ if (args.method === 'get_formview_id') {
+ return Promise.resolve(false);
+ }
+ return this._super(route, args);
+ },
+
+ interceptsPropagate: {
+ load_views: function (ev) {
+ var evaluatedContext = ev.data.context;
+ if (ev.data.modelName === 'instrument') {
+ assert.deepEqual(evaluatedContext, {tree_view_ref: 'some_tree_view'},
+ 'The correct _view_ref should have been sent to the server, first time');
+ }
+ if (ev.data.modelName === 'badassery') {
+ assert.deepEqual(evaluatedContext, {
+ base_model_name: 'instrument',
+ tree_view_ref: 'some_other_tree_view',
+ }, 'The correct _view_ref should have been sent to the server for the subview');
+ }
+ },
+ },
+ });
+
+ await testUtils.dom.click(form.$('.o_field_widget[name="instrument"] button.o_external_button'));
+ form.destroy();
+ });
+
+ QUnit.test('SelectCreateDialog: save current search', async function (assert) {
+ assert.expect(4);
+
+ testUtils.mock.patch(ListController, {
+ getOwnedQueryParams: function () {
+ return {
+ context: {
+ shouldBeInFilterContext: true,
+ },
+ };
+ },
+ });
+
+ var parent = await createParent({
+ data: this.data,
+ archs: {
+ 'partner,false,list':
+ '<tree>' +
+ '<field name="display_name"/>' +
+ '</tree>',
+ 'partner,false,search':
+ '<search>' +
+ '<filter name="bar" help="Bar" domain="[(\'bar\', \'=\', True)]"/>' +
+ '</search>',
+
+ },
+ env: {
+ dataManager: {
+ create_filter: function (filter) {
+ assert.strictEqual(filter.domain, `[("bar", "=", True)]`,
+ "should save the correct domain");
+ const expectedContext = {
+ group_by: [], // default groupby is an empty list
+ shouldBeInFilterContext: true,
+ };
+ assert.deepEqual(filter.context, expectedContext,
+ "should save the correct context");
+ },
+ }
+ },
+ });
+
+ var dialog;
+ new dialogs.SelectCreateDialog(parent, {
+ context: {shouldNotBeInFilterContext: false},
+ res_model: 'partner',
+ }).open().then(function (result) {
+ dialog = result;
+ });
+ await testUtils.nextTick();
+
+
+ assert.containsN(dialog, '.o_data_row', 3, "should contain 3 records");
+
+ // filter on bar
+ await cpHelpers.toggleFilterMenu('.modal');
+ await cpHelpers.toggleMenuItem('.modal', "Bar");
+
+ assert.containsN(dialog, '.o_data_row', 2, "should contain 2 records");
+
+ // save filter
+ await cpHelpers.toggleFavoriteMenu('.modal');
+ await cpHelpers.toggleSaveFavorite('.modal');
+ await cpHelpers.editFavoriteName('.modal', "some name");
+ await cpHelpers.saveFavorite('.modal');
+
+ testUtils.mock.unpatch(ListController);
+ parent.destroy();
+ });
+
+ QUnit.test('propagate can_create onto the search popup o2m', async function (assert) {
+ assert.expect(4);
+
+ this.data.instrument.records = [
+ {id: 1, name: 'Tromblon1'},
+ {id: 2, name: 'Tromblon2'},
+ {id: 3, name: 'Tromblon3'},
+ {id: 4, name: 'Tromblon4'},
+ {id: 5, name: 'Tromblon5'},
+ {id: 6, name: 'Tromblon6'},
+ {id: 7, name: 'Tromblon7'},
+ {id: 8, name: 'Tromblon8'},
+ ];
+
+ var form = await createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch: '<form>' +
+ '<field name="name"/>' +
+ '<field name="instrument" can_create="false"/>' +
+ '</form>',
+ res_id: 1,
+ archs: {
+ 'instrument,false,list': '<tree>'+
+ '<field name="name"/>'+
+ '</tree>',
+ 'instrument,false,search': '<search>'+
+ '<field name="name"/>'+
+ '</search>',
+ },
+ viewOptions: {
+ mode: 'edit',
+ },
+
+ mockRPC: function(route, args) {
+ if (args.method === 'get_formview_id') {
+ return Promise.resolve(false);
+ }
+ return this._super(route, args);
+ },
+ });
+
+ await testUtils.fields.many2one.clickOpenDropdown('instrument');
+
+ assert.containsNone(form, '.ui-autocomplete a:contains(Start typing...)');
+
+ await testUtils.fields.editInput(form.el.querySelector(".o_field_many2one[name=instrument] input"), "a");
+
+ assert.containsNone(form, '.ui-autocomplete a:contains(Create and Edit)');
+
+ await testUtils.fields.editInput(form.el.querySelector(".o_field_many2one[name=instrument] input"), "");
+ await testUtils.fields.many2one.clickItem('instrument', 'Search More...');
+
+ var $modal = $('.modal-dialog.modal-lg');
+
+ assert.strictEqual($modal.length, 1, 'Modal present');
+
+ assert.strictEqual($modal.find('.modal-footer button').text(), "Cancel",
+ 'Only the cancel button is present in modal');
+
+ form.destroy();
+ });
+
+ QUnit.test('formviewdialog is not closed when button handlers return a rejected promise', async function (assert) {
+ assert.expect(3);
+
+ this.data.partner.fields.poney_ids = { string: "Poneys", type: "one2many", relation: 'partner' };
+ this.data.partner.records[0].poney_ids = [];
+ var reject = true;
+
+ var parent = await createParent({
+ data: this.data,
+ archs: {
+ 'partner,false,form':
+ '<form string="Partner">' +
+ '<field name="poney_ids"><tree><field name="display_name"/></tree></field>' +
+ '</form>',
+ },
+ });
+
+ new dialogs.FormViewDialog(parent, {
+ res_model: 'partner',
+ res_id: 1,
+ buttons: [{
+ text: 'Click me !',
+ classes: "btn-secondary o_form_button_magic",
+ close: true,
+ click: function () {
+ return reject ? Promise.reject() : Promise.resolve();
+ },
+ }],
+ }).open();
+
+ await testUtils.nextTick();
+ assert.strictEqual($('.modal').length, 1, "should have a modal displayed");
+
+ await testUtils.dom.click($('.modal .o_form_button_magic'));
+ assert.strictEqual($('.modal').length, 1, "modal should still be opened");
+
+ reject = false;
+ await testUtils.dom.click($('.modal .o_form_button_magic'));
+ assert.strictEqual($('.modal').length, 0, "modal should be closed");
+
+ parent.destroy();
+ });
+
+});
+
+});