summaryrefslogtreecommitdiff
path: root/addons/web/static/test/fields/basic_fields_tests.js
diff options
context:
space:
mode:
authorGéry Debongnie <ged@odoo.com>2017-03-05 10:05:56 +0100
committerAaron Bohy <aab@odoo.com>2017-04-11 19:44:38 +0200
commit905e01921f3c3ef43ace6fc537d1d8c0d280002c (patch)
tree265c43ab21c5401a5d9f0f3d64d86f1ac417451c /addons/web/static/test/fields/basic_fields_tests.js
parent54d4c73af4ad05c7640d28c1892247c9538b8017 (diff)
[REF] web, *: redesign all JS views
This commit introduce a full redesign of all JS views. We started basically from scratch. The goal was to unify all the various views under a common framework, to make them testable, to make then usable in different conditions (in studio, or in the frontend), and to make our lives easier. Some important points are: - we introduced new coding guidelines (camelCase, 80 chars width, ...) - we have a brand new testing framework (still QUnit based) - kanban view moved to the web addon - calendar view (formerly web_calender) moved to web as well - the tree view was removed - all new code should be documented We hope that this code is the start of a new era for the Odoo web client, we want to have a high quality codebase, well documented, well tested, well designed. Work done by the framework team: mostly aab, ged, chm, dmo, qsm
Diffstat (limited to 'addons/web/static/test/fields/basic_fields_tests.js')
-rw-r--r--addons/web/static/test/fields/basic_fields_tests.js544
1 files changed, 544 insertions, 0 deletions
diff --git a/addons/web/static/test/fields/basic_fields_tests.js b/addons/web/static/test/fields/basic_fields_tests.js
new file mode 100644
index 00000000000..e1dbb1f0b24
--- /dev/null
+++ b/addons/web/static/test/fields/basic_fields_tests.js
@@ -0,0 +1,544 @@
+odoo.define('web.basic_fields_tests', function (require) {
+"use strict";
+
+var concurrency = require('web.concurrency');
+var FormView = require('web.FormView');
+var KanbanView = require('web.KanbanView');
+var ListView = require('web.ListView');
+var testUtils = require('web.test_utils');
+
+var createView = testUtils.createView;
+
+QUnit.module('fields', {}, function () {
+
+QUnit.module('basic_fields', {
+ beforeEach: function () {
+ this.data = {
+ partner: {
+ fields: {
+ date: {string: "A date", type: "date"},
+ display_name: { string: "Displayed name", type: "char" },
+ foo: {string: "Foo", type: "char", default: "My little Foo Value"},
+ bar: {string: "Bar", type: "boolean", default: true},
+ int_field: {string: "int_field", type: "integer", sortable: true},
+ qux: {string: "Qux", type: "float", digits: [16,1] },
+ p: {string: "one2many field", type: "one2many", relation: 'partner'},
+ trululu: {string: "Trululu", type: "many2one", relation: 'partner'},
+ timmy: { string: "pokemon", type: "many2many", relation: 'partner_type'},
+ product_id: {string: "Product", type: "many2one", relation: 'product'},
+ sequence: {type: "integer", string: "Sequence"},
+ },
+ records: [{
+ id: 1,
+ date: "2017-02-03",
+ display_name: "first record",
+ bar: true,
+ foo: "yop",
+ int_field: 10,
+ qux: 0.44,
+ p: [],
+ timmy: [],
+ trululu: 4,
+ }, {
+ id: 2,
+ display_name: "second record",
+ bar: true,
+ foo: "blip",
+ int_field: 9,
+ qux: 13,
+ p: [],
+ timmy: [],
+ trululu: 1,
+ sequence: 4
+ }, {
+ id: 4,
+ display_name: "aaa",
+ foo: "abc",
+ sequence: 9,
+ },
+ {id: 3, bar: true, foo: "gnap", int_field: 17, qux: -3, m2o: 1, m2m: []},
+ {id: 4, bar: false, foo: "blip", int_field: -4, qux: 9, m2o: 1, m2m: [1]}],
+ onchanges: {},
+ },
+ product: {
+ fields: {
+ name: {string: "Product Name", type: "char"}
+ },
+ records: [{
+ id: 37,
+ display_name: "xphone",
+ }, {
+ id: 41,
+ display_name: "xpad",
+ }]
+ },
+ partner_type: {
+ fields: {
+ name: {string: "Partner Type", type: "char"},
+ color: {string: "Color index", type: "int"},
+ },
+ records: [
+ {id: 12, display_name: "gold", color: 2},
+ {id: 14, display_name: "silver", color: 5},
+ ]
+ },
+ };
+ }
+}, function () {
+
+ QUnit.module('FieldBoolean');
+
+ QUnit.test('boolean field rendering in list view', function (assert) {
+ assert.expect(2);
+
+ var list = createView({
+ View: ListView,
+ model: 'partner',
+ data: this.data,
+ arch: '<tree><field name="bar"/></tree>',
+ });
+
+ assert.strictEqual(list.$('tbody td:not(.o_list_record_selector) .o_checkbox input:checked').length, 4,
+ "should have 4 checked input");
+ assert.strictEqual(list.$('tbody td:not(.o_list_record_selector) .o_checkbox input').length, 5,
+ "should have 5 checkboxes");
+ });
+
+ QUnit.module('FieldFloat');
+
+ QUnit.test('float field rendering in list view', function (assert) {
+ assert.expect(1);
+
+ var list = createView({
+ View: ListView,
+ model: 'partner',
+ data: this.data,
+ arch: '<tree><field name="qux"/></tree>',
+ });
+
+ assert.strictEqual(list.$('.o_list_number').length, 5, "should have 5 cells with .o_list_number");
+ });
+
+ 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_form_field_number:contains(0.4)').length, 1,
+ "should contain a number rounded to 1 decimal");
+ });
+
+ QUnit.module('EmailWidget');
+
+
+ QUnit.test('email widget works correctly', function (assert) {
+ assert.expect(1);
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch:'<form string="Partners">' +
+ '<sheet>' +
+ '<group>' +
+ '<field name="foo" widget="email"/>' +
+ '</group>' +
+ '</sheet>' +
+ '</form>',
+ res_id: 1,
+ });
+
+ assert.strictEqual(form.$('a.o_form_uri.o_form_field.o_text_overflow').length, 1,
+ "should have a anchor with correct classes");
+ });
+
+ QUnit.module('FieldChar');
+
+
+ QUnit.test('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 = form.renderer.widgets[0];
+ assert.strictEqual(charField.isValid(), true);
+ });
+
+ QUnit.test('char fields in edit mode', 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,
+ });
+
+ form.$buttons.find('.o_form_button_edit').click();
+ assert.strictEqual(form.$('input[type="text"].o_form_input.o_form_field').length, 1,
+ "should have an input for the char field foo");
+ });
+
+ QUnit.module('UrlWidget');
+
+ QUnit.test('url widget works correctly', function (assert) {
+ assert.expect(1);
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch:'<form string="Partners">' +
+ '<sheet>' +
+ '<group>' +
+ '<field name="foo" widget="url"/>' +
+ '</group>' +
+ '</sheet>' +
+ '</form>',
+ res_id: 2,
+ });
+
+ assert.strictEqual(form.$('a.o_form_uri.o_form_field.o_text_overflow').length, 1,
+ "should have a anchor with correct classes");
+ });
+
+ 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.$('div.o_form_textarea').length, "should have a text area");
+ assert.strictEqual(form.$('div.o_form_textarea').text(), 'yop', 'should be "yop" in readonly');
+
+ form.$buttons.find('.o_form_button_edit').click();
+
+ var $textarea = form.$('.o_form_textarea textarea');
+ 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.$('div.o_form_textarea').text(), 'hello world',
+ 'should be "hello world" after save');
+ });
+
+ 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.$('div.o_list_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");
+ });
+
+
+ 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");
+ });
+
+ 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.ok(list.$('textarea').first().is(':focus'),
+ "text area should have the focus (make sure the test window had the focus)");
+ });
+
+
+ QUnit.module('JournalDashboardGraph');
+
+ QUnit.test('graph dashboard widget is rendered correctly', function (assert) {
+ assert.expect(2);
+
+ _.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,
+ }]);
+ 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, 2]]],
+ manualDestroy: true,
+ });
+
+ // 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.
+ var done = assert.async();
+ return concurrency.delay(0).then(function () {
+ return concurrency.delay(0);
+ }).then(function () {
+ assert.ok(kanban.$('.o_kanban_record:first() .o_graph_barchart').length,
+ "graph of first record should be a barchart");
+ assert.ok(kanban.$('.o_kanban_record:nth(1) .o_graph_linechart').length,
+ "graph of second record should be a linechart");
+ kanban.destroy();
+ done();
+ });
+
+ });
+
+ QUnit.module('AceEditor');
+
+ QUnit.test('ace widget on text fields works', function (assert) {
+ assert.expect(3);
+ var done = assert.async();
+
+ assert.notOk('ace' in window, "the ace library should not be loaded");
+ 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 now be loaded");
+ assert.ok(form.$('div.ace_content').length, "should have rendered something with ace editor");
+ delete window.require;
+ delete window.ace;
+ done();
+ });
+ });
+
+ QUnit.module('HandleWidget');
+
+ QUnit.test('handle widget', function (assert) {
+ assert.expect(7);
+
+ 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_readonly'),
+ "column should be displayed as readonly");
+
+ 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");
+ });
+
+ QUnit.module('FieldDate');
+
+ QUnit.test('date field in edit mode', function (assert) {
+ assert.expect(7);
+
+ 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);
+ },
+ });
+
+ assert.strictEqual(form.$('.o_form_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');
+
+ // click on the input and select another value
+ form.$('.o_datepicker_input').click();
+ assert.ok(form.$('.bootstrap-datetimepicker-widget').length, 'datepicker should be open');
+ form.$('.day:contains(22)').click(); // select the 22 February
+ assert.ok(!form.$('.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_form_field_date').text(), '02/22/2017',
+ 'the selected date should be displayed after saving');
+ });
+
+ QUnit.test('field date in editable list view', function (assert) {
+ assert.expect(1);
+
+ this.data.partner.fields.date.default = "2017-02-10";
+ this.data.partner.records = [];
+
+ var list = createView({
+ View: ListView,
+ model: 'partner',
+ data: this.data,
+ arch: '<tree string="Phonecalls" editable="top">' +
+ '<field name="date"/>' +
+ '</tree>',
+ });
+
+ list.$buttons.find('.o_list_button_add').click();
+
+ assert.ok(list.$('input').is(':focus'),
+ "date input should have the focus (make sure the test window had the focus)");
+ });
+
+});
+});
+});