Skip to content

test(calling): add Playwright E2E base setup and SDK initialization tests#4790

Open
eigengravy wants to merge 11 commits intowebex:calling-sdk-e2e-testsfrom
eigengravy:calling-sdk-e2e-tests-sdk-init
Open

test(calling): add Playwright E2E base setup and SDK initialization tests#4790
eigengravy wants to merge 11 commits intowebex:calling-sdk-e2e-testsfrom
eigengravy:calling-sdk-e2e-tests-sdk-init

Conversation

@eigengravy
Copy link
Copy Markdown
Member

@eigengravy eigengravy commented Mar 18, 2026

COMPLETES https://jira-eng-gpk2.cisco.com/jira/browse/CAI-7736

This pull request addresses

Adding Playwright E2E test infrastructure for the Calling SDK kitchen sink sample app, starting with SDK initialization test cases (INIT-001 through INIT-003).

by making the following changes

  • Add Playwright config (playwright.config.ts) with Chrome WebRTC flags, web server setup, and project configuration
  • Add OAuth global setup (playwright/global.setup.ts) that fetches personal access tokens from developer.webex.com with parallel token fetching for caller, callee, and transfer users
  • Add shared test utilities (playwright/Utils/callingUtils.ts) for navigation, SDK init, and service indicator/domain selection (with commented-out future utils for registration, calls, hold, etc.)
  • Add constants (playwright/constants.ts) for element selectors and timeouts
  • Add SDK initialization test cases (playwright/tests/01-sdk-initialization.spec.ts)
  • Add @playwright/test devDependency and ESLint override for playwright files

Change Type

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Tooling change
  • Internal code refactor

The following scenarios were tested

  • INIT-001: Normal Calling — init with calling service indicator
  • INIT-002: Contact Center — init with contactcenter service indicator and service domain
  • INIT-003: Guest Calling — generate guest token and init with guestcalling service indicator
  • All 4 tests passing locally (OAuth + 3 init tests, ~1.5m)

Vidcast Link: https://app.vidcast.io/share/a69273ae-fa0d-4025-a67a-55bd06c16a23

The GAI Coding Policy And Copyright Annotation Best Practices

  • GAI was not used (or, no additional notation is required)
  • Code was generated entirely by GAI
  • GAI was used to create a draft that was subsequently customized or modified
  • Coder created a draft manually that was non-substantively modified by GAI (e.g., refactoring was performed by GAI on manually written code)
  • Tool used for AI assistance (GitHub Copilot / Other - specify)
    • Github Copilot
    • Other - Claude Code
  • This PR is related to
    • Feature
    • Defect fix
    • Tech Debt
    • Automation

I certified that

  • I have read and followed contributing guidelines
  • I discussed changes with code owners prior to submitting this pull request
  • I have not skipped any automated checks
  • All existing and new tests passed
  • I have updated the documentation accordingly

…ests

Add Playwright infrastructure for Calling SDK E2E tests against the
kitchen sink sample app, including OAuth global setup, shared utilities,
and INIT-001 through INIT-003 test cases for SDK initialization.
@eigengravy eigengravy requested a review from a team as a code owner March 18, 2026 09:36
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 504ec1deae

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 53f6565ebc

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@rarajes2 rarajes2 added the validated If the pull request is validated for automation. label Mar 20, 2026
…tory

Move test files, utilities, constants, and global setup into
playwright/tests/calling/ for better organization. Update OAuth
flow to use widgets.webex.com instead of developer portal.
Copy link
Copy Markdown
Contributor

@rarajes2 rarajes2 left a comment

Choose a reason for hiding this comment

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

As discussed the structure can be something like this

playwright
  - calling
    - tests
    - utils
  - foo

- Restructure playwright/tests/calling/ → playwright/calling/{tests,utils}
- Rename global.setup.ts → oauth.setup.ts
- Rename fullSetup → initAndRegister
- Extract ServiceIndicator type to constants
- Split callingUtils into setup.ts and registration.ts
- Add inline comments for Chrome launch flags in playwright.config.ts
Copy link
Copy Markdown
Contributor

@akulakum akulakum left a comment

Choose a reason for hiding this comment

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

PR Review

Good foundation for E2E testing infrastructure. The separation of concerns (utils, constants, setup, registration) is clean, the ServiceIndicator type is a nice pattern, and the Chrome flags are well-documented. However, there are a couple of critical issues that need to be addressed before merge.

Summary

Critical (P1): 2 issues — token handoff across Playwright projects is broken on clean runs; --disable-web-security masks real CORS bugs.

High (P2): 6 issues — unpinned dependency, overly strict SKIP_AUTH guard, phantom Contact Center project, DevTools flag in CI config, no CI integration, caret range on Playwright dep.

Medium (P3): 5 issues — unnecessary dynamic import, duplicated logic in guest test, fragile .env manipulation, missing serial mode annotation, text-based selector fragility.

See inline comments for details and recommendations.

- Remove unused baseline-browser-mapping dependency
- Gate --auto-open-devtools-for-tabs behind !process.env.CI
- Comment out Contact Center project placeholder
- Switch to static import in setup.ts
- Remove duplicate auth status check in Guest Calling test
- Run SDK init tests in parallel with separate credentials
- Add id to Generate Guest Token button, update selector
- Set retries to 3 and workers to 3
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 758b45f8f0

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

- SDK_INIT_TIMEOUT: 60s → 65s (RETRY_TIMER_UPPER_LIMIT + 5s)
- REGISTRATION_TIMEOUT: 40s → 35s (BASE_REG_RETRY_TIMER_VAL_IN_SEC + 5s)
- OPERATION_TIMEOUT: 30s → 15s (SUPPLEMENTARY_SERVICES_TIMEOUT + 5s)
@eigengravy eigengravy requested review from akulakum and rarajes2 March 26, 2026 07:18
@eigengravy eigengravy force-pushed the calling-sdk-e2e-tests-sdk-init branch from b403066 to c8d0594 Compare March 27, 2026 07:11
@eigengravy eigengravy requested a review from a team as a code owner March 27, 2026 07:11
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c8d0594bf6

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@eigengravy eigengravy force-pushed the calling-sdk-e2e-tests-sdk-init branch from c8d0594 to b403066 Compare March 27, 2026 07:29
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b403066242

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4ae9081768

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Copy link
Copy Markdown
Contributor

@Kesari3008 Kesari3008 left a comment

Choose a reason for hiding this comment

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

  1. Why are we using feature branch to merge E2E tests changes, how does this affect any working code files if we merge it next branch ?
  2. If we are planning to submit this in separate branch then we should be making change in pul request yml to make the pipeline run?
  3. Also do we have plan to add playwright.yml to run it in the pipeline. Maybe we should add that in initial PRs itself where we are setting the playwright config up

<input id="jwt-token-for-dest" name="jwtToken" placeholder="JWT token for destination" value="" type="text" style="margin: 0.5rem 0 0.5rem 0;">
<input id="guest-name" name="guestName" placeholder="Guest name" value="" type="text" style="margin: 0.5rem 0 0.5rem 0;">
<button type="button" onclick="generateGuestToken()">Generate Guest Token [Prod only]</button>
<button id="generate-guest-token" type="button" onclick="generateGuestToken()">Generate Guest Token [Prod only]</button>
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 is this change required ?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The id="generate-guest-token" was added to the button in the sample app HTML so the Playwright test can target it with a stable #generate-guest-token CSS selector. Previously the test used a fragile text-based selector (button:has-text("Generate Guest Token")) which would break if the button label ever changed. This was flagged by Akula in the review as a nit — adding an id makes the selector resilient to label changes.

"@babel/types": "^7.14.9",
"@commitlint/cli": "^17.1.2",
"@commitlint/config-conventional": "^17.1.0",
"@playwright/test": "^1.58.2",
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.

Do we not need the command(script) to run these tests here ?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done — added test:e2e:calling script: "test:e2e:calling": "yarn playwright test --project='Calling SDK E2E'"

/**
* Navigate, init SDK, verify, and optionally set service and register line.
*/
export const initAndRegister = async (
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.

Where are we using this and when we have individually testcases calling the below methods anyway then why we need this method

navigateToCallingApp(page) anyway then
if (options.service) {
await setServiceIndicator(page, options.service);
}
await initializeCallingSDK(page, accessToken);
await verifySDKInitialized(page);
if (options.registerLine) {
await registerLine(page);
await verifyLineRegistered(page);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

initAndRegister is used in the device registration tests (next PR) where each account's beforeAll needs to navigate → init → register. Avoids repeating the same 5-step sequence in every test group.


// Media
GET_MEDIA_STREAMS_BTN: '#sd-get-media-streams',
LOCAL_VIDEO: '#local-video',
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 added constants for local video and remote video, we do not have video mode supported in WebRTC ?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done — removed LOCAL_VIDEO and REMOTE_VIDEO selectors since calling doesn't have video.

// Timeouts — SDK timeout + 5s buffer for network/UI overhead
export const AWAIT_TIMEOUT = 10000; // General UI interactions
export const SDK_INIT_TIMEOUT = 65000; // RETRY_TIMER_UPPER_LIMIT (60s) + 5s
export const REGISTRATION_TIMEOUT = 35000; // BASE_REG_RETRY_TIMER_VAL_IN_SEC (30s) + 5s
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.

How did we come up with this timeout value ?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Each timeout is derived from the corresponding SDK constant + 5s buffer for network/UI overhead:

});
await expect(page.locator(SELECTORS.REGISTER_BTN)).toBeEnabled({timeout: SDK_INIT_TIMEOUT});

const hasCallingClient = await page.evaluate(() => !!(window as any).callingClient);
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.

We should also consider checking the config that is passed during initialization and based on that we should be checking which clients are active. There can be cases where we have CallingClient, CallHistoryClient, Voicemail etc instantiated too. I know we are focusing on CallingCleint specific tests for now but initialization should cover all scenarios or if we do not want to do that, add a TODO here to add expect statements for other clients

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Added a TODO comment in verifySDKInitialized to check which clients are active based on the initialization config. Currently we only verify callingClient exists — the TODO notes that different configs can also instantiate CallHistoryClient, Voicemail, etc. and we should add expect statements for each.

test.describe('SDK Initialization', () => {
test.describe.configure({mode: 'parallel'});

test('Normal Calling - init with calling service indicator', async ({page}) => {
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.

We should also have testcase where we are passing region and country during initialization. And verify mobius servers discovered based on that. HAve helper methods created to pass those values.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Added setRegion and setCountry helpers in setup.ts, along with REGION_INPUT/COUNTRY_INPUT selectors and REGION/COUNTRY constants. The test case itself will be added in the device registration PR where we have the TestManager for proper account isolation across parallel tests.

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.

Also do we have options to test from different browser, we should be providing that

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Adding config for firefox, edge and safari and ability to set broswer an env variable. Should we run tests across multiple browsers in the test command?


const getToken = (envVar: string): string => {
const token = process.env[envVar];
if (!token) {
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.

We are using 3 different tokens based on different scenarios, can that cause errors here? Maybe adding test.skip guards for optional users

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I am using the 3 available accounts to run the tests (that only require one account) in parallel sets. Here the 3 SDK Init tests run in parallel and in the following Device Registration tests, I have grouped them into sets with each account mapped to a set.

import {Page, expect} from '@playwright/test';
import {SELECTORS, AWAIT_TIMEOUT, REGISTRATION_TIMEOUT} from './constants';

export const registerLine = async (page: Page): Promise<void> => {
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.

This method and below method can be combined

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Keeping them separate — in the device registration tests (next PR), verifyLineRegistered is used standalone to assert auto-re-registration after network disconnect (REG-008) where the SDK re-registers automatically without us calling registerLine.

* - calling.register() is called automatically
* - After register, registerElm is enabled and callingClient + line are set up
*/
export const initializeCallingSDK = async (page: Page, accessToken: string): Promise<void> => {
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.

Same comment here, below and this can be combined and we should also be checking that after initialization init button and token textbox getting disabled

test.describe.configure({mode: 'parallel'});

test('Normal Calling - init with calling service indicator', async ({page}) => {
await navigateToCallingApp(page);
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.

Consider looking into approach of creating Page Object Model and using the page class objects to do verification directly under tests

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We're using the same utility-function pattern as the widgets repo. I did a feasibility analysis on POM and it doesn't work well with our test patterns — we rely on context.route() for network interception, browserContext.newPage() for multi-page scenarios, and shared browser context across chained tests (e.g. failover where one test's backup state feeds into the next). These are context-centric patterns that don't map cleanly to page class objects. The current utility-function approach keeps things flexible for route mocking and shared context.

@eigengravy
Copy link
Copy Markdown
Member Author

@Kesari3008

  1. Why are we using feature branch to merge E2E tests changes, how does this affect any working code files if we merge it next branch ?
  2. If we are planning to submit this in separate branch then we should be making change in pul request yml to make the pipeline run?
  3. Also do we have plan to add playwright.yml to run it in the pipeline. Maybe we should add that in initial PRs itself where we are setting the playwright config up

The idea was to first merge everything into a feature branch and then open a PR to next with the playwright test added to the pipeline once the CI testing accounts are setup as well. Currently I am testing with the Bifrost Testing Accounts.

Address PR review feedback: add yarn test:e2e:calling script to
package.json and extract CC service domain into a named constant.
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fdeed354fc

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

- Add Firefox, Edge, and Safari browser configs via PW_BROWSER env var
- Split constants into separate modules: selectors.ts, timeouts.ts, index.ts
- Move OAuth constants (ENV_PATH, WIDGETS_URL) from oauth.setup.ts to constants
- Remove unused LOCAL_VIDEO and REMOTE_VIDEO selectors
Add setRegion/setCountry helpers, REGION_INPUT/COUNTRY_INPUT selectors,
and REGION/COUNTRY constants for discovery configuration in E2E tests.
@eigengravy eigengravy requested a review from Kesari3008 April 1, 2026 09:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

validated If the pull request is validated for automation.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants