diff options
| author | Jérémy Hennecart <jeh@odoo.com> | 2020-06-19 07:06:31 +0000 |
|---|---|---|
| committer | Aaron Bohy <aab@odoo.com> | 2020-06-22 13:04:01 +0000 |
| commit | c7964657ecbbad278cec73cf231d7eef55b44347 (patch) | |
| tree | be77532a80cbed1283c2062cb2dc1159aa0fbdd4 /addons/web/static/tests/views/list_tests.js | |
| parent | 96fcefb6f1fe3fb5a5f197e2635e6d71d9a1d9dd (diff) | |
[IMP] web: add support of "sample" attribute in views
With this commit, it is now possible to display sample (fake)
data in empty views, in the hope of easing user onboarding.
This can be enabled (in list and kanban views) with attribute
sample="1" on the arch root element. In this case, if there is
no data to display, sample data will be generated based on
heuristics (depending on field types and names). This can be
used in addition to the no content helper.
Task 2232801
X-original-commit: 7c8e627ff5029cb539d702705e5ce53d658c76ed
Co-authored-by: Aaron Bohy <aab@odoo.com>
Co-authored-by: Mathieu Duckerts-Antoine <dam@odoo.com>
Co-authored-by: Jérémy Hennecart <jeh@odoo.com>
Co-authored-by: Julien Mougenot <jum@odoo.com>
Diffstat (limited to 'addons/web/static/tests/views/list_tests.js')
| -rw-r--r-- | addons/web/static/tests/views/list_tests.js | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/addons/web/static/tests/views/list_tests.js b/addons/web/static/tests/views/list_tests.js index 67c1a7962a0..3d49b2079cc 100644 --- a/addons/web/static/tests/views/list_tests.js +++ b/addons/web/static/tests/views/list_tests.js @@ -5,6 +5,7 @@ var AbstractFieldOwl = require('web.AbstractFieldOwl'); var AbstractStorageService = require('web.AbstractStorageService'); var BasicModel = require('web.BasicModel'); var core = require('web.core'); +const Domain = require('web.Domain') var basicFields = require('web.basic_fields'); var fieldRegistry = require('web.field_registry'); var fieldRegistryOwl = require('web.field_registry_owl'); @@ -3764,6 +3765,284 @@ QUnit.module('Views', { list.destroy(); }); + QUnit.test("empty list with sample data", async function (assert) { + assert.expect(19); + + const list = await createView({ + View: ListView, + model: 'foo', + data: this.data, + arch: ` + <tree sample="1"> + <field name="foo"/> + <field name="bar"/> + <field name="int_field"/> + <field name="m2o"/> + <field name="m2m" widget="many2many_tags"/> + <field name="date"/> + <field name="datetime"/> + </tree>`, + domain: [['id', '<', 0]], // such that no record matches the domain + viewOptions: { + action: { + help: '<p class="hello">click to add a partner</p>' + } + }, + }); + + assert.hasClass(list.$el, 'o_view_sample_data'); + assert.containsOnce(list, '.o_list_table'); + assert.containsN(list, '.o_data_row', 10); + assert.containsOnce(list, '.o_nocontent_help .hello'); + + // Check list sample data + const firstRow = list.el.querySelector('.o_data_row'); + const cells = firstRow.querySelectorAll(':scope > .o_data_cell'); + assert.strictEqual(cells[0].innerText.trim(), "", + "Char field should yield an empty element" + ); + assert.containsOnce(cells[1], '.custom-checkbox', + "Boolean field has been instantiated" + ); + assert.notOk(isNaN(cells[2].innerText.trim()), "Intger value is a number"); + assert.ok(cells[3].innerText.trim(), "Many2one field is a string"); + + const firstM2MTag = cells[4].querySelector( + ':scope span.o_badge_text' + ).innerText.trim(); + assert.ok(firstM2MTag.length > 0, "Many2many contains at least one string tag"); + + assert.ok(/\d{2}\/\d{2}\/\d{4}/.test(cells[5].innerText.trim()), + "Date field should have the right format" + ); + assert.ok(/\d{2}\/\d{2}\/\d{4} \d{2}:\d{2}:\d{2}/.test(cells[6].innerText.trim()), + "Datetime field should have the right format" + ); + + const textContent = list.$el.text(); + await list.reload(); + assert.strictEqual(textContent, list.$el.text(), + 'The content should be the same after reloading the view without change' + ); + + // reload with another domain -> should no longer display the sample records + await list.reload({ domain: Domain.FALSE_DOMAIN }); + + assert.doesNotHaveClass(list.$el, 'o_view_sample_data'); + assert.containsNone(list, '.o_list_table'); + assert.containsOnce(list, '.o_nocontent_help .hello'); + + // reload with another domain matching records + await list.reload({ domain: Domain.TRUE_DOMAIN }); + + assert.doesNotHaveClass(list.$el, 'o_view_sample_data'); + assert.containsOnce(list, '.o_list_table'); + assert.containsN(list, '.o_data_row', 4); + assert.containsNone(list, '.o_nocontent_help .hello'); + + list.destroy(); + }); + + QUnit.test("non empty list with sample data", async function (assert) { + assert.expect(6); + + const list = await createView({ + View: ListView, + model: 'foo', + data: this.data, + arch: ` + <tree sample="1"> + <field name="foo"/> + <field name="bar"/> + <field name="int_field"/> + </tree>`, + domain: Domain.TRUE_DOMAIN, + }); + + assert.containsOnce(list, '.o_list_table'); + assert.containsN(list, '.o_data_row', 4); + assert.doesNotHaveClass(list.$el, 'o_view_sample_data'); + + // reload with another domain matching no record (should not display the sample records) + await list.reload({ domain: Domain.FALSE_DOMAIN }); + + assert.containsOnce(list, '.o_list_table'); + assert.containsNone(list, '.o_data_row'); + assert.doesNotHaveClass(list.$el, 'o_view_sample_data'); + + list.destroy(); + }); + + QUnit.test('click on header in empty list with sample data', async function (assert) { + assert.expect(4); + + const list = await createView({ + View: ListView, + model: 'foo', + data: this.data, + arch: ` + <tree sample="1"> + <field name="foo"/> + <field name="bar"/> + <field name="int_field"/> + </tree>`, + domain: Domain.FALSE_DOMAIN, + }); + + assert.hasClass(list, 'o_view_sample_data'); + assert.containsOnce(list, '.o_list_table'); + assert.containsN(list, '.o_data_row', 10); + + const content = list.$el.text(); + await testUtils.dom.click(list.$('tr:first .o_column_sortable:first')); + assert.strictEqual(list.$el.text(), content, "the content should still be the same"); + + list.destroy(); + }); + + QUnit.test("non empty editable list with sample data: delete all records", async function (assert) { + assert.expect(7); + + const list = await createView({ + arch: ` + <tree editable="top" sample="1"> + <field name="foo"/> + <field name="bar"/> + <field name="int_field"/> + </tree>`, + data: this.data, + domain: Domain.TRUE_DOMAIN, + model: 'foo', + View: ListView, + viewOptions: { + action: { + help: '<p class="hello">click to add a partner</p>' + }, + hasActionMenus: true, + }, + }); + + // Initial state: all records displayed + assert.doesNotHaveClass(list, 'o_view_sample_data'); + assert.containsOnce(list, '.o_list_table'); + assert.containsN(list, '.o_data_row', 4); + assert.containsNone(list, '.o_nocontent_help'); + + // Delete all records + await testUtils.dom.click(list.el.querySelector('thead .o_list_record_selector input')); + await cpHelpers.toggleActionMenu(list); + await cpHelpers.toggleMenuItem(list, "Delete"); + await testUtils.dom.click($('.modal-footer .btn-primary')); + + // Final state: no more sample data, but nocontent helper displayed + assert.doesNotHaveClass(list, 'o_view_sample_data'); + assert.containsNone(list, '.o_list_table'); + assert.containsOnce(list, '.o_nocontent_help'); + + list.destroy(); + }); + + QUnit.test("empty editable list with sample data: start create record and cancel", async function (assert) { + assert.expect(10); + + const list = await createView({ + arch: ` + <tree editable="top" sample="1"> + <field name="foo"/> + <field name="bar"/> + <field name="int_field"/> + </tree>`, + data: this.data, + domain: Domain.FALSE_DOMAIN, + model: 'foo', + View: ListView, + viewOptions: { + action: { + help: '<p class="hello">click to add a partner</p>' + }, + }, + }); + + // Initial state: sample data and nocontent helper displayed + assert.hasClass(list, 'o_view_sample_data'); + assert.containsOnce(list, '.o_list_table'); + assert.containsN(list, '.o_data_row', 10); + assert.containsOnce(list, '.o_nocontent_help'); + + // Start creating a record + await testUtils.dom.click(list.el.querySelector('.btn.o_list_button_add')); + + assert.doesNotHaveClass(list, 'o_view_sample_data'); + assert.containsOnce(list, '.o_data_row'); + + // Discard temporary record + await testUtils.dom.click(list.el.querySelector('.btn.o_list_button_discard')); + + // Final state: table should be displayed with no data at all + assert.doesNotHaveClass(list, 'o_view_sample_data'); + assert.containsOnce(list, '.o_list_table'); + assert.containsNone(list, '.o_data_row'); + assert.containsNone(list, '.o_nocontent_help'); + + list.destroy(); + }); + + QUnit.test("empty editable list with sample data: create and delete record", async function (assert) { + assert.expect(13); + + const list = await createView({ + arch: ` + <tree editable="top" sample="1"> + <field name="foo"/> + <field name="bar"/> + <field name="int_field"/> + </tree>`, + data: this.data, + domain: Domain.FALSE_DOMAIN, + model: 'foo', + View: ListView, + viewOptions: { + action: { + help: '<p class="hello">click to add a partner</p>' + }, + hasActionMenus: true, + }, + }); + + // Initial state: sample data and nocontent helper displayed + assert.hasClass(list, 'o_view_sample_data'); + assert.containsOnce(list, '.o_list_table'); + assert.containsN(list, '.o_data_row', 10); + assert.containsOnce(list, '.o_nocontent_help'); + + // Start creating a record + await testUtils.dom.click(list.el.querySelector('.btn.o_list_button_add')); + + assert.doesNotHaveClass(list, 'o_view_sample_data'); + assert.containsOnce(list, '.o_data_row'); + + // Save temporary record + await testUtils.dom.click(list.el.querySelector('.btn.o_list_button_save')); + + assert.doesNotHaveClass(list, 'o_view_sample_data'); + assert.containsOnce(list, '.o_list_table'); + assert.containsOnce(list, '.o_data_row'); + assert.containsNone(list, '.o_nocontent_help'); + + // Delete newly created record + await testUtils.dom.click(list.el.querySelector('.o_data_row input')); + await cpHelpers.toggleActionMenu(list); + await cpHelpers.toggleMenuItem(list, "Delete"); + await testUtils.dom.click($('.modal-footer .btn-primary')); + + // Final state: there should be no table, but the no content helper + assert.doesNotHaveClass(list, 'o_view_sample_data'); + assert.containsNone(list, '.o_list_table'); + assert.containsOnce(list, '.o_nocontent_help'); + + list.destroy(); + }); + QUnit.test('groupby node with a button', async function (assert) { assert.expect(14); |
