From 9214775d34c7e41742c7646341d221a3e42b8972 Mon Sep 17 00:00:00 2001 From: YONGJAE LEE Date: Sat, 15 Aug 2026 22:49:20 +0900 Subject: [PATCH 1/3] test: assert imported users and rooms in import e2e tests Replace matcher-less locator expressions with awaited, row-scoped assertions and synchronize user searches with the matching API response. Constraint: Keep the existing import fixtures and admin-table behavior unchanged. Rejected: Generic table-cell locators | they can match rows unrelated to the imported entity. Confidence: high Scope-risk: Rocket.Chat admin import E2E only. Not-tested: Full Rocket.Chat E2E suite. --- apps/meteor/tests/e2e/imports.spec.ts | 37 ++++++++++++++++++--------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/apps/meteor/tests/e2e/imports.spec.ts b/apps/meteor/tests/e2e/imports.spec.ts index 0c9a4e3dd63e6..975e4f42c2664 100644 --- a/apps/meteor/tests/e2e/imports.spec.ts +++ b/apps/meteor/tests/e2e/imports.spec.ts @@ -4,7 +4,7 @@ import * as path from 'path'; import { parse } from 'csv-parse'; import { Users } from './fixtures/userStates'; -import { AdminImports, AdminRooms } from './page-objects'; +import { AdminImports, AdminRooms, AdminUsers } from './page-objects'; import { test, expect } from './utils/test'; test.use({ storageState: Users.admin.state }); @@ -46,7 +46,9 @@ const usersCsvsToJson = async (): Promise => { .pipe(parse({ delimiter: ',' })) .on('data', (rows) => { rowUserName.push(rows[0]); - csvImportedUsernames.push(rows[0]); + if (rows[0] !== 'billy.billy') { + csvImportedUsernames.push(rows[0]); + } }) .on('end', resolve), ); @@ -125,13 +127,21 @@ test.describe.serial('imports', () => { }); test('expect all imported users to be actually listed as users', async ({ page }) => { + const poAdmin = new AdminUsers(page); await page.goto('/admin/users'); for await (const user of rowUserName) { + const searchResponse = page.waitForResponse((response) => { + const url = new URL(response.url()); + return url.pathname.endsWith('/api/v1/users.listByStatus') && url.searchParams.get('searchTerm') === user && response.ok(); + }); + await page.getByRole('textbox', { name: 'Search Users' }).fill(user); + await searchResponse; if (user === 'billy.billy') { - await expect(page.locator(`tbody tr td:first-child >> text="${user}"`)).not.toBeVisible(); + await expect(page.getByRole('heading', { name: 'No users' })).toBeVisible(); + await expect(poAdmin.getUserRowByUsername(user)).not.toBeVisible(); } else { - expect(page.locator(`tbody tr td:first-child >> text="${user}"`)); + await expect(poAdmin.getUserRowByUsername(user)).toBeVisible(); } } }); @@ -143,8 +153,8 @@ test.describe.serial('imports', () => { for await (const room of importedRooms) { await poAdmin.inputSearchRooms.fill(room.name); - const expectedMembersCount = room.members.split(';').filter((username) => username !== room.ownerUsername).length + 1; - expect(page.locator(`tbody tr td:nth-child(2) >> text="${expectedMembersCount}"`)); + const expectedMembersCount = room.members.split(';').filter((username) => username && username !== room.ownerUsername).length + 1; + await expect(poAdmin.getRoomRow(room.name).getByRole('cell').nth(2)).toHaveText(String(expectedMembersCount)); } }); @@ -156,9 +166,11 @@ test.describe.serial('imports', () => { await poAdmin.inputSearchRooms.fill(room.name); await poAdmin.getRoomRow(room.name).click(); - room.visibility === 'private' - ? await expect(poAdmin.editRoom.privateInput).toBeChecked() - : await expect(poAdmin.editRoom.privateInput).not.toBeChecked(); + if (room.visibility === 'private') { + await expect(poAdmin.editRoom.privateInput).toBeChecked(); + } else { + await expect(poAdmin.editRoom.privateInput).not.toBeChecked(); + } await expect(poAdmin.editRoom.roomOwnerInput).toHaveValue(room.ownerUsername); } }); @@ -169,13 +181,14 @@ test.describe.serial('imports', () => { for await (const user of csvImportedUsernames) { await poAdmin.inputSearchRooms.fill(user); - expect(page.locator(`tbody tr td:first-child >> text="${user}"`)); + const roomRow = poAdmin.getRoomRow(user); + await expect(roomRow).toBeVisible(); const expectedMembersCount = 2; - expect(page.locator(`tbody tr td:nth-child(2) >> text="${expectedMembersCount}"`)); + await expect(roomRow.getByRole('cell').nth(2)).toHaveText(String(expectedMembersCount)); const expectedMessagesCount = dmMessages.length; - expect(page.locator(`tbody tr td:nth-child(3) >> text="${expectedMessagesCount}"`)); + await expect(roomRow.getByRole('cell').nth(3)).toHaveText(String(expectedMessagesCount)); } }); }); From 80614ad28b5d483e0579b1dfb8dc18f0d6263f84 Mon Sep 17 00:00:00 2001 From: YONGJAE LEE Date: Sun, 16 Aug 2026 00:36:58 +0900 Subject: [PATCH 2/3] test: align import assertions with page objects --- apps/meteor/tests/e2e/imports.spec.ts | 8 ++++---- apps/meteor/tests/e2e/page-objects/admin-rooms.ts | 8 ++++++++ apps/meteor/tests/e2e/page-objects/admin-users.ts | 6 +++++- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/apps/meteor/tests/e2e/imports.spec.ts b/apps/meteor/tests/e2e/imports.spec.ts index 975e4f42c2664..354eaf9ed860e 100644 --- a/apps/meteor/tests/e2e/imports.spec.ts +++ b/apps/meteor/tests/e2e/imports.spec.ts @@ -135,7 +135,7 @@ test.describe.serial('imports', () => { const url = new URL(response.url()); return url.pathname.endsWith('/api/v1/users.listByStatus') && url.searchParams.get('searchTerm') === user && response.ok(); }); - await page.getByRole('textbox', { name: 'Search Users' }).fill(user); + await poAdmin.fillUserSearch(user); await searchResponse; if (user === 'billy.billy') { await expect(page.getByRole('heading', { name: 'No users' })).toBeVisible(); @@ -154,7 +154,7 @@ test.describe.serial('imports', () => { await poAdmin.inputSearchRooms.fill(room.name); const expectedMembersCount = room.members.split(';').filter((username) => username && username !== room.ownerUsername).length + 1; - await expect(poAdmin.getRoomRow(room.name).getByRole('cell').nth(2)).toHaveText(String(expectedMembersCount)); + await expect(poAdmin.getRoomUsersCountCell(room.name)).toHaveText(String(expectedMembersCount)); } }); @@ -185,10 +185,10 @@ test.describe.serial('imports', () => { await expect(roomRow).toBeVisible(); const expectedMembersCount = 2; - await expect(roomRow.getByRole('cell').nth(2)).toHaveText(String(expectedMembersCount)); + await expect(poAdmin.getRoomUsersCountCell(user)).toHaveText(String(expectedMembersCount)); const expectedMessagesCount = dmMessages.length; - await expect(roomRow.getByRole('cell').nth(3)).toHaveText(String(expectedMessagesCount)); + await expect(poAdmin.getRoomMessagesCountCell(user)).toHaveText(String(expectedMessagesCount)); } }); }); diff --git a/apps/meteor/tests/e2e/page-objects/admin-rooms.ts b/apps/meteor/tests/e2e/page-objects/admin-rooms.ts index 40104eeeddb7b..6ea5c9816df5c 100644 --- a/apps/meteor/tests/e2e/page-objects/admin-rooms.ts +++ b/apps/meteor/tests/e2e/page-objects/admin-rooms.ts @@ -23,6 +23,14 @@ export class AdminRooms extends Admin { return this.adminPageContent.getByRole('link', { name }); } + getRoomUsersCountCell(name: string): Locator { + return this.getRoomRow(name).getByRole('cell').nth(2); + } + + getRoomMessagesCountCell(name: string): Locator { + return this.getRoomRow(name).getByRole('cell').nth(3); + } + get btnEdit(): Locator { return this.adminPageContent.getByRole('button', { name: 'Edit' }); } diff --git a/apps/meteor/tests/e2e/page-objects/admin-users.ts b/apps/meteor/tests/e2e/page-objects/admin-users.ts index 74e0ca44b1640..d16bee5591e36 100644 --- a/apps/meteor/tests/e2e/page-objects/admin-users.ts +++ b/apps/meteor/tests/e2e/page-objects/admin-users.ts @@ -64,8 +64,12 @@ export class AdminUsers extends Admin { await this.userInfo.menuItemDeleteUser.click(); } - async searchUser(username: string): Promise { + async fillUserSearch(username: string): Promise { await this.inputSearchUsers.fill(username); + } + + async searchUser(username: string): Promise { + await this.fillUserSearch(username); await expect(this.getUserRowByUsername(username)).toHaveCount(1); } } From cab99e91cad9b70afe48e3a5bc22ea5aa951356f Mon Sep 17 00:00:00 2001 From: YONGJAE LEE Date: Sun, 16 Aug 2026 00:59:25 +0900 Subject: [PATCH 3/3] test: use semantic room count locators --- .changeset/accessible-room-counts.md | 5 +++++ apps/meteor/client/views/admin/rooms/RoomRow.tsx | 10 ++++++++-- apps/meteor/tests/e2e/imports.spec.ts | 8 ++++---- apps/meteor/tests/e2e/page-objects/admin-rooms.ts | 8 ++++---- 4 files changed, 21 insertions(+), 10 deletions(-) create mode 100644 .changeset/accessible-room-counts.md diff --git a/.changeset/accessible-room-counts.md b/.changeset/accessible-room-counts.md new file mode 100644 index 0000000000000..a7d534e1414e3 --- /dev/null +++ b/.changeset/accessible-room-counts.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Added accessible labels to the Users and Msgs count cells in the admin Rooms table. diff --git a/apps/meteor/client/views/admin/rooms/RoomRow.tsx b/apps/meteor/client/views/admin/rooms/RoomRow.tsx index 722085881417d..30ec506de4e1c 100644 --- a/apps/meteor/client/views/admin/rooms/RoomRow.tsx +++ b/apps/meteor/client/views/admin/rooms/RoomRow.tsx @@ -84,8 +84,14 @@ const RoomRow = ({ room }: RoomRowProps) => { {t(getRoomType(room))} - {usersCount} - {mediaQuery && {msgs}} + + {usersCount} + + {mediaQuery && ( + + {msgs} + + )} {mediaQuery && {isDefault ? t('True') : t('False')}} {mediaQuery && {featured ? t('True') : t('False')}} {mediaQuery && {ts ? formatDate(ts) : ''}} diff --git a/apps/meteor/tests/e2e/imports.spec.ts b/apps/meteor/tests/e2e/imports.spec.ts index 354eaf9ed860e..4a91c23003d0a 100644 --- a/apps/meteor/tests/e2e/imports.spec.ts +++ b/apps/meteor/tests/e2e/imports.spec.ts @@ -7,7 +7,7 @@ import { Users } from './fixtures/userStates'; import { AdminImports, AdminRooms, AdminUsers } from './page-objects'; import { test, expect } from './utils/test'; -test.use({ storageState: Users.admin.state }); +test.use({ storageState: Users.admin.state, viewport: { width: 1280, height: 720 } }); type csvRoomSpec = { name: string; @@ -154,7 +154,7 @@ test.describe.serial('imports', () => { await poAdmin.inputSearchRooms.fill(room.name); const expectedMembersCount = room.members.split(';').filter((username) => username && username !== room.ownerUsername).length + 1; - await expect(poAdmin.getRoomUsersCountCell(room.name)).toHaveText(String(expectedMembersCount)); + await expect(poAdmin.getRoomUsersCountCell(room.name, expectedMembersCount)).toHaveText(String(expectedMembersCount)); } }); @@ -185,10 +185,10 @@ test.describe.serial('imports', () => { await expect(roomRow).toBeVisible(); const expectedMembersCount = 2; - await expect(poAdmin.getRoomUsersCountCell(user)).toHaveText(String(expectedMembersCount)); + await expect(poAdmin.getRoomUsersCountCell(user, expectedMembersCount)).toHaveText(String(expectedMembersCount)); const expectedMessagesCount = dmMessages.length; - await expect(poAdmin.getRoomMessagesCountCell(user)).toHaveText(String(expectedMessagesCount)); + await expect(poAdmin.getRoomMessagesCountCell(user, expectedMessagesCount)).toHaveText(String(expectedMessagesCount)); } }); }); diff --git a/apps/meteor/tests/e2e/page-objects/admin-rooms.ts b/apps/meteor/tests/e2e/page-objects/admin-rooms.ts index 6ea5c9816df5c..8402bff986bc2 100644 --- a/apps/meteor/tests/e2e/page-objects/admin-rooms.ts +++ b/apps/meteor/tests/e2e/page-objects/admin-rooms.ts @@ -23,12 +23,12 @@ export class AdminRooms extends Admin { return this.adminPageContent.getByRole('link', { name }); } - getRoomUsersCountCell(name: string): Locator { - return this.getRoomRow(name).getByRole('cell').nth(2); + getRoomUsersCountCell(name: string, count: number): Locator { + return this.getRoomRow(name).getByRole('cell', { name: `Users: ${count}`, exact: true }); } - getRoomMessagesCountCell(name: string): Locator { - return this.getRoomRow(name).getByRole('cell').nth(3); + getRoomMessagesCountCell(name: string, count: number): Locator { + return this.getRoomRow(name).getByRole('cell', { name: `Msgs: ${count}`, exact: true }); } get btnEdit(): Locator {