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);