Skip to content

Commit

Permalink
chore: improved agents e2e tests (#31196)
Browse files Browse the repository at this point in the history
* chore: added qa ids

* chore: refactored agents e2e tests
  • Loading branch information
aleksandernsilva committed Dec 13, 2023
1 parent d08b1d0 commit 08e597c
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 40 deletions.
20 changes: 10 additions & 10 deletions apps/meteor/client/views/omnichannel/agents/AgentEdit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ const AgentEdit = ({ agentData, userDepartments, availableDepartments }: AgentEd
const voipExtensionField = useUniqueId();

return (
<Contextualbar>
<Contextualbar data-qa-id='agent-edit-contextual-bar'>
<ContextualbarHeader>
<ContextualbarTitle>{t('Edit_User')}</ContextualbarTitle>
<ContextualbarClose onClick={() => router.navigate('/omnichannel/agents')} />
Expand All @@ -122,7 +122,7 @@ const AgentEdit = ({ agentData, userDepartments, availableDepartments }: AgentEd
<form id={formId} onSubmit={handleSubmit(handleSave)}>
{username && (
<Box display='flex' flexDirection='column' alignItems='center'>
<UserInfo.Avatar data-qa='AgentEdit-Avatar' username={username} />
<UserInfo.Avatar data-qa-id='agent-edit-avatar' username={username} />
</Box>
)}
<FieldGroup>
Expand All @@ -132,7 +132,7 @@ const AgentEdit = ({ agentData, userDepartments, availableDepartments }: AgentEd
<Controller
name='name'
control={control}
render={({ field }) => <TextInput id={nameField} data-qa='AgentEditTextInput-Name' {...field} readOnly />}
render={({ field }) => <TextInput id={nameField} data-qa-id='agent-edit-name' {...field} readOnly />}
/>
</FieldRow>
</Field>
Expand All @@ -145,7 +145,7 @@ const AgentEdit = ({ agentData, userDepartments, availableDepartments }: AgentEd
render={({ field }) => (
<TextInput
id={usernameField}
data-qa='AgentEditTextInput-Username'
data-qa-id='agent-edit-username'
{...field}
readOnly
addon={<Icon name='at' size='x20' />}
Expand All @@ -163,7 +163,7 @@ const AgentEdit = ({ agentData, userDepartments, availableDepartments }: AgentEd
render={({ field }) => (
<TextInput
id={emailField}
data-qa='AgentEditTextInput-Email'
data-qa-id='agent-edit-email'
{...field}
readOnly
addon={<Icon name='mail' size='x20' />}
Expand All @@ -181,7 +181,7 @@ const AgentEdit = ({ agentData, userDepartments, availableDepartments }: AgentEd
render={({ field }) => (
<MultiSelect
id={departmentsField}
data-qa='AgentEditTextInput-Departaments'
data-qa-id='agent-edit-departments'
options={departmentsOptions}
{...field}
placeholder={t('Select_an_option')}
Expand All @@ -199,7 +199,7 @@ const AgentEdit = ({ agentData, userDepartments, availableDepartments }: AgentEd
render={({ field }) => (
<Select
id={statusField}
data-qa='AgentEditTextInput-Status'
data-qa-id='agent-edit-status'
{...field}
options={statusOptions}
placeholder={t('Select_an_option')}
Expand All @@ -216,7 +216,7 @@ const AgentEdit = ({ agentData, userDepartments, availableDepartments }: AgentEd
<Controller
name='voipExtension'
control={control}
render={({ field }) => <TextInput id={voipExtensionField} {...field} data-qa='AgentEditTextInput-VoIP_Extension' />}
render={({ field }) => <TextInput id={voipExtensionField} {...field} data-qa-id='agent-edit-voip-extension' />}
/>
</FieldRow>
</Field>
Expand All @@ -227,10 +227,10 @@ const AgentEdit = ({ agentData, userDepartments, availableDepartments }: AgentEd
</ContextualbarScrollableContent>
<ContextualbarFooter>
<ButtonGroup stretch>
<Button data-qa='AgentEditButtonReset' type='reset' disabled={!isDirty} onClick={() => reset()}>
<Button data-qa-id='agent-edit-reset' type='reset' disabled={!isDirty} onClick={() => reset()}>
{t('Reset')}
</Button>
<Button form={formId} primary type='submit' data-qa='AgentEditButtonSave' disabled={!isDirty}>
<Button form={formId} primary type='submit' data-qa-id='agent-edit-save' disabled={!isDirty}>
{t('Save')}
</Button>
</ButtonGroup>
Expand Down
2 changes: 1 addition & 1 deletion apps/meteor/client/views/omnichannel/agents/AgentInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const AgentInfo = ({ uid }: AgentInfoProps) => {
const { username, statusLivechat, status: userStatus } = data?.user;

return (
<Contextualbar>
<Contextualbar data-qa-id='agent-info-contextual-bar'>
<ContextualbarHeader>
<ContextualbarTitle>{t('User_Info')}</ContextualbarTitle>
<ContextualbarClose onClick={() => router.navigate('/omnichannel/agents')} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type AgentInfoActionProps = {
} & Omit<HtmlHTMLAttributes<HTMLElement>, 'is'>;

const AgentInfoAction: FC<AgentInfoActionProps> = ({ icon, label, ...props }) => (
<Button icon={icon} data-qa={`AgentInfoAction-${label}`} title={label} {...props} mi={4}>
<Button icon={icon} data-qa={`agent-info-action-${label?.toLowerCase()}`} title={label} {...props} mi={4}>
{label}
</Button>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ const AgentsTable = () => {
)}
{isSuccess && data?.users.length > 0 && (
<>
<GenericTable aria-busy={filter !== debouncedFilter}>
<GenericTable aria-busy={filter !== debouncedFilter} data-qa-id='agents-table'>
<GenericTableHeader>{headers}</GenericTableHeader>
<GenericTableBody data-qa='GenericTableAgentInfoBody'>
{data?.users.map((user) => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const AgentsTableRow = ({
const handleDelete = useRemoveAgent(_id);

return (
<GenericTableRow action onClick={() => router.navigate(`/omnichannel/agents/info/${_id}`)}>
<GenericTableRow data-qa-id={username} action onClick={() => router.navigate(`/omnichannel/agents/info/${_id}`)}>
<GenericTableCell>
<Box display='flex' alignItems='center'>
{username && <UserAvatar size={mediaQuery ? 'x28' : 'x40'} title={username} username={username} etag={avatarETag} />}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,15 @@ export const useRemoveAgent = (uid: ILivechatAgent['_id']) => {
}
};

setModal(<GenericModal variant='danger' onConfirm={onDeleteAgent} onCancel={() => setModal()} confirmText={t('Delete')} />);
setModal(
<GenericModal
data-qa-id='remove-agent-modal'
variant='danger'
onConfirm={onDeleteAgent}
onCancel={() => setModal()}
confirmText={t('Delete')}
/>,
);
});

return handleDelete;
Expand Down
98 changes: 81 additions & 17 deletions apps/meteor/tests/e2e/omnichannel/omnichannel-agents.spec.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,108 @@
import { IS_EE } from '../config/constants';
import { Users } from '../fixtures/userStates';
import { OmnichannelAgents } from '../page-objects';
import { createDepartment } from '../utils/omnichannel/departments';
import { test, expect } from '../utils/test';

test.use({ storageState: Users.admin.state });

test.describe.serial('omnichannel-agents', () => {
test.describe.serial('OC - Manage Agents', () => {
let poOmnichannelAgents: OmnichannelAgents;
let department: Awaited<ReturnType<typeof createDepartment>>;

// Create agent and department
test.beforeEach(async ({ api }) => {
department = await createDepartment(api);
});

// Create page object and redirect to home
test.beforeEach(async ({ page }) => {
poOmnichannelAgents = new OmnichannelAgents(page);

await page.goto('/omnichannel');
await poOmnichannelAgents.sidenav.linkAgents.click();
});

test('expect add "user1" as agent', async ({ page }) => {
await poOmnichannelAgents.inputUsername.type('user1');
await page.locator('role=option[name="user1"]').click();
await poOmnichannelAgents.btnAdd.click();
// Ensure that there is no leftover data even if test fails
test.afterEach(async ({ api }) => {
await await api.delete('/livechat/users/agent/user1');
await api.post('/settings/Omnichannel_enable_department_removal', { value: true }).then((res) => expect(res.status()).toBe(200));
await department.delete();
await api.post('/settings/Omnichannel_enable_department_removal', { value: false }).then((res) => expect(res.status()).toBe(200));
});

await poOmnichannelAgents.inputSearch.fill('user1');
await expect(poOmnichannelAgents.firstRowInTable).toBeVisible();
test('OC - Manage Agents - Add, search and remove using table', async ({ page }) => {
await test.step('expect "user1" be first ', async () => {
await poOmnichannelAgents.inputUsername.type('user');
await expect(page.locator('role=option[name="user1"]')).toContainText('user1');

await poOmnichannelAgents.inputUsername.fill('');
});

await test.step('expect add "user1" as agent', async () => {
await poOmnichannelAgents.selectUsername('user1');
await poOmnichannelAgents.btnAdd.click();

await poOmnichannelAgents.inputSearch.fill('user1');
await expect(poOmnichannelAgents.firstRowInTable).toBeVisible();
await expect(poOmnichannelAgents.firstRowInTable).toHaveText('user1');
});

await test.step('expect remove "user1" as agent', async () => {
await poOmnichannelAgents.inputSearch.fill('user1');
await poOmnichannelAgents.btnDeletefirstRowInTable.click();
await poOmnichannelAgents.btnModalRemove.click();

await poOmnichannelAgents.inputSearch.fill('user1');
await expect(poOmnichannelAgents.findRowByUsername('user1')).not.toBeVisible();
});
});

test('expect update "user1" status', async ({ page }) => {
test('OC - Manage Agents [CE]- Edit and Remove', async () => {
test.skip(IS_EE, 'Community Edition Only');

await poOmnichannelAgents.selectUsername('user1');
await poOmnichannelAgents.btnAdd.click();

await poOmnichannelAgents.inputSearch.fill('user1');
await poOmnichannelAgents.firstRowInTable.click();

await poOmnichannelAgents.btnEdit.click();
await poOmnichannelAgents.btnStatus.click();
await page.locator(`.rcx-option__content:has-text("Not available")`).click();
await poOmnichannelAgents.btnSave.click();

await test.step('expect max chats fields to be hidden', async () => {
await expect(poOmnichannelAgents.inputMaxChats).toBeHidden();
});

await test.step('expect update "user1" information', async () => {
await poOmnichannelAgents.selectStatus('Not available');
await poOmnichannelAgents.selectDepartment(department.data.name);
await poOmnichannelAgents.btnSave.click();
});

await test.step('expect removing "user1" via sidebar', async () => {
await poOmnichannelAgents.inputSearch.fill('user1');
await poOmnichannelAgents.firstRowInTable.click();
await poOmnichannelAgents.btnRemove.click();
});
});

test('expect remove "user1" as agent', async () => {
await poOmnichannelAgents.inputSearch.fill('user1');
await poOmnichannelAgents.btnDeletefirstRowInTable.click();
await poOmnichannelAgents.btnModalRemove.click();
test('OC - Manage Agents [EE] - Edit ', async () => {
test.skip(!IS_EE, 'Enterprise Only');

await poOmnichannelAgents.selectUsername('user1');
await poOmnichannelAgents.btnAdd.click();

await poOmnichannelAgents.inputSearch.fill('user1');
await expect(poOmnichannelAgents.firstRowInTable).toBeHidden();
await poOmnichannelAgents.findRowByUsername('user1').click();
await poOmnichannelAgents.btnEdit.click();

await test.step('expect max chats field to be visible', async () => {
await expect(poOmnichannelAgents.inputMaxChats).toBeVisible();
});

await test.step('expect update "user1" information', async () => {
await poOmnichannelAgents.inputMaxChats.click();
await poOmnichannelAgents.inputMaxChats.fill('2');
await poOmnichannelAgents.btnSave.click();
});
});
});
59 changes: 51 additions & 8 deletions apps/meteor/tests/e2e/page-objects/omnichannel-agents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,19 @@ export class OmnichannelAgents {

readonly sidenav: OmnichannelSidenav;

readonly editCtxBar: Locator;

readonly infoCtxBar: Locator;

constructor(page: Page) {
this.page = page;
this.sidenav = new OmnichannelSidenav(page);
this.editCtxBar = page.locator('[data-qa-id="agent-edit-contextual-bar"]');
this.infoCtxBar = page.locator('[data-qa-id="agent-info-contextual-bar"]');
}

get inputUsername(): Locator {
return this.page.locator('input').first();
return this.page.locator('[data-qa-id="UserAutoComplete"]');
}

get inputSearch(): Locator {
Expand All @@ -25,26 +31,63 @@ export class OmnichannelAgents {
}

get firstRowInTable() {
return this.page.locator('[data-qa="GenericTableAgentInfoBody"] .rcx-table__row--action .rcx-table__cell:first-child');
return this.page.locator('[data-qa-id="agents-table"] tr:first-child td:first-child');
}

get btnDeletefirstRowInTable() {
return this.page.locator('button[title="Remove"]');
return this.page.locator('[data-qa-id="agents-table"] tr:first-child').locator('role=button[name="Remove"]');
}

get modalRemoveAgent(): Locator {
return this.page.locator('[data-qa-id="remove-agent-modal"]');
}

get btnModalRemove(): Locator {
return this.page.locator('#modal-root dialog .rcx-modal__inner .rcx-modal__footer .rcx-button--danger');
return this.modalRemoveAgent.locator('role=button[name="Delete"]');
}

get btnEdit(): Locator {
return this.page.locator('[data-qa="AgentInfoAction-Edit"]');
return this.infoCtxBar.locator('[data-qa="agent-info-action-edit"]');
}

get btnStatus(): Locator {
return this.page.locator('[data-qa="AgentEditTextInput-Status"]');
get btnRemove(): Locator {
return this.infoCtxBar.locator('role=button[name="Remove"]');
}

get btnSave(): Locator {
return this.page.locator('[data-qa="AgentEditButtonSave"]');
return this.editCtxBar.locator('[data-qa-id="agent-edit-save"]');
}

get inputMaxChats(): Locator {
return this.editCtxBar.locator('input[name="maxNumberSimultaneousChat"]');
}

get inputStatus(): Locator {
return this.page.locator('[data-qa-id="agent-edit-status"]');
}

get inputDepartment(): Locator {
return this.editCtxBar.locator('[data-qa-id="agent-edit-departments"]');
}

async selectDepartment(name: string) {
await this.inputDepartment.click();
await this.inputDepartment.type(name);
await this.page.locator(`.rcx-option__content:has-text("${name}")`).click();
}

async selectStatus(status: string) {
await this.inputStatus.click();
await this.page.locator(`.rcx-option__content:has-text("${status}")`).click();
}

async selectUsername(username: string) {
await this.inputUsername.fill('');
await this.inputUsername.type(username);
await this.page.locator(`role=option[name="${username}"]`).click();
}

findRowByUsername(username: string) {
return this.page.locator(`[data-qa-id="${username}"]`);
}
}

0 comments on commit 08e597c

Please sign in to comment.