Skip to content

Commit f02eeed

Browse files
authored
fix(cc-widgets): E2e peding comments and new Dial number tests (#535)
1 parent d2dfc35 commit f02eeed

8 files changed

Lines changed: 382 additions & 359 deletions

File tree

packages/contact-center/cc-components/src/components/task/CallControl/CallControlCustom/consult-transfer-dial-number.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ const DialNumberUI: React.FC<ConsultTransferDialNumberComponentProps> = (props)
1212
return (
1313
<div className="consult-transfer-dial-number-container">
1414
<Input
15-
id="dial-number-input"
16-
data-testid="dial-number-input"
15+
id="consult-transfer-dial-number-input"
16+
data-testid="consult-transfer-dial-number-input"
1717
value={value}
1818
onInput={(e) => onInputDialNumber(e, setValue)}
1919
placeholder="Enter Dial Number"

packages/contact-center/cc-components/tests/components/task/CallControl/CallControlCustom/__snapshots__/consult-transfer-dial-number.snapshot.test.tsx.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ exports[`DialNumberUI snapshot matches snapshot 1`] = `
77
>
88
<mdc-input
99
class="consult-transfer-dial-number-input"
10-
data-testid="dial-number-input"
10+
data-testid="consult-transfer-dial-number-input"
1111
/>
1212
<button
1313
class="md-button-circle-wrapper consult-transfer-dial-number-btn md-button-simple-wrapper"

packages/contact-center/cc-components/tests/components/task/CallControl/CallControlCustom/consult-transfer-dial-number.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,23 +32,23 @@ describe('DialNumberUI', () => {
3232

3333
it('renders input and button', () => {
3434
const {getByTestId} = render(<DialNumberUI {...defaultProps} />);
35-
const input = getByTestId('dial-number-input');
35+
const input = getByTestId('consult-transfer-dial-number-input');
3636
expect(input).toBeInTheDocument();
3737
const button = getByTestId('dial-number-btn');
3838
expect(button).toBeInTheDocument();
3939
});
4040

4141
it('calls onInputDialNumber utility when input event is fired', () => {
4242
const {getByTestId} = render(<DialNumberUI {...defaultProps} />);
43-
const numberInput = getByTestId('dial-number-input');
43+
const numberInput = getByTestId('consult-transfer-dial-number-input');
4444
const event = new CustomEvent('input', {detail: {value: '12345'}});
4545
fireEvent(numberInput, event);
4646
expect(mockOnInputDialNumber).toHaveBeenCalled();
4747
});
4848

4949
it('calls handleButtonPress utility when button is pressed', () => {
5050
const {getByTestId} = render(<DialNumberUI {...defaultProps} />);
51-
const numberInput = getByTestId('dial-number-input');
51+
const numberInput = getByTestId('consult-transfer-dial-number-input');
5252
// Simulate entering a value before clicking the button
5353
const inputValue = '98765';
5454
const event = new CustomEvent('input', {detail: {value: inputValue}});

playwright/Utils/advancedTaskControlUtils.ts

Lines changed: 58 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -103,55 +103,69 @@ export function verifyConsultTransferredLogs(): void {
103103
}
104104

105105
/**
106-
* Utility function to get all captured logs for debugging purposes.
107-
* @returns Array of all captured log messages
108-
*/
109-
export function getAllCapturedLogs(): string[] {
110-
return [...capturedAdvancedLogs];
111-
}
112-
113-
/**
114-
* Initiates a consult with another agent via the agents tab.
106+
* Unified function to handle consult and transfer actions for agent, queue, and dial number.
115107
* @param page - The agent's main page
116-
* @param agentName - Name of the agent to consult with (e.g., 'User1 Agent1')
108+
* @param type - 'agent' | 'queue' | 'dialNumber'
109+
* @param action - 'consult' | 'transfer'
110+
* @param value - agentName, queueName, or phoneNumber
117111
* @returns Promise<void>
118112
*/
119-
export async function consultViaAgent(page: Page, agentName: string): Promise<void> {
120-
// Click consult with another agent button
121-
await page.getByTestId('call-control:consult').nth(1).click({timeout: AWAIT_TIMEOUT});
122-
// Navigate to Agents tab
123-
await page.getByRole('tab', {name: 'Agents'}).click({timeout: AWAIT_TIMEOUT});
124-
125-
//hover over the agent name - use exact match to avoid confusion with similar names
126-
await page.getByRole('listitem', {name: agentName, exact: true}).hover({timeout: FORM_FIELD_TIMEOUT});
127-
128-
// Select the specific agent
129-
await page.getByRole('listitem', {name: agentName, exact: true}).getByRole('button').click({timeout: AWAIT_TIMEOUT});
130-
131-
// Wait a moment for the consult to be initiated
132-
await page.waitForTimeout(2000);
133-
}
134-
135-
/**
136-
* Initiates a consult with a queue via the queues tab.
137-
* @param page - The agent's main page
138-
* @param queueName - Name of the queue to consult with (e.g., 'Customer Service Queue')
139-
* @returns Promise<void>
140-
*/
141-
export async function consultViaQueue(page: Page, queueName: string): Promise<void> {
142-
// Click consult with another agent button
143-
await page.getByTestId('call-control:consult').nth(1).click({timeout: AWAIT_TIMEOUT});
144-
145-
// Navigate to Queues tab
146-
await page.getByRole('tab', {name: 'Queues'}).click({timeout: AWAIT_TIMEOUT});
147-
148-
// Hover over the queue name - use exact match to avoid confusion with similar names
149-
await page.getByRole('listitem', {name: queueName, exact: true}).hover({timeout: AWAIT_TIMEOUT});
113+
export async function consultOrTransfer(
114+
page: Page,
115+
type: 'agent' | 'queue' | 'dialNumber',
116+
action: 'consult' | 'transfer',
117+
value: string
118+
): Promise<void> {
119+
// Determine which button to click for consult or transfer
120+
if (action === 'consult') {
121+
await page.getByTestId('call-control:consult').nth(1).click({timeout: AWAIT_TIMEOUT});
122+
} else {
123+
await page
124+
.getByRole('group', {name: 'Call Control with Call'})
125+
.getByLabel('Transfer Call')
126+
.click({timeout: AWAIT_TIMEOUT});
127+
}
150128

151-
// Select the specific queue
152-
await page.getByRole('listitem', {name: queueName, exact: true}).getByRole('button').click({timeout: AWAIT_TIMEOUT});
129+
// Navigate to the correct tab and perform the action
130+
if (type === 'agent' || type === 'queue') {
131+
const tabName = type === 'agent' ? 'Agents' : 'Queues';
132+
await page.getByRole('tab', {name: tabName}).click({timeout: AWAIT_TIMEOUT});
133+
const listItem = page.getByRole('listitem', {name: value, exact: true});
134+
await listItem.waitFor({state: 'visible', timeout: AWAIT_TIMEOUT});
135+
await listItem.scrollIntoViewIfNeeded();
136+
await page.waitForTimeout(300);
137+
const button = listItem.getByRole('button');
138+
await button.waitFor({state: 'visible', timeout: AWAIT_TIMEOUT});
139+
await button.scrollIntoViewIfNeeded();
140+
await button.evaluate((el) => {
141+
if (el.hasAttribute('disabled')) {
142+
throw new Error(`${tabName.slice(0, -1)} button is disabled`);
143+
}
144+
});
145+
let lastError;
146+
for (let i = 0; i < 3; i++) {
147+
try {
148+
await button.click({timeout: AWAIT_TIMEOUT, force: true});
149+
lastError = undefined;
150+
break;
151+
} catch (e) {
152+
lastError = e;
153+
await page.waitForTimeout(400);
154+
}
155+
}
156+
if (lastError) {
157+
throw lastError;
158+
}
159+
} else if (type === 'dialNumber') {
160+
await page.getByRole('tab', {name: 'Dial Number'}).click({timeout: AWAIT_TIMEOUT});
161+
const inputLocator = page.getByTestId('consult-transfer-dial-number-input').locator('input');
162+
await inputLocator.waitFor({state: 'visible', timeout: AWAIT_TIMEOUT});
163+
await inputLocator.click({timeout: AWAIT_TIMEOUT});
164+
await inputLocator.fill(value, {timeout: AWAIT_TIMEOUT});
165+
await page.getByTestId('dial-number-btn').click({timeout: AWAIT_TIMEOUT});
166+
}
153167

154-
// Wait a moment for the consult to be initiated
168+
// Wait a moment for the action to be processed
155169
await page.waitForTimeout(2000);
156170
}
157171

@@ -164,58 +178,3 @@ export async function cancelConsult(page: Page): Promise<void> {
164178
// Click cancel consult button
165179
await page.getByTestId('cancel-consult-btn').click({timeout: AWAIT_TIMEOUT});
166180
}
167-
168-
/**
169-
* Initiates a transfer via the agents tab (without prior consult).
170-
* @param page - The agent's main page
171-
* @param agentName - Name of the agent to transfer to (e.g., 'User1 Agent1')
172-
* @returns Promise<void>
173-
*/
174-
export async function transferViaAgent(page: Page, agentName: string): Promise<void> {
175-
// Click transfer call button
176-
await page
177-
.getByRole('group', {name: 'Call Control with Call'})
178-
.getByLabel('Transfer Call')
179-
.click({timeout: AWAIT_TIMEOUT});
180-
181-
// Navigate to Agents tab
182-
await page.getByRole('tab', {name: 'Agents'}).click({timeout: AWAIT_TIMEOUT});
183-
184-
// Hover over the agent name - use exact match to avoid confusion with similar names
185-
await page.getByRole('listitem', {name: agentName, exact: true}).hover({timeout: FORM_FIELD_TIMEOUT});
186-
187-
// Select the specific agent
188-
await page
189-
.getByRole('listitem', {name: agentName, exact: true})
190-
.getByRole('button')
191-
.click({timeout: FORM_FIELD_TIMEOUT});
192-
193-
// Wait a moment for the transfer to be processed
194-
await page.waitForTimeout(2000);
195-
}
196-
197-
/**
198-
* Initiates a transfer via the queues tab (without prior consult).
199-
* @param page - The agent's main page
200-
* @param queueName - Name of the queue to transfer to (e.g., 'Customer Service Queue')
201-
* @returns Promise<void>
202-
*/
203-
export async function transferViaQueue(page: Page, queueName: string): Promise<void> {
204-
// Click transfer call button
205-
await page
206-
.getByRole('group', {name: 'Call Control with Call'})
207-
.getByLabel('Transfer Call')
208-
.click({timeout: AWAIT_TIMEOUT});
209-
210-
// Navigate to Queues tab
211-
await page.getByRole('tab', {name: 'Queues'}).click({timeout: AWAIT_TIMEOUT});
212-
213-
// Hover over the queue name - use exact match to avoid confusion with similar names
214-
await page.getByRole('listitem', {name: queueName, exact: true}).hover({timeout: AWAIT_TIMEOUT});
215-
216-
// Select the specific queue
217-
await page.getByRole('listitem', {name: queueName, exact: true}).getByRole('button').click({timeout: AWAIT_TIMEOUT});
218-
219-
// Wait a moment for the transfer to be processed
220-
await page.waitForTimeout(2000);
221-
}

playwright/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ export const PAGE_TYPES = {
7070
EXTENSION: 'extension',
7171
CHAT: 'chat',
7272
MULTI_SESSION: 'multiSession',
73+
DIAL_NUMBER: 'dialNumber',
7374
};
7475

7576
export type PageType = (typeof PAGE_TYPES)[keyof typeof PAGE_TYPES];

playwright/test-manager.ts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ interface SetupConfig {
3232
// Console logging
3333
enableConsoleLogging?: boolean;
3434
enableAdvancedLogging?: boolean;
35+
needDialNumberLogin?: boolean;
3536
}
3637

3738
// Environment variable helper interface
@@ -42,6 +43,8 @@ interface EnvTokens {
4243
agent2Username: string;
4344
agent1ExtensionNumber: string;
4445
password: string;
46+
dialNumberUsername?: string;
47+
dialNumberPassword?: string;
4548
}
4649

4750
// Context creation result interface
@@ -77,6 +80,12 @@ export class TestManager {
7780
public chatPage: Page;
7881
public chatContext: BrowserContext;
7982

83+
// Dial Number page
84+
public dialNumberPage: Page;
85+
public dialNumberContext: BrowserContext;
86+
87+
// Console messages collected from pages
88+
8089
public consoleMessages: string[] = [];
8190
public readonly maxRetries: number;
8291
public readonly projectName: string;
@@ -95,6 +104,8 @@ export class TestManager {
95104
agent2Username: process.env[`${this.projectName}_AGENT2_USERNAME`] ?? '',
96105
agent1ExtensionNumber: process.env[`${this.projectName}_AGENT1_EXTENSION_NUMBER`] ?? '',
97106
password: process.env.PW_SANDBOX_PASSWORD ?? '',
107+
dialNumberUsername: process.env.PW_DIAL_NUMBER_LOGIN_USERNAME ?? '',
108+
dialNumberPassword: process.env.PW_DIAL_NUMBER_LOGIN_PASSWORD ?? '',
98109
};
99110
}
100111

@@ -159,6 +170,7 @@ export class TestManager {
159170
agent1LoginMode: LOGIN_MODE.DESKTOP,
160171
enableConsoleLogging: true,
161172
enableAdvancedLogging: false,
173+
needDialNumberLogin: false,
162174
};
163175

164176
const finalConfig: Required<SetupConfig> = {...defaults, ...config} as Required<SetupConfig>;
@@ -197,6 +209,9 @@ export class TestManager {
197209
if (config.needsExtension) {
198210
promises.push(this.createContextWithPage(browser, PAGE_TYPES.EXTENSION));
199211
}
212+
if (config.needDialNumberLogin) {
213+
promises.push(this.createContextWithPage(browser, PAGE_TYPES.DIAL_NUMBER));
214+
}
200215
if (config.needsChat) {
201216
promises.push(this.createContextWithPage(browser, PAGE_TYPES.CHAT));
202217
}
@@ -243,6 +258,12 @@ export class TestManager {
243258
this.multiSessionContext = result.context;
244259
this.multiSessionAgent1Page = result.page;
245260
break;
261+
case PAGE_TYPES.DIAL_NUMBER:
262+
this.dialNumberContext = result.context;
263+
this.dialNumberPage = result.page;
264+
break;
265+
default:
266+
throw new Error(`Unknown page type: ${result.type}`);
246267
}
247268
}
248269
}
@@ -266,6 +287,10 @@ export class TestManager {
266287
setupPromises.push(this.setupCaller(envTokens));
267288
}
268289

290+
// Dial Number setup
291+
if (config.needDialNumberLogin && this.dialNumberPage) {
292+
setupPromises.push(this.setupDialNumber(envTokens));
293+
}
269294
return setupPromises;
270295
}
271296

@@ -295,6 +320,14 @@ export class TestManager {
295320
await pageSetup(this.agent2Page, LOGIN_MODE.DESKTOP, envTokens.agent2AccessToken);
296321
}
297322

323+
// Helper method for Dial Number setup
324+
private async setupDialNumber(envTokens: EnvTokens): Promise<void> {
325+
await this.retryOperation(
326+
() => loginExtension(this.dialNumberPage, envTokens.dialNumberUsername, envTokens.dialNumberPassword),
327+
'dial number login'
328+
);
329+
}
330+
298331
// Helper method for Caller setup
299332
private async setupCaller(envTokens: EnvTokens): Promise<void> {
300333
await this.retryOperation(
@@ -355,10 +388,12 @@ export class TestManager {
355388
await this.setup(browser, {
356389
needsAgent1: true,
357390
needsAgent2: true,
391+
needsExtension: true,
358392
needsCaller: true,
359-
agent1LoginMode: LOGIN_MODE.DESKTOP,
393+
agent1LoginMode: LOGIN_MODE.EXTENSION,
360394
enableConsoleLogging: true,
361395
enableAdvancedLogging: true,
396+
needDialNumberLogin: true,
362397
});
363398
}
364399

0 commit comments

Comments
 (0)