diff --git a/apps/meteor/client/views/omnichannel/directory/chats/ChatInfo/ChatInfo.tsx b/apps/meteor/client/views/omnichannel/directory/chats/ChatInfo/ChatInfo.tsx
index 9c76109b948cf..03e633e68eb86 100644
--- a/apps/meteor/client/views/omnichannel/directory/chats/ChatInfo/ChatInfo.tsx
+++ b/apps/meteor/client/views/omnichannel/directory/chats/ChatInfo/ChatInfo.tsx
@@ -53,6 +53,7 @@ function ChatInfo({ id, route }: ChatInfoProps) {
const { data: room } = useOmnichannelRoomInfo(id); // FIXME: `room` is serialized, but we need to deserialize it
const {
+ _id: roomId,
ts,
tags,
closedAt,
@@ -121,15 +122,17 @@ function ChatInfo({ id, route }: ChatInfoProps) {
{departmentId && }
{tags && tags.length > 0 && (
- {t('Tags')}
+ {t('Tags')}
- {tags.map((tag) => (
-
-
- {tag}
-
-
- ))}
+
+ {tags.map((tag) => (
+
+
+ {tag}
+
+
+ ))}
+
)}
diff --git a/apps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.ts b/apps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.ts
new file mode 100644
index 0000000000000..a76f3e1a67813
--- /dev/null
+++ b/apps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.ts
@@ -0,0 +1,135 @@
+import { createFakeVisitor } from '../../mocks/data';
+import { IS_EE } from '../config/constants';
+import { Users } from '../fixtures/userStates';
+import { HomeOmnichannel } from '../page-objects';
+import { createAgent } from '../utils/omnichannel/agents';
+import { addAgentToDepartment, createDepartment } from '../utils/omnichannel/departments';
+import { createConversation } from '../utils/omnichannel/rooms';
+import { createTag } from '../utils/omnichannel/tags';
+import { test, expect } from '../utils/test';
+
+const visitorA = createFakeVisitor();
+const visitorB = createFakeVisitor();
+
+test.use({ storageState: Users.user1.state });
+
+test.describe('OC - Tags Visibility', () => {
+ test.skip(!IS_EE, 'OC - Tags Visibility > Enterprise Edition Only');
+
+ let poOmnichannel: HomeOmnichannel;
+ let conversations: Awaited>[] = [];
+ let departmentA: Awaited>;
+ let departmentB: Awaited>;
+ let agent: Awaited>;
+ let tags: Awaited>[] = [];
+
+ test.beforeAll('Create departments', async ({ api }) => {
+ departmentA = await createDepartment(api, { name: 'Department A' });
+ departmentB = await createDepartment(api, { name: 'Department B' });
+ });
+
+ test.beforeAll('Create agent', async ({ api }) => {
+ agent = await createAgent(api, 'user1');
+ });
+
+ test.beforeAll('Add agents to departments', async ({ api }) => {
+ await Promise.all([
+ addAgentToDepartment(api, { department: departmentA.data, agentId: 'user1' }),
+ addAgentToDepartment(api, { department: departmentB.data, agentId: 'user1' }),
+ ]);
+ });
+
+ test.beforeAll('Create tags', async ({ api }) => {
+ tags = await Promise.all([
+ createTag(api, { name: 'TagA', description: 'tag A', departments: [departmentA.data._id] }),
+ createTag(api, { name: 'TagB', description: 'tag B', departments: [departmentB.data._id] }),
+ createTag(api, { name: 'GlobalTag', description: 'public tag', departments: [] }),
+ createTag(api, {
+ name: 'SharedTag',
+ description: 'tag for both departments',
+ departments: [departmentA.data._id, departmentB.data._id],
+ }),
+ ]);
+ });
+
+ test.beforeAll('Create conversations', async ({ api }) => {
+ conversations = await Promise.all([
+ createConversation(api, { visitorName: visitorA.name, agentId: 'user1', departmentId: departmentA.data._id }),
+ createConversation(api, { visitorName: visitorB.name, agentId: 'user1', departmentId: departmentB.data._id }),
+ ]);
+ });
+
+ test.beforeEach(async ({ page }) => {
+ poOmnichannel = new HomeOmnichannel(page);
+ await page.goto('/');
+ });
+
+ test.afterAll(async () => {
+ await Promise.all(conversations.map((conversation) => conversation.delete()));
+ await Promise.all(tags.map((tag) => tag.delete()));
+ await agent.delete();
+ await departmentA.delete();
+ await departmentB.delete();
+ });
+
+ test('Verify agent should see correct tags based on department association', async () => {
+ await test.step('Agent opens room', async () => {
+ await poOmnichannel.sidenav.getSidebarItemByName(visitorA.name).click();
+ });
+
+ await test.step('should not be able to see tags field', async () => {
+ await expect(poOmnichannel.roomInfo.getLabel('Tags')).not.toBeVisible();
+ });
+
+ await test.step('check available tags', async () => {
+ await poOmnichannel.roomInfo.btnEditRoomInfo.click();
+ await expect(poOmnichannel.roomInfo.dialogEditRoom).toBeVisible();
+ await poOmnichannel.roomInfo.inputTags.click();
+ });
+
+ await test.step('Should see TagA (department A specific)', async () => {
+ await expect(poOmnichannel.roomInfo.optionTags('TagA')).toBeVisible();
+ });
+
+ await test.step('Should see SharedTag (both departments)', async () => {
+ await expect(poOmnichannel.roomInfo.optionTags('SharedTag')).toBeVisible();
+ });
+
+ await test.step('Should see Public Tags for all chats (no department restriction)', async () => {
+ await expect(poOmnichannel.roomInfo.optionTags('GlobalTag')).toBeVisible();
+ });
+
+ await test.step('Should not see TagB (department B specific)', async () => {
+ await expect(poOmnichannel.roomInfo.optionTags('TagB')).not.toBeVisible();
+ });
+
+ await test.step('add tags and save', async () => {
+ await poOmnichannel.roomInfo.selectTag('TagA');
+ await poOmnichannel.roomInfo.selectTag('GlobalTag');
+ await poOmnichannel.roomInfo.btnSaveEditRoom.click();
+ });
+
+ await test.step('verify selected tags are displayed under room information', async () => {
+ await expect(poOmnichannel.roomInfo.getLabel('Tags')).toBeVisible();
+ await expect(poOmnichannel.roomInfo.getTagInfoByLabel('TagA')).toBeVisible();
+ await expect(poOmnichannel.roomInfo.getTagInfoByLabel('GlobalTag')).toBeVisible();
+ });
+ });
+
+ test('Verify tags visibility for agent associated with multiple departments', async () => {
+ await test.step('Open room info', async () => {
+ await poOmnichannel.sidenav.getSidebarItemByName(visitorB.name).click();
+ await poOmnichannel.roomInfo.btnEditRoomInfo.click();
+ await expect(poOmnichannel.roomInfo.dialogEditRoom).toBeVisible();
+ await poOmnichannel.roomInfo.inputTags.click();
+ });
+
+ await test.step('Agent associated with DepartmentB should be able to see tags for Department B', async () => {
+ await expect(poOmnichannel.roomInfo.optionTags('TagB')).toBeVisible();
+ });
+
+ await test.step('Agent associated with DepartmentB should not be able to see tags for DepartmentA', async () => {
+ await expect(poOmnichannel.roomInfo.optionTags('TagA')).not.toBeVisible();
+ });
+ });
+});
diff --git a/apps/meteor/tests/e2e/page-objects/omnichannel-room-info.ts b/apps/meteor/tests/e2e/page-objects/omnichannel-room-info.ts
index 84a49c01c13b2..7c415faccdb70 100644
--- a/apps/meteor/tests/e2e/page-objects/omnichannel-room-info.ts
+++ b/apps/meteor/tests/e2e/page-objects/omnichannel-room-info.ts
@@ -53,6 +53,22 @@ export class OmnichannelRoomInfo {
return this.page.getByRole('option', { name, exact: true }).click();
}
+ get inputTags(): Locator {
+ return this.page.getByRole('textbox', { name: 'Select an option' });
+ }
+
+ optionTags(name: string): Locator {
+ return this.page.getByRole('option', { name, exact: true });
+ }
+
+ async selectTag(name: string): Promise {
+ await this.optionTags(name).click();
+ }
+
+ getTagInfoByLabel(label: string): Locator {
+ return this.dialogRoomInfo.getByRole('list', { name: 'Tags' }).getByText(label, { exact: true });
+ }
+
getBadgeIndicator(name: string, title: string): Locator {
return this.homeSidenav.getSidebarItemByName(name).getByTitle(title);
}