From 21c8b58566937126624bc879c6f5b23a01770cc2 Mon Sep 17 00:00:00 2001 From: Martin Schoeler Date: Tue, 20 Feb 2024 10:25:09 -0300 Subject: [PATCH 1/6] fix: setDepartment not persisting on chat closed --- packages/livechat/src/lib/hooks.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/livechat/src/lib/hooks.js b/packages/livechat/src/lib/hooks.js index 311cf0b2a00bc..67e3313719485 100644 --- a/packages/livechat/src/lib/hooks.js +++ b/packages/livechat/src/lib/hooks.js @@ -88,6 +88,7 @@ const api = { const department = departments.find((dep) => dep._id === value || dep.name === value)?._id || ''; updateIframeGuestData({ department }); + store.setState({ department }); if (defaultAgent && defaultAgent.department !== department) { store.setState({ defaultAgent: null }); From 161ec4785f0adb8c689bf492bb9e7547d9d9c479 Mon Sep 17 00:00:00 2001 From: Martin Schoeler Date: Tue, 20 Feb 2024 10:32:10 -0300 Subject: [PATCH 2/6] Create thin-keys-observe.md --- .changeset/thin-keys-impress.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/thin-keys-impress.md diff --git a/.changeset/thin-keys-impress.md b/.changeset/thin-keys-impress.md new file mode 100644 index 0000000000000..8679299972fcc --- /dev/null +++ b/.changeset/thin-keys-impress.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/livechat": patch +--- + +Fixes issue of the `setDepartment` Livechat API method not setting the store value properly (is was only setting on the guest object) From ddb33342ace33094e7da0567f935fb358acc8c73 Mon Sep 17 00:00:00 2001 From: Martin Schoeler Date: Thu, 29 Feb 2024 13:53:26 -0300 Subject: [PATCH 3/6] use default value if none --- packages/livechat/src/lib/room.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/livechat/src/lib/room.js b/packages/livechat/src/lib/room.js index af69cd8c4c18a..e5dc22ed850ba 100644 --- a/packages/livechat/src/lib/room.js +++ b/packages/livechat/src/lib/room.js @@ -25,13 +25,13 @@ export const closeChat = async ({ transcriptRequested } = {}) => { await handleTranscript(); } - const { config: { settings: { clearLocalStorageWhenChatEnded } = {} } = {} } = store.state; + const { department, config: { settings: { clearLocalStorageWhenChatEnded } = {} } = {} } = store.state; if (clearLocalStorageWhenChatEnded) { // exclude UI-affecting flags const { iframe: currentIframe } = store.state; const { minimized, visible, undocked, expanded, businessUnit, config, iframe, ...initial } = initialState(); - initial.iframe = { ...currentIframe, guest: {} }; + initial.iframe = { ...currentIframe, guest: { department } }; await store.setState(initial); } From 3804b436931bfe41a89bbd97896ef3c811c250b3 Mon Sep 17 00:00:00 2001 From: Martin Schoeler Date: Fri, 8 Mar 2024 16:21:35 -0300 Subject: [PATCH 4/6] tests --- .../omnichannel-livechat-api.spec.ts | 94 ++++++++++++++++--- 1 file changed, 80 insertions(+), 14 deletions(-) diff --git a/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-api.spec.ts b/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-api.spec.ts index c8810fa4eb779..be1e560bb2a8d 100644 --- a/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-api.spec.ts +++ b/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-api.spec.ts @@ -32,7 +32,7 @@ declare const window: Window & { setAgent: (agent: { username: string; _id: string }) => void; setBusinessUnit: (businessUnit?: string) => void; setCustomField: (field: { key: string; value: string }) => void; - setDepartment: (department: { _id: string; name: string }) => void; + setDepartment: (dep: string) => void; setGuestEmail: (email: string) => void; setGuestName: (name: string) => void; setGuestToken: (token: string) => void; @@ -55,9 +55,9 @@ declare const window: Window & { }; }; -test.describe('OC - Livechat API', () => { - // TODO: Check if there is a way to add livechat to the global window object - +test.describe.only('OC - Livechat API', () => { + // TODO: Check if there is a way to add livechat to the global window object + test.describe('Basic Widget Interactions', () => { // Tests that rely only on the widget itself, without requiring further interaction from the main RC app let poAuxContext: { page: Page; poHomeOmnichannel: HomeOmnichannel }; @@ -213,27 +213,49 @@ test.describe('OC - Livechat API', () => { test.skip(!IS_EE, 'Enterprise Only'); // Tests that requires interaction from an agent or more let poAuxContext: { page: Page; poHomeOmnichannel: HomeOmnichannel }; + let poAuxContext2: { page: Page; poHomeOmnichannel: HomeOmnichannel }; let poLiveChat: OmnichannelLiveChatEmbedded; let page: Page; let depId: string; + let dep2Id: string; let agent: Awaited>; + let agent2: Awaited>; test.beforeAll(async ({ api }) => { agent = await createAgent(api, 'user1') - - const response = await api.post('/livechat/department', {department: { + agent2 = await createAgent(api, 'user2') + + const dep1 = await api.post('/livechat/department', {department: { enabled: true, email: faker.internet.email(), showOnRegistration: true, showOnOfflineForm: true, name: `new department ${Date.now()}`, description: 'created from api', + }}); - - expect(response.status()).toBe(200); - const resBody = await response.json(); - depId = resBody.department._id; + const dep2 = await api.post('/livechat/department', {department: { + enabled: true, + email: faker.internet.email(), + showOnRegistration: true, + showOnOfflineForm: true, + name: `new department ${Date.now()}`, + description: 'created from api', + }}); + + expect(dep1.status()).toBe(200); + expect(dep2.status()).toBe(200); + + const dep1Body = await dep1.json(); + depId = dep1Body.department._id; + const dep2Body = await dep1.json(); + dep2Id = dep2Body.department._id; + + // Assign agents to deps + await api.post('/v1/livechat/department/:_id/agents', { departmentId: depId, agentId: 'user1' }); + await api.post('/v1/livechat/department/:_id/agents', { departmentId: dep2Id, agentId: 'user2' }); + await expect((await api.post('/settings/Enable_CSP', { value: false })).status()).toBe(200); await expect((await api.post('/settings/Livechat_offline_email', { value: 'test@testing.com' })).status()).toBe(200); }); @@ -253,6 +275,11 @@ test.describe('OC - Livechat API', () => { await poAuxContext.poHomeOmnichannel.sidenav.switchStatus('online'); } + if (testInfo.title === 'OC - Livechat API - setDepartment') { + const { page: pageCtx2 } = await createAuxContext(browser, Users.user2); + poAuxContext2 = { page: pageCtx2, poHomeOmnichannel: new HomeOmnichannel(pageCtx) }; + } + await page.goto('/packages/rocketchat_livechat/assets/demo.html'); }); @@ -264,6 +291,7 @@ test.describe('OC - Livechat API', () => { test.afterAll(async ({ api }) => { await expect((await api.post('/settings/Enable_CSP', { value: true })).status()).toBe(200); await agent.delete(); + await agent2.delete(); await expect((await api.post('/settings/Omnichannel_enable_department_removal', { value: true })).status()).toBe(200); const response = await api.delete(`/livechat/department/${depId}`, { name: 'TestDep', email: 'TestDep@email.com' }); expect(response.status()).toBe(200); @@ -315,6 +343,44 @@ test.describe('OC - Livechat API', () => { }); }); + test('OC - Livechat API - setDepartment', async () => { + + const registerGuestVisitor = { + name: faker.person.firstName(), + email: faker.internet.email(), + token: faker.string.uuid(), + }; + + // Start Chat + await poLiveChat.page.evaluate(() => window.RocketChat.livechat.maximizeWidget()); + await expect(page.frameLocator('#rocketchat-iframe').getByText('Start Chat')).toBeVisible(); + + await poLiveChat.page.evaluate( + (registerGuestVisitor) => window.RocketChat.livechat.registerGuest(registerGuestVisitor), + registerGuestVisitor, + ); + + await expect(page.frameLocator('#rocketchat-iframe').getByText('Start Chat')).not.toBeVisible(); + + await poLiveChat.onlineAgentMessage.type('this_a_test_message_from_visitor'); + await poLiveChat.btnSendMessageToOnlineAgent.click(); + + await test.step('Expect registered guest to be in dep1', async () => { + await poAuxContext.poHomeOmnichannel.sidenav.openChat(registerGuestVisitor.name); + }); + + await test.step('Expect setDepartment to change a guest department', async () => { + await poLiveChat.page.evaluate( + (depId) => window.RocketChat.livechat.setDepartment(depId), + depId, + ); + }); + + await test.step('Expect registered guest to be in dep2', async () => { + await poAuxContext2.poHomeOmnichannel.sidenav.openChat(registerGuestVisitor.name); + }); + }); + test('OC - Livechat API - registerGuest', async ({ browser }) => { const registerGuestVisitor = { name: faker.person.firstName(), @@ -495,14 +561,14 @@ test.describe('OC - Livechat API', () => { const { page: pageCtx } = await createAuxContext(browser, Users.user1); poAuxContext = { page: pageCtx, poHomeOmnichannel: new HomeOmnichannel(pageCtx) }; - + // This is needed since the livechat will not react to online/offline status changes if already loaded in a page if (testInfo.title === 'Expect onOfflineFormSubmit to trigger callback') { await poAuxContext.poHomeOmnichannel.sidenav.switchStatus('offline'); } else { await poAuxContext.poHomeOmnichannel.sidenav.switchStatus('online'); } - + await page.goto('/packages/rocketchat_livechat/assets/demo.html'); }); @@ -635,7 +701,7 @@ test.describe('OC - Livechat API', () => { await poLiveChat.sendMessage(newVisitor, false); await poLiveChat.onlineAgentMessage.type('this_a_test_message_from_visitor'); await poLiveChat.btnSendMessageToOnlineAgent.click(); - + const watchForTrigger = page.waitForFunction(() => window.onAgentStatusChange === true); @@ -717,5 +783,5 @@ test.describe('OC - Livechat API', () => { }); }); }); - + }); From 4c8cf92df8162f27102597a7e82b047b3cbe4878 Mon Sep 17 00:00:00 2001 From: Martin Schoeler Date: Fri, 8 Mar 2024 18:38:09 -0300 Subject: [PATCH 5/6] use createdep --- .../omnichannel-livechat-api.spec.ts | 51 ++++++------------- 1 file changed, 15 insertions(+), 36 deletions(-) diff --git a/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-api.spec.ts b/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-api.spec.ts index be1e560bb2a8d..3d38ee3a37bc9 100644 --- a/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-api.spec.ts +++ b/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-api.spec.ts @@ -6,6 +6,7 @@ import { createAuxContext } from '../fixtures/createAuxContext'; import { Users } from '../fixtures/userStates'; import { HomeOmnichannel, OmnichannelLiveChatEmbedded } from '../page-objects'; import { createAgent } from '../utils/omnichannel/agents'; +import { addAgentToDepartment, createDepartment } from '../utils/omnichannel/departments'; import { test, expect } from '../utils/test'; // TODO: Use official widget typing once that is merged @@ -55,7 +56,7 @@ declare const window: Window & { }; }; -test.describe.only('OC - Livechat API', () => { +test.describe('OC - Livechat API', () => { // TODO: Check if there is a way to add livechat to the global window object test.describe('Basic Widget Interactions', () => { @@ -210,51 +211,26 @@ test.describe.only('OC - Livechat API', () => { test.describe('Complex Widget Interactions', () => { // Needs Departments to test this, so needs an EE license for multiple deps - test.skip(!IS_EE, 'Enterprise Only'); + // test.skip(!IS_EE, 'Enterprise Only'); // Tests that requires interaction from an agent or more let poAuxContext: { page: Page; poHomeOmnichannel: HomeOmnichannel }; let poAuxContext2: { page: Page; poHomeOmnichannel: HomeOmnichannel }; let poLiveChat: OmnichannelLiveChatEmbedded; let page: Page; - let depId: string; - let dep2Id: string; let agent: Awaited>; let agent2: Awaited>; + let departments: Awaited>[]; + test.beforeAll(async ({ api }) => { agent = await createAgent(api, 'user1') agent2 = await createAgent(api, 'user2') - const dep1 = await api.post('/livechat/department', {department: { - enabled: true, - email: faker.internet.email(), - showOnRegistration: true, - showOnOfflineForm: true, - name: `new department ${Date.now()}`, - description: 'created from api', - - }}); - - const dep2 = await api.post('/livechat/department', {department: { - enabled: true, - email: faker.internet.email(), - showOnRegistration: true, - showOnOfflineForm: true, - name: `new department ${Date.now()}`, - description: 'created from api', - }}); - - expect(dep1.status()).toBe(200); - expect(dep2.status()).toBe(200); - - const dep1Body = await dep1.json(); - depId = dep1Body.department._id; - const dep2Body = await dep1.json(); - dep2Id = dep2Body.department._id; + departments = await Promise.all([createDepartment(api), createDepartment(api)]); + const [departmentA, departmentB] = departments.map(({ data }) => data); - // Assign agents to deps - await api.post('/v1/livechat/department/:_id/agents', { departmentId: depId, agentId: 'user1' }); - await api.post('/v1/livechat/department/:_id/agents', { departmentId: dep2Id, agentId: 'user2' }); + await addAgentToDepartment(api, { department: departmentA, agentId: agent.data._id }) + await addAgentToDepartment(api, { department: departmentB, agentId: agent2.data._id }) await expect((await api.post('/settings/Enable_CSP', { value: false })).status()).toBe(200); await expect((await api.post('/settings/Livechat_offline_email', { value: 'test@testing.com' })).status()).toBe(200); @@ -292,9 +268,9 @@ test.describe.only('OC - Livechat API', () => { await expect((await api.post('/settings/Enable_CSP', { value: true })).status()).toBe(200); await agent.delete(); await agent2.delete(); + await expect((await api.post('/settings/Omnichannel_enable_department_removal', { value: true })).status()).toBe(200); - const response = await api.delete(`/livechat/department/${depId}`, { name: 'TestDep', email: 'TestDep@email.com' }); - expect(response.status()).toBe(200); + await Promise.all([...departments.map((department) => department.delete())]); await expect((await api.post('/settings/Omnichannel_enable_department_removal', { value: false })).status()).toBe(200); }); @@ -344,11 +320,12 @@ test.describe.only('OC - Livechat API', () => { }); test('OC - Livechat API - setDepartment', async () => { - + const [departmentA, departmentB] = departments.map(({ data }) => data); const registerGuestVisitor = { name: faker.person.firstName(), email: faker.internet.email(), token: faker.string.uuid(), + department: departmentA._id, }; // Start Chat @@ -369,6 +346,8 @@ test.describe.only('OC - Livechat API', () => { await poAuxContext.poHomeOmnichannel.sidenav.openChat(registerGuestVisitor.name); }); + const depId = departmentB._id; + await test.step('Expect setDepartment to change a guest department', async () => { await poLiveChat.page.evaluate( (depId) => window.RocketChat.livechat.setDepartment(depId), From e04494f94738fa10249f0917db3bb93fe3d26eb1 Mon Sep 17 00:00:00 2001 From: Martin Schoeler Date: Fri, 8 Mar 2024 18:54:01 -0300 Subject: [PATCH 6/6] oops --- .../tests/e2e/omnichannel/omnichannel-livechat-api.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-api.spec.ts b/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-api.spec.ts index 3d38ee3a37bc9..a8fa27eb5d2c7 100644 --- a/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-api.spec.ts +++ b/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-api.spec.ts @@ -211,7 +211,7 @@ test.describe('OC - Livechat API', () => { test.describe('Complex Widget Interactions', () => { // Needs Departments to test this, so needs an EE license for multiple deps - // test.skip(!IS_EE, 'Enterprise Only'); + test.skip(!IS_EE, 'Enterprise Only'); // Tests that requires interaction from an agent or more let poAuxContext: { page: Page; poHomeOmnichannel: HomeOmnichannel }; let poAuxContext2: { page: Page; poHomeOmnichannel: HomeOmnichannel };