-
Notifications
You must be signed in to change notification settings - Fork 65
feat(cc-widgets): outdial widget e2e tests #640
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: next
Are you sure you want to change the base?
Changes from 1 commit
d2f5f95
43f98cd
07c2e67
217573a
33bf3ba
4fdf079
f520d73
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| import {Page, expect} from '@playwright/test'; | ||
| import {ACCEPT_TASK_TIMEOUT, AWAIT_TIMEOUT, UI_SETTLE_TIMEOUT} from '../constants'; | ||
|
|
||
| /** | ||
| * Enters a phone number into the outdial number input field. | ||
| * Prerequisite: Agent must be logged in and outdial-call-container must be visible. | ||
| * @param page Playwright Page object (agent widget page) | ||
| * @param number Phone number to dial (e.g., +14698041796) | ||
| */ | ||
| export async function enterOutdialNumber(page: Page, number: string): Promise<void> { | ||
| await page.bringToFront(); | ||
| await expect(page.getByTestId('outdial-call-container')).toBeVisible({timeout: AWAIT_TIMEOUT}); | ||
| const input = page.getByTestId('outdial-number-input').locator('input'); | ||
| await input.fill(number, {timeout: AWAIT_TIMEOUT}); | ||
| } | ||
|
|
||
| /** | ||
| * Clicks the outdial call button to initiate the outbound call. | ||
| * Prerequisite: A valid number must be entered in the outdial input. | ||
| * @param page Playwright Page object (agent widget page) | ||
| */ | ||
| export async function clickOutdialButton(page: Page): Promise<void> { | ||
| await page.bringToFront(); | ||
| const dialButton = page.getByTestId('outdial-call-button'); | ||
| await expect(dialButton).toBeEnabled({timeout: AWAIT_TIMEOUT}); | ||
| await dialButton.click({timeout: AWAIT_TIMEOUT}); | ||
| } | ||
|
|
||
| /** | ||
| * Accepts an incoming call on the customer's Webex Calling web client. | ||
| * Used for outdial scenarios where the customer receives the outbound call. | ||
| * @param customerPage Playwright Page object (customer's Webex Calling web client) | ||
| */ | ||
| export async function acceptCustomerCall(customerPage: Page): Promise<void> { | ||
| await customerPage.bringToFront(); | ||
| await expect(customerPage.locator('#answer').first()).toBeEnabled({timeout: ACCEPT_TASK_TIMEOUT}); | ||
| await customerPage.waitForTimeout(UI_SETTLE_TIMEOUT); | ||
| await customerPage.locator('#answer').first().click({timeout: AWAIT_TIMEOUT}); | ||
| } | ||
|
|
||
| /** | ||
| * Ends the call on the customer's Webex Calling web client. | ||
| * @param customerPage Playwright Page object (customer's Webex Calling web client) | ||
| */ | ||
| export async function endCustomerCall(customerPage: Page): Promise<void> { | ||
| await customerPage.bringToFront(); | ||
| const endBtn = customerPage.locator('#end-call').first(); | ||
| await expect(endBtn).toBeEnabled({timeout: AWAIT_TIMEOUT}); | ||
| await endBtn.click({timeout: AWAIT_TIMEOUT}); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,10 @@ | ||
| import {test} from '@playwright/test'; | ||
| import { test } from '@playwright/test'; | ||
| import createStationLoginTests from '../tests/station-login-test.spec'; | ||
| import createUserStateTests from '../tests/user-state-test.spec'; | ||
| import createIncomingTelephonyTaskTests from '../tests/incoming-telephony-task-test.spec'; | ||
| import createOutdialCallTests from '../tests/outdial-call-test.spec'; | ||
|
|
||
| test.describe('Station Login Tests', createStationLoginTests); | ||
| test.describe('User State Tests', createUserStateTests); | ||
| test.describe('Incoming Telephony Task Tests', createIncomingTelephonyTaskTests); | ||
| test.describe('Outdial Call Tests', createOutdialCallTests); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -383,6 +383,9 @@ export class TestManager { | |
| 'agent1 extension login' | ||
| ), | ||
| ]); | ||
| } else if (config.agent1LoginMode === LOGIN_MODE.DIAL_NUMBER) { | ||
| const dialNumber = process.env.PW_DIAL_NUMBER_PSTN ?? ''; | ||
| await pageSetup(this.agent1Page, LOGIN_MODE.DIAL_NUMBER, envTokens.agent1AccessToken, null, dialNumber); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -520,6 +523,43 @@ export class TestManager { | |
| }); | ||
| } | ||
|
|
||
| async setupForOutdialDesktop(browser: Browser): Promise<void> { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Medium Severity - No cleanup on setup failure These methods call Impact: Resource leaks and potential conflicts in subsequent test runs. Suggestion: Consider wrapping in try/catch with cleanup, or document that cleanup is the caller's responsibility on setup failure.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No other test in the codebase uses try/catch in beforeAll — the convention is to let failures propagate to the test runner. Added the if (testManager) guard in afterAll to match the pattern used across all other test files (14 instances). |
||
| await this.setup(browser, { | ||
| needsAgent1: true, | ||
| agent1LoginMode: LOGIN_MODE.DESKTOP, | ||
| }); | ||
| await this.setupOutdialCustomer(browser); | ||
| } | ||
|
|
||
| async setupForOutdialExtension(browser: Browser): Promise<void> { | ||
| await this.setup(browser, { | ||
| needsAgent1: true, | ||
| needsExtension: true, | ||
| agent1LoginMode: LOGIN_MODE.EXTENSION, | ||
| }); | ||
| await this.setupOutdialCustomer(browser); | ||
| } | ||
|
|
||
| async setupForOutdialDN(browser: Browser): Promise<void> { | ||
| await this.setup(browser, { | ||
| needsAgent1: true, | ||
| agent1LoginMode: LOGIN_MODE.DIAL_NUMBER, | ||
| needDialNumberLogin: true, | ||
| }); | ||
| await this.setupOutdialCustomer(browser); | ||
| } | ||
|
|
||
| private async setupOutdialCustomer(browser: Browser): Promise<void> { | ||
| const customerToken = process.env.CUSTOMER_OUTDIAL_ACCESS_TOKEN ?? ''; | ||
| const result = await this.createContextWithPage(browser, PAGE_TYPES.CALLER); | ||
| this.callerExtensionContext = result.context; | ||
| this.callerPage = result.page; | ||
| await this.retryOperation( | ||
| () => loginExtension(this.callerPage, customerToken), | ||
| 'outdial customer login' | ||
eigengravy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ); | ||
| } | ||
|
|
||
| async setupForMultipartyConference(browser: Browser) { | ||
| await this.setup(browser, { | ||
| needsAgent1: true, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 Medium Severity - Hard-coded wait in utility function
This
waitForTimeout(UI_SETTLE_TIMEOUT)is a hard-coded delay that could be flaky. If this is for UI animation/settling, consider using a more deterministic condition.Suggestion: Replace with
waitForLoadStateor wait for a specific UI condition:There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UI_SETTLE_TIMEOUT is consistent with codebase convention — waitForTimeout is used throughout the test suite for UI settling between actions.