Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ const DialNumberUI: React.FC<ConsultTransferDialNumberComponentProps> = (props)
return (
<div className="consult-transfer-dial-number-container">
<Input
id="dial-number-input"
data-testid="dial-number-input"
id="consult-transfer-dial-number-input"
data-testid="consult-transfer-dial-number-input"
value={value}
onInput={(e) => onInputDialNumber(e, setValue)}
placeholder="Enter Dial Number"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ exports[`DialNumberUI snapshot matches snapshot 1`] = `
>
<mdc-input
class="consult-transfer-dial-number-input"
data-testid="dial-number-input"
data-testid="consult-transfer-dial-number-input"
/>
<button
class="md-button-circle-wrapper consult-transfer-dial-number-btn md-button-simple-wrapper"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,23 +32,23 @@ describe('DialNumberUI', () => {

it('renders input and button', () => {
const {getByTestId} = render(<DialNumberUI {...defaultProps} />);
const input = getByTestId('dial-number-input');
const input = getByTestId('consult-transfer-dial-number-input');
expect(input).toBeInTheDocument();
const button = getByTestId('dial-number-btn');
expect(button).toBeInTheDocument();
});

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

it('calls handleButtonPress utility when button is pressed', () => {
const {getByTestId} = render(<DialNumberUI {...defaultProps} />);
const numberInput = getByTestId('dial-number-input');
const numberInput = getByTestId('consult-transfer-dial-number-input');
// Simulate entering a value before clicking the button
const inputValue = '98765';
const event = new CustomEvent('input', {detail: {value: inputValue}});
Expand Down
157 changes: 58 additions & 99 deletions playwright/Utils/advancedTaskControlUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,55 +103,69 @@ export function verifyConsultTransferredLogs(): void {
}

/**
* Utility function to get all captured logs for debugging purposes.
* @returns Array of all captured log messages
*/
export function getAllCapturedLogs(): string[] {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why have we removed this? Do we not need it anymore?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes. we were not using this anywhere in codebase

return [...capturedAdvancedLogs];
}

/**
* Initiates a consult with another agent via the agents tab.
* Unified function to handle consult and transfer actions for agent, queue, and dial number.
* @param page - The agent's main page
* @param agentName - Name of the agent to consult with (e.g., 'User1 Agent1')
* @param type - 'agent' | 'queue' | 'dialNumber'
* @param action - 'consult' | 'transfer'
* @param value - agentName, queueName, or phoneNumber
* @returns Promise<void>
*/
export async function consultViaAgent(page: Page, agentName: string): Promise<void> {
// Click consult with another agent button
await page.getByTestId('call-control:consult').nth(1).click({timeout: AWAIT_TIMEOUT});
// Navigate to Agents tab
await page.getByRole('tab', {name: 'Agents'}).click({timeout: AWAIT_TIMEOUT});

//hover over the agent name - use exact match to avoid confusion with similar names
await page.getByRole('listitem', {name: agentName, exact: true}).hover({timeout: FORM_FIELD_TIMEOUT});

// Select the specific agent
await page.getByRole('listitem', {name: agentName, exact: true}).getByRole('button').click({timeout: AWAIT_TIMEOUT});

// Wait a moment for the consult to be initiated
await page.waitForTimeout(2000);
}

/**
* Initiates a consult with a queue via the queues tab.
* @param page - The agent's main page
* @param queueName - Name of the queue to consult with (e.g., 'Customer Service Queue')
* @returns Promise<void>
*/
export async function consultViaQueue(page: Page, queueName: string): Promise<void> {
// Click consult with another agent button
await page.getByTestId('call-control:consult').nth(1).click({timeout: AWAIT_TIMEOUT});

// Navigate to Queues tab
await page.getByRole('tab', {name: 'Queues'}).click({timeout: AWAIT_TIMEOUT});

// Hover over the queue name - use exact match to avoid confusion with similar names
await page.getByRole('listitem', {name: queueName, exact: true}).hover({timeout: AWAIT_TIMEOUT});
export async function consultOrTransfer(
page: Page,
type: 'agent' | 'queue' | 'dialNumber',
action: 'consult' | 'transfer',
value: string
): Promise<void> {
// Determine which button to click for consult or transfer
if (action === 'consult') {
await page.getByTestId('call-control:consult').nth(1).click({timeout: AWAIT_TIMEOUT});
} else {
await page
.getByRole('group', {name: 'Call Control with Call'})
.getByLabel('Transfer Call')
.click({timeout: AWAIT_TIMEOUT});
}

// Select the specific queue
await page.getByRole('listitem', {name: queueName, exact: true}).getByRole('button').click({timeout: AWAIT_TIMEOUT});
// Navigate to the correct tab and perform the action
if (type === 'agent' || type === 'queue') {
const tabName = type === 'agent' ? 'Agents' : 'Queues';
await page.getByRole('tab', {name: tabName}).click({timeout: AWAIT_TIMEOUT});
const listItem = page.getByRole('listitem', {name: value, exact: true});
await listItem.waitFor({state: 'visible', timeout: AWAIT_TIMEOUT});
await listItem.scrollIntoViewIfNeeded();
await page.waitForTimeout(300);
const button = listItem.getByRole('button');
await button.waitFor({state: 'visible', timeout: AWAIT_TIMEOUT});
await button.scrollIntoViewIfNeeded();
await button.evaluate((el) => {
if (el.hasAttribute('disabled')) {
throw new Error(`${tabName.slice(0, -1)} button is disabled`);
}
});
let lastError;
for (let i = 0; i < 3; i++) {
try {
await button.click({timeout: AWAIT_TIMEOUT, force: true});
lastError = undefined;
break;
} catch (e) {
lastError = e;
await page.waitForTimeout(400);
}
}
if (lastError) {
throw lastError;
}
} else if (type === 'dialNumber') {
await page.getByRole('tab', {name: 'Dial Number'}).click({timeout: AWAIT_TIMEOUT});
const inputLocator = page.getByTestId('consult-transfer-dial-number-input').locator('input');
await inputLocator.waitFor({state: 'visible', timeout: AWAIT_TIMEOUT});
await inputLocator.click({timeout: AWAIT_TIMEOUT});
await inputLocator.fill(value, {timeout: AWAIT_TIMEOUT});
await page.getByTestId('dial-number-btn').click({timeout: AWAIT_TIMEOUT});
}

// Wait a moment for the consult to be initiated
// Wait a moment for the action to be processed
await page.waitForTimeout(2000);
}

Expand All @@ -164,58 +178,3 @@ export async function cancelConsult(page: Page): Promise<void> {
// Click cancel consult button
await page.getByTestId('cancel-consult-btn').click({timeout: AWAIT_TIMEOUT});
}

/**
* Initiates a transfer via the agents tab (without prior consult).
* @param page - The agent's main page
* @param agentName - Name of the agent to transfer to (e.g., 'User1 Agent1')
* @returns Promise<void>
*/
export async function transferViaAgent(page: Page, agentName: string): Promise<void> {
// Click transfer call button
await page
.getByRole('group', {name: 'Call Control with Call'})
.getByLabel('Transfer Call')
.click({timeout: AWAIT_TIMEOUT});

// Navigate to Agents tab
await page.getByRole('tab', {name: 'Agents'}).click({timeout: AWAIT_TIMEOUT});

// Hover over the agent name - use exact match to avoid confusion with similar names
await page.getByRole('listitem', {name: agentName, exact: true}).hover({timeout: FORM_FIELD_TIMEOUT});

// Select the specific agent
await page
.getByRole('listitem', {name: agentName, exact: true})
.getByRole('button')
.click({timeout: FORM_FIELD_TIMEOUT});

// Wait a moment for the transfer to be processed
await page.waitForTimeout(2000);
}

/**
* Initiates a transfer via the queues tab (without prior consult).
* @param page - The agent's main page
* @param queueName - Name of the queue to transfer to (e.g., 'Customer Service Queue')
* @returns Promise<void>
*/
export async function transferViaQueue(page: Page, queueName: string): Promise<void> {
// Click transfer call button
await page
.getByRole('group', {name: 'Call Control with Call'})
.getByLabel('Transfer Call')
.click({timeout: AWAIT_TIMEOUT});

// Navigate to Queues tab
await page.getByRole('tab', {name: 'Queues'}).click({timeout: AWAIT_TIMEOUT});

// Hover over the queue name - use exact match to avoid confusion with similar names
await page.getByRole('listitem', {name: queueName, exact: true}).hover({timeout: AWAIT_TIMEOUT});

// Select the specific queue
await page.getByRole('listitem', {name: queueName, exact: true}).getByRole('button').click({timeout: AWAIT_TIMEOUT});

// Wait a moment for the transfer to be processed
await page.waitForTimeout(2000);
}
1 change: 1 addition & 0 deletions playwright/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export const PAGE_TYPES = {
EXTENSION: 'extension',
CHAT: 'chat',
MULTI_SESSION: 'multiSession',
DIAL_NUMBER: 'dialNumber',
};

export type PageType = (typeof PAGE_TYPES)[keyof typeof PAGE_TYPES];
Expand Down
37 changes: 36 additions & 1 deletion playwright/test-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ interface SetupConfig {
// Console logging
enableConsoleLogging?: boolean;
enableAdvancedLogging?: boolean;
needDialNumberLogin?: boolean;
}

// Environment variable helper interface
Expand All @@ -42,6 +43,8 @@ interface EnvTokens {
agent2Username: string;
agent1ExtensionNumber: string;
password: string;
dialNumberUsername?: string;
dialNumberPassword?: string;
}

// Context creation result interface
Expand Down Expand Up @@ -77,6 +80,12 @@ export class TestManager {
public chatPage: Page;
public chatContext: BrowserContext;

// Dial Number page
public dialNumberPage: Page;
public dialNumberContext: BrowserContext;

// Console messages collected from pages

public consoleMessages: string[] = [];
public readonly maxRetries: number;
public readonly projectName: string;
Expand All @@ -95,6 +104,8 @@ export class TestManager {
agent2Username: process.env[`${this.projectName}_AGENT2_USERNAME`] ?? '',
agent1ExtensionNumber: process.env[`${this.projectName}_AGENT1_EXTENSION_NUMBER`] ?? '',
password: process.env.PW_SANDBOX_PASSWORD ?? '',
dialNumberUsername: process.env.PW_DIAL_NUMBER_LOGIN_USERNAME ?? '',
dialNumberPassword: process.env.PW_DIAL_NUMBER_LOGIN_PASSWORD ?? '',
};
}

Expand Down Expand Up @@ -159,6 +170,7 @@ export class TestManager {
agent1LoginMode: LOGIN_MODE.DESKTOP,
enableConsoleLogging: true,
enableAdvancedLogging: false,
needDialNumberLogin: false,
};

const finalConfig: Required<SetupConfig> = {...defaults, ...config} as Required<SetupConfig>;
Expand Down Expand Up @@ -197,6 +209,9 @@ export class TestManager {
if (config.needsExtension) {
promises.push(this.createContextWithPage(browser, PAGE_TYPES.EXTENSION));
}
if (config.needDialNumberLogin) {
promises.push(this.createContextWithPage(browser, PAGE_TYPES.DIAL_NUMBER));
}
if (config.needsChat) {
promises.push(this.createContextWithPage(browser, PAGE_TYPES.CHAT));
}
Expand Down Expand Up @@ -243,6 +258,12 @@ export class TestManager {
this.multiSessionContext = result.context;
this.multiSessionAgent1Page = result.page;
break;
case PAGE_TYPES.DIAL_NUMBER:
this.dialNumberContext = result.context;
this.dialNumberPage = result.page;
break;
default:
throw new Error(`Unknown page type: ${result.type}`);
}
}
}
Expand All @@ -266,6 +287,10 @@ export class TestManager {
setupPromises.push(this.setupCaller(envTokens));
}

// Dial Number setup
if (config.needDialNumberLogin && this.dialNumberPage) {
setupPromises.push(this.setupDialNumber(envTokens));
}
return setupPromises;
}

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

// Helper method for Dial Number setup
private async setupDialNumber(envTokens: EnvTokens): Promise<void> {
await this.retryOperation(
() => loginExtension(this.dialNumberPage, envTokens.dialNumberUsername, envTokens.dialNumberPassword),
'dial number login'
);
}

// Helper method for Caller setup
private async setupCaller(envTokens: EnvTokens): Promise<void> {
await this.retryOperation(
Expand Down Expand Up @@ -355,10 +388,12 @@ export class TestManager {
await this.setup(browser, {
needsAgent1: true,
needsAgent2: true,
needsExtension: true,
needsCaller: true,
agent1LoginMode: LOGIN_MODE.DESKTOP,
agent1LoginMode: LOGIN_MODE.EXTENSION,
enableConsoleLogging: true,
enableAdvancedLogging: true,
needDialNumberLogin: true,
});
}

Expand Down
Loading
Loading