diff options
Diffstat (limited to 'addons/web/static/tests/fields/basic_fields_tests.js')
| -rw-r--r-- | addons/web/static/tests/fields/basic_fields_tests.js | 1123 |
1 files changed, 823 insertions, 300 deletions
diff --git a/addons/web/static/tests/fields/basic_fields_tests.js b/addons/web/static/tests/fields/basic_fields_tests.js index 9e94db14cb7..cb49e8b5bba 100644 --- a/addons/web/static/tests/fields/basic_fields_tests.js +++ b/addons/web/static/tests/fields/basic_fields_tests.js @@ -13,7 +13,9 @@ var testUtils = require('web.test_utils'); var field_registry = require('web.field_registry'); var createView = testUtils.createView; +var createAsyncView = testUtils.createAsyncView; var DebouncedField = basicFields.DebouncedField; +var JournalDashboardGraph = basicFields.JournalDashboardGraph; var _t = core._t; QUnit.module('fields', {}, function () { @@ -40,8 +42,6 @@ QUnit.module('basic_fields', { selection: {string: "Selection", type: "selection", searchable:true, selection: [['normal', 'Normal'],['blocked', 'Blocked'],['done', 'Done']]}, document: {string: "Binary", type: "binary"}, - image_selection: {string: "Image Selection", type: "selection", searchable:true, - selection: [['background', 'Background'],['boxed', 'Boxed'],['clean', 'Clean'],['standard', 'Standard']]}, }, records: [{ id: 1, @@ -233,12 +233,12 @@ QUnit.module('basic_fields', { "checkbox should now be unchecked"); // check the checkbox by clicking on label - form.$('label').click(); + form.$('label:first').click(); assert.strictEqual(form.$('.o_field_boolean input:checked').length, 1, "checkbox should now be checked"); // uncheck it back - form.$('label').click(); + form.$('label:first').click(); assert.strictEqual(form.$('.o_field_boolean input:checked').length, 0, "checkbox should now be unchecked"); @@ -273,52 +273,52 @@ QUnit.module('basic_fields', { arch: '<tree editable="bottom"><field name="bar"/></tree>', }); - assert.strictEqual(list.$('tbody td:not(.o_list_record_selector) .o_checkbox input').length, 5, + assert.strictEqual(list.$('tbody td:not(.o_list_record_selector) .custom-checkbox input').length, 5, "should have 5 checkboxes"); - assert.strictEqual(list.$('tbody td:not(.o_list_record_selector) .o_checkbox input:checked').length, 4, + assert.strictEqual(list.$('tbody td:not(.o_list_record_selector) .custom-checkbox input:checked').length, 4, "should have 4 checked input"); // Edit a line - var $cell = list.$('tr.o_data_row:has(.o_checkbox input:checked) td:not(.o_list_record_selector)').first(); - assert.ok($cell.find('.o_checkbox input:checked').prop('disabled'), + var $cell = list.$('tr.o_data_row:has(.custom-checkbox input:checked) td:not(.o_list_record_selector)').first(); + assert.ok($cell.find('.custom-checkbox input:checked').prop('disabled'), "input should be disabled in readonly mode"); $cell.click(); - assert.ok(!$cell.find('.o_checkbox input:checked').prop('disabled'), + assert.ok(!$cell.find('.custom-checkbox input:checked').prop('disabled'), "input should not have the disabled property in edit mode"); - $cell.find('.o_checkbox input:checked').click(); + $cell.find('.custom-checkbox input:checked').click(); // save list.$buttons.find('.o_list_button_save').click(); - $cell = list.$('tr.o_data_row:has(.o_checkbox input:not(:checked)) td:not(.o_list_record_selector)').first(); - assert.ok($cell.find('.o_checkbox input:not(:checked)').prop('disabled'), + $cell = list.$('tr.o_data_row:has(.custom-checkbox input:not(:checked)) td:not(.o_list_record_selector)').first(); + assert.ok($cell.find('.custom-checkbox input:not(:checked)').prop('disabled'), "input should be disabled again"); - assert.strictEqual(list.$('tbody td:not(.o_list_record_selector) .o_checkbox input').length, 5, + assert.strictEqual(list.$('tbody td:not(.o_list_record_selector) .custom-checkbox input').length, 5, "should still have 5 checkboxes"); - assert.strictEqual(list.$('tbody td:not(.o_list_record_selector) .o_checkbox input:checked').length, 3, + assert.strictEqual(list.$('tbody td:not(.o_list_record_selector) .custom-checkbox input:checked').length, 3, "should now have only 3 checked input"); // Re-Edit the line and fake-check the checkbox $cell.click(); - $cell.find('.o_checkbox input').click(); // Change the checkbox - $cell.find('.o_checkbox input').click(); // Undo the change + $cell.find('.custom-checkbox input').click(); // Change the checkbox + $cell.find('.custom-checkbox input').click(); // Undo the change // Save list.$buttons.find('.o_list_button_save').click(); - assert.strictEqual(list.$('tbody td:not(.o_list_record_selector) .o_checkbox input').length, 5, + assert.strictEqual(list.$('tbody td:not(.o_list_record_selector) .custom-checkbox input').length, 5, "should still have 5 checkboxes"); - assert.strictEqual(list.$('tbody td:not(.o_list_record_selector) .o_checkbox input:checked').length, 3, + assert.strictEqual(list.$('tbody td:not(.o_list_record_selector) .custom-checkbox input:checked').length, 3, "should still have only 3 checked input"); // Re-Edit the line to check the checkbox back but this time click on // the checkbox directly in readonly mode ! - $cell = list.$('tr.o_data_row:has(.o_checkbox input:not(:checked)) td:not(.o_list_record_selector)').first(); - $cell.find('.o_checkbox span').click(); + $cell = list.$('tr.o_data_row:has(.custom-checkbox input:not(:checked)) td:not(.o_list_record_selector)').first(); + $cell.find('.custom-checkbox .custom-control-label').click(); // save list.$buttons.find('.o_form_button_save').click(); - assert.strictEqual(list.$('tbody td:not(.o_list_record_selector) .o_checkbox input').length, 5, + assert.strictEqual(list.$('tbody td:not(.o_list_record_selector) .custom-checkbox input').length, 5, "should still have 5 checkboxes"); - assert.strictEqual(list.$('tbody td:not(.o_list_record_selector) .o_checkbox input:checked').length, 4, + assert.strictEqual(list.$('tbody td:not(.o_list_record_selector) .custom-checkbox input:checked').length, 4, "should now have 4 checked input back"); list.destroy(); }); @@ -360,7 +360,7 @@ QUnit.module('basic_fields', { QUnit.module('FieldBooleanToggle'); QUnit.test('use boolean toggle widget in form view', function (assert) { - assert.expect(2); + assert.expect(1); var form = createView({ View: FormView, @@ -370,8 +370,7 @@ QUnit.module('basic_fields', { res_id: 2, }); - assert.strictEqual(form.$(".o_checkbox.o_boolean_toggle").length, 1, "Boolean toggle widget applied to boolean field"); - assert.strictEqual(form.$(".o_checkbox.o_boolean_toggle").find(".slider").length, 1, "Boolean toggle contains slider to toggle"); + assert.strictEqual(form.$(".custom-checkbox.o_boolean_toggle").length, 1, "Boolean toggle widget applied to boolean field"); form.destroy(); }); @@ -709,6 +708,71 @@ QUnit.module('basic_fields', { form.destroy(); }); + QUnit.test('float field with type number option', function (assert) { + assert.expect(4); + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '<form string="Partners">' + + '<field name="qux" options="{\'type\': \'number\'}"/>' + + '</form>', + res_id: 4, + translateParameters: { + thousands_sep: ",", + grouping: [3, 0], + }, + }); + + form.$buttons.find('.o_form_button_edit').click(); + assert.ok(form.$('.o_field_widget')[0].hasAttribute('type'), + 'Float field with option type must have a type attribute.'); + assert.strictEqual(form.$('.o_field_widget').attr('type'), 'number', + 'Float field with option type must have a type attribute equals to "number".'); + form.$('input').val('123456.7890').trigger('input'); + form.$buttons.find('.o_form_button_save').click(); + form.$buttons.find('.o_form_button_edit').click(); + assert.strictEqual(form.$('.o_field_widget').val(), '123456.789', + 'Float value must be not formatted if input type is number.'); + form.$buttons.find('.o_form_button_save').click(); + assert.strictEqual(form.$('.o_field_widget').text(), '123,456.8', + 'Float value must be formatted in readonly view even if the input type is number.'); + + form.destroy(); + }); + + QUnit.test('float field without type number option', function (assert) { + assert.expect(2); + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '<form string="Partners">' + + '<field name="qux"/>' + + '</form>', + res_id: 4, + translateParameters: { + thousands_sep: ",", + grouping: [3, 0], + }, + }); + + form.$buttons.find('.o_form_button_edit').click(); + assert.strictEqual(form.$('.o_field_widget').attr('type'), 'text', + 'Float field with option type must have a text type (default type).'); + + form.$('input').val('123456.7890').trigger('input'); + form.$buttons.find('.o_form_button_save').click(); + form.$buttons.find('.o_form_button_edit').click(); + assert.strictEqual(form.$('.o_field_widget').val(), '123,456.8', + 'Float value must be formatted if input type isn\'t number.'); + + form.destroy(); + }); + + QUnit.module('FieldEmail'); QUnit.test('email field in form view', function (assert) { @@ -1183,6 +1247,62 @@ QUnit.module('basic_fields', { form.destroy(); }); + QUnit.test('input field: change password value', function (assert) { + assert.expect(4); + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '<form>' + + '<field name="foo" password="True"/>' + + '</form>', + res_id: 1, + }); + + assert.notEqual(form.$('.o_field_char').text(), "yop", + "password field value should not be visible in read mode"); + assert.strictEqual(form.$('.o_field_char').text(), "***", + "password field value should be hidden with '*' in read mode"); + + form.$buttons.find('.o_form_button_edit').click(); + + assert.strictEqual(form.$('input.o_field_char').attr('type'), 'password', + "password field input should be with type 'password' in edit mode"); + assert.strictEqual(form.$('input.o_field_char').val(), 'yop', + "password field input value should be the (non-hidden) password value"); + + form.destroy(); + }); + + QUnit.test('input field: empty password', function (assert) { + assert.expect(3); + + this.data.partner.records[0].foo = false; + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '<form>' + + '<field name="foo" password="True"/>' + + '</form>', + res_id: 1, + }); + + assert.strictEqual(form.$('.o_field_char').text(), "", + "password field value should be empty in read mode"); + + form.$buttons.find('.o_form_button_edit').click(); + + assert.strictEqual(form.$('input.o_field_char').attr('type'), 'password', + "password field input should be with type 'password' in edit mode"); + assert.strictEqual(form.$('input.o_field_char').val(), '', + "password field input value should be the (non-hidden, empty) password value"); + + form.destroy(); + }); + QUnit.module('UrlWidget'); QUnit.test('url widget in form view', function (assert) { @@ -1292,6 +1412,46 @@ QUnit.module('basic_fields', { list.destroy(); }); + QUnit.module('copy_clipboard', { + beforeEach: function () { + this.data = { + partner: { + fields: { + script_external: {string: "Script External", type: "text"}, + web_page: {string: "Web page link", type: "char"} + }, + records: [{ + id: 1, + script_external:'Random Text', + web_page: 'web page links' + },], + }, + }; + } + }); + + QUnit.test('Char & Text Fields: Copy to clipboard button', function (assert) { + assert.expect(2); + var done = assert.async(); + testUtils.createAsyncView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '<form string="Partners">' + + '<sheet>' + + '<div>' + + '<field name="script_external" widget="CopyClipboardText"/>' + + '<field name="web_page" widget="CopyClipboardChar"/>' + + '</div>' + + '</sheet>' + + '</form>', + }).then(function (form) { + assert.strictEqual(form.$('.o_clipboard_button.o_btn_text_copy').length, 1,"Should have copy button on text type field"); + assert.strictEqual(form.$('.o_clipboard_button.o_btn_char_copy').length, 1,"Should have copy button on char type field"); + form.destroy(); + done(); + }); + }); QUnit.module('FieldText'); @@ -1362,6 +1522,97 @@ QUnit.module('basic_fields', { form.destroy(); }); + QUnit.test('text fields in edit mode, no vertical resize', function (assert) { + assert.expect(1); + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '<form string="Partners">' + + '<field name="txt"/>' + + '</form>', + res_id: 1, + }); + + form.$buttons.find('.o_form_button_edit').click(); + + var $textarea = form.$('textarea:first'); + + assert.strictEqual($textarea.css('resize'), 'none', + "should not have vertical resize"); + + form.destroy(); + }); + + QUnit.test('text fields in editable list have correct height', function (assert) { + assert.expect(2); + + this.data.partner.records[0].txt = "a\nb\nc\nd\ne\nf"; + + var list = createView({ + View: ListView, + model: 'partner', + data: this.data, + arch: '<list editable="top">' + + '<field name="foo"/>' + + '<field name="txt"/>' + + '</list>', + }); + + // Click to enter edit: in this test we specifically do not set + // the focus on the textarea by clicking on another column. + // The main goal is to test the resize is actually triggered in this + // particular case. + list.$('.o_data_cell:first').click(); + var $textarea = list.$('textarea:first'); + + // make sure the correct data is there + assert.strictEqual($textarea.val(), this.data.partner.records[0].txt); + + // make sure there is no scroll bar + assert.strictEqual($textarea.innerHeight(), $textarea[0].scrollHeight, + "textarea should not have a scroll bar"); + + list.destroy(); + }); + + QUnit.test('text fields in edit mode should resize on reset', function (assert) { + assert.expect(1); + + this.data.partner.fields.foo.type = 'text'; + + this.data.partner.onchanges = { + bar: function (obj) { + obj.foo = 'a\nb\nc\nd\ne\nf'; + }, + }; + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '<form string="Partners">' + + '<field name="bar"/>' + + '<field name="foo"/>' + + '</form>', + res_id: 1, + }); + + // edit the form + // trigger a textarea reset (through onchange) by clicking the box + // then check there is no scroll bar + form.$buttons.find('.o_form_button_edit').click(); + + form.$('div[name="bar"] input').click(); + + var $textarea = form.$('textarea:first'); + assert.strictEqual($textarea.innerHeight(), $textarea[0].scrollHeight, + "textarea should not have a scroll bar"); + + form.destroy(); + }); + QUnit.test('text field translatable', function (assert) { assert.expect(3); @@ -1833,7 +2084,7 @@ QUnit.module('basic_fields', { "the widget should have the correct class"); assert.strictEqual(form.$('div[name="document"] > img').length, 1, "the widget should contain an image"); - assert.ok(form.$('div[name="document"] > img').hasClass('img-responsive'), + assert.ok(form.$('div[name="document"] > img').hasClass('img-fluid'), "the image should have the correct class"); assert.strictEqual(form.$('div[name="document"] > img').attr('width'), "90", "the image should correctly set its attributes"); @@ -1886,7 +2137,7 @@ QUnit.module('basic_fields', { // Actual flow: click on an element of the m2m to get its form view form.$('tbody td:contains(gold)').click(); - assert.strictEqual($('.modal-dialog').length, 1, + assert.strictEqual($('.modal').length, 1, 'The modal should have opened'); assert.verifySteps([ "The view's image should have been fetched", @@ -1992,12 +2243,24 @@ QUnit.module('basic_fields', { }, }); - QUnit.test('graph dashboard widget is rendered correctly', function (assert) { + QUnit.test('graph dashboard widget attach/detach callbacks', function (assert) { + // This widget is rendered with nvd3, and nvd3 renders the graphs when + // the svg is in the DOM. The intent of this test is to determine when + // the field widgets are in the DOM, so that we can tell nvd3 to render + // them. var done = assert.async(); - assert.expect(4); + assert.expect(6); - var graph_key = JSON.parse(this.data.partner.records[0].graph_data)[0].key; - var kanban = createView({ + testUtils.patch(JournalDashboardGraph, { + on_attach_callback: function () { + assert.step('on_attach_callback'); + }, + on_detach_callback: function () { + assert.step('on_detach_callback'); + }, + }); + + createAsyncView({ View: KanbanView, model: 'partner', data: this.data, @@ -2010,42 +2273,80 @@ QUnit.module('basic_fields', { '</t>' + '</templates></kanban>', domain: [['id', 'in', [1, 2]]], - }); + }).then(function (kanban) { + assert.verifySteps([ + 'on_attach_callback', + 'on_attach_callback' + ]); - // nvd3 seems to do a setTimeout(0) each time the addGraph function is - // called, which is done twice in this case as there are 2 records. - // for that reason, we need to do two setTimeout(0) as well here to ensure - // that both graphs are rendered before starting to check if the rendering - // is correct. - concurrency.delay(0).then(function () { - return concurrency.delay(0); - }).then(function () { - assert.strictEqual(kanban.$('.o_kanban_record:first() .o_graph_barchart').length, 1, - "graph of first record should be a barchart"); - assert.strictEqual(kanban.$('.o_kanban_record:nth(1) .o_graph_linechart').length, 1, - "graph of second record should be a linechart"); - - var evt = document.createEvent("MouseEvents"); //taken ref from https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/initMouseEvent - evt.initMouseEvent("mouseover", true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null); - $('.discreteBar')[0].dispatchEvent(evt); - var tooltip = $('.nvtooltip').find('table').find('.key')[0].innerText.trim(); - assert.equal(tooltip, graph_key, "graph tooltip should be generated "); - $('.nvtooltip').remove(); - - // force a re-rendering of the first record (to check if the - // previous rendered graph is correctly removed from the DOM) - var firstRecordState = kanban.model.get(kanban.handle).data[0]; - return kanban.renderer.updateRecord(firstRecordState); - }).then(function () { - return concurrency.delay(0); // one graph is re-rendered - }).then(function () { - assert.strictEqual(kanban.$('.o_kanban_record:first() svg').length, 1, - "there should be only one rendered graph by record"); + kanban.on_detach_callback(); + + assert.verifySteps([ + 'on_attach_callback', + 'on_attach_callback', + 'on_detach_callback', + 'on_detach_callback' + ]); kanban.destroy(); + testUtils.unpatch(JournalDashboardGraph); done(); }); + }); + + QUnit.test('graph dashboard widget is rendered correctly', function (assert) { + var done = assert.async(); + assert.expect(4); + var graph_key = JSON.parse(this.data.partner.records[0].graph_data)[0].key; + createAsyncView({ + View: KanbanView, + model: 'partner', + data: this.data, + arch: '<kanban class="o_kanban_test">' + + '<field name="graph_type"/>' + + '<templates><t t-name="kanban-box">' + + '<div>' + + '<field name="graph_data" t-att-graph_type="record.graph_type.raw_value" widget="dashboard_graph"/>' + + '</div>' + + '</t>' + + '</templates></kanban>', + domain: [['id', 'in', [1, 2]]], + }).then(function (kanban) { + // nvd3 seems to do a setTimeout(0) each time the addGraph function is + // called, which is done twice in this case as there are 2 records. + // for that reason, we need to do two setTimeout(0) as well here to ensure + // that both graphs are rendered before starting to check if the rendering + // is correct. + concurrency.delay(0).then(function () { + return concurrency.delay(0); + }).then(function () { + assert.strictEqual(kanban.$('.o_kanban_record:first() .o_graph_barchart svg').length, 1, + "graph of first record should be a barchart"); + assert.strictEqual(kanban.$('.o_kanban_record:nth(1) .o_graph_linechart svg').length, 1, + "graph of second record should be a linechart"); + + var evt = document.createEvent("MouseEvents"); //taken ref from https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/initMouseEvent + evt.initMouseEvent("mouseover", true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null); + $('.discreteBar')[0].dispatchEvent(evt); + var tooltip = $('.nvtooltip').find('table').find('.key')[0].innerText.trim(); + assert.equal(tooltip, graph_key, "graph tooltip should be generated "); + $('.nvtooltip').remove(); + + // force a re-rendering of the first record (to check if the + // previous rendered graph is correctly removed from the DOM) + var firstRecordState = kanban.model.get(kanban.handle).data[0]; + return kanban.renderer.updateRecord(firstRecordState); + }).then(function () { + return concurrency.delay(0); // one graph is re-rendered + }).then(function () { + assert.strictEqual(kanban.$('.o_kanban_record:first() svg').length, 1, + "there should be only one rendered graph by record"); + + kanban.destroy(); + done(); + }); + }); }); QUnit.test('graph dashboard widget does not need nv to be destroyed', function (assert) { @@ -2053,14 +2354,15 @@ QUnit.module('basic_fields', { // when being destroyed before nv has been loaded assert.expect(2); - var destroy = basicFields.JournalDashboardGraph.prototype.destroy; - basicFields.JournalDashboardGraph.prototype.destroy = function () { - assert.step('destroy'); - var nv = window.nv; - delete window.nv; - destroy.apply(this, arguments); - window.nv = nv; - }; + testUtils.patch(basicFields.JournalDashboardGraph, { + destroy: function () { + assert.step('destroy'); + var nv = window.nv; + delete window.nv; + this._super.apply(this, arguments); + window.nv = nv; + } + }); var kanban = createView({ View: KanbanView, @@ -2078,9 +2380,12 @@ QUnit.module('basic_fields', { }); kanban.destroy(); - basicFields.JournalDashboardGraph.prototype.destroy = destroy; + testUtils.unpatch(basicFields.JournalDashboardGraph); assert.verifySteps(['destroy']); + + // Wait nvd3 to fully render the graph. If ommited, may slow down following tests. + return concurrency.delay(0); }); QUnit.test('graph dashboard widget can be destroyed when nv is partially loaded', function (assert) { @@ -2120,6 +2425,79 @@ QUnit.module('basic_fields', { testUtils.unpatch(basicFields.JournalDashboardGraph); assert.verifySteps(['destroy']); + + // Wait nvd3 to fully render the graph. If ommited, may slow down following tests. + return concurrency.delay(0); + }); + + QUnit.test('rendering of a field with dashboard_graph widget in an updated kanban view (ungrouped)', function (assert) { + + var done = assert.async(); + assert.expect(2); + + createAsyncView({ + View: KanbanView, + model: 'partner', + data: this.data, + arch: '<kanban class="o_kanban_test">' + + '<field name="graph_type"/>' + + '<templates><t t-name="kanban-box">' + + '<div>' + + '<field name="graph_data" t-att-graph_type="record.graph_type.raw_value" widget="dashboard_graph"/>' + + '</div>' + + '</t>' + + '</templates></kanban>', + domain: [['id', 'in', [1, 2]]], + }).then(function (kanban) { + concurrency.delay(0).then(function () { + return concurrency.delay(0); + }).then(function () { + assert.strictEqual(kanban.$('.o_dashboard_graph svg').length, 2, "there should be two graph rendered"); + return kanban.update({}); + }).then(function () { + return concurrency.delay(0); // one graph is re-rendered + }).then(function () { + return concurrency.delay(0); // one graph is re-rendered + }).then(function () { + assert.strictEqual(kanban.$('.o_dashboard_graph svg').length, 2, "there should be one graph rendered"); + kanban.destroy(); + done(); + }); + }); + }); + + QUnit.test('rendering of a field with dashboard_graph widget in an updated kanban view (grouped)', function (assert) { + + var done = assert.async(); + assert.expect(2); + + createAsyncView({ + View: KanbanView, + model: 'partner', + data: this.data, + arch: '<kanban class="o_kanban_test">' + + '<field name="graph_type"/>' + + '<templates><t t-name="kanban-box">' + + '<div>' + + '<field name="graph_data" t-att-graph_type="record.graph_type.raw_value" widget="dashboard_graph"/>' + + '</div>' + + '</t>' + + '</templates></kanban>', + domain: [['id', 'in', [1, 2]]], + }).then(function (kanban) { + concurrency.delay(0).then(function () { + return concurrency.delay(0); + }).then(function () { + assert.strictEqual(kanban.$('.o_dashboard_graph svg').length, 2, "there should be two graph rendered"); + return kanban.update({groupBy: ['selection'], domain: [['int_field', '=', 10]]}); + }).then(function () { + return concurrency.delay(0); + }).then(function () { + assert.strictEqual(kanban.$('.o_dashboard_graph svg').length, 1, "there should be one graph rendered"); + kanban.destroy(); + done(); + }); + }); }); QUnit.module('AceEditor'); @@ -2209,6 +2587,36 @@ QUnit.module('basic_fields', { QUnit.module('FieldDate'); + QUnit.test('date field: toggle datepicker', function (assert) { + assert.expect(3); + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch:'<form><field name="foo"/><field name="date"/></form>', + translateParameters: { // Avoid issues due to localization formats + date_format: '%m/%d/%Y', + }, + }); + + assert.strictEqual($('.bootstrap-datetimepicker-widget:visible').length, 0, + "datepicker should be closed initially"); + + testUtils.openDatepicker(form.$('.o_datepicker')); + + assert.strictEqual($('.bootstrap-datetimepicker-widget:visible').length, 1, + "datepicker should be opened"); + + // focus another field + form.$('.o_field_widget[name=foo]').click().focus(); + + assert.strictEqual($('.bootstrap-datetimepicker-widget:visible').length, 0, + "datepicker should close itself when the user clicks outside"); + + form.destroy(); + }); + QUnit.test('date field is empty if no date is set', function (assert) { assert.expect(2); @@ -2226,7 +2634,7 @@ QUnit.module('basic_fields', { }); QUnit.test('date field value should not set on first click', function (assert) { - assert.expect(3); + assert.expect(2); var form = createView({ View: FormView, @@ -2235,12 +2643,19 @@ QUnit.module('basic_fields', { arch:'<form string="Partners"><field name="date"/></form>', res_id: 4, }); + form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual($('.bootstrap-datetimepicker-widget').length, 1, "there should be a datepicker (autofocus)"); + + // open datepicker and select a date + testUtils.openDatepicker(form.$('.o_datepicker')); assert.strictEqual(form.$('.o_datepicker_input').val(), '', "date field's input should be empty on first click"); $('.day:contains(22)').click(); - form.$('.o_datepicker_input').focus(); // Open Datepicker second time - assert.strictEqual($('.day.active').text(), '22', 'datepicker should be highlight with 22nd day of month'); + + // re-open datepicker + testUtils.openDatepicker(form.$('.o_datepicker')); + assert.strictEqual($('.day.active').text(), '22', + "datepicker should be highlight with 22nd day of month"); + form.destroy(); }); @@ -2277,7 +2692,8 @@ QUnit.module('basic_fields', { assert.strictEqual(form.$('.o_datepicker_input').val(), '02/03/2017', 'the date should be correct in edit mode'); - // select another value + // open datepicker and select another value + testUtils.openDatepicker(form.$('.o_datepicker')); assert.ok($('.bootstrap-datetimepicker-widget').length, 'datepicker should be open'); assert.strictEqual($('.day.active').data('day'), '02/03/2017', 'datepicker should be highlight February 3'); $('.bootstrap-datetimepicker-widget .picker-switch').first().click(); // Month selection @@ -2326,6 +2742,76 @@ QUnit.module('basic_fields', { form.destroy(); }); + QUnit.test('date field with warn_future option', function (assert) { + assert.expect(2); + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch:'<form string="Partners">' + + '<field name="date" options="{\'datepicker\': {\'warn_future\': true}}"/>' + + '</form>', + res_id: 4, + }); + + // switch to edit mode + form.$buttons.find('.o_form_button_edit').click(); + // open datepicker and select another value + testUtils.openDatepicker(form.$('.o_datepicker')); + $('.bootstrap-datetimepicker-widget .picker-switch').first().click(); // Month selection + $('.bootstrap-datetimepicker-widget .picker-switch').first().click(); // Year selection + $('.bootstrap-datetimepicker-widget .year').eq(11).click(); // last year + $('.bootstrap-datetimepicker-widget .month').eq(11).click(); // December + $('.day:contains(31)').click(); // select the 31 December + + var $warn = form.$('.o_datepicker_warning:visible'); + assert.strictEqual($warn.length, 1, "should have a warning in the form view"); + + form.$('.o_field_widget[name=date] input').val('').trigger('change'); // remove the value + + $warn = form.$('.o_datepicker_warning:visible'); + assert.strictEqual($warn.length, 0, "the warning in the form view should be hidden"); + + form.destroy(); + }); + + QUnit.test('date field with warn_future option: do not overwrite datepicker option', function (assert) { + assert.expect(2); + + // Making sure we don't have a legit default value + // or any onchange that would set the value + this.data.partner.fields.date.default = undefined; + this.data.partner.onchanges = {}; + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch:'<form string="Partners">' + + '<field name="foo" />' + // Do not let the date field get the focus in the first place + '<field name="date" options="{\'datepicker\': {\'warn_future\': true}}"/>' + + '</form>', + res_id: 1, + }); + + // switch to edit mode + form.$buttons.find('.o_form_button_edit').click(); + assert.strictEqual(form.$('input[name="date"]').val(), '02/03/2017', + 'The existing record should have a value for the date field'); + + // save with no changes + form.$buttons.find('.o_form_button_save').click(); + + //Create a new record + form.$buttons.find('.o_form_button_create').click(); + + assert.notOk(form.$('input[name="date"]').val(), + 'The new record should not have a value that the framework would have set'); + + form.destroy(); + }); + QUnit.test('date field in editable list view', function (assert) { assert.expect(8); @@ -2360,7 +2846,8 @@ QUnit.module('basic_fields', { assert.strictEqual(list.$('input.o_datepicker_input').val(), '02/03/2017', 'the date should be correct in edit mode'); - // select another value + // open datepicker and select another value + testUtils.openDatepicker(list.$('.o_datepicker')); assert.ok($('.bootstrap-datetimepicker-widget').length, 'datepicker should be open'); $('.bootstrap-datetimepicker-widget .picker-switch').first().click(); // Month selection $('.bootstrap-datetimepicker-widget .picker-switch').first().click(); // Year selection @@ -2404,13 +2891,15 @@ QUnit.module('basic_fields', { assert.strictEqual(form.$('.o_datepicker_input').val(), '02/03/2017', 'the date should be correct in edit mode'); - $('.o_datepicker_input').val('').trigger('input').trigger('change'); - assert.ok(!form.$('.o_datepicker_input').val()); + form.$('.o_datepicker_input').val('').trigger('input').trigger('change').trigger('focusout'); + assert.strictEqual(form.$('.o_datepicker_input').val(), '', + 'should have correctly removed the value'); // save form.$buttons.find('.o_form_button_save').click(); assert.strictEqual(form.$('.o_field_date').text(), '', 'the selected date should be displayed after saving'); + form.destroy(); }); @@ -2439,7 +2928,8 @@ QUnit.module('basic_fields', { assert.strictEqual(form.$('.o_datepicker_input').val(), '02/08/2017', 'the date should be correct'); - form.$('input[name="datetime"]').val('02/08/2017').trigger('input').trigger('change'); + form.$('input[name="datetime"]').val('02/08/2017') + .trigger('input').trigger('change').trigger('focusout'); form.$buttons.find('.o_form_button_save').click(); assert.verifySteps(['read']); // should not have save as nothing changed @@ -2447,6 +2937,38 @@ QUnit.module('basic_fields', { form.destroy(); }); + QUnit.test('field date should select its content onclick when there is one', function (assert) { + assert.expect(2); + var done = assert.async(); + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch:'<form string="Partners">' + + '<field name="display_name" /> ' + // Do not focus on the date field right away + '<field name="date" />' + + '</form>', + res_id: 1, + viewOptions: { + mode: 'edit', + }, + }); + + form.$el.on({ + 'show.datetimepicker': function () { + assert.ok($('.bootstrap-datetimepicker-widget').is(':visible'), + 'bootstrap-datetimepicker is visible'); + assert.strictEqual(window.getSelection().toString(), "02/03/2017", + 'The whole input of the date field should have been selected'); + done(); + } + }); + form.$('.o_input[name="date"]').mouseenter().trigger('focus'); + + form.destroy(); + }); + QUnit.module('FieldDatetime'); QUnit.test('datetime field in form view', function (assert) { @@ -2506,9 +3028,34 @@ QUnit.module('basic_fields', { form.destroy(); }); - QUnit.test('datetime field in form view', function (assert) { + + QUnit.test('datetime field not visible in form view should not capture the focus on keyboard navigation', function (assert) { assert.expect(1); + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch:'<form string="Partners"><field name="txt"/>' + + '<field name="datetime" invisible="True"/></form>', + res_id: 1, + viewOptions: { + mode: 'edit', + }, + }); + + form.$el.find('textarea[name=txt]').trigger($.Event('keydown', { + which: $.ui.keyCode.TAB, + keyCode: $.ui.keyCode.TAB, + })); + assert.strictEqual(document.activeElement, form.$buttons.find('.o_form_button_save')[0], + "the save button should be selected, because the datepicker did not capture the focus"); + form.destroy(); + }); + + QUnit.test('datetime field with datetime formatted without second', function (assert) { + assert.expect(2); + this.data.partner.fields.datetime.default = "2017-08-02 12:00:05"; this.data.partner.fields.datetime.required = true; @@ -2517,24 +3064,21 @@ QUnit.module('basic_fields', { model: 'partner', data: this.data, arch:'<form string="Partners"><field name="datetime"/></form>', - res_id: 1, translateParameters: { // Avoid issues due to localization formats date_format: '%m/%d/%Y', time_format: '%H:%M', }, }); - testUtils.patch(basicFields.FieldDate, { - _setValue: function () { - throw "The time format of the language must be taken into account." - return this._super.apply(this, arguments); - }, - }); - form.$buttons.find('.o_form_button_create').click(); + var expectedDateString = "08/02/2017 12:00"; // 10:00:00 without timezone assert.strictEqual(form.$('.o_field_date input').val(), expectedDateString, 'the datetime should be correctly displayed in readonly'); - testUtils.unpatch(basicFields.FieldDate); + form.$buttons.find('.o_form_button_cancel').click(); + + assert.strictEqual($('.modal').length, 0, + "there should not be a Warning dialog"); + form.destroy(); }); @@ -2635,13 +3179,15 @@ QUnit.module('basic_fields', { assert.strictEqual(form.$('.o_datepicker_input').val(), '02/08/2017 12:00:00', 'the date time should be correct in edit mode'); - $('.o_datepicker_input').val('').trigger('input').trigger('change'); - assert.ok(!form.$('.o_datepicker_input').val()); + $('.o_datepicker_input').val('').trigger('input').trigger('change').trigger('focusout'); + assert.strictEqual(form.$('.o_datepicker_input').val(), '', + "should have an empty input"); // save form.$buttons.find('.o_form_button_save').click(); assert.strictEqual(form.$('.o_field_date').text(), '', 'the selected date should be displayed after saving'); + form.destroy(); }); @@ -3263,6 +3809,71 @@ QUnit.module('basic_fields', { list.destroy(); }); + QUnit.test('integer field with type number option', function (assert) { + assert.expect(4); + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '<form string="Partners">' + + '<field name="int_field" options="{\'type\': \'number\'}"/>' + + '</form>', + res_id: 4, + translateParameters: { + thousands_sep: ",", + grouping: [3, 0], + }, + }); + + form.$buttons.find('.o_form_button_edit').click(); + assert.ok(form.$('.o_field_widget')[0].hasAttribute('type'), + 'Integer field with option type must have a type attribute.'); + assert.strictEqual(form.$('.o_field_widget').attr('type'), 'number', + 'Integer field with option type must have a type attribute equals to "number".'); + + form.$('input').val('1234567890').trigger('input'); + form.$buttons.find('.o_form_button_save').click(); + form.$buttons.find('.o_form_button_edit').click(); + assert.strictEqual(form.$('.o_field_widget').val(), '1234567890', + 'Integer value must be not formatted if input type is number.'); + form.$buttons.find('.o_form_button_save').click(); + assert.strictEqual(form.$('.o_field_widget').text(), '1,234,567,890', + 'Integer value must be formatted in readonly view even if the input type is number.'); + + form.destroy(); + }); + + QUnit.test('integer field without type number option', function (assert) { + assert.expect(2); + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '<form string="Partners">' + + '<field name="int_field"/>' + + '</form>', + res_id: 4, + translateParameters: { + thousands_sep: ",", + grouping: [3, 0], + }, + }); + + form.$buttons.find('.o_form_button_edit').click(); + assert.strictEqual(form.$('.o_field_widget').attr('type'), 'text', + 'Integer field without option type must have a text type (default type).'); + + form.$('input').val('1234567890').trigger('input'); + form.$buttons.find('.o_form_button_save').click(); + form.$buttons.find('.o_form_button_edit').click(); + assert.strictEqual(form.$('.o_field_widget').val(), '1,234,567,890', + 'Integer value must be formatted if input type isn\'t number.'); + + form.destroy(); + }); + QUnit.module('FieldFloatTime'); @@ -3308,10 +3919,10 @@ QUnit.module('basic_fields', { }); - QUnit.module('PhoneWidget'); + QUnit.module('FieldFloatFactor'); - QUnit.test('phone field in form view on extra small screens', function (assert) { - assert.expect(7); + QUnit.test('float_factor field in form view', function (assert) { + assert.expect(4); var form = createView({ View: FormView, @@ -3319,97 +3930,81 @@ QUnit.module('basic_fields', { data: this.data, arch:'<form string="Partners">' + '<sheet>' + - '<group>' + - '<field name="foo" widget="phone"/>' + - '</group>' + + '<field name="qux" widget="float_factor" options="{\'factor\': 0.5}" digits="[16,2]"/>' + '</sheet>' + '</form>', - res_id: 1, - config: { - device: { - size_class: config.device.SIZES.XS, - }, + mockRPC: function (route, args) { + if (route === '/web/dataset/call_kw/partner/write') { + // 16.4 / 2 = 8.2 + assert.strictEqual(args.args[1].qux, 4.6, 'the correct float value should be saved'); + } + return this._super.apply(this, arguments); }, + res_id: 5, }); + assert.strictEqual(form.$('.o_field_widget').first().text(), '4.55', // 9.1 / 0.5 + 'The formatted value should be displayed properly.'); - var $phoneLink = form.$('a.o_form_uri.o_field_widget'); - assert.strictEqual($phoneLink.length, 1, - "should have a anchor with correct classes"); - assert.strictEqual($phoneLink.text(), 'yop', - "value should be displayed properly"); - assert.strictEqual($phoneLink.attr('href'), 'tel:yop', - "should have proper tel prefix"); - - // switch to edit mode and check the result form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('input[type="text"].o_field_widget').length, 1, - "should have an input for the phone field"); - assert.strictEqual(form.$('input[type="text"].o_field_widget').val(), 'yop', - "input should contain field value in edit mode"); + assert.strictEqual(form.$('input').val(), '4.55', + 'The value should be rendered correctly in the input.'); - // change value in edit mode - form.$('input[type="text"].o_field_widget').val('new').trigger('input'); + form.$('input').val('2.3').trigger('input'); - // save form.$buttons.find('.o_form_button_save').click(); - $phoneLink = form.$('a.o_form_uri.o_field_widget'); - assert.strictEqual($phoneLink.text(), 'new', - "new value should be displayed properly"); - assert.strictEqual($phoneLink.attr('href'), 'tel:new', - "should still have proper tel prefix"); + assert.strictEqual(form.$('.o_field_widget').first().text(), '2.30', + 'The new value should be saved and displayed properly.'); form.destroy(); }); - QUnit.test('phone field in editable list view on extra small screens', function (assert) { - assert.expect(10); + QUnit.module('FieldFloatToggle'); - var list = createView({ - View: ListView, + QUnit.test('float_toggle field in form view', function (assert) { + assert.expect(5); + + var form = createView({ + View: FormView, model: 'partner', data: this.data, - arch: '<tree editable="bottom"><field name="foo" widget="phone"/></tree>', - config: { - device: { - size_class: config.device.SIZES.XS, - }, + arch:'<form string="Partners">' + + '<sheet>' + + '<field name="qux" widget="float_toggle" options="{\'factor\': 0.125, \'range\': [0, 1, 0.75, 0.5, 0.25]}" digits="[5,3]"/>' + + '</sheet>' + + '</form>', + mockRPC: function (route, args) { + if (route === '/web/dataset/call_kw/partner/write') { + // 1.000 / 0.125 = 8 + assert.strictEqual(args.args[1].qux, 8, 'the correct float value should be saved'); + } + return this._super.apply(this, arguments); }, + res_id: 1, }); + assert.strictEqual(form.$('.o_field_widget').first().text(), '0.056', + 'The formatted time value should be displayed properly.'); - assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').length, 5, - "should have 5 cells"); - assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').first().text(), 'yop', - "value should be displayed properly"); + form.$buttons.find('.o_form_button_edit').click(); - var $phoneLink = list.$('a.o_form_uri.o_field_widget'); - assert.strictEqual($phoneLink.length, 5, - "should have anchors with correct classes"); - assert.strictEqual($phoneLink.first().attr('href'), 'tel:yop', - "should have proper tel prefix"); + assert.strictEqual(form.$('button.o_field_float_toggle').text(), '0.056', + 'The value should be rendered correctly on the button.'); - // Edit a line and check the result - var $cell = list.$('tbody td:not(.o_list_record_selector)').first(); - $cell.click(); - assert.ok($cell.parent().hasClass('o_selected_row'), 'should be set as edit mode'); - assert.strictEqual($cell.find('input').val(), 'yop', - 'should have the corect value in internal input'); - $cell.find('input').val('new').trigger('input'); + form.$('button.o_field_float_toggle').click(); // clicking will make the next value 1, since 0 was the closest of 0.056 - // save - list.$buttons.find('.o_list_button_save').click(); - $cell = list.$('tbody td:not(.o_list_record_selector)').first(); - assert.ok(!$cell.parent().hasClass('o_selected_row'), 'should not be in edit mode anymore'); - assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').first().text(), 'new', - "value should be properly updated"); - $phoneLink = list.$('a.o_form_uri.o_field_widget'); - assert.strictEqual($phoneLink.length, 5, - "should still have anchors with correct classes"); - assert.strictEqual($phoneLink.first().attr('href'), 'tel:new', - "should still have proper tel prefix"); + assert.strictEqual(form.$('button.o_field_float_toggle').text(), '1.000', + 'The value should be rendered correctly on the button.'); - list.destroy(); + form.$buttons.find('.o_form_button_save').click(); + + assert.strictEqual(form.$('.o_field_widget').first().text(), '1.000', + 'The new value should be saved and displayed properly.'); + + form.destroy(); }); + + QUnit.module('PhoneWidget'); + QUnit.test('phone field in form view on normal screens', function (assert) { assert.expect(5); @@ -3427,7 +4022,7 @@ QUnit.module('basic_fields', { res_id: 1, config: { device: { - size_class: config.device.SIZES.SM, + size_class: config.device.SIZES.LG, }, }, }); @@ -3466,7 +4061,7 @@ QUnit.module('basic_fields', { arch: '<tree editable="bottom"><field name="foo" widget="phone"/></tree>', config: { device: { - size_class: config.device.SIZES.SM, + size_class: config.device.SIZES.LG, }, }, }); @@ -3499,42 +4094,6 @@ QUnit.module('basic_fields', { list.destroy(); }); - QUnit.test('phone field does not allow html injections', function (assert) { - assert.expect(1); - - var form = createView({ - View: FormView, - model: 'partner', - data: this.data, - arch:'<form string="Partners">' + - '<sheet>' + - '<group>' + - '<field name="foo" widget="phone"/>' + - '</group>' + - '</sheet>' + - '</form>', - res_id: 1, - viewOptions: { - mode: 'edit', - }, - config: { - device: { - size_class: config.device.SIZES.XS, - }, - }, - }); - - var val = '<script>throw Error();</script><script>throw Error();</script>'; - form.$('input').val(val).trigger('input'); - - // save - form.$buttons.find('.o_form_button_save').click(); - assert.strictEqual(form.$('.o_field_widget').text(), val, - "value should have been correctly escaped"); - - form.destroy(); - }); - QUnit.test('use TAB to navigate to a phone field', function (assert) { assert.expect(2); @@ -3791,25 +4350,28 @@ QUnit.module('basic_fields', { '</sheet>' + '</form>', res_id: 1, + viewOptions: { + disable_autofocus: true, + }, }); assert.strictEqual(form.$('.o_field_widget.o_selection > a span.o_status.o_status_red').length, 1, "should have one red status since selection is the second, blocked state"); assert.strictEqual(form.$('.o_field_widget.o_selection > a span.o_status.o_status_green').length, 0, "should not have one green status since selection is the second, blocked state"); - assert.strictEqual(form.$('ul.dropdown-menu.state:visible').length, 0, + assert.strictEqual(form.$('.dropdown-menu.state:visible').length, 0, "there should not be a dropdown"); // Click on the status button to make the dropdown appear form.$('.o_field_widget.o_selection .o_status').first().click(); - assert.strictEqual(form.$('ul.dropdown-menu.state:visible').length, 1, + assert.strictEqual(form.$('.dropdown-menu.state:visible').length, 1, "there should be a dropdown"); - assert.strictEqual(form.$('ul.dropdown-menu.state:visible li').length, 2, + assert.strictEqual(form.$('.dropdown-menu.state:visible .dropdown-item').length, 2, "there should be two options in the dropdown"); // Click on the first option, "Normal" - form.$('ul.dropdown-menu.state:visible li').first().click(); - assert.strictEqual(form.$('ul.dropdown-menu.state:visible').length, 0, + form.$('.dropdown-menu.state:visible .dropdown-item').first().click(); + assert.strictEqual(form.$('.dropdown-menu.state:visible').length, 0, "there should not be a dropdown anymore"); assert.strictEqual(form.$('.o_field_widget.o_selection > a span.o_status.o_status_red').length, 0, "should not have one red status since selection is the first, normal state"); @@ -3820,7 +4382,7 @@ QUnit.module('basic_fields', { // switch to edit mode and check the result form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('ul.dropdown-menu.state:visible').length, 0, + assert.strictEqual(form.$('.dropdown-menu.state:visible').length, 0, "there should still not be a dropdown"); assert.strictEqual(form.$('.o_field_widget.o_selection > a span.o_status.o_status_red').length, 0, "should still not have one red status since selection is the first, normal state"); @@ -3831,14 +4393,14 @@ QUnit.module('basic_fields', { // Click on the status button to make the dropdown appear form.$('.o_field_widget.o_selection .o_status').first().click(); - assert.strictEqual(form.$('ul.dropdown-menu.state:visible').length, 1, + assert.strictEqual(form.$('.dropdown-menu.state:visible').length, 1, "there should be a dropdown"); - assert.strictEqual(form.$('ul.dropdown-menu.state:visible li').length, 2, + assert.strictEqual(form.$('.dropdown-menu.state:visible .dropdown-item').length, 2, "there should be two options in the dropdown"); // Click on the last option, "Done" - form.$('ul.dropdown-menu.state:visible li').last().click(); - assert.strictEqual(form.$('ul.dropdown-menu.state:visible').length, 0, + form.$('.dropdown-menu.state:visible .dropdown-item').last().click(); + assert.strictEqual(form.$('.dropdown-menu.state:visible').length, 0, "there should not be a dropdown anymore"); assert.strictEqual(form.$('.o_field_widget.o_selection > a span.o_status.o_status_red').length, 0, "should not have one red status since selection is the third, done state"); @@ -3847,7 +4409,7 @@ QUnit.module('basic_fields', { // save form.$buttons.find('.o_form_button_save').click(); - assert.strictEqual(form.$('ul.dropdown-menu.state:visible').length, 0, + assert.strictEqual(form.$('.dropdown-menu.state:visible').length, 0, "there should still not be a dropdown anymore"); assert.strictEqual(form.$('.o_field_widget.o_selection > a span.o_status.o_status_red').length, 0, "should still not have one red status since selection is the third, done state"); @@ -3876,7 +4438,7 @@ QUnit.module('basic_fields', { "should have one red status"); assert.strictEqual(list.$('.o_state_selection_cell .o_selection > a span.o_status.o_status_green').length, 1, "should have one green status"); - assert.strictEqual(list.$('ul.dropdown-menu.state:visible').length, 0, + assert.strictEqual(list.$('.dropdown-menu.state:visible').length, 0, "there should not be a dropdown"); // Click on the status button to make the dropdown appear @@ -3884,20 +4446,20 @@ QUnit.module('basic_fields', { list.$('.o_state_selection_cell .o_selection > a span.o_status').first().click(); assert.ok(!$cell.parent().hasClass('o_selected_row'), 'should not be in edit mode since we clicked on the state selection widget'); - assert.strictEqual(list.$('ul.dropdown-menu.state:visible').length, 1, + assert.strictEqual(list.$('.dropdown-menu.state:visible').length, 1, "there should be a dropdown"); - assert.strictEqual(list.$('ul.dropdown-menu.state:visible li').length, 2, + assert.strictEqual(list.$('.dropdown-menu.state:visible .dropdown-item').length, 2, "there should be two options in the dropdown"); // Click on the first option, "Normal" - list.$('ul.dropdown-menu.state:visible li').first().click(); + list.$('.dropdown-menu.state:visible .dropdown-item').first().click(); assert.strictEqual(list.$('.o_state_selection_cell .o_selection > a span.o_status').length, 5, "should still have five status selection widgets"); assert.strictEqual(list.$('.o_state_selection_cell .o_selection > a span.o_status.o_status_red').length, 0, "should now have no red status"); assert.strictEqual(list.$('.o_state_selection_cell .o_selection > a span.o_status.o_status_green').length, 1, "should still have one green status"); - assert.strictEqual(list.$('ul.dropdown-menu.state:visible').length, 0, + assert.strictEqual(list.$('.dropdown-menu.state:visible').length, 0, "there should not be a dropdown"); // switch to edit mode and check the result @@ -3911,21 +4473,21 @@ QUnit.module('basic_fields', { "should now have no red status"); assert.strictEqual(list.$('.o_state_selection_cell .o_selection > a span.o_status.o_status_green').length, 1, "should still have one green status"); - assert.strictEqual(list.$('ul.dropdown-menu.state:visible').length, 0, + assert.strictEqual(list.$('.dropdown-menu.state:visible').length, 0, "there should not be a dropdown"); // Click on the status button to make the dropdown appear list.$('.o_state_selection_cell .o_selection > a span.o_status').first().click(); - assert.strictEqual(list.$('ul.dropdown-menu.state:visible').length, 1, + assert.strictEqual(list.$('.dropdown-menu.state:visible').length, 1, "there should be a dropdown"); - assert.strictEqual(list.$('ul.dropdown-menu.state:visible li').length, 2, + assert.strictEqual(list.$('.dropdown-menu.state:visible .dropdown-item').length, 2, "there should be two options in the dropdown"); // Click on another row var $firstCell = list.$('tbody td.o_state_selection_cell').first(); var $lastCell = list.$('tbody td.o_state_selection_cell').last(); $lastCell.click(); - assert.strictEqual(list.$('ul.dropdown-menu.state:visible').length, 0, + assert.strictEqual(list.$('.dropdown-menu.state:visible').length, 0, "there should not be a dropdown anymore"); assert.ok(!$firstCell.parent().hasClass('o_selected_row'), 'first row should not be in edit mode anymore'); @@ -3934,14 +4496,14 @@ QUnit.module('basic_fields', { // Click on the last status button to make the dropdown appear list.$('.o_state_selection_cell .o_selection > a span.o_status').last().click(); - assert.strictEqual(list.$('ul.dropdown-menu.state:visible').length, 1, + assert.strictEqual(list.$('.dropdown-menu.state:visible').length, 1, "there should be a dropdown"); - assert.strictEqual(list.$('ul.dropdown-menu.state:visible li').length, 2, + assert.strictEqual(list.$('.dropdown-menu.state:visible .dropdown-item').length, 2, "there should be two options in the dropdown"); // Click on the last option, "Done" - list.$('ul.dropdown-menu.state:visible li').last().click(); - assert.strictEqual(list.$('ul.dropdown-menu.state:visible').length, 0, + list.$('.dropdown-menu.state:visible .dropdown-item').last().click(); + assert.strictEqual(list.$('.dropdown-menu.state:visible').length, 0, "there should not be a dropdown anymore"); assert.strictEqual(list.$('.o_state_selection_cell .o_selection > a span.o_status').length, 5, "should still have five status selection widgets"); @@ -3949,7 +4511,7 @@ QUnit.module('basic_fields', { "should still have no red status"); assert.strictEqual(list.$('.o_state_selection_cell .o_selection > a span.o_status.o_status_green').length, 2, "should now have two green status"); - assert.strictEqual(list.$('ul.dropdown-menu.state:visible').length, 0, + assert.strictEqual(list.$('.dropdown-menu.state:visible').length, 0, "there should not be a dropdown"); // save @@ -3960,7 +4522,7 @@ QUnit.module('basic_fields', { "should have no red status"); assert.strictEqual(list.$('.o_state_selection_cell .o_selection > a span.o_status.o_status_green').length, 2, "should have two green status"); - assert.strictEqual(list.$('ul.dropdown-menu.state:visible').length, 0, + assert.strictEqual(list.$('.dropdown-menu.state:visible').length, 0, "there should not be a dropdown"); list.destroy(); @@ -4103,42 +4665,42 @@ QUnit.module('basic_fields', { '<sheet>' + '<group>' + '<field name="selection" widget="label_selection" ' + - ' options="{\'classes\': {\'normal\': \'default\', \'blocked\': \'warning\',\'done\': \'success\'}}"/>' + + ' options="{\'classes\': {\'normal\': \'secondary\', \'blocked\': \'warning\',\'done\': \'success\'}}"/>' + '</group>' + '</sheet>' + '</form>', res_id: 1, }); - assert.strictEqual(form.$('.o_field_widget.label.label-warning').length, 1, + assert.strictEqual(form.$('.o_field_widget.badge.badge-warning').length, 1, "should have a warning status label since selection is the second, blocked state"); - assert.strictEqual(form.$('.o_field_widget.label.label-default').length, 0, + assert.strictEqual(form.$('.o_field_widget.badge.badge-secondary').length, 0, "should not have a default status since selection is the second, blocked state"); - assert.strictEqual(form.$('.o_field_widget.label.label-success').length, 0, + assert.strictEqual(form.$('.o_field_widget.badge.badge-success').length, 0, "should not have a success status since selection is the second, blocked state"); - assert.strictEqual(form.$('.o_field_widget.label.label-warning').text(), 'Blocked', + assert.strictEqual(form.$('.o_field_widget.badge.badge-warning').text(), 'Blocked', "the label should say 'Blocked' since this is the label value for that state"); // // switch to edit mode and check the result form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('.o_field_widget.label.label-warning').length, 1, + assert.strictEqual(form.$('.o_field_widget.badge.badge-warning').length, 1, "should have a warning status label since selection is the second, blocked state"); - assert.strictEqual(form.$('.o_field_widget.label.label-default').length, 0, + assert.strictEqual(form.$('.o_field_widget.badge.badge-secondary').length, 0, "should not have a default status since selection is the second, blocked state"); - assert.strictEqual(form.$('.o_field_widget.label.label-success').length, 0, + assert.strictEqual(form.$('.o_field_widget.badge.badge-success').length, 0, "should not have a success status since selection is the second, blocked state"); - assert.strictEqual(form.$('.o_field_widget.label.label-warning').text(), 'Blocked', + assert.strictEqual(form.$('.o_field_widget.badge.badge-warning').text(), 'Blocked', "the label should say 'Blocked' since this is the label value for that state"); // save form.$buttons.find('.o_form_button_save').click(); - assert.strictEqual(form.$('.o_field_widget.label.label-warning').length, 1, + assert.strictEqual(form.$('.o_field_widget.badge.badge-warning').length, 1, "should have a warning status label since selection is the second, blocked state"); - assert.strictEqual(form.$('.o_field_widget.label.label-default').length, 0, + assert.strictEqual(form.$('.o_field_widget.badge.badge-secondary').length, 0, "should not have a default status since selection is the second, blocked state"); - assert.strictEqual(form.$('.o_field_widget.label.label-success').length, 0, + assert.strictEqual(form.$('.o_field_widget.badge.badge-success').length, 0, "should not have a success status since selection is the second, blocked state"); - assert.strictEqual(form.$('.o_field_widget.label.label-warning').text(), 'Blocked', + assert.strictEqual(form.$('.o_field_widget.badge.badge-warning').text(), 'Blocked', "the label should say 'Blocked' since this is the label value for that state"); form.destroy(); @@ -4154,57 +4716,57 @@ QUnit.module('basic_fields', { arch: '<tree editable="bottom">' + '<field name="foo"/>' + '<field name="selection" widget="label_selection"' + - ' options="{\'classes\': {\'normal\': \'default\', \'blocked\': \'warning\',\'done\': \'success\'}}"/>' + + ' options="{\'classes\': {\'normal\': \'secondary\', \'blocked\': \'warning\',\'done\': \'success\'}}"/>' + '</tree>', }); - assert.strictEqual(list.$('.o_field_widget.label:not(:empty)').length, 3, + assert.strictEqual(list.$('.o_field_widget.badge:not(:empty)').length, 3, "should have three visible status labels"); - assert.strictEqual(list.$('.o_field_widget.label.label-warning').length, 1, + assert.strictEqual(list.$('.o_field_widget.badge.badge-warning').length, 1, "should have one warning status label"); - assert.strictEqual(list.$('.o_field_widget.label.label-warning').text(), 'Blocked', + assert.strictEqual(list.$('.o_field_widget.badge.badge-warning').text(), 'Blocked', "the warning label should read 'Blocked'"); - assert.strictEqual(list.$('.o_field_widget.label.label-default').length, 1, + assert.strictEqual(list.$('.o_field_widget.badge.badge-secondary').length, 1, "should have one default status label"); - assert.strictEqual(list.$('.o_field_widget.label.label-default').text(), 'Normal', + assert.strictEqual(list.$('.o_field_widget.badge.badge-secondary').text(), 'Normal', "the default label should read 'Normal'"); - assert.strictEqual(list.$('.o_field_widget.label.label-success').length, 1, + assert.strictEqual(list.$('.o_field_widget.badge.badge-success').length, 1, "should have one success status label"); - assert.strictEqual(list.$('.o_field_widget.label.label-success').text(), 'Done', + assert.strictEqual(list.$('.o_field_widget.badge.badge-success').text(), 'Done', "the success label should read 'Done'"); // switch to edit mode and check the result list.$('tbody td:not(.o_list_record_selector)').first().click(); - assert.strictEqual(list.$('.o_field_widget.label:not(:empty)').length, 3, + assert.strictEqual(list.$('.o_field_widget.badge:not(:empty)').length, 3, "should have three visible status labels"); - assert.strictEqual(list.$('.o_field_widget.label.label-warning').length, 1, + assert.strictEqual(list.$('.o_field_widget.badge.badge-warning').length, 1, "should have one warning status label"); - assert.strictEqual(list.$('.o_field_widget.label.label-warning').text(), 'Blocked', + assert.strictEqual(list.$('.o_field_widget.badge.badge-warning').text(), 'Blocked', "the warning label should read 'Blocked'"); - assert.strictEqual(list.$('.o_field_widget.label.label-default').length, 1, + assert.strictEqual(list.$('.o_field_widget.badge.badge-secondary').length, 1, "should have one default status label"); - assert.strictEqual(list.$('.o_field_widget.label.label-default').text(), 'Normal', + assert.strictEqual(list.$('.o_field_widget.badge.badge-secondary').text(), 'Normal', "the default label should read 'Normal'"); - assert.strictEqual(list.$('.o_field_widget.label.label-success').length, 1, + assert.strictEqual(list.$('.o_field_widget.badge.badge-success').length, 1, "should have one success status label"); - assert.strictEqual(list.$('.o_field_widget.label.label-success').text(), 'Done', + assert.strictEqual(list.$('.o_field_widget.badge.badge-success').text(), 'Done', "the success label should read 'Done'"); // save and check the result list.$buttons.find('.o_list_button_save').click(); - assert.strictEqual(list.$('.o_field_widget.label:not(:empty)').length, 3, + assert.strictEqual(list.$('.o_field_widget.badge:not(:empty)').length, 3, "should have three visible status labels"); - assert.strictEqual(list.$('.o_field_widget.label.label-warning').length, 1, + assert.strictEqual(list.$('.o_field_widget.badge.badge-warning').length, 1, "should have one warning status label"); - assert.strictEqual(list.$('.o_field_widget.label.label-warning').text(), 'Blocked', + assert.strictEqual(list.$('.o_field_widget.badge.badge-warning').text(), 'Blocked', "the warning label should read 'Blocked'"); - assert.strictEqual(list.$('.o_field_widget.label.label-default').length, 1, + assert.strictEqual(list.$('.o_field_widget.badge.badge-secondary').length, 1, "should have one default status label"); - assert.strictEqual(list.$('.o_field_widget.label.label-default').text(), 'Normal', + assert.strictEqual(list.$('.o_field_widget.badge.badge-secondary').text(), 'Normal', "the default label should read 'Normal'"); - assert.strictEqual(list.$('.o_field_widget.label.label-success').length, 1, + assert.strictEqual(list.$('.o_field_widget.badge.badge-success').length, 1, "should have one success status label"); - assert.strictEqual(list.$('.o_field_widget.label.label-success').text(), 'Done', + assert.strictEqual(list.$('.o_field_widget.badge.badge-success').text(), 'Done', "the success label should read 'Done'"); list.destroy(); @@ -4507,9 +5069,9 @@ QUnit.module('basic_fields', { // TODO: This test would pass without any issue since all the classes and // custom style attributes are correctly set on the widget in list - // view, but since the less itself for this widget currently only + // view, but since the scss itself for this widget currently only // applies inside the form view, the widget is unusable. This test can - // be uncommented when we refactor the less files so that this widget + // be uncommented when we refactor the scss files so that this widget // stylesheet applies in both form and list view. // QUnit.test('percentpie widget in editable list view', function(assert) { // assert.expect(10); @@ -4850,45 +5412,6 @@ QUnit.module('basic_fields', { form.destroy(); }); - QUnit.module('FieldImageSelection'); - - QUnit.test('image selection widget in form view', function (assert) { - assert.expect(3); - - var nodeOptions = { - background: { - image_link: '/base/static/img/preview_background.png', - preview_link: '/base/static/pdf/preview_background.pdf', - }, - boxed: { - image_link: '/base/static/img/preview_boxed.png', - preview_link: '/base/static/pdf/preview_boxed.pdf', - }, - }; - var form = createView({ - View: FormView, - model: 'partner', - data: this.data, - arch: '<form>' + - '<field name="image_selection" widget="image_selection"' + - ' options=\'' + JSON.stringify(nodeOptions) + '\'/> '+ - '</form>', - res_id: 2, - }); - - assert.strictEqual(form.$('.img.img-responsive').length, 2, - "Two images should be rendered"); - assert.strictEqual(form.$('.img.btn-info').length, 0, - "No image should be selected"); - - // select first image - form.$(".img.img-responsive:first").click(); - assert.ok(form.$(".img.img-responsive:first").hasClass('btn-info'), - "First image should be selected"); - - form.destroy(); - }); - QUnit.module('FieldProgressBar'); QUnit.test('Field ProgressBar: max_value should update', function (assert) { |
