From c484ff74fc94cc3e48852a9438329335c0e1120f Mon Sep 17 00:00:00 2001 From: tsm-odoo Date: Thu, 21 Apr 2022 12:28:01 +0000 Subject: [PATCH] [IMP] test_mail: adapt activity test to use startServer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR helps reducing the noise in the one adapting discuss to use wowlEnv. Indeed, the start method will now only rely on the createWebClient method. This means we'll need to adapt those tests to use real models. To do so, we need to move those tests in the test_mail module. task-2582313 closes odoo/odoo#89666 Signed-off-by: Sébastien Theys (seb) --- .../test_mail/static/tests/activity_tests.js | 413 +++++++----------- 1 file changed, 160 insertions(+), 253 deletions(-) diff --git a/addons/test_mail/static/tests/activity_tests.js b/addons/test_mail/static/tests/activity_tests.js index ee59cd8475c..02fb895f1f2 100644 --- a/addons/test_mail/static/tests/activity_tests.js +++ b/addons/test_mail/static/tests/activity_tests.js @@ -2,120 +2,81 @@ import ActivityRenderer from '@mail/js/views/activity/activity_renderer'; import ActivityView from '@mail/js/views/activity/activity_view'; +import { start, startServer } from '@mail/../tests/helpers/test_utils'; + import testUtils from 'web.test_utils'; import domUtils from 'web.dom'; import { getFixture, legacyExtraNextTick, patchWithCleanup, click } from "@web/../tests/helpers/utils"; -import { createWebClient, doAction } from "@web/../tests/webclient/helpers"; +import { doAction } from "@web/../tests/webclient/helpers"; import { session } from '@web/session'; let serverData; +let pyEnv; let target; -var createView = testUtils.createView; - -QUnit.module('mail', {}, function () { +QUnit.module('test_mail', {}, function () { QUnit.module('activity view', { - beforeEach: function () { - this.data = { - task: { - fields: { - id: {string: 'ID', type: 'integer'}, - foo: {string: "Foo", type: "char"}, - activity_ids: { - string: 'Activities', - type: 'one2many', - relation: 'mail.activity', - relation_field: 'res_id', - }, - }, - records: [ - {id: 13, foo: 'Meeting Room Furnitures', activity_ids: [1]}, - {id: 30, foo: 'Office planning', activity_ids: [2, 3]}, - ], + async beforeEach() { + pyEnv = await startServer(); + const mailTemplateIds = pyEnv['mail.template'].create([{ name: "Template1" }, { name: "Template2" }]); + // reset incompatible setup + pyEnv['mail.activity.type'].unlink(pyEnv['mail.activity.type'].search([])); + const mailActivityTypeIds = pyEnv['mail.activity.type'].create([ + { name: "Email", mail_template_ids: mailTemplateIds }, + { name: "Call" }, + { name: "Call for Demo" }, + { name: "To Do" }, + ]); + const resUsersId1 = pyEnv['res.users'].create({ display_name: 'first user' }); + const mailActivityIds = pyEnv['mail.activity'].create([ + { + display_name: "An activity", + date_deadline: moment().add(3, "days").format("YYYY-MM-DD"), // now + can_write: true, + state: "planned", + activity_type_id: mailActivityTypeIds[0], + mail_template_ids: mailTemplateIds, + user_id: resUsersId1, }, - partner: { - fields: { - display_name: { string: "Displayed name", type: "char" }, - }, - records: [{ - id: 2, - display_name: "first partner", - }] + { + display_name: "An activity", + date_deadline: moment().format("YYYY-MM-DD"), // now + can_write: true, + state: "today", + activity_type_id: mailActivityTypeIds[0], + mail_template_ids: mailTemplateIds, + user_id: resUsersId1, }, - 'mail.activity': { - fields: { - res_id: { string: 'Related document id', type: 'integer' }, - activity_type_id: { string: "Activity type", type: "many2one", relation: "mail.activity.type" }, - display_name: { string: "Display name", type: "char" }, - date_deadline: { string: "Due Date", type: "date" }, - can_write: { string: "Can write", type: "boolean" }, - state: { - string: 'State', - type: 'selection', - selection: [['overdue', 'Overdue'], ['today', 'Today'], ['planned', 'Planned']], - }, - mail_template_ids: { string: "Mail templates", type: "many2many", relation: "mail.template" }, - user_id: { string: "Assigned to", type: "many2one", relation: 'partner' }, - }, - records:[ - { - id: 1, - res_id: 13, - display_name: "An activity", - date_deadline: moment().add(3, "days").format("YYYY-MM-DD"), // now - can_write: true, - - state: "planned", - activity_type_id: 1, - mail_template_ids: [8, 9], - user_id:2, - },{ - id: 2, - res_id: 30, - display_name: "An activity", - date_deadline: moment().format("YYYY-MM-DD"), // now - can_write: true, - state: "today", - activity_type_id: 1, - mail_template_ids: [8, 9], - user_id:2, - },{ - id: 3, - res_id: 30, - display_name: "An activity", - date_deadline: moment().subtract(2, "days").format("YYYY-MM-DD"), // now - can_write: true, - state: "overdue", - activity_type_id: 2, - mail_template_ids: [], - user_id:2, - } - ], + { + res_model: 'mail.test.activity', + display_name: "An activity", + date_deadline: moment().subtract(2, "days").format("YYYY-MM-DD"), // now + can_write: true, + state: "overdue", + activity_type_id: mailActivityTypeIds[1], + user_id: resUsersId1, }, - 'mail.template': { - fields: { - name: { string: "Name", type: "char" }, - }, - records: [ - { id: 8, name: "Template1" }, - { id: 9, name: "Template2" }, - ], - }, - 'mail.activity.type': { - fields: { - mail_template_ids: { string: "Mail templates", type: "many2many", relation: "mail.template" }, - name: { string: "Name", type: "char" }, - }, - records: [ - { id: 1, name: "Email", mail_template_ids: [8, 9]}, - { id: 2, name: "Call" }, - { id: 3, name: "Call for Demo" }, - { id: 4, name: "To Do" }, - ], + ]); + pyEnv['mail.test.activity'].create([ + { name: 'Meeting Room Furnitures', activity_ids: [mailActivityIds[0]] }, + { name: 'Office planning', activity_ids: [mailActivityIds[1], mailActivityIds[2]] }, + ]); + serverData = { + views : { + 'mail.test.activity,false,activity': + '' + + '' + + '
' + + '' + + '
' + + '
' + + '
', + 'mail.activity,false,form': '
', + 'mail.test.activity,false,form': '', + 'mail.test.activity,false,search': '', }, }; - serverData = { models: this.data }; target = getFixture(); } }); @@ -126,14 +87,16 @@ var activityDateFormat = function (date) { QUnit.test('activity view: simple activity rendering', async function (assert) { assert.expect(14); - var activity = await createView({ + const mailTestActivityIds = pyEnv['mail.test.activity'].search([]); + const mailActivityTypeIds = pyEnv['mail.activity.type'].search([]); + var { widget: activity } = await start({ View: ActivityView, - model: 'task', - data: this.data, + hasView: true, + model: 'mail.test.activity', arch: '' + '' + '
' + - '' + + '' + '
' + '
' + '
', @@ -141,9 +104,9 @@ QUnit.test('activity view: simple activity rendering', async function (assert) { do_action: function (event) { assert.deepEqual(event.data.action, { context: { - default_res_id: 30, - default_res_model: "task", - default_activity_type_id: 3, + default_res_id: mailTestActivityIds[1], + default_res_model: "mail.test.activity", + default_activity_type_id: mailActivityTypeIds[2], }, res_id: false, res_model: "mail.activity", @@ -190,28 +153,22 @@ QUnit.test('activity view: simple activity rendering', async function (assert) { await testUtils.fields.editAndTrigger(activity.$(td + ':first'), null, ['mouseenter', 'click']); assert.containsOnce(activity, 'table tfoot tr .o_record_selector', 'should contain search more selector to choose the record to schedule an activity for it'); - - activity.destroy(); }); QUnit.test('activity view: no content rendering', async function (assert) { assert.expect(2); // reset incompatible setup - this.data['mail.activity'].records = []; - this.data.task.records.forEach(function (task) { - task.activity_ids = false; - }); - this.data['mail.activity.type'].records = []; + pyEnv['mail.activity.type'].unlink(pyEnv['mail.activity.type'].search([])); - var activity = await createView({ + var { widget: activity } = await start({ + hasView: true, View: ActivityView, - model: 'task', - data: this.data, + model: 'mail.test.activity', arch: '' + '' + '
' + - '' + + '' + '
' + '
' + '
', @@ -222,20 +179,21 @@ QUnit.test('activity view: no content rendering', async function (assert) { assert.strictEqual(activity.$('.o_view_nocontent .o_view_nocontent_empty_folder').text().trim(), "No data to display", "should display the no content helper text"); - - activity.destroy(); }); QUnit.test('activity view: batch send mail on activity', async function (assert) { assert.expect(6); - var activity = await createView({ + + const mailTestActivityIds = pyEnv['mail.test.activity'].search([]); + const mailTemplateIds = pyEnv['mail.template'].search([]); + var { widget: activity } = await start({ + hasView: true, View: ActivityView, - model: 'task', - data: this.data, + model: 'mail.test.activity', arch: '' + '' + '
' + - '' + + '' + '
' + '
' + '
', @@ -261,30 +219,31 @@ QUnit.test('activity view: batch send mail on activity', async function (assert) testUtils.dom.click(activity.$('table thead tr:first th:nth-child(2) span:nth-child(2) i.fa-ellipsis-v')); testUtils.dom.click(activity.$('table thead tr:first th:nth-child(2) span:nth-child(2) .dropdown-menu.show .o_send_mail_template:contains(Template1)')); assert.verifySteps([ - '[[13,30],9]', // send mail template 9 on tasks 13 and 30 - '[[13,30],8]', // send mail template 8 on tasks 13 and 30 + `[[${mailTestActivityIds[0]},${mailTestActivityIds[1]}],${mailTemplateIds[1]}]`, // send mail template 1 on mail.test.activity 1 and 2 + `[[${mailTestActivityIds[0]},${mailTestActivityIds[1]}],${mailTemplateIds[0]}]`, // send mail template 2 on mail.test.activity 1 and 2 ]); - - activity.destroy(); }); QUnit.test('activity view: activity widget', async function (assert) { assert.expect(16); + const mailActivityTypeIds = pyEnv['mail.activity.type'].search([]); + const [mailTestActivityId2] = pyEnv['mail.test.activity'].search([['name', '=', 'Office planning']]); + const [mailTemplateId1] = pyEnv['mail.template'].search([['name', '=', 'Template1']]); const params = { + hasView: true, View: ActivityView, - model: 'task', - data: this.data, + model: 'mail.test.activity', arch: '' + '' + '
' + - '' + + '' + '
' + '
'+ '
', mockRPC: function(route, args) { if (args.method === 'activity_send_mail'){ - assert.deepEqual([[30],8],args.args, "Should send template 8 on record 30"); + assert.deepEqual([[mailTestActivityId2],mailTemplateId1],args.args, "Should send template 8 on record 30"); assert.step('activity_send_mail'); return Promise.resolve(); } @@ -303,18 +262,18 @@ QUnit.test('activity view: activity widget', async function (assert) { assert.step('serverGeneratedAction'); } else if (action.res_model === 'mail.compose.message') { assert.deepEqual({ - default_model: "task", - default_res_id: 30, - default_template_id: 8, + default_model: 'mail.test.activity', + default_res_id: mailTestActivityId2, + default_template_id: mailTemplateId1, default_use_template: true, force_email: true }, action.context); assert.step("do_action_compose"); } else if (action.res_model === 'mail.activity') { assert.deepEqual({ - "default_activity_type_id": 2, - "default_res_id": 30, - "default_res_model": "task" + "default_activity_type_id": mailActivityTypeIds[1], + "default_res_id": mailTestActivityId2, + "default_res_model": 'mail.test.activity', }, action.context); assert.step("do_action_activity"); } else { @@ -324,7 +283,7 @@ QUnit.test('activity view: activity widget', async function (assert) { }, }; - var activity = await createView(params); + var { widget: activity } = await start(params); var today = activity.$('table tbody tr:first td:nth-child(2).today'); var dropdown = today.find('.dropdown-menu.o_activity'); @@ -367,25 +326,13 @@ QUnit.test("activity view: no group_by_menu and no comparison_menu", async funct serverData.actions = { 1: { id: 1, - name: "Task Action", - res_model: "task", + name: "MailTestActivity Action", + res_model: "mail.test.activity", type: "ir.actions.act_window", views: [[false, "activity"]], }, }; - serverData.views = { - "task,false,activity": - '' + - "" + - '
' + - '' + - "
" + - "
" + - "
", - "task,false,search": "", - }; - const mockRPC = (route, args) => { if (args.method === "get_activity_data") { assert.strictEqual( @@ -398,7 +345,7 @@ QUnit.test("activity view: no group_by_menu and no comparison_menu", async funct patchWithCleanup(session.user_context, { lang: "zz_ZZ" }); - const webClient = await createWebClient({ serverData, mockRPC , legacyParams: {withLegacyMockServer: true}}); + const { widget: webClient } = await start({ hasWebClient: true, serverData, mockRPC, legacyParams: {withLegacyMockServer: true}}); await doAction(webClient, 1); @@ -420,24 +367,24 @@ QUnit.test("activity view: no group_by_menu and no comparison_menu", async funct QUnit.test('activity view: search more to schedule an activity for a record of a respecting model', async function (assert) { assert.expect(5); - _.extend(this.data.task.fields, { - name: { string: "Name", type: "char" }, + const mailTestActivityId1 = pyEnv['mail.test.activity'].create({ name: 'MailTestActivity 3' }); + Object.assign(serverData.views, { + 'mail.test.activity,false,list': '', }); - this.data.task.records[2] = { id: 31, name: "Task 3" }; - var activity = await createView({ + var { widget: activity } = await start({ + hasView: true, View: ActivityView, - model: 'task', - data: this.data, + model: 'mail.test.activity', arch: '' + '' + '
' + - '' + + '' + '
' + '
' + '
', archs: { - "task,false,list": '', - "task,false,search": '', + "mail.test.activity,false,list": '', + "mail.test.activity,false,search": '', }, mockRPC: function(route, args) { if (args.method === 'name_search') { @@ -450,8 +397,8 @@ QUnit.test('activity view: search more to schedule an activity for a record of a assert.step('doAction'); var expectedAction = { context: { - default_res_id: { id: 31, display_name: undefined }, - default_res_model: "task", + default_res_id: { id: mailTestActivityId1, display_name: undefined }, + default_res_model: "mail.test.activity", }, name: "Schedule Activity", res_id: false, @@ -487,31 +434,22 @@ QUnit.test("Activity view: discard an activity creation dialog", async function serverData.actions = { 1: { id: 1, - name: "Task Action", - res_model: "task", + name: "MailTestActivity Action", + res_model: "mail.test.activity", type: "ir.actions.act_window", views: [[false, "activity"]], }, }; - serverData.views = { - "task,false,activity": ` - - -
- -
-
-
`, - "task,false,search": "", - "mail.activity,false,form": ` - - -
-
- `, - }; + Object.assign(serverData.views, { + 'mail.activity,false,form': + `
+ +
+
+ `, + }); const mockRPC = (route, args) => { if (args.method === "check_access_rights") { @@ -519,7 +457,7 @@ QUnit.test("Activity view: discard an activity creation dialog", async function } }; - const webClient = await createWebClient({ serverData, mockRPC, legacyParams: {withLegacyMockServer: true} }); + const { widget: webClient } = await start({ hasWebClient: true, serverData, mockRPC, legacyParams: {withLegacyMockServer: true} }); await doAction(webClient, 1); await testUtils.dom.click( @@ -536,51 +474,39 @@ QUnit.test("Activity view: discard an activity creation dialog", async function QUnit.test('Activity view: many2one_avatar_user widget in activity view', async function (assert) { assert.expect(3); - const taskModel = serverData.models.task; - - serverData.models['res.users'] = { - fields: { - display_name: { string: "Displayed name", type: "char" }, - avatar_128: { string: "Image 128", type: 'image' }, - }, - records: [{ - id: 1, - display_name: "first user", - avatar_128: "Atmaram Bhide", - }], - }; - taskModel.fields.user_id = { string: "Related User", type: "many2one", relation: 'res.users' }; - taskModel.records[0].user_id = 1; - + const [mailTestActivityId1] = pyEnv['mail.test.activity'].search([['name', '=', 'Meeting Room Furnitures']]); + const resUsersId1 = pyEnv['res.users'].create({ + display_name: "first user", + avatar_128: "Atmaram Bhide", + }); + pyEnv['mail.test.activity'].write([mailTestActivityId1], { activity_user_id: resUsersId1 }); + Object.assign(serverData.views, { + 'mail.test.activity,false,activity': + ` + +
+ + +
+
+
`, + }); serverData.actions = { 1: { id: 1, - name: 'Task Action', - res_model: 'task', + name: 'MailTestActivity Action', + res_model: 'mail.test.activity', type: 'ir.actions.act_window', views: [[false, 'activity']], } }; - serverData.views = { - 'task,false,activity': ` - - -
- - -
-
-
`, - 'task,false,search': '' - }; - - const webClient = await createWebClient({ serverData, legacyParams: { withLegacyMockServer: true } }); + const { widget: webClient } = await start({ hasWebClient: true, serverData, legacyParams: { withLegacyMockServer: true } }); await doAction(webClient, 1); await legacyExtraNextTick(); assert.containsN(target, '.o_m2o_avatar', 2); - assert.containsOnce(target, 'tr[data-res-id=13] .o_m2o_avatar > img[data-src="/web/image/res.users/1/avatar_128"]', + assert.containsOnce(target, `tr[data-res-id=${mailTestActivityId1}] .o_m2o_avatar > img[data-src="/web/image/res.users/${resUsersId1}/avatar_128"]`, "should have m2o avatar image"); assert.containsNone(target, '.o_m2o_avatar > span', "should not have text on many2one_avatar_user if onlyImage node option is passed"); @@ -590,13 +516,14 @@ QUnit.test("Activity view: on_destroy_callback doesn't crash", async function (a assert.expect(3); const params = { + hasView: true, View: ActivityView, - model: 'task', + model: 'mail.test.activity', data: this.data, arch: `
- +
`, @@ -614,7 +541,7 @@ QUnit.test("Activity view: on_destroy_callback doesn't crash", async function (a } }); - const activity = await createView(params); + const { widget: activity } = await start(params); domUtils.detach([{ widget: activity }]); assert.verifySteps([ @@ -627,21 +554,12 @@ QUnit.test("Activity view: on_destroy_callback doesn't crash", async function (a QUnit.test("Schedule activity dialog uses the same search view as activity view", async function (assert) { assert.expect(8); - serverData.models.task.records = []; - serverData.views = { - "task,false,activity": ` - - -
- -
-
-
- `, - "task,false,list": ``, - "task,false,search": ``, - 'task,1,search': ``, - }; + pyEnv['mail.test.activity'].unlink(pyEnv['mail.test.activity'].search([])); + Object.assign(serverData.views, { + "mail.test.activity,false,list": ``, + "mail.test.activity,false,search": ``, + 'mail.test.activity,1,search': ``, + }); function mockRPC(route, args) { if (args.method === "load_views") { @@ -649,12 +567,12 @@ QUnit.test("Schedule activity dialog uses the same search view as activity view" } } - const webClient = await createWebClient({ serverData, mockRPC, legacyParams: {withLegacyMockServer: true} }); + const { widget: webClient } = await start({ hasWebClient: true, serverData, mockRPC, legacyParams: {withLegacyMockServer: true} }); // open an activity view (with default search arch) await doAction(webClient, { name: 'Dashboard', - res_model: 'task', + res_model: 'mail.test.activity', type: 'ir.actions.act_window', views: [[false, 'activity']], }); @@ -673,7 +591,7 @@ QUnit.test("Schedule activity dialog uses the same search view as activity view" // open an activity view (with search arch 1) await doAction(webClient, { name: 'Dashboard', - res_model: 'task', + res_model: 'mail.test.activity', type: 'ir.actions.act_window', views: [[false, 'activity']], search_view_id: [1,"search"], @@ -697,25 +615,14 @@ QUnit.test('Activity view: apply progressbar filter', async function (assert) { serverData.actions = { 1: { id: 1, - name: 'Task Action', - res_model: 'task', + name: 'MailTestActivity Action', + res_model: 'mail.test.activity', type: 'ir.actions.act_window', views: [[false, 'activity']], } }; - serverData.views = { - 'task,false,activity': - ` - -
- -
-
-
`, - 'task,false,search': '', - }; - const webClient = await createWebClient({ serverData, legacyParams: { withLegacyMockServer: true } }); + const { widget: webClient } = await start({ hasWebClient:true, serverData, legacyParams: { withLegacyMockServer: true } }); await doAction(webClient, 1);