From 6592600c4ac4ed7203ab63ae601508b29149fb6c Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Thu, 24 Oct 2024 15:23:27 -0600 Subject: [PATCH 1/8] restore waiting queue behavior --- .../app/livechat/server/lib/QueueManager.ts | 44 ++++++++++++++++--- .../app/livechat/server/lib/RoutingManager.ts | 2 +- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/apps/meteor/app/livechat/server/lib/QueueManager.ts b/apps/meteor/app/livechat/server/lib/QueueManager.ts index 24be8d42b7a4..d2aae06f5b5f 100644 --- a/apps/meteor/app/livechat/server/lib/QueueManager.ts +++ b/apps/meteor/app/livechat/server/lib/QueueManager.ts @@ -133,11 +133,7 @@ export class QueueManager { return LivechatInquiryStatus.READY; } - static async queueInquiry(inquiry: ILivechatInquiryRecord, room: IOmnichannelRoom, defaultAgent?: SelectedAgent | null) { - if (inquiry.status === 'ready') { - return RoutingManager.delegateInquiry(inquiry, defaultAgent, undefined, room); - } - + static async notifyQueuedInquiry(inquiry: ILivechatInquiryRecord, room: IOmnichannelRoom, defaultAgent?: SelectedAgent | null) { await callbacks.run('livechat.afterInquiryQueued', inquiry); void callbacks.run('livechat.chatQueued', room); @@ -145,6 +141,34 @@ export class QueueManager { await this.dispatchInquiryQueued(inquiry, room, defaultAgent); } + static async queueInquiry(inquiry: ILivechatInquiryRecord, room: IOmnichannelRoom, defaultAgent?: SelectedAgent | null) { + if (!(await Omnichannel.isWithinMACLimit(room))) { + logger.error({ msg: 'MAC limit reached, not routing inquiry', inquiry }); + // We'll queue these inquiries so when new license is applied, they just start rolling again + // Minimizing disruption + await saveQueueInquiry(inquiry); + await this.notifyQueuedInquiry(inquiry, room, defaultAgent); + return; + } + + await callbacks.run('livechat.beforeRouteChat', inquiry, defaultAgent); + const dbInquiry = await LivechatInquiry.findOneById(inquiry._id); + + if (!dbInquiry) { + throw new Error('inquiry-not-found'); + } + + if (dbInquiry.status === 'ready') { + logger.debug({ msg: 'Inquiry is ready. Delegating', inquiry, defaultAgent }); + return RoutingManager.delegateInquiry(dbInquiry, defaultAgent, undefined, room); + } + + if (dbInquiry.status === 'queued') { + logger.debug(`Inquiry with id ${inquiry._id} is queued. Notifying`); + await this.notifyQueuedInquiry(inquiry, room, defaultAgent); + } + } + static async requestRoom({ guest, rid = Random.id(), @@ -252,7 +276,11 @@ export class QueueManager { throw new Error('room-not-found'); } - if (!newRoom.servedBy && settings.get('Omnichannel_calculate_dispatch_service_queue_statistics')) { + if ( + !newRoom.servedBy && + settings.get('Livechat_waiting_queue') && + settings.get('Omnichannel_calculate_dispatch_service_queue_statistics') + ) { const [inq] = await LivechatInquiry.getCurrentSortedQueueAsync({ inquiryId: inquiry._id, department, @@ -320,6 +348,10 @@ export class QueueManager { } private static dispatchInquiryQueued = async (inquiry: ILivechatInquiryRecord, room: IOmnichannelRoom, agent?: SelectedAgent | null) => { + if (RoutingManager.getConfig()?.autoAssignAgent) { + return; + } + logger.debug(`Notifying agents of new inquiry ${inquiry._id} queued`); const { department, rid, v } = inquiry; diff --git a/apps/meteor/app/livechat/server/lib/RoutingManager.ts b/apps/meteor/app/livechat/server/lib/RoutingManager.ts index 8781f675ebf9..ece6e05c33b5 100644 --- a/apps/meteor/app/livechat/server/lib/RoutingManager.ts +++ b/apps/meteor/app/livechat/server/lib/RoutingManager.ts @@ -57,7 +57,7 @@ type Routing = { room: IOmnichannelRoom, ): Promise; transferRoom(room: IOmnichannelRoom, guest: ILivechatVisitor, transferData: TransferData): Promise; - delegateAgent(agent: SelectedAgent | undefined, inquiry: ILivechatInquiryRecord): Promise; + delegateAgent(agent: SelectedAgent | undefined | null, inquiry: ILivechatInquiryRecord): Promise; removeAllRoomSubscriptions(room: Pick, ignoreUser?: { _id: string }): Promise; assignAgent(inquiry: InquiryWithAgentInfo, room: IOmnichannelRoom, agent: SelectedAgent): Promise; From 72d747bb149d6cb671bfe03069d1e93e26c9176a Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Fri, 25 Oct 2024 13:34:22 -0600 Subject: [PATCH 2/8] return inq --- apps/meteor/app/livechat/server/lib/QueueManager.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/meteor/app/livechat/server/lib/QueueManager.ts b/apps/meteor/app/livechat/server/lib/QueueManager.ts index d2aae06f5b5f..18dd1c970597 100644 --- a/apps/meteor/app/livechat/server/lib/QueueManager.ts +++ b/apps/meteor/app/livechat/server/lib/QueueManager.ts @@ -94,8 +94,7 @@ export class QueueManager { const inquiryAgent = await RoutingManager.delegateAgent(defaultAgent, inquiry); logger.debug(`Delegating inquiry with id ${inquiry._id} to agent ${defaultAgent?.username}`); - await callbacks.run('livechat.beforeRouteChat', inquiry, inquiryAgent); - const dbInquiry = await LivechatInquiry.findOneById(inquiry._id); + const dbInquiry = await callbacks.run('livechat.beforeRouteChat', inquiry, inquiryAgent); if (!dbInquiry) { throw new Error('inquiry-not-found'); @@ -151,8 +150,7 @@ export class QueueManager { return; } - await callbacks.run('livechat.beforeRouteChat', inquiry, defaultAgent); - const dbInquiry = await LivechatInquiry.findOneById(inquiry._id); + const dbInquiry = await callbacks.run('livechat.beforeRouteChat', inquiry, defaultAgent); if (!dbInquiry) { throw new Error('inquiry-not-found'); From aa52f0d304127e5d6f9ca24439365992c3592870 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Fri, 25 Oct 2024 17:26:11 -0600 Subject: [PATCH 3/8] tests --- .../server/hooks/beforeRoutingChat.ts | 2 + apps/meteor/playwright.config.ts | 2 +- ...hat-queue-management-autoselection.spec.ts | 120 ++++++++++++++++++ docker-compose-local-monolith.yml | 30 +++++ 4 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-queue-management-autoselection.spec.ts create mode 100644 docker-compose-local-monolith.yml diff --git a/apps/meteor/ee/app/livechat-enterprise/server/hooks/beforeRoutingChat.ts b/apps/meteor/ee/app/livechat-enterprise/server/hooks/beforeRoutingChat.ts index e288e08de89b..444d310b3c5f 100644 --- a/apps/meteor/ee/app/livechat-enterprise/server/hooks/beforeRoutingChat.ts +++ b/apps/meteor/ee/app/livechat-enterprise/server/hooks/beforeRoutingChat.ts @@ -63,6 +63,8 @@ callbacks.add( } await saveQueueInquiry(inquiry); + + return LivechatInquiry.findOneById(inquiry._id); }, callbacks.priority.HIGH, 'livechat-before-routing-chat', diff --git a/apps/meteor/playwright.config.ts b/apps/meteor/playwright.config.ts index 822f78e28741..18a5160ad442 100644 --- a/apps/meteor/playwright.config.ts +++ b/apps/meteor/playwright.config.ts @@ -6,7 +6,7 @@ export default { globalSetup: require.resolve('./tests/e2e/config/global-setup.ts'), use: { channel: 'chromium', - headless: true, + headless: false, ignoreHTTPSErrors: true, trace: 'retain-on-failure', baseURL: constants.BASE_URL, diff --git a/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-queue-management-autoselection.spec.ts b/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-queue-management-autoselection.spec.ts new file mode 100644 index 000000000000..69b1b9eb7481 --- /dev/null +++ b/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-queue-management-autoselection.spec.ts @@ -0,0 +1,120 @@ +import { createFakeVisitor } from '../../mocks/data'; +import { IS_EE } from '../config/constants'; +import { createAuxContext } from '../fixtures/createAuxContext'; +import { Users } from '../fixtures/userStates'; +import { HomeOmnichannel, OmnichannelLiveChat } from '../page-objects'; +import { test, expect } from '../utils/test'; + +const firstVisitor = createFakeVisitor(); + +const secondVisitor = createFakeVisitor(); + +test.use({ storageState: Users.user1.state }); + +test.describe('OC - Livechat - Queue Management', () => { + test.skip(!IS_EE, 'Enterprise Only'); + + let poHomeOmnichannel: HomeOmnichannel; + let poLiveChat: OmnichannelLiveChat; + + const waitingQueueMessage = 'This is a message from Waiting Queue'; + const queuePosition1 = 'Your spot is #1'; + const queuePosition2 = 'Your spot is #2'; + + test.beforeAll(async ({ api, browser }) => { + await Promise.all([ + api.post('/settings/Livechat_Routing_Method', { value: 'Auto_Selection' }), + api.post('/settings/Livechat_accept_chats_with_no_agents', { value: true }), + api.post('/settings/Livechat_waiting_queue', { value: true }), + api.post('/settings/Livechat_waiting_queue_message', { value: waitingQueueMessage }), + api.post('/livechat/users/agent', { username: 'user1' }), + ]); + + const { page: omniPage } = await createAuxContext(browser, Users.user1, '/', true); + poHomeOmnichannel = new HomeOmnichannel(omniPage); + + // Agent will be offline for these tests + await poHomeOmnichannel.sidenav.switchOmnichannelStatus('offline'); + }); + + test.beforeEach(async ({ browser, api }) => { + const context = await browser.newContext(); + const page2 = await context.newPage(); + + poLiveChat = new OmnichannelLiveChat(page2, api); + await poLiveChat.page.goto('/livechat'); + }); + + test.afterAll(async ({ api }) => { + await Promise.all([ + api.post('/settings/Livechat_waiting_queue', { value: false }), + api.post('/settings/Livechat_waiting_queue_message', { value: '' }), + api.delete('/livechat/users/agent/user1'), + ]); + await poHomeOmnichannel.page.close(); + }); + + test.describe('OC - Queue Management - Auto Selection', () => { + let poLiveChat2: OmnichannelLiveChat; + + test.beforeEach(async ({ browser, api }) => { + const context = await browser.newContext(); + const page = await context.newPage(); + poLiveChat2 = new OmnichannelLiveChat(page, api); + await poLiveChat2.page.goto('/livechat'); + }); + + test.afterEach(async () => { + await poLiveChat2.closeChat(); + await poLiveChat2.page.close(); + await poLiveChat.closeChat(); + await poLiveChat.page.close(); + }); + + test('Update user position on Queue', async () => { + await test.step('should start livechat session', async () => { + await poLiveChat.openAnyLiveChatAndSendMessage({ + liveChatUser: firstVisitor, + message: 'Test message', + isOffline: false, + }); + }); + + await test.step('expect to receive Waiting Queue message on chat', async () => { + await expect(poLiveChat.page.locator(`div >> text=${waitingQueueMessage}`)).toBeVisible(); + }); + + await test.step('expect to be on spot #1', async () => { + await expect(poLiveChat.page.locator(`div[role='alert'] >> text=${queuePosition1}`)).toBeVisible(); + }); + + await test.step('should start secondary livechat session', async () => { + await poLiveChat2.openAnyLiveChatAndSendMessage({ + liveChatUser: secondVisitor, + message: 'Test message', + isOffline: false, + }); + }); + + await test.step('should start secondary livechat on spot #2', async () => { + await expect(poLiveChat2.page.locator(`div[role='alert'] >> text=${queuePosition2}`)).toBeVisible(); + }); + + await test.step('should start the queue by making the agent available again', async () => { + await poHomeOmnichannel.sidenav.switchOmnichannelStatus('online'); + }); + + await test.step('user1 should get assigned to the first chat', async () => { + await expect(poLiveChat.page.locator(`div[role='alert'] >> text=${queuePosition1}`)).not.toBeVisible(); + }); + + await test.step('secondary session should be on position #1', async () => { + await expect(poLiveChat2.page.locator(`div[role='alert'] >> text=${queuePosition1}`)).toBeVisible(); + }); + + await test.step('secondary session should be taken by user1', async () => { + await expect(poLiveChat2.page.locator(`div[role='alert'] >> text=${queuePosition1}`)).not.toBeVisible(); + }); + }); + }); +}); diff --git a/docker-compose-local-monolith.yml b/docker-compose-local-monolith.yml new file mode 100644 index 000000000000..d248e386e61f --- /dev/null +++ b/docker-compose-local-monolith.yml @@ -0,0 +1,30 @@ +version: '3.8' + +services: + rocketchat: + platform: linux/amd64 + image: rocketchat/rocket.chat:6.9.2 + environment: + - TEST_MODE=true + - EXIT_UNHANDLEDPROMISEREJECTION=true + - 'MONGO_URL=${MONGO_URL}' + - OVERWRITE_SETTING_Log_Level=2 + extra_hosts: + - 'host.docker.internal:host-gateway' + depends_on: + - mongo + ports: + - '3000:3000' + + mongo: + image: docker.io/bitnami/mongodb:7.0 + restart: on-failure + environment: + MONGODB_REPLICA_SET_MODE: primary + MONGODB_REPLICA_SET_NAME: ${MONGODB_REPLICA_SET_NAME:-rs0} + MONGODB_PORT_NUMBER: ${MONGODB_PORT_NUMBER:-27017} + MONGODB_INITIAL_PRIMARY_HOST: ${MONGODB_INITIAL_PRIMARY_HOST:-mongo} + MONGODB_INITIAL_PRIMARY_PORT_NUMBER: ${MONGODB_INITIAL_PRIMARY_PORT_NUMBER:-27017} + MONGODB_ADVERTISED_HOSTNAME: ${MONGODB_ADVERTISED_HOSTNAME:-mongo} + MONGODB_ENABLE_JOURNAL: ${MONGODB_ENABLE_JOURNAL:-true} + ALLOW_EMPTY_PASSWORD: ${ALLOW_EMPTY_PASSWORD:-yes} From ebe35b1908952b256ad96aff78c9129b1d91de6a Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Fri, 25 Oct 2024 17:44:55 -0600 Subject: [PATCH 4/8] Discard changes to apps/meteor/playwright.config.ts --- apps/meteor/playwright.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/meteor/playwright.config.ts b/apps/meteor/playwright.config.ts index 18a5160ad442..822f78e28741 100644 --- a/apps/meteor/playwright.config.ts +++ b/apps/meteor/playwright.config.ts @@ -6,7 +6,7 @@ export default { globalSetup: require.resolve('./tests/e2e/config/global-setup.ts'), use: { channel: 'chromium', - headless: false, + headless: true, ignoreHTTPSErrors: true, trace: 'retain-on-failure', baseURL: constants.BASE_URL, From 9ef9de02aa7657093242f770293c7aec9f60ab86 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Mon, 28 Oct 2024 12:37:42 -0600 Subject: [PATCH 5/8] better --- .../app/livechat/server/lib/QueueManager.ts | 38 +++++-------------- .../app/livechat/server/lib/RoutingManager.ts | 2 +- 2 files changed, 11 insertions(+), 29 deletions(-) diff --git a/apps/meteor/app/livechat/server/lib/QueueManager.ts b/apps/meteor/app/livechat/server/lib/QueueManager.ts index 18dd1c970597..a467b6e0b360 100644 --- a/apps/meteor/app/livechat/server/lib/QueueManager.ts +++ b/apps/meteor/app/livechat/server/lib/QueueManager.ts @@ -121,6 +121,10 @@ export class QueueManager { return LivechatInquiryStatus.QUEUED; } + if (settings.get('Livechat_waiting_queue')) { + return LivechatInquiryStatus.QUEUED; + } + if (RoutingManager.getConfig()?.autoAssignAgent) { return LivechatInquiryStatus.READY; } @@ -132,39 +136,17 @@ export class QueueManager { return LivechatInquiryStatus.READY; } - static async notifyQueuedInquiry(inquiry: ILivechatInquiryRecord, room: IOmnichannelRoom, defaultAgent?: SelectedAgent | null) { - await callbacks.run('livechat.afterInquiryQueued', inquiry); - - void callbacks.run('livechat.chatQueued', room); - - await this.dispatchInquiryQueued(inquiry, room, defaultAgent); - } - static async queueInquiry(inquiry: ILivechatInquiryRecord, room: IOmnichannelRoom, defaultAgent?: SelectedAgent | null) { - if (!(await Omnichannel.isWithinMACLimit(room))) { - logger.error({ msg: 'MAC limit reached, not routing inquiry', inquiry }); - // We'll queue these inquiries so when new license is applied, they just start rolling again - // Minimizing disruption - await saveQueueInquiry(inquiry); - await this.notifyQueuedInquiry(inquiry, room, defaultAgent); - return; + if (inquiry.status === 'ready') { + logger.debug({ msg: 'Inquiry is ready. Delegating', inquiry, defaultAgent }); + return RoutingManager.delegateInquiry(inquiry, defaultAgent, undefined, room); } - const dbInquiry = await callbacks.run('livechat.beforeRouteChat', inquiry, defaultAgent); - - if (!dbInquiry) { - throw new Error('inquiry-not-found'); - } + await callbacks.run('livechat.afterInquiryQueued', inquiry); - if (dbInquiry.status === 'ready') { - logger.debug({ msg: 'Inquiry is ready. Delegating', inquiry, defaultAgent }); - return RoutingManager.delegateInquiry(dbInquiry, defaultAgent, undefined, room); - } + void callbacks.run('livechat.chatQueued', room); - if (dbInquiry.status === 'queued') { - logger.debug(`Inquiry with id ${inquiry._id} is queued. Notifying`); - await this.notifyQueuedInquiry(inquiry, room, defaultAgent); - } + await this.dispatchInquiryQueued(inquiry, room, defaultAgent); } static async requestRoom({ diff --git a/apps/meteor/app/livechat/server/lib/RoutingManager.ts b/apps/meteor/app/livechat/server/lib/RoutingManager.ts index ece6e05c33b5..8781f675ebf9 100644 --- a/apps/meteor/app/livechat/server/lib/RoutingManager.ts +++ b/apps/meteor/app/livechat/server/lib/RoutingManager.ts @@ -57,7 +57,7 @@ type Routing = { room: IOmnichannelRoom, ): Promise; transferRoom(room: IOmnichannelRoom, guest: ILivechatVisitor, transferData: TransferData): Promise; - delegateAgent(agent: SelectedAgent | undefined | null, inquiry: ILivechatInquiryRecord): Promise; + delegateAgent(agent: SelectedAgent | undefined, inquiry: ILivechatInquiryRecord): Promise; removeAllRoomSubscriptions(room: Pick, ignoreUser?: { _id: string }): Promise; assignAgent(inquiry: InquiryWithAgentInfo, room: IOmnichannelRoom, agent: SelectedAgent): Promise; From 711f5657ba15b029d1d10eb865a099c2dc569dba Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Mon, 28 Oct 2024 12:38:24 -0600 Subject: [PATCH 6/8] Delete docker-compose-local-monolith.yml --- docker-compose-local-monolith.yml | 30 ------------------------------ 1 file changed, 30 deletions(-) delete mode 100644 docker-compose-local-monolith.yml diff --git a/docker-compose-local-monolith.yml b/docker-compose-local-monolith.yml deleted file mode 100644 index d248e386e61f..000000000000 --- a/docker-compose-local-monolith.yml +++ /dev/null @@ -1,30 +0,0 @@ -version: '3.8' - -services: - rocketchat: - platform: linux/amd64 - image: rocketchat/rocket.chat:6.9.2 - environment: - - TEST_MODE=true - - EXIT_UNHANDLEDPROMISEREJECTION=true - - 'MONGO_URL=${MONGO_URL}' - - OVERWRITE_SETTING_Log_Level=2 - extra_hosts: - - 'host.docker.internal:host-gateway' - depends_on: - - mongo - ports: - - '3000:3000' - - mongo: - image: docker.io/bitnami/mongodb:7.0 - restart: on-failure - environment: - MONGODB_REPLICA_SET_MODE: primary - MONGODB_REPLICA_SET_NAME: ${MONGODB_REPLICA_SET_NAME:-rs0} - MONGODB_PORT_NUMBER: ${MONGODB_PORT_NUMBER:-27017} - MONGODB_INITIAL_PRIMARY_HOST: ${MONGODB_INITIAL_PRIMARY_HOST:-mongo} - MONGODB_INITIAL_PRIMARY_PORT_NUMBER: ${MONGODB_INITIAL_PRIMARY_PORT_NUMBER:-27017} - MONGODB_ADVERTISED_HOSTNAME: ${MONGODB_ADVERTISED_HOSTNAME:-mongo} - MONGODB_ENABLE_JOURNAL: ${MONGODB_ENABLE_JOURNAL:-true} - ALLOW_EMPTY_PASSWORD: ${ALLOW_EMPTY_PASSWORD:-yes} From 5c65a2b1e99fb770b3a473aea8da8bb46225aa5a Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Mon, 28 Oct 2024 13:31:59 -0600 Subject: [PATCH 7/8] Create stale-actors-enjoy.md --- .changeset/stale-actors-enjoy.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/stale-actors-enjoy.md diff --git a/.changeset/stale-actors-enjoy.md b/.changeset/stale-actors-enjoy.md new file mode 100644 index 000000000000..baff2b19b667 --- /dev/null +++ b/.changeset/stale-actors-enjoy.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixes `waiting queue` feature. When `Livechat_waiting_queue` setting is enabled, incoming conversations should be sent to the queue instead of being assigned directly. From 0f1e34f7d5301d191a451bc2c8d1f02f677061c8 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Tue, 5 Nov 2024 14:16:14 -0600 Subject: [PATCH 8/8] cr --- ...l-livechat-queue-management-autoselection.spec.ts | 12 +++++------- .../tests/e2e/page-objects/omnichannel-livechat.ts | 9 ++++++++- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-queue-management-autoselection.spec.ts b/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-queue-management-autoselection.spec.ts index 69b1b9eb7481..62bf3111cab7 100644 --- a/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-queue-management-autoselection.spec.ts +++ b/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-queue-management-autoselection.spec.ts @@ -18,8 +18,6 @@ test.describe('OC - Livechat - Queue Management', () => { let poLiveChat: OmnichannelLiveChat; const waitingQueueMessage = 'This is a message from Waiting Queue'; - const queuePosition1 = 'Your spot is #1'; - const queuePosition2 = 'Your spot is #2'; test.beforeAll(async ({ api, browser }) => { await Promise.all([ @@ -85,7 +83,7 @@ test.describe('OC - Livechat - Queue Management', () => { }); await test.step('expect to be on spot #1', async () => { - await expect(poLiveChat.page.locator(`div[role='alert'] >> text=${queuePosition1}`)).toBeVisible(); + await expect(poLiveChat.queuePosition(1)).toBeVisible(); }); await test.step('should start secondary livechat session', async () => { @@ -97,7 +95,7 @@ test.describe('OC - Livechat - Queue Management', () => { }); await test.step('should start secondary livechat on spot #2', async () => { - await expect(poLiveChat2.page.locator(`div[role='alert'] >> text=${queuePosition2}`)).toBeVisible(); + await expect(poLiveChat2.queuePosition(2)).toBeVisible(); }); await test.step('should start the queue by making the agent available again', async () => { @@ -105,15 +103,15 @@ test.describe('OC - Livechat - Queue Management', () => { }); await test.step('user1 should get assigned to the first chat', async () => { - await expect(poLiveChat.page.locator(`div[role='alert'] >> text=${queuePosition1}`)).not.toBeVisible(); + await expect(poLiveChat.queuePosition(1)).not.toBeVisible(); }); await test.step('secondary session should be on position #1', async () => { - await expect(poLiveChat2.page.locator(`div[role='alert'] >> text=${queuePosition1}`)).toBeVisible(); + await expect(poLiveChat2.queuePosition(1)).toBeVisible(); }); await test.step('secondary session should be taken by user1', async () => { - await expect(poLiveChat2.page.locator(`div[role='alert'] >> text=${queuePosition1}`)).not.toBeVisible(); + await expect(poLiveChat2.queuePosition(1)).not.toBeVisible(); }); }); }); diff --git a/apps/meteor/tests/e2e/page-objects/omnichannel-livechat.ts b/apps/meteor/tests/e2e/page-objects/omnichannel-livechat.ts index e52ae45782c8..0973b39ef89a 100644 --- a/apps/meteor/tests/e2e/page-objects/omnichannel-livechat.ts +++ b/apps/meteor/tests/e2e/page-objects/omnichannel-livechat.ts @@ -7,7 +7,10 @@ import { expect } from '../utils/test'; export class OmnichannelLiveChat { readonly page: Page; - constructor(page: Page, private readonly api: { get(url: string): Promise }) { + constructor( + page: Page, + private readonly api: { get(url: string): Promise }, + ) { this.page = page; } @@ -220,4 +223,8 @@ export class OmnichannelLiveChat { await this.fileUploadTarget.dispatchEvent('drop', { dataTransfer }); } + + queuePosition(position: number): Locator { + return this.page.locator(`div[role='alert'] >> text=Your spot is #${position}`); + } }