Some tests were skipped these last months. This is a slippery slope.
The best time to reactivate them is the moment they were skipped, the
next best time to reactivate them is now. So, this is what this commit
does.
Three kinds of tests were skipped:
- 3 password tests
- 2 kanban progress bar tests
- one keyboard navigation test
Password tests
--------------
When the auth_password_policy addon was introduced, two tests in web/
were skipped, because they would fail when the auth_password_policy
addon is installed.
Since then, a commit was done to change the way the password field works
(commit 5bbbd25edf). With this commit,
the password field is no longer an 'include', but a new field widget.
This means that the skipped tests no longer fails.
Kanban progress bar tests:
--------------------------
In saas 11.2, the 'archive all' feature was removed, but it was readded
in saas 11.4. The tests had to be slightly adapted to make sure they
use the proper css selectors.
Keyboard navigation test:
-------------------------
It is now a functional decision not to allow moving from one cell to the
next by using left/right arrow, so this test is no longer valid.
closes odoo/odoo#28685
5349 lines
222 KiB
JavaScript
5349 lines
222 KiB
JavaScript
odoo.define('web.basic_fields_tests', function (require) {
|
|
"use strict";
|
|
|
|
var basicFields = require('web.basic_fields');
|
|
var concurrency = require('web.concurrency');
|
|
var config = require('web.config');
|
|
var core = require('web.core');
|
|
var FormView = require('web.FormView');
|
|
var KanbanView = require('web.KanbanView');
|
|
var ListView = require('web.ListView');
|
|
var session = require('web.session');
|
|
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 () {
|
|
|
|
QUnit.module('basic_fields', {
|
|
beforeEach: function () {
|
|
this.data = {
|
|
partner: {
|
|
fields: {
|
|
date: {string: "A date", type: "date", searchable: true},
|
|
datetime: {string: "A datetime", type: "datetime", searchable: true},
|
|
display_name: {string: "Displayed name", type: "char", searchable: true},
|
|
foo: {string: "Foo", type: "char", default: "My little Foo Value", searchable: true, trim: true},
|
|
bar: {string: "Bar", type: "boolean", default: true, searchable: true},
|
|
txt: {string: "txt", type: "text", default: "My little txt Value\nHo-ho-hoooo Merry Christmas"},
|
|
int_field: {string: "int_field", type: "integer", sortable: true, searchable: true},
|
|
qux: {string: "Qux", type: "float", digits: [16,1], searchable: true},
|
|
p: {string: "one2many field", type: "one2many", relation: 'partner', searchable: true},
|
|
trululu: {string: "Trululu", type: "many2one", relation: 'partner', searchable: true},
|
|
timmy: {string: "pokemon", type: "many2many", relation: 'partner_type', searchable: true},
|
|
product_id: {string: "Product", type: "many2one", relation: 'product', searchable: true},
|
|
sequence: {type: "integer", string: "Sequence", searchable: true},
|
|
currency_id: {string: "Currency", type: "many2one", relation: "currency", searchable: true},
|
|
selection: {string: "Selection", type: "selection", searchable:true,
|
|
selection: [['normal', 'Normal'],['blocked', 'Blocked'],['done', 'Done']]},
|
|
document: {string: "Binary", type: "binary"},
|
|
},
|
|
records: [{
|
|
id: 1,
|
|
date: "2017-02-03",
|
|
datetime: "2017-02-08 10:00:00",
|
|
display_name: "first record",
|
|
bar: true,
|
|
foo: "yop",
|
|
int_field: 10,
|
|
qux: 0.44444,
|
|
p: [],
|
|
timmy: [],
|
|
trululu: 4,
|
|
selection: 'blocked',
|
|
document: 'coucou==\n',
|
|
}, {
|
|
id: 2,
|
|
display_name: "second record",
|
|
bar: true,
|
|
foo: "blip",
|
|
int_field: 0,
|
|
qux: 0,
|
|
p: [],
|
|
timmy: [],
|
|
trululu: 1,
|
|
sequence: 4,
|
|
currency_id: 2,
|
|
selection: 'normal',
|
|
}, {
|
|
id: 4,
|
|
display_name: "aaa",
|
|
foo: "abc",
|
|
sequence: 9,
|
|
int_field: false,
|
|
qux: false,
|
|
selection: 'done',
|
|
},
|
|
{id: 3, bar: true, foo: "gnap", int_field: 80, qux: -3.89859, m2o: 1, m2m: []},
|
|
{id: 5, bar: false, foo: "blop", int_field: -4, qux: 9.1, m2o: 1, m2m: [1], currency_id: 1}],
|
|
onchanges: {},
|
|
},
|
|
product: {
|
|
fields: {
|
|
name: {string: "Product Name", type: "char", searchable: true}
|
|
},
|
|
records: [{
|
|
id: 37,
|
|
display_name: "xphone",
|
|
}, {
|
|
id: 41,
|
|
display_name: "xpad",
|
|
}]
|
|
},
|
|
partner_type: {
|
|
fields: {
|
|
name: {string: "Partner Type", type: "char", searchable: true},
|
|
color: {string: "Color index", type: "integer", searchable: true},
|
|
},
|
|
records: [
|
|
{id: 12, display_name: "gold", color: 2},
|
|
{id: 14, display_name: "silver", color: 5},
|
|
]
|
|
},
|
|
currency: {
|
|
fields: {
|
|
symbol: {string: "Currency Sumbol", type: "char", searchable: true},
|
|
position: {string: "Currency Position", type: "char", searchable: true},
|
|
},
|
|
records: [{
|
|
id: 1,
|
|
display_name: "$",
|
|
symbol: "$",
|
|
position: "before",
|
|
}, {
|
|
id: 2,
|
|
display_name: "€",
|
|
symbol: "€",
|
|
position: "after",
|
|
}]
|
|
},
|
|
};
|
|
}
|
|
}, function () {
|
|
|
|
QUnit.module('DebouncedField');
|
|
|
|
QUnit.test('debounced fields do not trigger call _setValue once destroyed', function (assert) {
|
|
var done = assert.async();
|
|
assert.expect(4);
|
|
|
|
var def = $.Deferred();
|
|
var _doAction = DebouncedField.prototype._doAction;
|
|
DebouncedField.prototype._doAction = function () {
|
|
_doAction.apply(this, arguments);
|
|
def.resolve();
|
|
};
|
|
var _setValue = DebouncedField.prototype._setValue;
|
|
DebouncedField.prototype._setValue = function () {
|
|
assert.step('_setValue');
|
|
_setValue.apply(this, arguments);
|
|
};
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<group>' +
|
|
'<field name="foo"/>' +
|
|
'</group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
fieldDebounce: 3,
|
|
viewOptions: {
|
|
mode: 'edit',
|
|
},
|
|
});
|
|
|
|
// change the value
|
|
form.$('input').val('new value').trigger('input');
|
|
assert.verifySteps([], "_setValue shouldn't have been called yet");
|
|
|
|
// save
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
assert.verifySteps(['_setValue'], "_setValue should have been called once");
|
|
|
|
// destroy the form view
|
|
def = $.Deferred();
|
|
form.destroy();
|
|
|
|
// wait for the debounced callback to be called
|
|
def.then(function () {
|
|
assert.verifySteps(['_setValue'],
|
|
"_setValue should not have been called after widget destruction");
|
|
|
|
DebouncedField.prototype._doAction = _doAction;
|
|
DebouncedField.prototype._setValue = _setValue;
|
|
done();
|
|
});
|
|
|
|
});
|
|
|
|
QUnit.module('FieldBoolean');
|
|
|
|
QUnit.test('boolean field in form view', function (assert) {
|
|
assert.expect(12);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form><label for="bar" string="Awesome checkbox"/><field name="bar"/></form>',
|
|
res_id: 1,
|
|
});
|
|
|
|
assert.strictEqual(form.$('.o_field_boolean input:checked').length, 1,
|
|
"checkbox should be checked");
|
|
|
|
// switch to edit mode and check the result
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
assert.strictEqual(form.$('.o_field_boolean input:checked').length, 1,
|
|
"checkbox should still be checked");
|
|
|
|
// uncheck the checkbox
|
|
form.$('.o_field_boolean input:checked').click();
|
|
assert.strictEqual(form.$('.o_field_boolean input:checked').length, 0,
|
|
"checkbox should no longer be checked");
|
|
|
|
// save
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
assert.strictEqual(form.$('.o_field_boolean input:checked').length, 0,
|
|
"checkbox should still no longer be checked");
|
|
|
|
// switch to edit mode and test the opposite change
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
assert.strictEqual(form.$('.o_field_boolean input:checked').length, 0,
|
|
"checkbox should still be unchecked");
|
|
|
|
// check the checkbox
|
|
form.$('.o_field_boolean input').click();
|
|
assert.strictEqual(form.$('.o_field_boolean input:checked').length, 1,
|
|
"checkbox should now be checked");
|
|
|
|
// uncheck it back
|
|
form.$('.o_field_boolean input').click();
|
|
assert.strictEqual(form.$('.o_field_boolean input:checked').length, 0,
|
|
"checkbox should now be unchecked");
|
|
|
|
// check the checkbox by clicking on label
|
|
form.$('label:first').click();
|
|
assert.strictEqual(form.$('.o_field_boolean input:checked').length, 1,
|
|
"checkbox should now be checked");
|
|
|
|
// uncheck it back
|
|
form.$('label:first').click();
|
|
assert.strictEqual(form.$('.o_field_boolean input:checked').length, 0,
|
|
"checkbox should now be unchecked");
|
|
|
|
// check the checkbox by hitting the "enter" key after focusing it
|
|
form.$('.o_field_boolean input')
|
|
.trigger("focusin")
|
|
.trigger({type: "keydown", which: $.ui.keyCode.ENTER})
|
|
.trigger({type: "keyup", which: $.ui.keyCode.ENTER});
|
|
assert.strictEqual(form.$('.o_field_boolean input:checked').length, 1,
|
|
"checkbox should now be checked");
|
|
// blindly press enter again, it should uncheck the checkbox
|
|
$(document.activeElement).trigger({type: "keydown", which: $.ui.keyCode.ENTER});
|
|
assert.strictEqual(form.$('.o_field_boolean input:checked').length, 0,
|
|
"checkbox should not be checked");
|
|
// blindly press enter again, it should check the checkbox back
|
|
$(document.activeElement).trigger({type: "keydown", which: $.ui.keyCode.ENTER});
|
|
|
|
// save
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
assert.strictEqual(form.$('.o_field_boolean input:checked').length, 1,
|
|
"checkbox should still be checked");
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('boolean field in editable list view', function (assert) {
|
|
assert.expect(11);
|
|
|
|
var list = createView({
|
|
View: ListView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<tree editable="bottom"><field name="bar"/></tree>',
|
|
});
|
|
|
|
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) .custom-checkbox input:checked').length, 4,
|
|
"should have 4 checked input");
|
|
|
|
// Edit a line
|
|
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('.custom-checkbox input:checked').prop('disabled'),
|
|
"input should not have the disabled property in edit mode");
|
|
$cell.find('.custom-checkbox input:checked').click();
|
|
|
|
// save
|
|
list.$buttons.find('.o_list_button_save').click();
|
|
$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) .custom-checkbox input').length, 5,
|
|
"should still have 5 checkboxes");
|
|
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('.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) .custom-checkbox input').length, 5,
|
|
"should still have 5 checkboxes");
|
|
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(.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) .custom-checkbox input').length, 5,
|
|
"should still have 5 checkboxes");
|
|
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();
|
|
});
|
|
|
|
|
|
QUnit.module('FieldBooleanButton');
|
|
|
|
QUnit.test('use custom terminology in form view', function (assert) {
|
|
assert.expect(2);
|
|
|
|
var terminology = {
|
|
string_true: "Production Environment",
|
|
hover_true: "Switch to test environment",
|
|
string_false: "Test Environment",
|
|
hover_false: "Switch to production environment"
|
|
};
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form>' +
|
|
'<div name="button_box" class="oe_button_box">' +
|
|
'<button type="object" class="oe_stat_button" icon="fa-check-square">' +
|
|
'<field name="bar" widget="boolean_button" options=\'{"terminology": ' +
|
|
JSON.stringify(terminology) + '}\'/>' +
|
|
'</button>' +
|
|
'</div>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
});
|
|
|
|
assert.strictEqual(form.$('.o_stat_text.o_not_hover:contains(Production Environment)').length, 1,
|
|
"button should contain correct string");
|
|
assert.strictEqual(form.$('.o_stat_text.o_hover:contains(Switch to test environment)').length, 1,
|
|
"button should display correct string when hovering");
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.module('FieldBooleanToggle');
|
|
|
|
QUnit.test('use boolean toggle widget in form view', function (assert) {
|
|
assert.expect(1);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form><field name="bar" widget="boolean_toggle"/></form>',
|
|
res_id: 2,
|
|
});
|
|
|
|
assert.strictEqual(form.$(".custom-checkbox.o_boolean_toggle").length, 1, "Boolean toggle widget applied to boolean field");
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.module('FieldToggleButton');
|
|
|
|
QUnit.test('use toggle_button in list view', function (assert) {
|
|
assert.expect(6);
|
|
|
|
var list = createView({
|
|
View: ListView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<tree>' +
|
|
'<field name="bar" widget="toggle_button" ' +
|
|
'options="{"active": "Reported in last payslips", "inactive": "To Report in Payslip"}"/>' +
|
|
'</tree>',
|
|
});
|
|
|
|
assert.strictEqual(list.$('button i.fa.fa-circle.o_toggle_button_success').length, 4,
|
|
"should have 4 green buttons");
|
|
assert.strictEqual(list.$('button i.fa.fa-circle.text-muted').length, 1,
|
|
"should have 1 muted button");
|
|
|
|
assert.strictEqual(list.$('button').first().attr('title'), "Reported in last payslips",
|
|
"active buttons should have proper tooltip");
|
|
assert.strictEqual(list.$('button').last().attr('title'), "To Report in Payslip",
|
|
"inactive buttons should have proper tooltip");
|
|
|
|
// clicking on first button to check the state is properly changed
|
|
list.$('button').first().click();
|
|
assert.strictEqual(list.$('button i.fa.fa-circle.o_toggle_button_success').length, 3,
|
|
"should have 3 green buttons");
|
|
|
|
list.$('button').first().click();
|
|
assert.strictEqual(list.$('button i.fa.fa-circle.o_toggle_button_success').length, 4,
|
|
"should have 4 green buttons");
|
|
list.destroy();
|
|
});
|
|
|
|
QUnit.test('toggle_button in form view (edit mode)', function (assert) {
|
|
assert.expect(6);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form>' +
|
|
'<field name="bar" widget="toggle_button" ' +
|
|
'options="{\'active\': \'Active value\', \'inactive\': \'Inactive value\'}"/>' +
|
|
'</form>',
|
|
mockRPC: function (route, args) {
|
|
if (args.method === 'write') {
|
|
assert.step('write');
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
res_id: 2,
|
|
viewOptions: {
|
|
mode: 'edit',
|
|
},
|
|
});
|
|
|
|
assert.strictEqual(form.$('.o_field_widget[name=bar] i.o_toggle_button_success:not(.text-muted)').length,
|
|
1, "should be green");
|
|
|
|
// click on the button to toggle the value
|
|
form.$('.o_field_widget[name=bar]').click();
|
|
|
|
assert.strictEqual(form.$('.o_field_widget[name=bar] i.text-muted:not(.o_toggle_button_success)').length,
|
|
1, "should be gray");
|
|
assert.verifySteps([]);
|
|
|
|
// save
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
|
|
assert.strictEqual(form.$('.o_field_widget[name=bar] i.text-muted:not(.o_toggle_button_success)').length,
|
|
1, "should still be gray");
|
|
assert.verifySteps(['write']);
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('toggle_button in form view (readonly mode)', function (assert) {
|
|
assert.expect(4);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form>' +
|
|
'<field name="bar" widget="toggle_button" ' +
|
|
'options="{\'active\': \'Active value\', \'inactive\': \'Inactive value\'}"/>' +
|
|
'</form>',
|
|
mockRPC: function (route, args) {
|
|
if (args.method === 'write') {
|
|
assert.step('write');
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
res_id: 2,
|
|
});
|
|
|
|
assert.strictEqual(form.$('.o_field_widget[name=bar] i.o_toggle_button_success:not(.text-muted)').length,
|
|
1, "should be green");
|
|
|
|
// click on the button to toggle the value
|
|
form.$('.o_field_widget[name=bar]').click();
|
|
|
|
assert.strictEqual(form.$('.o_field_widget[name=bar] i.text-muted:not(.o_toggle_button_success)').length,
|
|
1, "should be gray");
|
|
assert.verifySteps(['write']);
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.module('FieldFloat');
|
|
|
|
QUnit.test('float field when unset', function (assert) {
|
|
assert.expect(2);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="qux" digits="[5,3]"/>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 4,
|
|
});
|
|
|
|
assert.notOk(form.$('.o_field_widget').hasClass('o_field_empty'),
|
|
'Non-set float field should be considered as 0.');
|
|
assert.strictEqual(form.$('.o_field_widget').text(), "0.000",
|
|
'Non-set float field should be considered as 0.');
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('float fields use correct digit precision', function (assert) {
|
|
assert.expect(1);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<group>' +
|
|
'<field name="qux"/>' +
|
|
'</group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
});
|
|
assert.strictEqual(form.$('span.o_field_number:contains(0.4)').length, 1,
|
|
"should contain a number rounded to 1 decimal");
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('float field in form view', function (assert) {
|
|
assert.expect(5);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="qux" widget="float" digits="[5,3]"/>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
});
|
|
|
|
assert.ok(!form.$('.o_field_widget').hasClass('o_field_empty'),
|
|
'Float field should be considered set for value 0.');
|
|
assert.strictEqual(form.$('.o_field_widget').first().text(), '0.000',
|
|
'The value should be displayed properly.');
|
|
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
assert.strictEqual(form.$('input').val(), '0.000',
|
|
'The value should be rendered with correct precision.');
|
|
|
|
form.$('input').val('108.2458938598598').trigger('input');
|
|
assert.strictEqual(form.$('input').val(), '108.2458938598598',
|
|
'The value should not be formated yet.');
|
|
|
|
form.$('input').val('18.8958938598598').trigger('input');
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
assert.strictEqual(form.$('.o_field_widget').first().text(), '18.896',
|
|
'The new value should be rounded properly.');
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('float field in editable list view', function (assert) {
|
|
assert.expect(4);
|
|
|
|
var list = createView({
|
|
View: ListView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<tree editable="bottom">' +
|
|
'<field name="qux" widget="float" digits="[5,3]"/>' +
|
|
'</tree>',
|
|
});
|
|
|
|
var zeroValues = list.$('td.o_data_cell').filter(function () {return $(this).text() === '';});
|
|
assert.strictEqual(zeroValues.length, 1,
|
|
'Unset float values should be rendered as empty strings.');
|
|
|
|
// switch to edit mode
|
|
var $cell = list.$('tr.o_data_row td:not(.o_list_record_selector)').first();
|
|
$cell.click();
|
|
|
|
assert.strictEqual(list.$('input[name="qux"]').length, 1,
|
|
'The view should have 1 input for editable float.');
|
|
|
|
list.$('input[name="qux"]').val('108.2458938598598').trigger('input');
|
|
assert.strictEqual(list.$('input[name="qux"]').val(), '108.2458938598598',
|
|
'The value should not be formated yet.');
|
|
|
|
list.$('input[name="qux"]').val('18.8958938598598').trigger('input');
|
|
list.$buttons.find('.o_list_button_save').click();
|
|
assert.strictEqual(list.$('.o_field_widget').first().text(), '18.896',
|
|
'The new value should be rounded properly.');
|
|
|
|
list.destroy();
|
|
});
|
|
|
|
QUnit.test('do not trigger a field_changed if they have not changed', function (assert) {
|
|
assert.expect(2);
|
|
|
|
this.data.partner.records[1].qux = false;
|
|
this.data.partner.records[1].int_field = false;
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="qux" widget="float" digits="[5,3]"/>' +
|
|
'<field name="int_field"/>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
mockRPC: function (route, args) {
|
|
assert.step(args.method);
|
|
return this._super.apply(this, arguments);
|
|
}
|
|
});
|
|
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
|
|
assert.verifySteps(['read']); // should not have save as nothing changed
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('float widget on monetary field', function (assert) {
|
|
assert.expect(1);
|
|
|
|
this.data.partner.fields.monetary = {string: "Monetary", type: 'monetary'};
|
|
this.data.partner.records[0].monetary = 9.99;
|
|
this.data.partner.records[0].currency_id = 1;
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="monetary" widget="float"/>' +
|
|
'<field name="currency_id" invisible="1"/>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
session: {
|
|
currencies: _.indexBy(this.data.currency.records, 'id'),
|
|
},
|
|
});
|
|
|
|
assert.strictEqual(form.$('.o_field_widget[name=monetary]').text(), '9.99',
|
|
'value should be correctly formatted (with the float formatter)');
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('float field with monetary widget and decimal precision', function (assert) {
|
|
assert.expect(5);
|
|
|
|
this.data.partner.records = [{
|
|
id: 1,
|
|
qux: -8.89859,
|
|
currency_id: 1,
|
|
}]
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="qux" widget="monetary" options="{\'field_digits\': True}"/>' +
|
|
'<field name="currency_id" invisible="1"/>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
session: {
|
|
currencies: _.indexBy(this.data.currency.records, 'id'),
|
|
},
|
|
});
|
|
|
|
// Non-breaking space between the currency and the amount
|
|
assert.strictEqual(form.$('.o_field_widget').first().text(), '$\u00a0-8.9',
|
|
'The value should be displayed properly.');
|
|
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
assert.strictEqual(form.$('input').val(), '-8.9',
|
|
'The input should be rendered without the currency symbol.');
|
|
assert.strictEqual(form.$('input').parent().children().first().text(), '$',
|
|
'The input should be preceded by a span containing the currency symbol.');
|
|
|
|
form.$('input').val('109.2458938598598').trigger('input');
|
|
assert.strictEqual(form.$('input').val(), '109.2458938598598',
|
|
'The value should not be formated yet.');
|
|
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
// Non-breaking space between the currency and the amount
|
|
assert.strictEqual(form.$('.o_field_widget').first().text(), '$\u00a0109.2',
|
|
'The new value should be rounded properly.');
|
|
|
|
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) {
|
|
assert.expect(7);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<group>' +
|
|
'<field name="foo" widget="email"/>' +
|
|
'</group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
});
|
|
|
|
var $mailtoLink = form.$('a.o_form_uri.o_field_widget.o_text_overflow');
|
|
assert.strictEqual($mailtoLink.length, 1,
|
|
"should have a anchor with correct classes");
|
|
assert.strictEqual($mailtoLink.text(), 'yop',
|
|
"the value should be displayed properly");
|
|
assert.strictEqual($mailtoLink.attr('href'), 'mailto:yop',
|
|
"should have proper mailto 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 email field");
|
|
assert.strictEqual(form.$('input[type="text"].o_field_widget').val(), 'yop',
|
|
"input should contain field value in edit mode");
|
|
|
|
// change value in edit mode
|
|
form.$('input[type="text"].o_field_widget').val('new').trigger('input');
|
|
|
|
// save
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
$mailtoLink = form.$('a.o_form_uri.o_field_widget.o_text_overflow');
|
|
assert.strictEqual($mailtoLink.text(), 'new',
|
|
"new value should be displayed properly");
|
|
assert.strictEqual($mailtoLink.attr('href'), 'mailto:new',
|
|
"should still have proper mailto prefix");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('email field in editable list view', function (assert) {
|
|
assert.expect(10);
|
|
|
|
var list = createView({
|
|
View: ListView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<tree editable="bottom"><field name="foo" widget="email"/></tree>',
|
|
});
|
|
|
|
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 as text");
|
|
|
|
var $mailtoLink = list.$('a.o_form_uri.o_field_widget.o_text_overflow');
|
|
assert.strictEqual($mailtoLink.length, 5,
|
|
"should have anchors with correct classes");
|
|
assert.strictEqual($mailtoLink.first().attr('href'), 'mailto:yop',
|
|
"should have proper mailto prefix");
|
|
|
|
// 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');
|
|
|
|
// 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");
|
|
$mailtoLink = list.$('a.o_form_uri.o_field_widget.o_text_overflow');
|
|
assert.strictEqual($mailtoLink.length, 5,
|
|
"should still have anchors with correct classes");
|
|
assert.strictEqual($mailtoLink.first().attr('href'), 'mailto:new',
|
|
"should still have proper mailto prefix");
|
|
|
|
list.destroy();
|
|
});
|
|
|
|
|
|
QUnit.module('FieldChar');
|
|
|
|
QUnit.test('char widget isValid method works', function (assert) {
|
|
assert.expect(1);
|
|
|
|
this.data.partner.fields.foo.required = true;
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners">' +
|
|
'<field name="foo"/>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
});
|
|
|
|
var charField = _.find(form.renderer.allFieldWidgets)[0];
|
|
assert.strictEqual(charField.isValid(), true);
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('char field in form view', function (assert) {
|
|
assert.expect(4);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<group>' +
|
|
'<field name="foo"/>' +
|
|
'</group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
});
|
|
|
|
assert.strictEqual(form.$('.o_field_widget').text(), 'yop',
|
|
"the value should be displayed properly");
|
|
|
|
// 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 char field");
|
|
assert.strictEqual(form.$('input[type="text"].o_field_widget').val(), 'yop',
|
|
"input should contain field value in edit mode");
|
|
|
|
// change value in edit mode
|
|
form.$('input[type="text"].o_field_widget').val('limbo').trigger('input');
|
|
|
|
// save
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
assert.strictEqual(form.$('.o_field_widget').text(), 'limbo',
|
|
'the new value should be displayed');
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('setting a char field to empty string is saved as a false value', function (assert) {
|
|
assert.expect(1);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<group>' +
|
|
'<field name="foo"/>' +
|
|
'</group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
viewOptions: {mode: 'edit'},
|
|
mockRPC: function (route, args) {
|
|
if (args.method === 'write') {
|
|
assert.strictEqual(args.args[1].foo, false,
|
|
'the foo value should be false');
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
}
|
|
});
|
|
|
|
form.$('input[type="text"].o_field_widget').val('').trigger('input');
|
|
|
|
// save
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('char field with size attribute', function (assert) {
|
|
assert.expect(1);
|
|
|
|
this.data.partner.fields.foo.size = 5; // max length
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form>' +
|
|
'<sheet>' +
|
|
'<group><field name="foo"/></group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
viewOptions: {
|
|
mode: 'edit',
|
|
},
|
|
});
|
|
|
|
assert.strictEqual(form.$('input.o_field_widget').attr('maxlength'), '5',
|
|
"maxlength attribute should have been set correctly on the input");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('char field in editable list view', function (assert) {
|
|
assert.expect(6);
|
|
|
|
var list = createView({
|
|
View: ListView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<tree editable="bottom"><field name="foo"/></tree>',
|
|
});
|
|
|
|
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 as text");
|
|
|
|
// 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('brolo').trigger('input');
|
|
|
|
// 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(), 'brolo',
|
|
"value should be properly updated");
|
|
list.destroy();
|
|
});
|
|
|
|
QUnit.test('char field translatable', function (assert) {
|
|
assert.expect(3);
|
|
|
|
this.data.partner.fields.foo.translate = true;
|
|
|
|
var multiLang = _t.database.multi_lang;
|
|
_t.database.multi_lang = true;
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<group>' +
|
|
'<field name="foo"/>' +
|
|
'</group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
mockRPC: function (route, args) {
|
|
if (route === "/web/dataset/call_button" && args.method === 'translate_fields') {
|
|
assert.deepEqual(args.args, ["partner",1,"foo",{}], 'should call "call_button" route');
|
|
return $.when();
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
var $button = form.$('input[type="text"].o_field_char + .o_field_translate');
|
|
assert.strictEqual($button.length, 1, "should have a translate button");
|
|
$button.click();
|
|
form.destroy();
|
|
|
|
form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<group>' +
|
|
'<field name="foo"/>' +
|
|
'</group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
});
|
|
$button = form.$('input[type="text"].o_field_char + .o_field_translate');
|
|
assert.strictEqual($button.length, 0, "should not have a translate button in create mode");
|
|
form.destroy();
|
|
|
|
_t.database.multi_lang = multiLang;
|
|
});
|
|
|
|
QUnit.test('char 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"/>' +
|
|
'</group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
viewOptions: {
|
|
mode: 'edit',
|
|
},
|
|
});
|
|
|
|
form.$('input').val('<script>throw Error();</script>').trigger('input');
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
assert.strictEqual(form.$('.o_field_widget').text(), '<script>throw Error();</script>',
|
|
'the value should have been properly escaped');
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('char field trim (or not) characters', function (assert) {
|
|
assert.expect(2);
|
|
|
|
this.data.partner.fields.foo2 = {string: "Foo2", type: "char", trim: false};
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<group>' +
|
|
'<field name="foo"/>' +
|
|
'<field name="foo2"/>' +
|
|
'</group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
viewOptions: {
|
|
mode: 'edit',
|
|
},
|
|
});
|
|
|
|
form.$('input[name="foo"]').val(' abc ').trigger('input');
|
|
form.$('input[name="foo2"]').val(' def ').trigger('input');
|
|
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
|
|
// edit mode
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
|
|
assert.strictEqual(form.$('input[name="foo"]').val(), 'abc', 'Foo value should have been trimmed');
|
|
assert.strictEqual(form.$('input[name="foo2"]').val(), ' def ', 'Foo2 value should not have been trimmed');
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('input field: change value before pending onchange returns', function (assert) {
|
|
assert.expect(3);
|
|
|
|
this.data.partner.onchanges = {
|
|
product_id: function () {},
|
|
};
|
|
|
|
var def;
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form>' +
|
|
'<sheet>' +
|
|
'<field name="p">' +
|
|
'<tree editable="bottom">' +
|
|
'<field name="product_id"/>' +
|
|
'<field name="foo"/>' +
|
|
'</tree>' +
|
|
'</field>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
mockRPC: function (route, args) {
|
|
var result = this._super.apply(this, arguments);
|
|
if (args.method === "onchange") {
|
|
return $.when(def).then(function () {
|
|
return result;
|
|
});
|
|
} else {
|
|
return result;
|
|
}
|
|
},
|
|
viewOptions: {
|
|
mode: 'edit',
|
|
},
|
|
});
|
|
|
|
form.$('.o_field_x2many_list_row_add a').click();
|
|
assert.strictEqual(form.$('input[name="foo"]').val(), 'My little Foo Value',
|
|
'should contain the default value');
|
|
|
|
def = $.Deferred();
|
|
form.$('.o_field_many2one input').click();
|
|
var $dropdown = form.$('.o_field_many2one input').autocomplete('widget');
|
|
$dropdown.find('li:first()').click();
|
|
|
|
// set foo before onchange
|
|
form.$('input[name="foo"]').val("tralala").trigger('input');
|
|
assert.strictEqual(form.$('input[name="foo"]').val(), 'tralala',
|
|
'input should contain tralala');
|
|
|
|
// complete the onchange
|
|
def.resolve();
|
|
assert.strictEqual(form.$('input[name="foo"]').val(), 'tralala',
|
|
'input should contain the same value as before onchange');
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('input field: change value before pending onchange renaming', function (assert) {
|
|
assert.expect(3);
|
|
|
|
this.data.partner.onchanges = {
|
|
product_id: function (obj) {
|
|
obj.foo = 'on change value';
|
|
},
|
|
};
|
|
|
|
var def = $.Deferred();
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form>' +
|
|
'<sheet>' +
|
|
'<field name="product_id"/>' +
|
|
'<field name="foo"/>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
mockRPC: function (route, args) {
|
|
var result = this._super.apply(this, arguments);
|
|
if (args.method === "onchange") {
|
|
return $.when(def).then(function () {
|
|
return result;
|
|
});
|
|
} else {
|
|
return result;
|
|
}
|
|
},
|
|
viewOptions: {
|
|
mode: 'edit',
|
|
},
|
|
});
|
|
|
|
assert.strictEqual(form.$('input[name="foo"]').val(), 'yop',
|
|
'should contain the correct value');
|
|
|
|
form.$('.o_field_many2one input').click();
|
|
var $dropdown = form.$('.o_field_many2one input').autocomplete('widget');
|
|
$dropdown.find('li:first()').click();
|
|
|
|
// set foo before onchange
|
|
form.$('input[name="foo"]').val("tralala").trigger('input');
|
|
assert.strictEqual(form.$('input[name="foo"]').val(), 'tralala',
|
|
'input should contain tralala');
|
|
|
|
// complete the onchange
|
|
def.resolve();
|
|
assert.strictEqual(form.$('input[name="foo"]').val(), 'tralala',
|
|
'input should contain the same value as before onchange');
|
|
|
|
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) {
|
|
assert.expect(9);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<group>' +
|
|
'<field name="foo" widget="url"/>' +
|
|
'</group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
});
|
|
|
|
assert.strictEqual(form.$('a.o_form_uri.o_field_widget.o_text_overflow').length, 1,
|
|
"should have a anchor with correct classes");
|
|
assert.strictEqual(form.$('a.o_form_uri.o_field_widget.o_text_overflow').attr('href'), 'yop',
|
|
"should have proper href link");
|
|
assert.strictEqual(form.$('a.o_form_uri.o_field_widget.o_text_overflow').attr('target'), '_blank',
|
|
"should have target attribute set to _blank");
|
|
assert.strictEqual(form.$('a.o_form_uri.o_field_widget.o_text_overflow').text(), 'yop',
|
|
"the value should be displayed properly");
|
|
|
|
// 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 char field");
|
|
assert.strictEqual(form.$('input[type="text"].o_field_widget').val(), 'yop',
|
|
"input should contain field value in edit mode");
|
|
|
|
// change value in edit mode
|
|
form.$('input[type="text"].o_field_widget').val('limbo').trigger('input');
|
|
|
|
// save
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
assert.strictEqual(form.$('a.o_form_uri.o_field_widget.o_text_overflow').length, 1,
|
|
"should still have a anchor with correct classes");
|
|
assert.strictEqual(form.$('a.o_form_uri.o_field_widget.o_text_overflow').attr('href'), 'limbo',
|
|
"should have proper new href link");
|
|
assert.strictEqual(form.$('a.o_form_uri.o_field_widget.o_text_overflow').text(), 'limbo',
|
|
'the new value should be displayed');
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('url widget takes text from proper attribute', function (assert) {
|
|
assert.expect(1);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners">' +
|
|
'<field name="foo" widget="url" text="kebeclibre"/>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
});
|
|
|
|
assert.strictEqual(form.$('a[name="foo"]').text(), 'kebeclibre',
|
|
"url text should come from the text attribute");
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('char field in editable list view', function (assert) {
|
|
assert.expect(10);
|
|
|
|
var list = createView({
|
|
View: ListView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<tree editable="bottom"><field name="foo" widget="url"/></tree>',
|
|
});
|
|
|
|
assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').length, 5,
|
|
"should have 5 cells");
|
|
assert.strictEqual(list.$('a.o_form_uri.o_field_widget.o_text_overflow').length, 5,
|
|
"should have 5 anchors with correct classes");
|
|
assert.strictEqual(list.$('a.o_form_uri.o_field_widget.o_text_overflow').first().attr('href'), 'yop',
|
|
"should have proper href link");
|
|
assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').first().text(), 'yop',
|
|
"value should be displayed properly as text");
|
|
|
|
// 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('brolo').trigger('input');
|
|
|
|
// 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.$('a.o_form_uri.o_field_widget.o_text_overflow').length, 5,
|
|
"should still have 5 anchors with correct classes");
|
|
assert.strictEqual(list.$('a.o_form_uri.o_field_widget.o_text_overflow').first().attr('href'), 'brolo',
|
|
"should have proper new href link");
|
|
assert.strictEqual(list.$('a.o_form_uri.o_field_widget.o_text_overflow').first().text(), 'brolo',
|
|
"value should be properly updated");
|
|
|
|
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');
|
|
|
|
QUnit.test('text fields are correctly rendered', function (assert) {
|
|
assert.expect(7);
|
|
|
|
this.data.partner.fields.foo.type = 'text';
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<field name="int_field"/>' +
|
|
'<field name="foo"/>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
});
|
|
|
|
assert.ok(form.$('.o_field_text').length, "should have a text area");
|
|
assert.strictEqual(form.$('.o_field_text').text(), 'yop', 'should be "yop" in readonly');
|
|
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
|
|
var $textarea = form.$('textarea.o_field_text');
|
|
assert.ok($textarea.length, "should have a text area");
|
|
assert.strictEqual($textarea.val(), 'yop', 'should still be "yop" in edit');
|
|
|
|
$textarea.val('hello').trigger('input');
|
|
assert.strictEqual($textarea.val(), 'hello', 'should be "hello" after first edition');
|
|
|
|
$textarea.val('hello world').trigger('input');
|
|
assert.strictEqual($textarea.val(), 'hello world', 'should be "hello world" after second edition');
|
|
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
|
|
assert.strictEqual(form.$('.o_field_text').text(), 'hello world',
|
|
'should be "hello world" after save');
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('text fields in edit mode have correct height', function (assert) {
|
|
assert.expect(2);
|
|
|
|
this.data.partner.fields.foo.type = 'text';
|
|
this.data.partner.records[0].foo = "f\nu\nc\nk\nm\ni\nl\ng\nr\no\nm";
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<field name="foo"/>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
});
|
|
|
|
var $field = form.$('.o_field_text');
|
|
|
|
assert.strictEqual($field.outerHeight(), $field[0].scrollHeight,
|
|
"text field should not have a scroll bar");
|
|
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
|
|
var $textarea = form.$('textarea:first');
|
|
|
|
// the difference is to take small calculation errors into account
|
|
assert.strictEqual($textarea.innerHeight(), $textarea[0].scrollHeight,
|
|
"textarea should not have a scroll bar");
|
|
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);
|
|
|
|
this.data.partner.fields.txt.translate = true;
|
|
|
|
var multiLang = _t.database.multi_lang;
|
|
_t.database.multi_lang = true;
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<group>' +
|
|
'<field name="txt"/>' +
|
|
'</group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
mockRPC: function (route, args) {
|
|
if (route === "/web/dataset/call_button" && args.method === 'translate_fields') {
|
|
assert.deepEqual(args.args, ["partner",1,"txt",{}], 'should call "call_button" route');
|
|
return $.when();
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
var $button = form.$('textarea + .o_field_translate');
|
|
assert.strictEqual($button.length, 1, "should have a translate button");
|
|
$button.click();
|
|
form.destroy();
|
|
|
|
form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<group>' +
|
|
'<field name="txt"/>' +
|
|
'</group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
});
|
|
$button = form.$('textarea + .o_field_translate');
|
|
assert.strictEqual($button.length, 0, "should not have a translate button in create mode");
|
|
form.destroy();
|
|
|
|
_t.database.multi_lang = multiLang;
|
|
});
|
|
|
|
QUnit.test('go to next line (and not the next row) when pressing enter', function (assert) {
|
|
assert.expect(4);
|
|
|
|
this.data.partner.fields.foo.type = 'text';
|
|
var list = createView({
|
|
View: ListView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<list editable="top">' +
|
|
'<field name="int_field"/>' +
|
|
'<field name="foo"/>' +
|
|
'<field name="qux"/>' +
|
|
'</list>',
|
|
});
|
|
|
|
list.$('tbody tr:first .o_list_text').click();
|
|
var $textarea = list.$('textarea.o_field_text');
|
|
assert.strictEqual($textarea.length, 1, "should have a text area");
|
|
assert.strictEqual($textarea.val(), 'yop', 'should still be "yop" in edit');
|
|
|
|
assert.strictEqual(list.$('textarea').get(0), document.activeElement,
|
|
"text area should have the focus");
|
|
|
|
// click on enter
|
|
list.$('textarea')
|
|
.trigger({type: "keydown", which: $.ui.keyCode.ENTER})
|
|
.trigger({type: "keyup", which: $.ui.keyCode.ENTER});
|
|
|
|
assert.strictEqual(list.$('textarea').first().get(0), document.activeElement,
|
|
"text area should still have the focus");
|
|
|
|
list.destroy();
|
|
});
|
|
|
|
// Firefox-specific
|
|
// Copying from <div style="white-space:pre-wrap"> does not keep line breaks
|
|
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1390115
|
|
QUnit.test('copying text fields in RO mode should preserve line breaks', function (assert) {
|
|
assert.expect(1);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<group>' +
|
|
'<field name="txt"/>' +
|
|
'</group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
});
|
|
|
|
// Copying from a div tag with white-space:pre-wrap doesn't work in Firefox
|
|
assert.strictEqual(form.$('[name="txt"]').prop("tagName").toLowerCase(), 'span',
|
|
"the field contents should be surrounded by a span tag");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.module('FieldBinary');
|
|
|
|
QUnit.test('binary fields are correctly rendered', function (assert) {
|
|
assert.expect(16);
|
|
|
|
// save the session function
|
|
var oldGetFile = session.get_file;
|
|
session.get_file = function (option) {
|
|
assert.strictEqual(option.data.field, 'document',
|
|
"we should download the field document");
|
|
assert.strictEqual(option.data.data, 'coucou==\n',
|
|
"we should download the correct data");
|
|
option.complete();
|
|
return $.when();
|
|
};
|
|
|
|
this.data.partner.records[0].foo = 'coucou.txt';
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<field name="document" filename="foo"/>' +
|
|
'<field name="foo"/>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
});
|
|
|
|
assert.strictEqual(form.$('a.o_field_widget[name="document"] > .fa-download').length, 1,
|
|
"the binary field should be rendered as a downloadable link in readonly");
|
|
assert.strictEqual(form.$('a.o_field_widget[name="document"]').text().trim(), 'coucou.txt',
|
|
"the binary field should display the name of the file in the link");
|
|
assert.strictEqual(form.$('.o_field_char').text(), 'coucou.txt',
|
|
"the filename field should have the file name as value");
|
|
|
|
form.$('a.o_field_widget[name="document"]').click();
|
|
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
|
|
assert.strictEqual(form.$('a.o_field_widget[name="document"] > .fa-download').length, 0,
|
|
"the binary field should not be rendered as a downloadable link in edit");
|
|
assert.strictEqual(form.$('div.o_field_binary_file[name="document"] > input').val(), 'coucou.txt',
|
|
"the binary field should display the file name in the input edit mode");
|
|
assert.strictEqual(form.$('.o_field_binary_file > input').attr('readonly'), 'readonly',
|
|
"the input should be readonly");
|
|
assert.strictEqual(form.$('.o_field_binary_file > .o_clear_file_button').length, 1,
|
|
"there shoud be a button to clear the file");
|
|
assert.strictEqual(form.$('input.o_field_char').val(), 'coucou.txt',
|
|
"the filename field should have the file name as value");
|
|
|
|
|
|
form.$('.o_field_binary_file > .o_clear_file_button').click();
|
|
|
|
assert.ok(form.$('.o_field_binary_file > input').hasClass('o_hidden'),
|
|
"the input should be hidden");
|
|
assert.strictEqual(form.$('.o_field_binary_file > .o_select_file_button:not(.o_hidden)').length, 1,
|
|
"there shoud be a button to upload the file");
|
|
assert.strictEqual(form.$('input.o_field_char').val(), '',
|
|
"the filename field should be empty since we removed the file");
|
|
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
assert.strictEqual(form.$('a.o_field_widget[name="document"] > .fa-download').length, 0,
|
|
"the binary field should not render as a downloadable link since we removed the file");
|
|
assert.strictEqual(form.$('a.o_field_widget[name="document"]').text().trim(), '',
|
|
"the binary field should not display a filename in the link since we removed the file");
|
|
assert.strictEqual(form.$('.o_field_char').text().trim(), '',
|
|
"the filename field should be empty since we removed the file");
|
|
|
|
form.destroy();
|
|
|
|
// restore the session function
|
|
session.get_file = oldGetFile;
|
|
});
|
|
|
|
QUnit.test('binary fields that are readonly in create mode do not download', function (assert) {
|
|
assert.expect(2);
|
|
|
|
// save the session function
|
|
var oldGetFile = session.get_file;
|
|
session.get_file = function (option) {
|
|
assert.step('We shouldn\'t be getting the file.');
|
|
return oldGetFile.bind(session)(option);
|
|
};
|
|
|
|
this.data.partner.onchanges = {
|
|
product_id: function (obj) {
|
|
obj.document = "onchange==\n";
|
|
},
|
|
};
|
|
|
|
this.data.partner.fields.document.readonly = true;
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<field name="product_id"/>' +
|
|
'<field name="document" filename="\'yooo\'"/>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
});
|
|
|
|
form.$buttons.find('.o_form_button_create').click();
|
|
var $dropdown = form.$('.o_field_many2one input').autocomplete('widget');
|
|
|
|
form.$('.o_field_many2one input').click();
|
|
$dropdown.find('li:not(.o_m2o_dropdown_option):contains(xphone)').click();
|
|
|
|
assert.strictEqual(form.$('a.o_field_widget[name="document"] > .fa-download').length, 1,
|
|
'The link to download the binary should be present');
|
|
|
|
form.$('a.o_field_widget[name="document"]').click();
|
|
|
|
assert.verifySteps([]); // We shoudln't have passed through steps
|
|
|
|
form.destroy();
|
|
session.get_file = oldGetFile;
|
|
});
|
|
|
|
QUnit.module('FieldPdfViewer');
|
|
|
|
QUnit.test("pdf_viewer without data", function (assert) {
|
|
assert.expect(4);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:
|
|
'<form>' +
|
|
'<field name="document" widget="pdf_viewer"/>' +
|
|
'</form>',
|
|
});
|
|
|
|
assert.ok(form.$('.o_field_widget').hasClass('o_field_pdfviewer'));
|
|
assert.strictEqual(form.$('.o_select_file_button:not(.o_hidden)').length, 1,
|
|
"there should be a visible 'Upload' button");
|
|
assert.ok(form.$('.o_field_widget iframe.o_pdfview_iframe').hasClass('o_hidden'),
|
|
"there should be an invisible iframe");
|
|
assert.strictEqual(form.$('input[type="file"]').length, 1,
|
|
"there should be one input");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test("pdf_viewer: basic rendering", function (assert) {
|
|
assert.expect(4);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
res_id: 1,
|
|
arch:
|
|
'<form>' +
|
|
'<field name="document" widget="pdf_viewer"/>' +
|
|
'</form>',
|
|
mockRPC: function (route) {
|
|
if (route.indexOf('/web/static/lib/pdfjs/web/viewer.html') !== -1) {
|
|
return $.when();
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
}
|
|
});
|
|
|
|
assert.ok(form.$('.o_field_widget').hasClass('o_field_pdfviewer'));
|
|
assert.strictEqual(form.$('.o_select_file_button:not(.o_hidden)').length, 0,
|
|
"there should not be a any visible 'Upload' button");
|
|
assert.notOk(form.$('.o_field_widget iframe.o_pdfview_iframe').hasClass('o_hidden'),
|
|
"there should be an visible iframe");
|
|
assert.strictEqual(form.$('.o_field_widget iframe.o_pdfview_iframe').attr('data-src'),
|
|
'/web/static/lib/pdfjs/web/viewer.html?file=%2Fweb%2Fimage%3Fmodel%3Dpartner%26field%3Ddocument%26id%3D1#page=1',
|
|
"the src attribute should be correctly set on the iframe");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test("pdf_viewer: upload rendering", function (assert) {
|
|
assert.expect(6);
|
|
|
|
testUtils.patch(field_registry.map.pdf_viewer, {
|
|
on_file_change: function (ev) {
|
|
ev.target = {files: [new Blob()]};
|
|
this._super.apply(this, arguments);
|
|
},
|
|
_getURI: function (fileURI) {
|
|
var res = this._super.apply(this, arguments);
|
|
assert.step('_getURI');
|
|
assert.ok(_.str.startsWith(fileURI, 'blob:'));
|
|
this.PDFViewerApplication = {
|
|
open: function (URI) {
|
|
assert.step('open');
|
|
assert.ok(_.str.startsWith(URI, 'blob:'));
|
|
},
|
|
};
|
|
return 'about:blank';
|
|
},
|
|
});
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:
|
|
'<form>' +
|
|
'<field name="document" widget="pdf_viewer"/>' +
|
|
'</form>',
|
|
});
|
|
|
|
// first upload initialize iframe
|
|
form.$('input[type="file"]').trigger('change');
|
|
assert.verifySteps(['_getURI']);
|
|
// second upload call pdfjs method inside iframe
|
|
form.$('input[type="file"]').trigger('change');
|
|
assert.verifySteps(['_getURI', 'open']);
|
|
|
|
testUtils.unpatch(field_registry.map.pdf_viewer);
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('text field rendering in list view', function (assert) {
|
|
assert.expect(1);
|
|
|
|
var data = {
|
|
foo: {
|
|
fields: {foo: {string: "F", type: "text"}},
|
|
records: [{id: 1, foo: "some text"}]
|
|
},
|
|
};
|
|
var list = createView({
|
|
View: ListView,
|
|
model: 'foo',
|
|
data: data,
|
|
arch: '<tree><field name="foo"/></tree>',
|
|
});
|
|
|
|
assert.strictEqual(list.$('tbody td.o_list_text:contains(some text)').length, 1,
|
|
"should have a td with the .o_list_text class");
|
|
list.destroy();
|
|
});
|
|
|
|
QUnit.test('field text in editable list view', function (assert) {
|
|
assert.expect(1);
|
|
|
|
this.data.partner.fields.foo.type = 'text';
|
|
|
|
var list = createView({
|
|
View: ListView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<tree string="Phonecalls" editable="top">' +
|
|
'<field name="foo"/>' +
|
|
'</tree>',
|
|
});
|
|
|
|
list.$buttons.find('.o_list_button_add').click();
|
|
|
|
assert.strictEqual(list.$('textarea').first().get(0), document.activeElement,
|
|
"text area should have the focus");
|
|
list.destroy();
|
|
});
|
|
|
|
QUnit.test('field changes are correctly debounced in text fields', function (assert) {
|
|
var done = assert.async();
|
|
assert.expect(5);
|
|
|
|
this.data.partner.fields.foo.type = 'text';
|
|
|
|
var def = $.Deferred();
|
|
var nbNotifyChanges = 0;
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<field name="foo"/>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
fieldDebounce: 3,
|
|
});
|
|
|
|
var _onFieldChanged = form._onFieldChanged;
|
|
form._onFieldChanged = function () {
|
|
_onFieldChanged.apply(form, arguments);
|
|
nbNotifyChanges++;
|
|
def.resolve();
|
|
};
|
|
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
|
|
form.$('textarea').val("1").trigger('input');
|
|
assert.strictEqual(nbNotifyChanges, 0,
|
|
"no event should have been triggered");
|
|
form.$('textarea').val("12").trigger('input');
|
|
assert.strictEqual(nbNotifyChanges, 0,
|
|
"no event should have been triggered");
|
|
|
|
return waitForChangeTriggered().then(function () {
|
|
assert.strictEqual(nbNotifyChanges, 1,
|
|
"one event should have been triggered");
|
|
|
|
// add something in the textarea, then focus another input
|
|
form.$('textarea').first().val("123").trigger('input');
|
|
form.$('textarea').first().change();
|
|
assert.strictEqual(nbNotifyChanges, 2,
|
|
"one event should have been triggered immediately");
|
|
|
|
return waitForChangeTriggered();
|
|
}).then(function () {
|
|
assert.strictEqual(nbNotifyChanges, 2,
|
|
"no extra event should have been triggered");
|
|
|
|
form.destroy();
|
|
done();
|
|
});
|
|
|
|
function waitForChangeTriggered() {
|
|
return def.then(function () {
|
|
def = $.Deferred();
|
|
return concurrency.delay(0);
|
|
});
|
|
}
|
|
});
|
|
|
|
QUnit.module('FieldImage');
|
|
|
|
QUnit.test('image fields are correctly rendered', function (assert) {
|
|
assert.expect(7);
|
|
|
|
this.data.partner.records[0].__last_update = '2017-02-08 10:00:00';
|
|
this.data.partner.records[0].document = 'myimage';
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<field name="document" widget="image" options="{\'size\': [90, 90]}"/> ' +
|
|
'</form>',
|
|
res_id: 1,
|
|
mockRPC: function (route, args) {
|
|
if (route === '/web/dataset/call_kw/partner/read') {
|
|
assert.deepEqual(args.args[1], ['document', '__last_update', 'display_name'], "The fields document, display_name and __last_update should be present when reading an image");
|
|
}
|
|
if (route === 'data:image/png;base64,myimage') {
|
|
assert.ok(true, "should called the correct route");
|
|
return $.when('wow');
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
|
|
assert.ok(form.$('div[name="document"]').hasClass('o_field_image'),
|
|
"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-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");
|
|
assert.strictEqual(form.$('div[name="document"] > img').css('max-width'), "90px",
|
|
"the image should correctly set its attributes");
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('image fields in subviews are loaded correctly', function (assert) {
|
|
assert.expect(6);
|
|
|
|
this.data.partner.records[0].__last_update = '2017-02-08 10:00:00';
|
|
this.data.partner.records[0].document = 'myimage';
|
|
this.data.partner_type.fields.image = {name: 'image', type: 'binary'};
|
|
this.data.partner_type.records[0].image = 'product_image';
|
|
this.data.partner.records[0].timmy = [12];
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<field name="document" widget="image" options="{\'size\': [90, 90]}"/>' +
|
|
'<field name="timmy" widget="many2many">' +
|
|
'<tree>' +
|
|
'<field name="display_name"/>' +
|
|
'</tree>' +
|
|
'<form>' +
|
|
'<field name="image" widget="image"/>' +
|
|
'</form>' +
|
|
'</field>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
mockRPC: function (route, args) {
|
|
if (route === 'data:image/png;base64,myimage') {
|
|
assert.step("The view's image should have been fetched");
|
|
return $.when('wow');
|
|
}
|
|
if (route === 'data:image/png;base64,product_image') {
|
|
assert.step("The dialog's image should have been fetched");
|
|
return $.when();
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
assert.verifySteps(["The view's image should have been fetched"]);
|
|
|
|
assert.strictEqual(form.$('tr.o_data_row').length, 1,
|
|
'There should be one record in the many2many');
|
|
|
|
// Actual flow: click on an element of the m2m to get its form view
|
|
form.$('tbody td:contains(gold)').click();
|
|
assert.strictEqual($('.modal').length, 1,
|
|
'The modal should have opened');
|
|
assert.verifySteps([
|
|
"The view's image should have been fetched",
|
|
"The dialog's image should have been fetched",
|
|
]);
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('image fields in x2many list are loaded correctly', function (assert) {
|
|
assert.expect(2);
|
|
|
|
this.data.partner_type.fields.image = {name: 'image', type: 'binary'};
|
|
this.data.partner_type.records[0].image = 'product_image';
|
|
this.data.partner.records[0].timmy = [12];
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<field name="timmy" widget="many2many">' +
|
|
'<tree>' +
|
|
'<field name="image" widget="image"/>' +
|
|
'</tree>' +
|
|
'</field>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
mockRPC: function (route, args) {
|
|
if (route === 'data:image/png;base64,product_image') {
|
|
assert.ok(true, "The list's image should have been fetched");
|
|
return $.when();
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
|
|
assert.strictEqual(form.$('tr.o_data_row').length, 1,
|
|
'There should be one record in the many2many');
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('image fields with required attribute', function (assert) {
|
|
assert.expect(2);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<field name="document" required="1" widget="image"/>' +
|
|
'</form>',
|
|
mockRPC: function (route, args) {
|
|
if (args.method === 'create') {
|
|
throw new Error("Should not do a create RPC with unset required image field");
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
|
|
assert.ok(form.$('.o_form_view').hasClass('o_form_editable'),
|
|
"form view should still be editable");
|
|
assert.ok(form.$('.o_field_widget').hasClass('o_field_invalid'),
|
|
"image field should be displayed as invalid");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.module('JournalDashboardGraph', {
|
|
beforeEach: function () {
|
|
_.extend(this.data.partner.fields, {
|
|
graph_data: { string: "Graph Data", type: "text" },
|
|
graph_type: {
|
|
string: "Graph Type",
|
|
type: "selection",
|
|
selection: [['line', 'Line'], ['bar', 'Bar']]
|
|
},
|
|
});
|
|
this.data.partner.records[0].graph_type = "bar";
|
|
this.data.partner.records[1].graph_type = "line";
|
|
var graph_values = [
|
|
{'value': 300, 'label': '5-11 Dec'},
|
|
{'value': 500, 'label': '12-18 Dec'},
|
|
{'value': 100, 'label': '19-25 Dec'},
|
|
];
|
|
this.data.partner.records[0].graph_data = JSON.stringify([{
|
|
color: 'red',
|
|
title: 'Partner 0',
|
|
values: graph_values,
|
|
key: 'A key',
|
|
area: true,
|
|
}]);
|
|
this.data.partner.records[1].graph_data = JSON.stringify([{
|
|
color: 'blue',
|
|
title: 'Partner 1',
|
|
values: graph_values,
|
|
key: 'A key',
|
|
area: true,
|
|
}]);
|
|
},
|
|
});
|
|
|
|
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(6);
|
|
|
|
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,
|
|
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) {
|
|
assert.verifySteps([
|
|
'on_attach_callback',
|
|
'on_attach_callback'
|
|
]);
|
|
|
|
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) {
|
|
// this test ensures that the JournalDashboardGraph widget doesn't crash
|
|
// when being destroyed before nv has been loaded
|
|
assert.expect(2);
|
|
|
|
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,
|
|
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]]],
|
|
});
|
|
|
|
kanban.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) {
|
|
// this test ensures that the JournalDashboardGraph widget doesn't crash
|
|
// when being destroyed before nv has been completely loaded
|
|
assert.expect(2);
|
|
|
|
testUtils.patch(basicFields.JournalDashboardGraph, {
|
|
destroy: function () {
|
|
assert.step('destroy');
|
|
// nv is fully loaded only when nvd3.js has been loaded
|
|
// which happens sequentially after nv.d3.js
|
|
// we simulate this race condition with:
|
|
var offWindowResize = window.nv.utils.offWindowResize;
|
|
window.nv.utils.offWindowResize = undefined;
|
|
this._super.apply(this, arguments);
|
|
window.nv.utils.offWindowResize = offWindowResize;
|
|
},
|
|
});
|
|
|
|
var kanban = createView({
|
|
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]]],
|
|
});
|
|
|
|
kanban.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('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');
|
|
|
|
QUnit.test('ace widget on text fields works', function (assert) {
|
|
assert.expect(2);
|
|
var done = assert.async();
|
|
|
|
this.data.partner.fields.foo.type = 'text';
|
|
testUtils.createAsyncView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<field name="foo" widget="ace"/>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
}).then(function (form) {
|
|
assert.ok('ace' in window, "the ace library should be loaded");
|
|
assert.ok(form.$('div.ace_content').length, "should have rendered something with ace editor");
|
|
form.destroy();
|
|
done();
|
|
});
|
|
});
|
|
|
|
QUnit.module('HandleWidget');
|
|
|
|
QUnit.test('handle widget in x2m', function (assert) {
|
|
assert.expect(6);
|
|
|
|
this.data.partner.records[0].p = [2, 4];
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<field name="p">' +
|
|
'<tree editable="bottom">' +
|
|
'<field name="sequence" widget="handle"/>' +
|
|
'<field name="display_name"/>' +
|
|
'</tree>' +
|
|
'</field>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
});
|
|
|
|
assert.strictEqual(form.$('td span.o_row_handle').text(), "",
|
|
"handle should not have any content");
|
|
|
|
assert.notOk(form.$('td span.o_row_handle').is(':visible'),
|
|
"handle should be invisible in readonly mode");
|
|
|
|
assert.strictEqual(form.$('span.o_row_handle').length, 2, "should have 2 handles");
|
|
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
|
|
assert.ok(form.$('td:first').hasClass('o_handle_cell'),
|
|
"column widget should be displayed in css class");
|
|
|
|
assert.ok(form.$('td span.o_row_handle').is(':visible'),
|
|
"handle should be visible in readonly mode");
|
|
|
|
form.$('td').eq(1).click();
|
|
assert.strictEqual(form.$('td:first span.o_row_handle').length, 1,
|
|
"content of the cell should have been replaced");
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('handle widget with falsy values', function (assert) {
|
|
assert.expect(1);
|
|
|
|
var list = createView({
|
|
View: ListView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<tree>' +
|
|
'<field name="sequence" widget="handle"/>' +
|
|
'<field name="display_name"/>' +
|
|
'</tree>',
|
|
});
|
|
|
|
assert.strictEqual(list.$('.o_row_handle:visible').length, this.data.partner.records.length,
|
|
'there should be a visible handle for each record');
|
|
list.destroy();
|
|
});
|
|
|
|
|
|
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);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners"><field name="date"/></form>',
|
|
res_id: 4,
|
|
});
|
|
var $span = form.$('span.o_field_widget');
|
|
assert.strictEqual($span.length, 1, "should have one span in the form view");
|
|
assert.strictEqual($span.text(), "", "and it should be empty");
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('date field value should not set on first click', function (assert) {
|
|
assert.expect(2);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners"><field name="date"/></form>',
|
|
res_id: 4,
|
|
});
|
|
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
|
|
// 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();
|
|
|
|
// 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();
|
|
});
|
|
|
|
QUnit.test('date field in form view (with positive time zone offset)', function (assert) {
|
|
assert.expect(8);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners"><field name="date"/></form>',
|
|
res_id: 1,
|
|
mockRPC: function (route, args) {
|
|
if (route === '/web/dataset/call_kw/partner/write') {
|
|
assert.strictEqual(args.args[1].date, '2017-02-22', 'the correct value should be saved');
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
translateParameters: { // Avoid issues due to localization formats
|
|
date_format: '%m/%d/%Y',
|
|
},
|
|
session: {
|
|
getTZOffset: function () {
|
|
return 120; // Should be ignored by date fields
|
|
},
|
|
},
|
|
});
|
|
|
|
assert.strictEqual(form.$('.o_field_date').text(), '02/03/2017',
|
|
'the date should be correctly displayed in readonly');
|
|
|
|
// switch to edit mode
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
assert.strictEqual(form.$('.o_datepicker_input').val(), '02/03/2017',
|
|
'the date should be correct in edit mode');
|
|
|
|
// 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
|
|
$('.bootstrap-datetimepicker-widget .picker-switch').first().click(); // Year selection
|
|
$('.bootstrap-datetimepicker-widget .year:contains(2017)').click();
|
|
$('.bootstrap-datetimepicker-widget .month').eq(1).click(); // February
|
|
$('.day:contains(22)').click(); // select the 22 February
|
|
assert.ok(!$('.bootstrap-datetimepicker-widget').length, 'datepicker should be closed');
|
|
assert.strictEqual(form.$('.o_datepicker_input').val(), '02/22/2017',
|
|
'the selected date should be displayed in the input');
|
|
|
|
// save
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
assert.strictEqual(form.$('.o_field_date').text(), '02/22/2017',
|
|
'the selected date should be displayed after saving');
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('date field in form view (with negative time zone offset)', function (assert) {
|
|
assert.expect(2);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners"><field name="date"/></form>',
|
|
res_id: 1,
|
|
translateParameters: { // Avoid issues due to localization formats
|
|
date_format: '%m/%d/%Y',
|
|
},
|
|
session: {
|
|
getTZOffset: function () {
|
|
return -120; // Should be ignored by date fields
|
|
},
|
|
},
|
|
});
|
|
|
|
assert.strictEqual(form.$('.o_field_date').text(), '02/03/2017',
|
|
'the date should be correctly displayed in readonly');
|
|
|
|
// switch to edit mode
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
assert.strictEqual(form.$('.o_datepicker_input').val(), '02/03/2017',
|
|
'the date should be correct in edit mode');
|
|
|
|
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 in editable list view', function (assert) {
|
|
assert.expect(8);
|
|
|
|
var list = createView({
|
|
View: ListView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<tree editable="bottom">' +
|
|
'<field name="date"/>' +
|
|
'</tree>',
|
|
translateParameters: { // Avoid issues due to localization formats
|
|
date_format: '%m/%d/%Y',
|
|
},
|
|
session: {
|
|
getTZOffset: function () {
|
|
return 0;
|
|
},
|
|
},
|
|
});
|
|
|
|
var $cell = list.$('tr.o_data_row td:not(.o_list_record_selector)').first();
|
|
assert.strictEqual($cell.text(), '02/03/2017',
|
|
'the date should be displayed correctly in readonly');
|
|
$cell.click();
|
|
|
|
assert.strictEqual(list.$('input.o_datepicker_input').length, 1,
|
|
"the view should have a date input for editable mode");
|
|
|
|
assert.strictEqual(list.$('input.o_datepicker_input').get(0), document.activeElement,
|
|
"date input should have the focus");
|
|
|
|
assert.strictEqual(list.$('input.o_datepicker_input').val(), '02/03/2017',
|
|
'the date should be correct in edit mode');
|
|
|
|
// 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
|
|
$('.bootstrap-datetimepicker-widget .year:contains(2017)').click();
|
|
$('.bootstrap-datetimepicker-widget .month').eq(1).click(); // February
|
|
$('.day:contains(22)').click(); // select the 22 February
|
|
assert.ok(!$('.bootstrap-datetimepicker-widget').length, 'datepicker should be closed');
|
|
assert.strictEqual(list.$('.o_datepicker_input').val(), '02/22/2017',
|
|
'the selected date should be displayed in the input');
|
|
|
|
// save
|
|
list.$buttons.find('.o_list_button_save').click();
|
|
assert.strictEqual(list.$('tr.o_data_row td:not(.o_list_record_selector)').text(), '02/22/2017',
|
|
'the selected date should be displayed after saving');
|
|
|
|
list.destroy();
|
|
});
|
|
|
|
QUnit.test('date field remove value', function (assert) {
|
|
assert.expect(4);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners"><field name="date"/></form>',
|
|
res_id: 1,
|
|
mockRPC: function (route, args) {
|
|
if (route === '/web/dataset/call_kw/partner/write') {
|
|
assert.strictEqual(args.args[1].date, false, 'the correct value should be saved');
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
translateParameters: { // Avoid issues due to localization formats
|
|
date_format: '%m/%d/%Y',
|
|
},
|
|
});
|
|
|
|
// switch to edit mode
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
assert.strictEqual(form.$('.o_datepicker_input').val(), '02/03/2017',
|
|
'the date should be correct in edit mode');
|
|
|
|
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();
|
|
});
|
|
|
|
QUnit.test('do not trigger a field_changed for datetime field with date widget', function (assert) {
|
|
assert.expect(3);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners"><field name="datetime" widget="date"/></form>',
|
|
translateParameters: { // Avoid issues due to localization formats
|
|
date_format: '%m/%d/%Y',
|
|
time_format: '%H:%M:%S',
|
|
},
|
|
res_id: 1,
|
|
viewOptions: {
|
|
mode: 'edit',
|
|
},
|
|
mockRPC: function (route, args) {
|
|
assert.step(args.method);
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
|
|
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').trigger('focusout');
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
|
|
assert.verifySteps(['read']); // should not have save as nothing changed
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.module('FieldDatetime');
|
|
|
|
QUnit.test('datetime field in form view', function (assert) {
|
|
assert.expect(6);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
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:%S',
|
|
},
|
|
session: {
|
|
getTZOffset: function () {
|
|
return 120;
|
|
},
|
|
},
|
|
});
|
|
|
|
var expectedDateString = "02/08/2017 12:00:00"; // 10:00:00 without timezone
|
|
assert.strictEqual(form.$('.o_field_date').text(), expectedDateString,
|
|
'the datetime should be correctly displayed in readonly');
|
|
|
|
// switch to edit mode
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
assert.strictEqual(form.$('.o_datepicker_input').val(), expectedDateString,
|
|
'the datetime should be correct in edit mode');
|
|
// select 22 February at 8:23:33
|
|
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
|
|
$('.bootstrap-datetimepicker-widget .year:contains(2017)').click();
|
|
$('.bootstrap-datetimepicker-widget .month').eq(3).click(); // April
|
|
$('.bootstrap-datetimepicker-widget .day:contains(22)').click();
|
|
$('.bootstrap-datetimepicker-widget .fa-clock-o').click();
|
|
$('.bootstrap-datetimepicker-widget .timepicker-hour').click();
|
|
$('.bootstrap-datetimepicker-widget .hour:contains(08)').click();
|
|
$('.bootstrap-datetimepicker-widget .timepicker-minute').click();
|
|
$('.bootstrap-datetimepicker-widget .minute:contains(25)').click();
|
|
$('.bootstrap-datetimepicker-widget .timepicker-second').click();
|
|
$('.bootstrap-datetimepicker-widget .second:contains(35)').click();
|
|
$('.bootstrap-datetimepicker-widget .fa-times').click(); // close
|
|
assert.ok(!$('.bootstrap-datetimepicker-widget').length, 'datepicker should be closed');
|
|
|
|
var newExpectedDateString = "04/22/2017 08:25:35";
|
|
assert.strictEqual(form.$('.o_datepicker_input').val(), newExpectedDateString,
|
|
'the selected date should be displayed in the input');
|
|
|
|
// save
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
assert.strictEqual(form.$('.o_field_date').text(), newExpectedDateString,
|
|
'the selected date should be displayed after saving');
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
|
|
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;
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners"><field name="datetime"/></form>',
|
|
translateParameters: { // Avoid issues due to localization formats
|
|
date_format: '%m/%d/%Y',
|
|
time_format: '%H:%M',
|
|
},
|
|
});
|
|
|
|
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');
|
|
|
|
form.$buttons.find('.o_form_button_cancel').click();
|
|
|
|
assert.strictEqual($('.modal').length, 0,
|
|
"there should not be a Warning dialog");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('datetime field in editable list view', function (assert) {
|
|
assert.expect(8);
|
|
|
|
var list = createView({
|
|
View: ListView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<tree editable="bottom">' +
|
|
'<field name="datetime"/>' +
|
|
'</tree>',
|
|
translateParameters: { // Avoid issues due to localization formats
|
|
date_format: '%m/%d/%Y',
|
|
time_format: '%H:%M:%S',
|
|
},
|
|
session: {
|
|
getTZOffset: function () {
|
|
return 120;
|
|
},
|
|
},
|
|
});
|
|
|
|
var expectedDateString = "02/08/2017 12:00:00"; // 10:00:00 without timezone
|
|
var $cell = list.$('tr.o_data_row td:not(.o_list_record_selector)').first();
|
|
assert.strictEqual($cell.text(), expectedDateString,
|
|
'the datetime should be correctly displayed in readonly');
|
|
|
|
// switch to edit mode
|
|
$cell.click();
|
|
assert.strictEqual(list.$('input.o_datepicker_input').length, 1,
|
|
"the view should have a date input for editable mode");
|
|
|
|
assert.strictEqual(list.$('input.o_datepicker_input').get(0), document.activeElement,
|
|
"date input should have the focus");
|
|
|
|
assert.strictEqual(list.$('input.o_datepicker_input').val(), expectedDateString,
|
|
'the date should be correct in edit mode');
|
|
|
|
// select 22 February at 8:23:33
|
|
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
|
|
$('.bootstrap-datetimepicker-widget .year:contains(2017)').click();
|
|
$('.bootstrap-datetimepicker-widget .month').eq(3).click(); // April
|
|
$('.bootstrap-datetimepicker-widget .day:contains(22)').click();
|
|
$('.bootstrap-datetimepicker-widget .fa-clock-o').click();
|
|
$('.bootstrap-datetimepicker-widget .timepicker-hour').click();
|
|
$('.bootstrap-datetimepicker-widget .hour:contains(08)').click();
|
|
$('.bootstrap-datetimepicker-widget .timepicker-minute').click();
|
|
$('.bootstrap-datetimepicker-widget .minute:contains(25)').click();
|
|
$('.bootstrap-datetimepicker-widget .timepicker-second').click();
|
|
$('.bootstrap-datetimepicker-widget .second:contains(35)').click();
|
|
$('.bootstrap-datetimepicker-widget .fa-times').click(); // close
|
|
assert.ok(!$('.bootstrap-datetimepicker-widget').length, 'datepicker should be closed');
|
|
|
|
var newExpectedDateString = "04/22/2017 08:25:35";
|
|
assert.strictEqual(list.$('.o_datepicker_input').val(), newExpectedDateString,
|
|
'the selected datetime should be displayed in the input');
|
|
|
|
// save
|
|
list.$buttons.find('.o_list_button_save').click();
|
|
assert.strictEqual(list.$('tr.o_data_row td:not(.o_list_record_selector)').text(), newExpectedDateString,
|
|
'the selected datetime should be displayed after saving');
|
|
|
|
list.destroy();
|
|
});
|
|
|
|
QUnit.test('datetime field remove value', function (assert) {
|
|
assert.expect(4);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners"><field name="datetime"/></form>',
|
|
res_id: 1,
|
|
mockRPC: function (route, args) {
|
|
if (route === '/web/dataset/call_kw/partner/write') {
|
|
assert.strictEqual(args.args[1].datetime, false, 'the correct value should be saved');
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
translateParameters: { // Avoid issues due to localization formats
|
|
date_format: '%m/%d/%Y',
|
|
time_format: '%H:%M:%S',
|
|
},
|
|
session: {
|
|
getTZOffset: function () {
|
|
return 120;
|
|
},
|
|
},
|
|
});
|
|
|
|
// switch to edit mode
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
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').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();
|
|
});
|
|
|
|
QUnit.test('datetime field with date/datetime widget (with day change)', function (assert) {
|
|
assert.expect(2);
|
|
|
|
this.data.partner.records[0].p = [2];
|
|
this.data.partner.records[1].datetime = "2017-02-08 02:00:00"; // UTC
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners">' +
|
|
'<field name="p">' +
|
|
'<tree>' +
|
|
'<field name="datetime"/>' +
|
|
'</tree>' +
|
|
'<form>' +
|
|
'<field name="datetime" widget="date"/>' +
|
|
'</form>' +
|
|
'</field>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
translateParameters: { // Avoid issues due to localization formats
|
|
date_format: '%m/%d/%Y',
|
|
time_format: '%H:%M:%S',
|
|
},
|
|
session: {
|
|
getTZOffset: function () {
|
|
return -240;
|
|
},
|
|
},
|
|
});
|
|
|
|
var expectedDateString = "02/07/2017 22:00:00"; // local time zone
|
|
assert.strictEqual(form.$('.o_field_widget[name=p] .o_data_cell').text(), expectedDateString,
|
|
'the datetime (datetime widget) should be correctly displayed in tree view');
|
|
|
|
// switch to form view
|
|
form.$('.o_field_widget[name=p] .o_data_row').click();
|
|
assert.strictEqual($('.modal .o_field_date[name=datetime]').text(), '02/07/2017',
|
|
'the datetime (date widget) should be correctly displayed in form view');
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('datetime field with date/datetime widget (without day change)', function (assert) {
|
|
assert.expect(2);
|
|
|
|
this.data.partner.records[0].p = [2];
|
|
this.data.partner.records[1].datetime = "2017-02-08 10:00:00"; // without timezone
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners">' +
|
|
'<field name="p">' +
|
|
'<tree>' +
|
|
'<field name="datetime"/>' +
|
|
'</tree>' +
|
|
'<form>' +
|
|
'<field name="datetime" widget="date"/>' +
|
|
'</form>' +
|
|
'</field>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
translateParameters: { // Avoid issues due to localization formats
|
|
date_format: '%m/%d/%Y',
|
|
time_format: '%H:%M:%S',
|
|
},
|
|
session: {
|
|
getTZOffset: function () {
|
|
return -240;
|
|
},
|
|
},
|
|
});
|
|
|
|
var expectedDateString = "02/08/2017 06:00:00"; // with timezone
|
|
assert.strictEqual(form.$('.o_field_widget[name=p] .o_data_cell').text(), expectedDateString,
|
|
'the datetime (datetime widget) should be correctly displayed in tree view');
|
|
|
|
// switch to form view
|
|
form.$('.o_field_widget[name=p] .o_data_row').click();
|
|
assert.strictEqual($('.modal .o_field_date[name=datetime]').text(), '02/08/2017',
|
|
'the datetime (date widget) should be correctly displayed in form view');
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('datepicker option: daysOfWeekDisabled', function (assert) {
|
|
assert.expect(2);
|
|
|
|
this.data.partner.fields.datetime.default = "2017-08-02 12:00:05";
|
|
this.data.partner.fields.datetime.required = true;
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners">' +
|
|
'<field name="datetime" ' +
|
|
'options=\'{"datepicker": {"daysOfWeekDisabled": [0, 6]}}\'/>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
});
|
|
|
|
form.$buttons.find('.o_form_button_create').click();
|
|
assert.ok($('.day:last-child(),.day:nth-child(2)').hasClass('disabled'),
|
|
'first and last days must be disabled');
|
|
assert.notOk($('.day:not(:last-child()):not(:nth-child(2))').hasClass('disabled'),
|
|
'other days must stay clickable');
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.module('FieldMonetary');
|
|
|
|
QUnit.test('monetary field in form view', function (assert) {
|
|
assert.expect(5);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="qux" widget="monetary"/>' +
|
|
'<field name="currency_id" invisible="1"/>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 5,
|
|
session: {
|
|
currencies: _.indexBy(this.data.currency.records, 'id'),
|
|
},
|
|
});
|
|
|
|
// Non-breaking space between the currency and the amount
|
|
assert.strictEqual(form.$('.o_field_widget').first().text(), '$\u00a09.10',
|
|
'The value should be displayed properly.');
|
|
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
assert.strictEqual(form.$('input').val(), '9.10',
|
|
'The input should be rendered without the currency symbol.');
|
|
assert.strictEqual(form.$('input').parent().children().first().text(), '$',
|
|
'The input should be preceded by a span containing the currency symbol.');
|
|
|
|
form.$('input').val('108.2458938598598').trigger('input');
|
|
assert.strictEqual(form.$('input').val(), '108.2458938598598',
|
|
'The value should not be formated yet.');
|
|
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
// Non-breaking space between the currency and the amount
|
|
assert.strictEqual(form.$('.o_field_widget').first().text(), '$\u00a0108.25',
|
|
'The new value should be rounded properly.');
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('monetary field with currency symbol after', function (assert) {
|
|
assert.expect(5);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="qux" widget="monetary"/>' +
|
|
'<field name="currency_id" invisible="1"/>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
session: {
|
|
currencies: _.indexBy(this.data.currency.records, 'id'),
|
|
},
|
|
});
|
|
|
|
// Non-breaking space between the currency and the amount
|
|
assert.strictEqual(form.$('.o_field_widget').first().text(), '0.00\u00a0€',
|
|
'The value should be displayed properly.');
|
|
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
assert.strictEqual(form.$('input').first().val(), '0.00',
|
|
'The input should be rendered without the currency symbol.');
|
|
assert.strictEqual(form.$('input').parent().children().eq(1).text(), '€',
|
|
'The input should be followed by a span containing the currency symbol.');
|
|
|
|
form.$('input').first().val('108.2458938598598').trigger('input');
|
|
assert.strictEqual(form.$('input').first().val(), '108.2458938598598',
|
|
'The value should not be formated yet.');
|
|
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
// Non-breaking space between the currency and the amount
|
|
assert.strictEqual(form.$('.o_field_widget').first().text(), '108.25\u00a0€',
|
|
'The new value should be rounded properly.');
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('monetary field with currency digits != 2', function (assert) {
|
|
assert.expect(5);
|
|
|
|
this.data.partner.records = [{
|
|
id: 1,
|
|
bar: false,
|
|
foo: "pouet",
|
|
int_field: 68,
|
|
qux: 99.1234,
|
|
currency_id: 1,
|
|
}];
|
|
this.data.currency.records = [{
|
|
id: 1,
|
|
display_name: "VEF",
|
|
symbol: "Bs.F",
|
|
position: "after",
|
|
digits: [16, 4],
|
|
}];
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="qux" widget="monetary"/>' +
|
|
'<field name="currency_id" invisible="1"/>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
session: {
|
|
currencies: _.indexBy(this.data.currency.records, 'id'),
|
|
},
|
|
});
|
|
|
|
// Non-breaking space between the currency and the amount
|
|
assert.strictEqual(form.$('.o_field_widget').first().text(), '99.1234\u00a0Bs.F',
|
|
'The value should be displayed properly.');
|
|
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
assert.strictEqual(form.$('input').first().val(), '99.1234',
|
|
'The input should be rendered without the currency symbol.');
|
|
assert.strictEqual(form.$('input').parent().children().eq(1).text(), 'Bs.F',
|
|
'The input should be followed by a span containing the currency symbol.');
|
|
|
|
form.$('input').first().val('99.111111111').trigger('input');
|
|
assert.strictEqual(form.$('input').first().val(), '99.111111111',
|
|
'The value should not be formated yet.');
|
|
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
// Non-breaking space between the currency and the amount
|
|
assert.strictEqual(form.$('.o_field_widget').first().text(), '99.1111\u00a0Bs.F',
|
|
'The new value should be rounded properly.');
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('monetary field in editable list view', function (assert) {
|
|
assert.expect(9);
|
|
|
|
var list = createView({
|
|
View: ListView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<tree editable="bottom">' +
|
|
'<field name="qux" widget="monetary"/>' +
|
|
'<field name="currency_id" invisible="1"/>' +
|
|
'</tree>',
|
|
session: {
|
|
currencies: _.indexBy(this.data.currency.records, 'id'),
|
|
},
|
|
});
|
|
|
|
var dollarValues = list.$('td').filter(function () {return _.str.include($(this).text(), '$');});
|
|
assert.strictEqual(dollarValues.length, 1,
|
|
'Only one line has dollar as a currency.');
|
|
|
|
var euroValues = list.$('td').filter(function () {return _.str.include($(this).text(), '€');});
|
|
assert.strictEqual(euroValues.length, 1,
|
|
'One one line has euro as a currency.');
|
|
|
|
var zeroValues = list.$('td.o_data_cell').filter(function () {return $(this).text() === '';});
|
|
assert.strictEqual(zeroValues.length, 1,
|
|
'Unset float values should be rendered as empty strings.');
|
|
|
|
// switch to edit mode
|
|
var $cell = list.$('tr.o_data_row td:not(.o_list_record_selector):contains($)');
|
|
$cell.click();
|
|
|
|
assert.strictEqual($cell.children().length, 1,
|
|
'The cell td should only contain the special div of monetary widget.');
|
|
assert.strictEqual(list.$('[name="qux"] input').length, 1,
|
|
'The view should have 1 input for editable monetary float.');
|
|
assert.strictEqual(list.$('[name="qux"] input').val(), '9.10',
|
|
'The input should be rendered without the currency symbol.');
|
|
assert.strictEqual(list.$('[name="qux"] input').parent().children().first().text(), '$',
|
|
'The input should be preceded by a span containing the currency symbol.');
|
|
|
|
list.$('[name="qux"] input').val('108.2458938598598').trigger('input');
|
|
assert.strictEqual(list.$('[name="qux"] input').val(), '108.2458938598598',
|
|
'The typed value should be correctly displayed.');
|
|
|
|
list.$buttons.find('.o_list_button_save').click();
|
|
assert.strictEqual(list.$('tr.o_data_row td:not(.o_list_record_selector):contains($)').text(), '$\u00a0108.25',
|
|
'The new value should be rounded properly.');
|
|
|
|
list.destroy();
|
|
});
|
|
|
|
QUnit.test('monetary field with real monetary field in model', function (assert) {
|
|
assert.expect(7);
|
|
|
|
this.data.partner.fields.qux.type = "monetary";
|
|
this.data.partner.fields.quux = {
|
|
string: "Quux", type: "monetary", digits: [16,1], searchable: true, readonly: true,
|
|
};
|
|
|
|
(_.find(this.data.partner.records, function (record) { return record.id === 5 })).quux = 4.2;
|
|
|
|
this.data.partner.onchanges = {
|
|
bar: function (obj) {
|
|
obj.qux = obj.bar ? 100 : obj.qux;
|
|
},
|
|
};
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="qux"/>' +
|
|
'<field name="quux"/>' +
|
|
'<field name="currency_id"/>' +
|
|
'<field name="bar"/>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 5,
|
|
session: {
|
|
currencies: _.indexBy(this.data.currency.records, 'id'),
|
|
},
|
|
});
|
|
|
|
assert.strictEqual(form.$('.o_field_monetary').first().html(), "$ 9.10",
|
|
"readonly value should contain the currency");
|
|
assert.strictEqual(form.$('.o_field_monetary').first().next().html(), "$ 4.20",
|
|
"readonly value should contain the currency");
|
|
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
|
|
assert.strictEqual(form.$('.o_field_monetary > input').val(), "9.10",
|
|
"input value in edition should only contain the value, without the currency");
|
|
|
|
form.$('input[type="checkbox"]').click(); // Change the field on which the monetary depends
|
|
assert.strictEqual(form.$('.o_field_monetary > input').length, 1,
|
|
"After the onchange, the monetary <input/> should not have been duplicated");
|
|
assert.strictEqual(form.$('.o_field_monetary[name=quux]').length, 1,
|
|
"After the onchange, the monetary readonly field should not have been duplicated");
|
|
|
|
var $dropdown = form.$('.o_field_many2one input').autocomplete('widget');
|
|
form.$('.o_field_many2one input').click();
|
|
$dropdown.find('li:not(.o_m2o_dropdown_option):last').mouseenter().click();
|
|
assert.strictEqual(form.$('.o_field_monetary > span').html(), "€",
|
|
"After currency change, the monetary field currency should have been updated");
|
|
assert.strictEqual(form.$('.o_field_monetary').first().next().html(), "4.20 €",
|
|
"readonly value should contain the updated currency");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('monetary field with monetary field given in options', function (assert) {
|
|
assert.expect(1);
|
|
|
|
this.data.partner.fields.qux.type = "monetary";
|
|
this.data.partner.fields.company_currency_id = {
|
|
string: "Company Currency", type: "many2one", relation: "currency",
|
|
};
|
|
this.data.partner.records[4].company_currency_id = 2;
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="qux" options="{\'currency_field\': \'company_currency_id\'}"/>' +
|
|
'<field name="company_currency_id"/>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 5,
|
|
session: {
|
|
currencies: _.indexBy(this.data.currency.records, 'id'),
|
|
},
|
|
});
|
|
|
|
assert.strictEqual(form.$('.o_field_monetary').html(), "9.10 €",
|
|
"field monetary should be formatted with correct currency");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('should keep the focus when being edited in x2many lists', function (assert) {
|
|
assert.expect(6);
|
|
|
|
this.data.partner.fields.currency_id.default = 1;
|
|
this.data.partner.fields.m2m = {
|
|
string: "m2m", type: "many2many", relation: 'partner', default: [[6, false, [2]]],
|
|
};
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="p"/>' +
|
|
'<field name="m2m"/>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
archs: {
|
|
'partner,false,list': '<tree editable="bottom">' +
|
|
'<field name="qux" widget="monetary"/>' +
|
|
'<field name="currency_id" invisible="1"/>' +
|
|
'</tree>',
|
|
},
|
|
session: {
|
|
currencies: _.indexBy(this.data.currency.records, 'id'),
|
|
},
|
|
});
|
|
|
|
// test the monetary field inside the one2many
|
|
var $o2m = form.$('.o_field_widget[name=p]');
|
|
$o2m.find('.o_field_x2many_list_row_add a').click();
|
|
$o2m.find('.o_field_widget input').val("22").trigger('input');
|
|
|
|
assert.strictEqual($o2m.find('.o_field_widget input').get(0), document.activeElement,
|
|
"the focus should still be on the input");
|
|
assert.strictEqual($o2m.find('.o_field_widget input').val(), "22",
|
|
"the value should not have been formatted yet");
|
|
|
|
form.$el.click(); // focusout the input
|
|
|
|
assert.strictEqual($o2m.find('.o_field_widget[name=qux]').html(), "$ 22.00",
|
|
"the value should have been formatted after losing the focus");
|
|
|
|
// test the monetary field inside the many2many
|
|
var $m2m = form.$('.o_field_widget[name=m2m]');
|
|
$m2m.find('.o_data_row td:first').click();
|
|
$m2m.find('.o_field_widget input').val("22").trigger('input');
|
|
|
|
assert.strictEqual($m2m.find('.o_field_widget input').get(0), document.activeElement,
|
|
"the focus should still be on the input");
|
|
assert.strictEqual($m2m.find('.o_field_widget input').val(), "22",
|
|
"the value should not have been formatted yet");
|
|
|
|
form.$el.click(); // focusout the input
|
|
|
|
assert.strictEqual($m2m.find('.o_field_widget[name=qux]').html(), "22.00 €",
|
|
"the value should have been formatted after losing the focus");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('monetary field with currency set by an onchange', function (assert) {
|
|
// this test ensures that the monetary field can be re-rendered with and
|
|
// without currency (which can happen as the currency can be set by an
|
|
// onchange)
|
|
assert.expect(8);
|
|
|
|
this.data.partner.onchanges = {
|
|
int_field: function (obj) {
|
|
obj.currency_id = obj.int_field ? 2 : null;
|
|
},
|
|
};
|
|
|
|
var list = createView({
|
|
View: ListView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<tree editable="top">' +
|
|
'<field name="int_field"/>' +
|
|
'<field name="qux" widget="monetary"/>' +
|
|
'<field name="currency_id" invisible="1"/>' +
|
|
'</tree>',
|
|
session: {
|
|
currencies: _.indexBy(this.data.currency.records, 'id'),
|
|
},
|
|
});
|
|
|
|
list.$buttons.find('.o_list_button_add').click();
|
|
assert.strictEqual(list.$('div.o_field_widget[name=qux] input').length, 1,
|
|
"monetary field should have been rendered correctly (without currency)");
|
|
assert.strictEqual(list.$('.o_field_widget[name=qux] span').length, 0,
|
|
"monetary field should have been rendered correctly (without currency)");
|
|
|
|
// set a value for int_field -> should set the currency and re-render qux
|
|
list.$('.o_field_widget[name=int_field]').click().val('7').trigger('input');
|
|
assert.strictEqual(list.$('div.o_field_widget[name=qux] input').length, 1,
|
|
"monetary field should have been re-rendered correctly (with currency)");
|
|
assert.strictEqual(list.$('.o_field_widget[name=qux] span:contains(€)').length, 1,
|
|
"monetary field should have been re-rendered correctly (with currency)");
|
|
var $quxInput = list.$('.o_field_widget[name=qux] input');
|
|
$quxInput.click(); // check that the field is focusable
|
|
assert.strictEqual(document.activeElement, $quxInput[0],
|
|
"focus should be on the qux field's input");
|
|
|
|
// unset the value of int_field -> should unset the currency and re-render qux
|
|
list.$('.o_field_widget[name=int_field]').click().val('0').trigger('input');
|
|
$quxInput = list.$('div.o_field_widget[name=qux] input');
|
|
assert.strictEqual($quxInput.length, 1,
|
|
"monetary field should have been re-rendered correctly (without currency)");
|
|
assert.strictEqual(list.$('.o_field_widget[name=qux] span').length, 0,
|
|
"monetary field should have been re-rendered correctly (without currency)");
|
|
$quxInput.click(); // check that the field is still focusable
|
|
assert.strictEqual(document.activeElement, $quxInput[0],
|
|
"focus should be on the qux field's input");
|
|
|
|
list.destroy();
|
|
});
|
|
|
|
QUnit.module('FieldInteger');
|
|
|
|
QUnit.test('integer field when unset', 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,
|
|
});
|
|
|
|
assert.notOk(form.$('.o_field_widget').hasClass('o_field_empty'),
|
|
'Non-set integer field should be recognized as 0.');
|
|
assert.strictEqual(form.$('.o_field_widget').text(), "0",
|
|
'Non-set integer field should be recognized as 0.');
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('integer field in form view', function (assert) {
|
|
assert.expect(4);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners"><field name="int_field"/></form>',
|
|
res_id: 2,
|
|
});
|
|
|
|
assert.ok(!form.$('.o_field_widget').hasClass('o_field_empty'),
|
|
'Integer field should be considered set for value 0.');
|
|
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
assert.strictEqual(form.$('input').val(), '0',
|
|
'The value should be rendered correctly in edit mode.');
|
|
|
|
form.$('input').val('-18').trigger('input');
|
|
assert.strictEqual(form.$('input').val(), '-18',
|
|
'The value should be correctly displayed in the input.');
|
|
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
assert.strictEqual(form.$('.o_field_widget').text(), '-18',
|
|
'The new value should be saved and displayed properly.');
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('integer field in form view with virtual id', function (assert) {
|
|
assert.expect(1);
|
|
var params = {
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners"><field name="id"/></form>',
|
|
};
|
|
|
|
params.res_id = this.data.partner.records[1].id = "2-20170808020000";
|
|
var form = createView(params);
|
|
assert.strictEqual(form.$('.o_field_widget').text(), "2-20170808020000",
|
|
"Should display virtual id");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('integer field in editable list view', function (assert) {
|
|
assert.expect(4);
|
|
|
|
var list = createView({
|
|
View: ListView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<tree editable="bottom">' +
|
|
'<field name="int_field"/>' +
|
|
'</tree>',
|
|
});
|
|
|
|
var zeroValues = list.$('td').filter(function () {return $(this).text() === '0';});
|
|
assert.strictEqual(zeroValues.length, 1,
|
|
'Unset integer values should not be rendered as zeros.');
|
|
|
|
// switch to edit mode
|
|
var $cell = list.$('tr.o_data_row td:not(.o_list_record_selector)').first();
|
|
$cell.click();
|
|
|
|
assert.strictEqual(list.$('input[name="int_field"]').length, 1,
|
|
'The view should have 1 input for editable integer.');
|
|
|
|
list.$('input[name="int_field"]').val('-28').trigger('input');
|
|
assert.strictEqual(list.$('input[name="int_field"]').val(), '-28',
|
|
'The value should be displayed properly in the input.');
|
|
|
|
list.$buttons.find('.o_list_button_save').click();
|
|
assert.strictEqual(list.$('td:not(.o_list_record_selector)').first().text(), '-28',
|
|
'The new value should be saved and displayed properly.');
|
|
|
|
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');
|
|
|
|
QUnit.test('float_time field in form view', function (assert) {
|
|
assert.expect(5);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="qux" widget="float_time"/>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
mockRPC: function (route, args) {
|
|
if (route === '/web/dataset/call_kw/partner/write') {
|
|
// 48 / 60 = 0.8
|
|
assert.strictEqual(args.args[1].qux, -11.8, 'the correct float value should be saved');
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
res_id: 5,
|
|
});
|
|
|
|
// 9 + 0.1 * 60 = 9.06
|
|
assert.strictEqual(form.$('.o_field_widget').first().text(), '09:06',
|
|
'The formatted time value should be displayed properly.');
|
|
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
assert.strictEqual(form.$('input').val(), '09:06',
|
|
'The value should be rendered correctly in the input.');
|
|
|
|
form.$('input').val('-11:48').trigger('input');
|
|
assert.strictEqual(form.$('input').val(), '-11:48',
|
|
'The new value should be displayed properly in the input.');
|
|
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
assert.strictEqual(form.$('.o_field_widget').first().text(), '-11:48',
|
|
'The new value should be saved and displayed properly.');
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
|
|
QUnit.module('FieldFloatFactor');
|
|
|
|
QUnit.test('float_factor field in form view', function (assert) {
|
|
assert.expect(4);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<field name="qux" widget="float_factor" options="{\'factor\': 0.5}" digits="[16,2]"/>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
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.');
|
|
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
assert.strictEqual(form.$('input').val(), '4.55',
|
|
'The value should be rendered correctly in the input.');
|
|
|
|
form.$('input').val('2.3').trigger('input');
|
|
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
assert.strictEqual(form.$('.o_field_widget').first().text(), '2.30',
|
|
'The new value should be saved and displayed properly.');
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.module('FieldFloatToggle');
|
|
|
|
QUnit.test('float_toggle field in form view', function (assert) {
|
|
assert.expect(5);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
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.');
|
|
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
|
|
assert.strictEqual(form.$('button.o_field_float_toggle').text(), '0.056',
|
|
'The value should be rendered correctly on the button.');
|
|
|
|
form.$('button.o_field_float_toggle').click(); // clicking will make the next value 1, since 0 was the closest of 0.056
|
|
|
|
assert.strictEqual(form.$('button.o_field_float_toggle').text(), '1.000',
|
|
'The value should be rendered correctly on the button.');
|
|
|
|
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);
|
|
|
|
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,
|
|
config: {
|
|
device: {
|
|
size_class: config.device.SIZES.LG,
|
|
},
|
|
},
|
|
});
|
|
|
|
var $phone = form.$('a.o_field_widget.o_form_uri');
|
|
assert.strictEqual($phone.length, 1,
|
|
"should have rendered the phone number as a link with correct classes");
|
|
assert.strictEqual($phone.text(), 'yop',
|
|
"value should be displayed properly");
|
|
|
|
// 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");
|
|
|
|
// change value in edit mode
|
|
form.$('input[type="text"].o_field_widget').val('new').trigger('input');
|
|
|
|
// save
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
assert.strictEqual(form.$('a.o_field_widget.o_form_uri').text(), 'new',
|
|
"new value should be displayed properly");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('phone field in editable list view on normal screens', function (assert) {
|
|
assert.expect(8);
|
|
|
|
var list = createView({
|
|
View: ListView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<tree editable="bottom"><field name="foo" widget="phone"/></tree>',
|
|
config: {
|
|
device: {
|
|
size_class: config.device.SIZES.LG,
|
|
},
|
|
},
|
|
});
|
|
|
|
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");
|
|
|
|
assert.strictEqual(list.$('a.o_field_widget.o_form_uri').length, 5,
|
|
"should have the correct classnames");
|
|
|
|
// 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');
|
|
|
|
// 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");
|
|
assert.strictEqual(list.$('a.o_field_widget.o_form_uri').length, 5,
|
|
"should still have links with correct classes");
|
|
|
|
list.destroy();
|
|
});
|
|
|
|
QUnit.test('use TAB to navigate to a phone field', function (assert) {
|
|
assert.expect(2);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:'<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<group>' +
|
|
'<field name="display_name"/>' +
|
|
'<field name="foo" widget="phone"/>' +
|
|
'</group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
});
|
|
|
|
form.$('input[name=display_name]').click();
|
|
assert.strictEqual(form.$('input[name="display_name"]')[0], document.activeElement,
|
|
"display_name should be focused");
|
|
form.$('input[name="display_name"]').trigger($.Event('keydown', {which: $.ui.keyCode.TAB}));
|
|
assert.strictEqual(form.$('input[name="foo"]')[0], document.activeElement,
|
|
"foo should be focused");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.module('PriorityWidget');
|
|
|
|
QUnit.test('priority widget when not set', function (assert) {
|
|
assert.expect(4);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<group>' +
|
|
'<field name="selection" widget="priority"/>' +
|
|
'</group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 2,
|
|
});
|
|
|
|
assert.strictEqual(form.$('.o_field_widget.o_priority:not(.o_field_empty)').length, 1,
|
|
"widget should be considered set, even though there is no value for this field");
|
|
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star').length, 2,
|
|
"should have two stars for representing each possible value: no star, one star and two stars");
|
|
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star.fa-star').length, 0,
|
|
"should have no full star since there is no value");
|
|
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star.fa-star-o').length, 2,
|
|
"should have two empty stars since there is no value");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('priority widget in form view', function (assert) {
|
|
assert.expect(22);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<group>' +
|
|
'<field name="selection" widget="priority"/>' +
|
|
'</group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
});
|
|
|
|
assert.strictEqual(form.$('.o_field_widget.o_priority:not(.o_field_empty)').length, 1,
|
|
"widget should be considered set");
|
|
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star').length, 2,
|
|
"should have two stars for representing each possible value: no star, one star and two stars");
|
|
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star.fa-star').length, 1,
|
|
"should have one full star since the value is the second value");
|
|
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star.fa-star-o').length, 1,
|
|
"should have one empty star since the value is the second value");
|
|
|
|
// hover last star
|
|
form.$('.o_field_widget.o_priority a.o_priority_star.fa-star-o').last().trigger('mouseover');
|
|
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star').length, 2,
|
|
"should have two stars for representing each possible value: no star, one star and two stars");
|
|
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star.fa-star').length, 2,
|
|
"should temporary have two full stars since we are hovering the third value");
|
|
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star.fa-star-o').length, 0,
|
|
"should temporary have no empty star since we are hovering the third value");
|
|
|
|
// Here we should test with mouseout, but currently the effect associated with it
|
|
// occurs in a setTimeout after 200ms so it's not trivial to test it here.
|
|
|
|
// switch to edit mode and check the result
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star').length, 2,
|
|
"should still have two stars");
|
|
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star.fa-star').length, 1,
|
|
"should still have one full star since the value is the second value");
|
|
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star.fa-star-o').length, 1,
|
|
"should still have one empty star since the value is the second value");
|
|
|
|
// save
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star').length, 2,
|
|
"should still have two stars");
|
|
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star.fa-star').length, 1,
|
|
"should still have one full star since the value is the second value");
|
|
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star.fa-star-o').length, 1,
|
|
"should still have one empty star since the value is the second value");
|
|
|
|
// switch to edit mode to check that the new value was properly written
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star').length, 2,
|
|
"should still have two stars");
|
|
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star.fa-star').length, 1,
|
|
"should still have one full star since the value is the second value");
|
|
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star.fa-star-o').length, 1,
|
|
"should still have one empty star since the value is the second value");
|
|
|
|
// click on the second star in edit mode
|
|
form.$('.o_field_widget.o_priority a.o_priority_star.fa-star-o').last().click();
|
|
|
|
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star').length, 2,
|
|
"should still have two stars");
|
|
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star.fa-star').length, 2,
|
|
"should now have two full stars since the value is the third value");
|
|
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star.fa-star-o').length, 0,
|
|
"should now have no empty star since the value is the third value");
|
|
|
|
// save
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star').length, 2,
|
|
"should still have two stars");
|
|
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star.fa-star').length, 2,
|
|
"should now have two full stars since the value is the third value");
|
|
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star.fa-star-o').length, 0,
|
|
"should now have no empty star since the value is the third value");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('priority widget in editable list view', function (assert) {
|
|
assert.expect(25);
|
|
|
|
var list = createView({
|
|
View: ListView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<tree editable="bottom"><field name="selection" widget="priority"/></tree>',
|
|
});
|
|
|
|
assert.strictEqual(list.$('.o_data_row').first().find('.o_priority:not(.o_field_empty)').length, 1,
|
|
"widget should be considered set");
|
|
assert.strictEqual(list.$('.o_data_row').first().find('.o_priority a.o_priority_star').length, 2,
|
|
"should have two stars for representing each possible value: no star, one star and two stars");
|
|
assert.strictEqual(list.$('.o_data_row').first().find('.o_priority a.o_priority_star.fa-star').length, 1,
|
|
"should have one full star since the value is the second value");
|
|
assert.strictEqual(list.$('.o_data_row').first().find('.o_priority a.o_priority_star.fa-star-o').length, 1,
|
|
"should have one empty star since the value is the second value");
|
|
|
|
// Here we should test with mouseout, but currently the effect associated with it
|
|
// occurs in a setTimeout after 200ms so it's not trivial to test it here.
|
|
|
|
// switch to edit mode and check the result
|
|
var $cell = list.$('tbody td:not(.o_list_record_selector)').first();
|
|
$cell.click();
|
|
assert.strictEqual(list.$('.o_data_row').first().find('.o_priority a.o_priority_star').length, 2,
|
|
"should have two stars for representing each possible value: no star, one star and two stars");
|
|
assert.strictEqual(list.$('.o_data_row').first().find('.o_priority a.o_priority_star.fa-star').length, 1,
|
|
"should have one full star since the value is the second value");
|
|
assert.strictEqual(list.$('.o_data_row').first().find('.o_priority a.o_priority_star.fa-star-o').length, 1,
|
|
"should have one empty star since the value is the second value");
|
|
|
|
// save
|
|
list.$buttons.find('.o_list_button_save').click();
|
|
assert.strictEqual(list.$('.o_data_row').first().find('.o_priority a.o_priority_star').length, 2,
|
|
"should have two stars for representing each possible value: no star, one star and two stars");
|
|
assert.strictEqual(list.$('.o_data_row').first().find('.o_priority a.o_priority_star.fa-star').length, 1,
|
|
"should have one full star since the value is the second value");
|
|
assert.strictEqual(list.$('.o_data_row').first().find('.o_priority a.o_priority_star.fa-star-o').length, 1,
|
|
"should have one empty star since the value is the second value");
|
|
|
|
// hover last star
|
|
list.$('.o_data_row .o_priority a.o_priority_star.fa-star-o').first().trigger('mouseenter');
|
|
assert.strictEqual(list.$('.o_data_row').first().find('.o_priority a.o_priority_star').length, 2,
|
|
"should have two stars for representing each possible value: no star, one star and two stars");
|
|
assert.strictEqual(list.$('.o_data_row').first().find('a.o_priority_star.fa-star').length, 2,
|
|
"should temporary have two full stars since we are hovering the third value");
|
|
assert.strictEqual(list.$('.o_data_row').first().find('a.o_priority_star.fa-star-o').length, 0,
|
|
"should temporary have no empty star since we are hovering the third value");
|
|
|
|
// click on the first star in readonly mode
|
|
list.$('.o_priority a.o_priority_star.fa-star').first().click();
|
|
|
|
assert.strictEqual(list.$('.o_data_row').first().find('.o_priority a.o_priority_star').length, 2,
|
|
"should still have two stars");
|
|
assert.strictEqual(list.$('.o_data_row').first().find('.o_priority a.o_priority_star.fa-star').length, 0,
|
|
"should now have no full star since the value is the first value");
|
|
assert.strictEqual(list.$('.o_data_row').first().find('.o_priority a.o_priority_star.fa-star-o').length, 2,
|
|
"should now have two empty stars since the value is the first value");
|
|
|
|
// re-enter edit mode to force re-rendering the widget to check if the value was correctly saved
|
|
$cell = list.$('tbody td:not(.o_list_record_selector)').first();
|
|
$cell.click();
|
|
|
|
assert.strictEqual(list.$('.o_data_row').first().find('.o_priority a.o_priority_star').length, 2,
|
|
"should still have two stars");
|
|
assert.strictEqual(list.$('.o_data_row').first().find('.o_priority a.o_priority_star.fa-star').length, 0,
|
|
"should now only have no full star since the value is the first value");
|
|
assert.strictEqual(list.$('.o_data_row').first().find('.o_priority a.o_priority_star.fa-star-o').length, 2,
|
|
"should now have two empty stars since the value is the first value");
|
|
|
|
// Click on second star in edit mode
|
|
list.$('.o_priority a.o_priority_star.fa-star-o').last().click();
|
|
|
|
assert.strictEqual(list.$('.o_data_row').last().find('.o_priority a.o_priority_star').length, 2,
|
|
"should still have two stars");
|
|
assert.strictEqual(list.$('.o_data_row').last().find('.o_priority a.o_priority_star.fa-star').length, 2,
|
|
"should now have two full stars since the value is the third value");
|
|
assert.strictEqual(list.$('.o_data_row').last().find('.o_priority a.o_priority_star.fa-star-o').length, 0,
|
|
"should now have no empty star since the value is the third value");
|
|
|
|
// save
|
|
list.$buttons.find('.o_list_button_save').click();
|
|
assert.strictEqual(list.$('.o_data_row').last().find('.o_priority a.o_priority_star').length, 2,
|
|
"should still have two stars");
|
|
assert.strictEqual(list.$('.o_data_row').last().find('.o_priority a.o_priority_star.fa-star').length, 2,
|
|
"should now have two full stars since the value is the third value");
|
|
assert.strictEqual(list.$('.o_data_row').last().find('.o_priority a.o_priority_star.fa-star-o').length, 0,
|
|
"should now have no empty star since the value is the third value");
|
|
|
|
list.destroy();
|
|
});
|
|
|
|
|
|
QUnit.module('StateSelection Widget');
|
|
|
|
QUnit.test('state_selection widget in form view', function (assert) {
|
|
assert.expect(21);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<group>' +
|
|
'<field name="selection" widget="state_selection"/>' +
|
|
'</group>' +
|
|
'</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.$('.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.$('.dropdown-menu.state:visible').length, 1,
|
|
"there should be a dropdown");
|
|
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.$('.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");
|
|
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 first, normal state");
|
|
assert.strictEqual(form.$('.o_field_widget.o_selection > a span.o_status').length, 1,
|
|
"should have one grey status since selection is the first, normal state");
|
|
|
|
// switch to edit mode and check the result
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
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");
|
|
assert.strictEqual(form.$('.o_field_widget.o_selection > a span.o_status.o_status_green').length, 0,
|
|
"should still not have one green status since selection is the first, normal state");
|
|
assert.strictEqual(form.$('.o_field_widget.o_selection > a span.o_status').length, 1,
|
|
"should still have one grey status since selection is the first, normal state");
|
|
|
|
// Click on the status button to make the dropdown appear
|
|
form.$('.o_field_widget.o_selection .o_status').first().click();
|
|
assert.strictEqual(form.$('.dropdown-menu.state:visible').length, 1,
|
|
"there should be a dropdown");
|
|
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.$('.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");
|
|
assert.strictEqual(form.$('.o_field_widget.o_selection > a span.o_status.o_status_green').length, 1,
|
|
"should have one green status since selection is the third, done state");
|
|
|
|
// save
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
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");
|
|
assert.strictEqual(form.$('.o_field_widget.o_selection > a span.o_status.o_status_green').length, 1,
|
|
"should still have one green status since selection is the third, done state");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('state_selection widget in editable list view', function (assert) {
|
|
assert.expect(32);
|
|
|
|
var list = createView({
|
|
View: ListView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<tree editable="bottom">' +
|
|
'<field name="foo"/>' +
|
|
'<field name="selection" widget="state_selection"/>' +
|
|
'</tree>',
|
|
});
|
|
|
|
assert.strictEqual(list.$('.o_state_selection_cell .o_selection > a span.o_status').length, 5,
|
|
"should have five status selection widgets");
|
|
assert.strictEqual(list.$('.o_state_selection_cell .o_selection > a span.o_status.o_status_red').length, 1,
|
|
"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.$('.dropdown-menu.state:visible').length, 0,
|
|
"there should not be a dropdown");
|
|
|
|
// Click on the status button to make the dropdown appear
|
|
var $cell = list.$('tbody td.o_state_selection_cell').first();
|
|
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.$('.dropdown-menu.state:visible').length, 1,
|
|
"there should be a dropdown");
|
|
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.$('.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.$('.dropdown-menu.state:visible').length, 0,
|
|
"there should not be a dropdown");
|
|
|
|
// switch to edit mode and check the result
|
|
$cell = list.$('tbody td.o_state_selection_cell').first();
|
|
$cell.click();
|
|
assert.ok($cell.parent().hasClass('o_selected_row'),
|
|
'should now be in edit mode');
|
|
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.$('.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.$('.dropdown-menu.state:visible').length, 1,
|
|
"there should be a dropdown");
|
|
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.$('.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');
|
|
assert.ok($lastCell.parent().hasClass('o_selected_row'),
|
|
'last row should be in edit mode');
|
|
|
|
// 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.$('.dropdown-menu.state:visible').length, 1,
|
|
"there should be a dropdown");
|
|
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.$('.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");
|
|
assert.strictEqual(list.$('.o_state_selection_cell .o_selection > a span.o_status.o_status_red').length, 0,
|
|
"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.$('.dropdown-menu.state:visible').length, 0,
|
|
"there should not be a dropdown");
|
|
|
|
// save
|
|
list.$buttons.find('.o_list_button_save').click();
|
|
assert.strictEqual(list.$('.o_state_selection_cell .o_selection > a span.o_status').length, 5,
|
|
"should have five status selection widgets");
|
|
assert.strictEqual(list.$('.o_state_selection_cell .o_selection > a span.o_status.o_status_red').length, 0,
|
|
"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.$('.dropdown-menu.state:visible').length, 0,
|
|
"there should not be a dropdown");
|
|
|
|
list.destroy();
|
|
});
|
|
|
|
|
|
QUnit.module('FavoriteWidget');
|
|
|
|
QUnit.test('favorite widget in kanban view', function (assert) {
|
|
assert.expect(4);
|
|
|
|
var kanban = createView({
|
|
View: KanbanView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<kanban class="o_kanban_test">' +
|
|
'<templates>' +
|
|
'<t t-name="kanban-box">' +
|
|
'<div>' +
|
|
'<field name="bar" widget="boolean_favorite" />' +
|
|
'</div>' +
|
|
'</t>' +
|
|
'</templates>' +
|
|
'</kanban>',
|
|
domain: [['id', '=', 1]],
|
|
});
|
|
|
|
assert.strictEqual(kanban.$('.o_kanban_record .o_field_widget.o_favorite > a i.fa.fa-star').length, 1,
|
|
'should be favorite');
|
|
assert.strictEqual(kanban.$('.o_kanban_record .o_field_widget.o_favorite > a').text(), ' Remove from Favorites',
|
|
'the label should say "Remove from Favorites"');
|
|
|
|
// click on favorite
|
|
kanban.$('.o_field_widget.o_favorite').click();
|
|
assert.strictEqual(kanban.$('.o_kanban_record .o_field_widget.o_favorite > a i.fa.fa-star').length, 0,
|
|
'should not be favorite');
|
|
assert.strictEqual(kanban.$('.o_kanban_record .o_field_widget.o_favorite > a').text(), ' Add to Favorites',
|
|
'the label should say "Add to Favorites"');
|
|
|
|
kanban.destroy();
|
|
});
|
|
|
|
QUnit.test('favorite widget in form view', function (assert) {
|
|
assert.expect(10);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<group>' +
|
|
'<field name="bar" widget="boolean_favorite" />' +
|
|
'</group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
});
|
|
|
|
assert.strictEqual(form.$('.o_field_widget.o_favorite > a i.fa.fa-star').length, 1,
|
|
'should be favorite');
|
|
assert.strictEqual(form.$('.o_field_widget.o_favorite > a').text(), ' Remove from Favorites',
|
|
'the label should say "Remove from Favorites"');
|
|
|
|
// click on favorite
|
|
form.$('.o_field_widget.o_favorite').click();
|
|
assert.strictEqual(form.$('.o_field_widget.o_favorite > a i.fa.fa-star').length, 0,
|
|
'should not be favorite');
|
|
assert.strictEqual(form.$('.o_field_widget.o_favorite > a').text(), ' Add to Favorites',
|
|
'the label should say "Add to Favorites"');
|
|
|
|
// switch to edit mode
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
assert.strictEqual(form.$('.o_field_widget.o_favorite > a i.fa.fa-star-o').length, 1,
|
|
'should not be favorite');
|
|
assert.strictEqual(form.$('.o_field_widget.o_favorite > a').text(), ' Add to Favorites',
|
|
'the label should say "Add to Favorites"');
|
|
|
|
// click on favorite
|
|
form.$('.o_field_widget.o_favorite').click();
|
|
assert.strictEqual(form.$('.o_field_widget.o_favorite > a i.fa.fa-star').length, 1,
|
|
'should be favorite');
|
|
assert.strictEqual(form.$('.o_field_widget.o_favorite > a').text(), ' Remove from Favorites',
|
|
'the label should say "Remove from Favorites"');
|
|
|
|
// save
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
assert.strictEqual(form.$('.o_field_widget.o_favorite > a i.fa.fa-star').length, 1,
|
|
'should be favorite');
|
|
assert.strictEqual(form.$('.o_field_widget.o_favorite > a').text(), ' Remove from Favorites',
|
|
'the label should say "Remove from Favorites"');
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('favorite widget in editable list view without label', function (assert) {
|
|
assert.expect(4);
|
|
|
|
var list = createView({
|
|
View: ListView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<tree editable="bottom">' +
|
|
'<field name="bar" widget="boolean_favorite" nolabel="1" />' +
|
|
'</tree>',
|
|
});
|
|
|
|
assert.strictEqual(list.$('.o_data_row:first .o_field_widget.o_favorite > a i.fa.fa-star').length, 1,
|
|
'should be favorite');
|
|
|
|
// switch to edit mode
|
|
list.$('tbody td:not(.o_list_record_selector)').first().click();
|
|
assert.strictEqual(list.$('.o_data_row:first .o_field_widget.o_favorite > a i.fa.fa-star').length, 1,
|
|
'should be favorite');
|
|
|
|
// click on favorite
|
|
list.$('.o_data_row:first .o_field_widget.o_favorite').click();
|
|
assert.strictEqual(list.$('.o_data_row:first .o_field_widget.o_favorite > a i.fa.fa-star').length, 0,
|
|
'should not be favorite');
|
|
|
|
// save
|
|
list.$buttons.find('.o_list_button_save').click();
|
|
assert.strictEqual(list.$('.o_data_row:first .o_field_widget.o_favorite > a i.fa.fa-star-o').length, 1,
|
|
'should not be favorite');
|
|
|
|
list.destroy();
|
|
});
|
|
|
|
|
|
QUnit.module('LabelSelectionWidget');
|
|
|
|
QUnit.test('label_selection widget in form view', function (assert) {
|
|
assert.expect(12);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<group>' +
|
|
'<field name="selection" widget="label_selection" ' +
|
|
' options="{\'classes\': {\'normal\': \'secondary\', \'blocked\': \'warning\',\'done\': \'success\'}}"/>' +
|
|
'</group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 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.badge.badge-secondary').length, 0,
|
|
"should not have a default status since selection is the second, blocked state");
|
|
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.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.badge.badge-warning').length, 1,
|
|
"should have a warning status label since selection is the second, blocked state");
|
|
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.badge.badge-success').length, 0,
|
|
"should not have a success status since selection is the second, blocked state");
|
|
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.badge.badge-warning').length, 1,
|
|
"should have a warning status label since selection is the second, blocked state");
|
|
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.badge.badge-success').length, 0,
|
|
"should not have a success status since selection is the second, blocked state");
|
|
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();
|
|
});
|
|
|
|
QUnit.test('label_selection widget in editable list view', function (assert) {
|
|
assert.expect(21);
|
|
|
|
var list = createView({
|
|
View: ListView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<tree editable="bottom">' +
|
|
'<field name="foo"/>' +
|
|
'<field name="selection" widget="label_selection"' +
|
|
' options="{\'classes\': {\'normal\': \'secondary\', \'blocked\': \'warning\',\'done\': \'success\'}}"/>' +
|
|
'</tree>',
|
|
});
|
|
|
|
assert.strictEqual(list.$('.o_field_widget.badge:not(:empty)').length, 3,
|
|
"should have three visible status labels");
|
|
assert.strictEqual(list.$('.o_field_widget.badge.badge-warning').length, 1,
|
|
"should have one warning status label");
|
|
assert.strictEqual(list.$('.o_field_widget.badge.badge-warning').text(), 'Blocked',
|
|
"the warning label should read 'Blocked'");
|
|
assert.strictEqual(list.$('.o_field_widget.badge.badge-secondary').length, 1,
|
|
"should have one default status label");
|
|
assert.strictEqual(list.$('.o_field_widget.badge.badge-secondary').text(), 'Normal',
|
|
"the default label should read 'Normal'");
|
|
assert.strictEqual(list.$('.o_field_widget.badge.badge-success').length, 1,
|
|
"should have one success status label");
|
|
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.badge:not(:empty)').length, 3,
|
|
"should have three visible status labels");
|
|
assert.strictEqual(list.$('.o_field_widget.badge.badge-warning').length, 1,
|
|
"should have one warning status label");
|
|
assert.strictEqual(list.$('.o_field_widget.badge.badge-warning').text(), 'Blocked',
|
|
"the warning label should read 'Blocked'");
|
|
assert.strictEqual(list.$('.o_field_widget.badge.badge-secondary').length, 1,
|
|
"should have one default status label");
|
|
assert.strictEqual(list.$('.o_field_widget.badge.badge-secondary').text(), 'Normal',
|
|
"the default label should read 'Normal'");
|
|
assert.strictEqual(list.$('.o_field_widget.badge.badge-success').length, 1,
|
|
"should have one success status label");
|
|
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.badge:not(:empty)').length, 3,
|
|
"should have three visible status labels");
|
|
assert.strictEqual(list.$('.o_field_widget.badge.badge-warning').length, 1,
|
|
"should have one warning status label");
|
|
assert.strictEqual(list.$('.o_field_widget.badge.badge-warning').text(), 'Blocked',
|
|
"the warning label should read 'Blocked'");
|
|
assert.strictEqual(list.$('.o_field_widget.badge.badge-secondary').length, 1,
|
|
"should have one default status label");
|
|
assert.strictEqual(list.$('.o_field_widget.badge.badge-secondary').text(), 'Normal',
|
|
"the default label should read 'Normal'");
|
|
assert.strictEqual(list.$('.o_field_widget.badge.badge-success').length, 1,
|
|
"should have one success status label");
|
|
assert.strictEqual(list.$('.o_field_widget.badge.badge-success').text(), 'Done',
|
|
"the success label should read 'Done'");
|
|
|
|
list.destroy();
|
|
});
|
|
|
|
|
|
QUnit.module('StatInfo');
|
|
|
|
QUnit.test('statinfo widget formats decimal precision', function (assert) {
|
|
// sometimes the round method can return numbers such as 14.000001
|
|
// when asked to round a number to 2 decimals, as such is the behaviour of floats.
|
|
// we check that even in that eventuality, only two decimals are displayed
|
|
assert.expect(2);
|
|
|
|
this.data.partner.fields.monetary = {string: "Monetary", type: 'monetary'};
|
|
this.data.partner.records[0].monetary = 9.999999;
|
|
this.data.partner.records[0].currency_id = 1;
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<button class="oe_stat_button" name="items" icon="fa-gear">' +
|
|
'<field name="qux" widget="statinfo"/>' +
|
|
'</button>' +
|
|
'<button class="oe_stat_button" name="money" icon="fa-money">' +
|
|
'<field name="monetary" widget="statinfo"/>' +
|
|
'</button>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
});
|
|
|
|
// formatFloat renders according to this.field.digits
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_value').eq(0).text(),
|
|
'0.4', "Default precision should be [16,1]");
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_value').eq(1).text(),
|
|
'10.00', "Currency decimal precision should be 2");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('statinfo widget in form view', function (assert) {
|
|
assert.expect(9);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<div class="oe_button_box" name="button_box">' +
|
|
'<button class="oe_stat_button" name="items" type="object" icon="fa-gear">' +
|
|
'<field name="int_field" widget="statinfo"/>' +
|
|
'</button>' +
|
|
'</div>' +
|
|
'<group>' +
|
|
'<field name="foo"/>' +
|
|
'</group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
});
|
|
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info').length, 1,
|
|
"should have one stat button");
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_value').text(),
|
|
'10', "should have 10 as value");
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_text').text(),
|
|
'int_field', "should have 'int_field' as text");
|
|
|
|
// switch to edit mode and check the result
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info').length, 1,
|
|
"should still have one stat button");
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_value').text(),
|
|
'10', "should still have 10 as value");
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_text').text(),
|
|
'int_field', "should have 'int_field' as text");
|
|
|
|
// save
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info').length, 1,
|
|
"should have one stat button");
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_value').text(),
|
|
'10', "should have 10 as value");
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_text').text(),
|
|
'int_field', "should have 'int_field' as text");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('statinfo widget in form view with specific label_field', function (assert) {
|
|
assert.expect(9);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<div class="oe_button_box" name="button_box">' +
|
|
'<button class="oe_stat_button" name="items" type="object" icon="fa-gear">' +
|
|
'<field string="Useful stat button" name="int_field" widget="statinfo" ' +
|
|
'options="{\'label_field\': \'foo\'}"/>' +
|
|
'</button>' +
|
|
'</div>' +
|
|
'<group>' +
|
|
'<field name="foo" invisible="1"/>' +
|
|
'<field name="bar"/>' +
|
|
'</group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
});
|
|
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info').length, 1,
|
|
"should have one stat button");
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_value').text(),
|
|
'10', "should have 10 as value");
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_text').text(),
|
|
'yop', "should have 'yop' as text, since it is the value of field foo");
|
|
|
|
// switch to edit mode and check the result
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info').length, 1,
|
|
"should still have one stat button");
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_value').text(),
|
|
'10', "should still have 10 as value");
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_text').text(),
|
|
'yop', "should have 'yop' as text, since it is the value of field foo");
|
|
|
|
// save
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info').length, 1,
|
|
"should have one stat button");
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_value').text(),
|
|
'10', "should have 10 as value");
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_text').text(),
|
|
'yop', "should have 'yop' as text, since it is the value of field foo");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('statinfo widget in form view with no label', function (assert) {
|
|
assert.expect(9);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<div class="oe_button_box" name="button_box">' +
|
|
'<button class="oe_stat_button" name="items" type="object" icon="fa-gear">' +
|
|
'<field string="Useful stat button" name="int_field" widget="statinfo" nolabel="1"/>' +
|
|
'</button>' +
|
|
'</div>' +
|
|
'<group>' +
|
|
'<field name="foo" invisible="1"/>' +
|
|
'<field name="bar"/>' +
|
|
'</group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
});
|
|
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info').length, 1,
|
|
"should have one stat button");
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_value').text(),
|
|
'10', "should have 10 as value");
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_text').text(),
|
|
'', "should not have any label");
|
|
|
|
// switch to edit mode and check the result
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info').length, 1,
|
|
"should still have one stat button");
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_value').text(),
|
|
'10', "should still have 10 as value");
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_text').text(),
|
|
'', "should not have any label");
|
|
|
|
// save
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info').length, 1,
|
|
"should have one stat button");
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_value').text(),
|
|
'10', "should have 10 as value");
|
|
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_text').text(),
|
|
'', "should not have any label");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
|
|
QUnit.module('PercentPie');
|
|
|
|
QUnit.test('percentpie widget in form view with value < 50%', function (assert) {
|
|
assert.expect(12);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<group>' +
|
|
'<field name="int_field" widget="percentpie"/>' +
|
|
'</group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
});
|
|
|
|
assert.strictEqual(form.$('.o_field_percent_pie.o_field_widget .o_pie').length, 1,
|
|
"should have a pie chart");
|
|
assert.strictEqual(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_pie_value').text(),
|
|
'10%', "should have 10% as pie value since int_field=10");
|
|
assert.ok(_.str.include(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_mask').first().attr('style'),
|
|
'transform: rotate(180deg);'), "left mask should be covering the whole left side of the pie");
|
|
assert.ok(_.str.include(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_mask').last().attr('style'),
|
|
'transform: rotate(36deg);'), "right mask should be rotated from 360*(10/100) = 36 degrees");
|
|
|
|
// switch to edit mode and check the result
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
assert.strictEqual(form.$('.o_field_percent_pie.o_field_widget .o_pie').length, 1,
|
|
"should have a pie chart");
|
|
assert.strictEqual(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_pie_value').text(),
|
|
'10%', "should have 10% as pie value since int_field=10");
|
|
assert.ok(_.str.include(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_mask').first().attr('style'),
|
|
'transform: rotate(180deg);'), "left mask should be covering the whole left side of the pie");
|
|
assert.ok(_.str.include(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_mask').last().attr('style'),
|
|
'transform: rotate(36deg);'), "right mask should be rotated from 360*(10/100) = 36 degrees");
|
|
|
|
// save
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
assert.strictEqual(form.$('.o_field_percent_pie.o_field_widget .o_pie').length, 1,
|
|
"should have a pie chart");
|
|
assert.strictEqual(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_pie_value').text(),
|
|
'10%', "should have 10% as pie value since int_field=10");
|
|
assert.ok(_.str.include(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_mask').first().attr('style'),
|
|
'transform: rotate(180deg);'), "left mask should be covering the whole left side of the pie");
|
|
assert.ok(_.str.include(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_mask').last().attr('style'),
|
|
'transform: rotate(36deg);'), "right mask should be rotated from 360*(10/100) = 36 degrees");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('percentpie widget in form view with value > 50%', function (assert) {
|
|
assert.expect(12);
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<form string="Partners">' +
|
|
'<sheet>' +
|
|
'<group>' +
|
|
'<field name="int_field" widget="percentpie"/>' +
|
|
'</group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 3,
|
|
});
|
|
|
|
assert.strictEqual(form.$('.o_field_percent_pie.o_field_widget .o_pie').length, 1,
|
|
"should have a pie chart");
|
|
assert.strictEqual(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_pie_value').text(),
|
|
'80%', "should have 80% as pie value since int_field=80");
|
|
assert.ok(_.str.include(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_mask').first().attr('style'),
|
|
'transform: rotate(288deg);'), "left mask should be rotated from 360*(80/100) = 288 degrees");
|
|
assert.ok(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_mask').last().hasClass('o_full'),
|
|
"right mask should be hidden since the value > 50%");
|
|
|
|
// switch to edit mode and check the result
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
assert.strictEqual(form.$('.o_field_percent_pie.o_field_widget .o_pie').length, 1,
|
|
"should have a pie chart");
|
|
assert.strictEqual(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_pie_value').text(),
|
|
'80%', "should have 80% as pie value since int_field=80");
|
|
assert.ok(_.str.include(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_mask').first().attr('style'),
|
|
'transform: rotate(288deg);'), "left mask should be rotated from 360*(80/100) = 288 degrees");
|
|
assert.ok(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_mask').last().hasClass('o_full'),
|
|
"right mask should be hidden since the value > 50%");
|
|
|
|
// save
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
assert.strictEqual(form.$('.o_field_percent_pie.o_field_widget .o_pie').length, 1,
|
|
"should have a pie chart");
|
|
assert.strictEqual(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_pie_value').text(),
|
|
'80%', "should have 80% as pie value since int_field=80");
|
|
assert.ok(_.str.include(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_mask').first().attr('style'),
|
|
'transform: rotate(288deg);'), "left mask should be rotated from 360*(80/100) = 288 degrees");
|
|
assert.ok(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_mask').last().hasClass('o_full'),
|
|
"right mask should be hidden since the value > 50%");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
// 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 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 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);
|
|
//
|
|
// var list = createView({
|
|
// View: ListView,
|
|
// model: 'partner',
|
|
// data: this.data,
|
|
// arch: '<tree editable="bottom">' +
|
|
// '<field name="foo"/>' +
|
|
// '<field name="int_field" widget="percentpie"/>' +
|
|
// '</tree>',
|
|
// });
|
|
//
|
|
// assert.strictEqual(list.$('.o_field_percent_pie .o_pie').length, 5,
|
|
// "should have five pie charts");
|
|
// assert.strictEqual(list.$('.o_field_percent_pie:first .o_pie .o_pie_value').first().text(),
|
|
// '10%', "should have 10% as pie value since int_field=10");
|
|
// assert.strictEqual(list.$('.o_field_percent_pie:first .o_pie .o_mask').first().attr('style'),
|
|
// 'transform: rotate(180deg);', "left mask should be covering the whole left side of the pie");
|
|
// assert.strictEqual(list.$('.o_field_percent_pie:first .o_pie .o_mask').last().attr('style'),
|
|
// 'transform: rotate(36deg);', "right mask should be rotated from 360*(10/100) = 36 degrees");
|
|
//
|
|
// // switch to edit mode and check the result
|
|
// list.$('tbody td:not(.o_list_record_selector)').first().click();
|
|
// assert.strictEqual(list.$('.o_field_percent_pie:first .o_pie .o_pie_value').first().text(),
|
|
// '10%', "should have 10% as pie value since int_field=10");
|
|
// assert.strictEqual(list.$('.o_field_percent_pie:first .o_pie .o_mask').first().attr('style'),
|
|
// 'transform: rotate(180deg);', "left mask should be covering the whole right side of the pie");
|
|
// assert.strictEqual(list.$('.o_field_percent_pie:first .o_pie .o_mask').last().attr('style'),
|
|
// 'transform: rotate(36deg);', "right mask should be rotated from 360*(10/100) = 36 degrees");
|
|
//
|
|
// // save
|
|
// list.$buttons.find('.o_list_button_save').click();
|
|
// assert.strictEqual(list.$('.o_field_percent_pie:first .o_pie .o_pie_value').first().text(),
|
|
// '10%', "should have 10% as pie value since int_field=10");
|
|
// assert.strictEqual(list.$('.o_field_percent_pie:first .o_pie .o_mask').first().attr('style'),
|
|
// 'transform: rotate(180deg);', "left mask should be covering the whole right side of the pie");
|
|
// assert.strictEqual(list.$('.o_field_percent_pie:first .o_pie .o_mask').last().attr('style'),
|
|
// 'transform: rotate(36deg);', "right mask should be rotated from 360*(10/100) = 36 degrees");
|
|
//
|
|
// list.destroy();
|
|
// });
|
|
|
|
|
|
QUnit.module('FieldDomain');
|
|
|
|
QUnit.test('The domain editor should not crash the view when given a dynamic filter', function (assert) {
|
|
//dynamic filters (containing variables, such as uid, parent or today)
|
|
//are not handled by the domain editor, but it shouldn't crash the view
|
|
assert.expect(1);
|
|
|
|
this.data.partner.records[0].foo = '[["int_field", "=", uid]]';
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:
|
|
'<form>' +
|
|
'<field name="foo" widget="domain" options="{\'model\': \'partner\'}"/>' +
|
|
'<field name="int_field" invisible="1"/>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
session: {
|
|
user_context: {uid: 14},
|
|
},
|
|
});
|
|
|
|
assert.strictEqual(form.$('.o_read_mode').text(), "This domain is not supported.",
|
|
"The widget should not crash the view, but gracefully admit its failure.");
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('basic domain field usage is ok', function (assert) {
|
|
assert.expect(6);
|
|
|
|
this.data.partner.records[0].foo = "[]";
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:
|
|
'<form>' +
|
|
'<sheet>' +
|
|
'<group>' +
|
|
'<field name="foo" widget="domain" options="{\'model\': \'partner_type\'}"/>' +
|
|
'</group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
});
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
|
|
// As the domain is empty, there should be a button to add the first
|
|
// domain part
|
|
var $domain = form.$(".o_field_domain");
|
|
var $domainAddFirstNodeButton = $domain.find(".o_domain_add_first_node_button");
|
|
assert.equal($domainAddFirstNodeButton.length, 1,
|
|
"there should be a button to create first domain element");
|
|
|
|
// Clicking on the button should add the [["id", "=", "1"]] domain, so
|
|
// there should be a field selector in the DOM
|
|
$domainAddFirstNodeButton.click();
|
|
var $fieldSelector = $domain.find(".o_field_selector");
|
|
assert.equal($fieldSelector.length, 1,
|
|
"there should be a field selector");
|
|
|
|
// Focusing the field selector input should open the field selector
|
|
// popover
|
|
$fieldSelector.trigger('focusin');
|
|
var $fieldSelectorPopover = $fieldSelector.find(".o_field_selector_popover");
|
|
assert.ok($fieldSelectorPopover.is(":visible"),
|
|
"field selector popover should be visible");
|
|
|
|
// The popover should contain the list of partner_type fields and so
|
|
// there should be the "Color index" field
|
|
var $lis = $fieldSelectorPopover.find("li");
|
|
var $colorIndex = $();
|
|
$lis.each(function () {
|
|
var $li = $(this);
|
|
if ($li.html().indexOf("Color index") >= 0) {
|
|
$colorIndex = $li;
|
|
}
|
|
});
|
|
assert.equal($colorIndex.length, 1,
|
|
"field selector popover should contain 'Color index' field");
|
|
|
|
// Clicking on this field should close the popover, then changing the
|
|
// associated value should reveal one matched record
|
|
$colorIndex.click();
|
|
$domain.find(".o_domain_leaf_value_input").val(2).change();
|
|
assert.equal($domain.find(".o_domain_show_selection_button").text().trim().substr(0, 2), "1 ",
|
|
"changing color value to 2 should reveal only one record");
|
|
|
|
// Saving the form view should show a readonly domain containing the
|
|
// "color" field
|
|
form.$buttons.find('.o_form_button_save').click();
|
|
$domain = form.$(".o_field_domain");
|
|
assert.ok($domain.html().indexOf("Color index") >= 0,
|
|
"field selector readonly value should now contain 'Color index'");
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('domain field is correctly reset on every view change', function (assert) {
|
|
assert.expect(7);
|
|
|
|
this.data.partner.records[0].foo = '[["id","=",1]]';
|
|
this.data.partner.fields.bar.type = "char";
|
|
this.data.partner.records[0].bar = "product";
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:
|
|
'<form>' +
|
|
'<sheet>' +
|
|
'<group>' +
|
|
'<field name="bar"/>' +
|
|
'<field name="foo" widget="domain" options="{\'model\': \'bar\'}"/>' +
|
|
'</group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
});
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
|
|
// As the domain is equal to [["id", "=", 1]] there should be a field
|
|
// selector to change this
|
|
var $domain = form.$(".o_field_domain");
|
|
var $fieldSelector = $domain.find(".o_field_selector");
|
|
assert.equal($fieldSelector.length, 1,
|
|
"there should be a field selector");
|
|
|
|
// Focusing its input should open the field selector popover
|
|
$fieldSelector.trigger('focusin');
|
|
var $fieldSelectorPopover = $fieldSelector.find(".o_field_selector_popover");
|
|
assert.ok($fieldSelectorPopover.is(":visible"),
|
|
"field selector popover should be visible");
|
|
|
|
// As the value of the "bar" field is "product", the field selector
|
|
// popover should contain the list of "product" fields
|
|
var $lis = $fieldSelectorPopover.find("li");
|
|
var $sampleLi = $();
|
|
$lis.each(function () {
|
|
var $li = $(this);
|
|
if ($li.html().indexOf("Product Name") >= 0) {
|
|
$sampleLi = $li;
|
|
}
|
|
});
|
|
assert.strictEqual($lis.length, 1,
|
|
"field selector popover should contain only one field");
|
|
assert.strictEqual($sampleLi.length, 1,
|
|
"field selector popover should contain 'Product Name' field");
|
|
|
|
// Now change the value of the "bar" field to "partner_type"
|
|
form.$("input.o_field_widget").click().val("partner_type").trigger("input");
|
|
|
|
// Refocusing the field selector input should open the popover again
|
|
$fieldSelector = form.$(".o_field_selector");
|
|
$fieldSelector.trigger('focusin');
|
|
$fieldSelectorPopover = $fieldSelector.find(".o_field_selector_popover");
|
|
assert.ok($fieldSelectorPopover.is(":visible"),
|
|
"field selector popover should be visible");
|
|
|
|
// Now the list of fields should be the ones of the "partner_type" model
|
|
$lis = $fieldSelectorPopover.find("li");
|
|
$sampleLi = $();
|
|
$lis.each(function () {
|
|
var $li = $(this);
|
|
if ($li.html().indexOf("Color index") >= 0) {
|
|
$sampleLi = $li;
|
|
}
|
|
});
|
|
assert.strictEqual($lis.length, 2,
|
|
"field selector popover should contain two fields");
|
|
assert.strictEqual($sampleLi.length, 1,
|
|
"field selector popover should contain 'Color index' field");
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('domain field can be reset with a new domain (from onchange)', function (assert) {
|
|
assert.expect(2);
|
|
|
|
this.data.partner.records[0].foo = '[]';
|
|
this.data.partner.onchanges = {
|
|
display_name: function (obj) {
|
|
obj.foo = '[["id", "=", 1]]';
|
|
},
|
|
};
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:
|
|
'<form>' +
|
|
'<field name="display_name"/>' +
|
|
'<field name="foo" widget="domain" options="{\'model\': \'partner\'}"/>' +
|
|
'</form>',
|
|
res_id: 1,
|
|
viewOptions: {
|
|
mode: 'edit',
|
|
},
|
|
});
|
|
|
|
assert.equal(form.$('.o_domain_show_selection_button').text().trim(), '5 record(s)',
|
|
"the domain being empty, there should be 5 records");
|
|
|
|
// update display_name to trigger the onchange and reset foo
|
|
form.$('.o_field_widget[name=display_name]').val('new value').trigger('input');
|
|
|
|
assert.equal(form.$('.o_domain_show_selection_button').text().trim(), '1 record(s)',
|
|
"the domain has changed, there should be only 1 record");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('domain field: handle false domain as []', function (assert) {
|
|
assert.expect(3);
|
|
|
|
this.data.partner.records[0].foo = false;
|
|
this.data.partner.fields.bar.type = "char";
|
|
this.data.partner.records[0].bar = "product";
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:
|
|
'<form>' +
|
|
'<sheet>' +
|
|
'<group>' +
|
|
'<field name="bar"/>' +
|
|
'<field name="foo" widget="domain" options="{\'model\': \'bar\'}"/>' +
|
|
'</group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
mockRPC: function (route, args) {
|
|
if (args.method === 'search_count') {
|
|
assert.deepEqual(args.args[0], [], "should send a valid domain");
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
res_id: 1,
|
|
});
|
|
|
|
assert.strictEqual(form.$('.o_field_widget[name=foo]:not(.o_field_empty)').length, 1,
|
|
"there should be a domain field, not considered empty");
|
|
|
|
form.$buttons.find('.o_form_button_edit').click();
|
|
|
|
var $warning = form.$('.o_field_widget[name=foo] .text-warning');
|
|
assert.strictEqual($warning.length, 0, "should not display that the domain is invalid");
|
|
|
|
form.destroy();
|
|
});
|
|
|
|
QUnit.test('basic domain field: show the selection', function (assert) {
|
|
assert.expect(2);
|
|
|
|
this.data.partner.records[0].foo = "[]";
|
|
|
|
var form = createView({
|
|
View: FormView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch:
|
|
'<form>' +
|
|
'<sheet>' +
|
|
'<group>' +
|
|
'<field name="foo" widget="domain" options="{\'model\': \'partner_type\'}"/>' +
|
|
'</group>' +
|
|
'</sheet>' +
|
|
'</form>',
|
|
archs: {
|
|
'partner_type,false,list': '<tree><field name="display_name"/></tree>',
|
|
'partner_type,false,search': '<search><field name="name" string="Name"/></search>',
|
|
},
|
|
res_id: 1,
|
|
});
|
|
|
|
assert.equal(form.$(".o_domain_show_selection_button").text().trim().substr(0, 2), "2 ",
|
|
"selection should contain 2 records");
|
|
|
|
// open the selection
|
|
form.$(".o_domain_show_selection_button").click();
|
|
assert.strictEqual($('.modal .o_list_view .o_data_row').length, 2,
|
|
"should have open a list view with 2 records in a dialog");
|
|
|
|
// click on a record -> should not open the record
|
|
// we don't actually check that it doesn't open the record because even
|
|
// if it tries to, it will crash as we don't define an arch in this test
|
|
$('.modal .o_list_view .o_data_row:first .o_data_cell').click();
|
|
|
|
form.destroy();
|
|
});
|
|
});
|
|
});
|
|
});
|