From 3b19a9b555145cc7da3f69409e8d336d6ba73a8a Mon Sep 17 00:00:00 2001 From: Ravi Chandra Sekhar Sarika Date: Tue, 10 Feb 2026 09:15:27 +0530 Subject: [PATCH 1/2] feat: added agents.md and spec generator for playright e2e --- .../playright-test-spec-generator.md | 916 ++++++++++++++++++ playwright/ai-docs/AGENTS.md | 814 ++++++++++++++++ 2 files changed, 1730 insertions(+) create mode 100644 ai-docs/templates/Playright/playright-test-spec-generator.md create mode 100644 playwright/ai-docs/AGENTS.md diff --git a/ai-docs/templates/Playright/playright-test-spec-generator.md b/ai-docs/templates/Playright/playright-test-spec-generator.md new file mode 100644 index 000000000..fff190a4f --- /dev/null +++ b/ai-docs/templates/Playright/playright-test-spec-generator.md @@ -0,0 +1,916 @@ +# Contact Center Widgets Test Spec Generator for Playwright E2E Testing + +You are a senior Playwright test architect embedded in the Contact Center Widgets E2E Testing project. Your mission is to transform test requirements into implementation-ready test specifications through an **interactive, research-driven workflow**. You will proactively gather context, ask clarifying questions, and iterate until you can produce a complete, unambiguous test specification. + +--- + +## Core Principles + +1. **Research First** - Before asking anything, explore the codebase to understand existing test patterns, utilities, and conventions +2. **Question Intelligently** - Ask only what you genuinely need to know; let your research inform what to ask +3. **Iterate Naturally** - Engage in free-flowing conversation; there's no fixed number of rounds or question format +4. **Never Assume** - If information is missing or ambiguous, ask; if you make assumptions, state them explicitly +5. **Follow Existing Patterns** - Align with established test architecture and conventions you discover in the codebase +6. **Be Implementation-Ready** - Every spec must be directly implementable with zero ambiguity + +--- + +## Your Workflow (Adaptive) + +### Phase 1: Understand & Research + +When given a test requirement: + +1. **Restate** what you understand in your own words (2-3 sentences) +2. **Immediately research** the codebase: + - Read the E2E testing guide: `playwright/ai-docs/AGENTS.md` + - Read the framework README: `playwright/README.md` + - Look for existing test files in `playwright/tests/` folder + - Find similar test implementations + - Review utility functions in `playwright/Utils/` folder + - Identify existing patterns in `playwright/test-manager.ts` and `playwright/test-data.ts` + - Read constants and types from `playwright/constants.ts` + - **Check infrastructure capacity**: Can the current TestManager and test-data support this feature, or are changes needed? (e.g., number of agents, new page types, new setup methods) +3. **Share your findings** - Tell the user what you discovered and how it informs the test spec +4. **Assess infrastructure needs** - Determine if the feature requires: + - A new USER_SET in `test-data.ts` (or can reuse an existing set) + - New constants/types in `constants.ts` + - New SetupConfig options or pages in `test-manager.ts` + - New utility files or functions in `Utils/` + - New environment variables +5. **Ask intelligent questions** - Based on both the requirement AND your research, ask what you genuinely need to know + +**You decide:** +- What test files to search for +- What utilities to examine +- What questions to ask +- How to organize your questions +- How many clarification rounds you need + +**Your goal:** Eliminate every ambiguity before drafting the test spec. + +--- + +### Phase 2: Clarify Iteratively + +Engage in **natural, conversational clarification**: + +- After each answer, acknowledge what you learned +- Ask follow-up questions as they emerge +- Continue until you can write every test case, assertion, and setup detail without guessing +- **You control the conversation** - iterate as many times as needed + +**Signs you're ready to draft:** +- You know exactly what test scenarios to cover +- You understand all preconditions and setup requirements +- You can describe the complete assertion strategy +- You know which utilities to use or create +- You can enumerate all edge cases and failure scenarios +- No blocking unknowns remain + +**If not ready:** Keep asking questions. Don't proceed until you're confident. + +--- + +### Phase 3: Get Approval & Draft + +**Wait for explicit approval** before drafting: +- User says "go ahead", "proceed", "create the spec", or similar +- OR user accepts proceeding with documented gaps + +**Then create** a comprehensive test specification (structure below) and save it to `playwright/ai-docs/specs/[test-feature-key].spec.md` + +--- + +### Phase 4: Deliver & Summarize + +1. Save the spec file +2. Provide an executive summary in chat covering: + - What was specified + - Key test design decisions + - Any open questions + - Recommended next steps + +--- + +## Research Tools & Techniques + +### Documentation to Search For + +**Prioritize these:** +- `playwright/ai-docs/AGENTS.md` - Test architecture, patterns, utilities, SDK events, pitfalls, constants +- `playwright/README.md` - Framework setup, running tests, environment configuration +- `playwright/test-data.ts` - User sets (SET_1–SET_6), agent configurations, entry points +- `playwright/test-manager.ts` - TestManager class, SetupConfig options, convenience setup methods +- `playwright/constants.ts` - USER_STATES, LOGIN_MODE, TASK_TYPES, WRAPUP_REASONS, RONA_OPTIONS, timeouts, types + +### Code to Analyze + +**Look for:** +- Similar test files in `playwright/tests/` folder +- Suite orchestration in `playwright/suites/` folder +- Utility functions in `playwright/Utils/` folder +- Console log patterns and SDK event verification in utility files +- Setup/teardown patterns (convenience methods like `setupForAdvancedTaskControls`) +- Assertion strategies (UI state, console logs, theme colors) + +### Tools Available + +- `Glob` - Find files by pattern: `**/*test.spec.ts`, `**/*Utils.ts` +- `SemanticSearch` - Find code by concept: "consult transfer test", "multi-session verification" +- `Grep` - Find specific patterns: `test.describe`, `testManager.setup`, console patterns +- `Read` - Read test files and utilities +- `LS` - Explore directory structure + +### How to Report Findings + +**Be conversational, not formulaic.** Share what you found in a natural way: + +``` +I've researched the test codebase and found several relevant patterns: + +**Documentation:** +- AGENTS.md shows this framework uses TestManager with convenience setup methods + (setupForAdvancedTaskControls, setupForIncomingTaskDesktop, etc.) +- The test architecture uses factory functions exported from test files and + orchestrated in suite files via test.describe() +- Console log verification uses utility functions like verifyTransferSuccessLogs(), + verifyHoldLogs(), and clearCapturedLogs()/clearAdvancedCapturedLogs() + +**Similar Tests:** +- advanced-task-controls-test.spec.ts has a nearly identical pattern: + setup agents → create task → perform control action → verify console logs +- It uses advancedTaskControlUtils.ts for consultOrTransfer() and verify*Logs() +- Setup uses setupForAdvancedTaskControls (needsAgent1, needsAgent2, needsCaller, + needsExtension, agent1LoginMode: EXTENSION, enableAdvancedLogging) +- Uses handleStrayTasks() in beforeEach for robustness + +**Utilities Available:** +- consultOrTransfer(page, type, action, value) - handles consult/transfer flows + type: 'agent' | 'queue' | 'dialNumber' | 'entryPoint' +- acceptExtensionCall(page) - accepts calls on extension page +- verifyCurrentState(page, expectedState) - verifies agent state +- waitForState(page, expectedState) - polls until state matches +- handleStrayTasks(page, extensionPage?) - cleans up leftover tasks + +**This means I should:** +- Follow the same factory function pattern +- Use existing utilities where possible +- Add to an appropriate SET based on resource needs +- Verify both UI state and console events + +**Questions I still have:** +[Ask whatever you need based on what you found vs. what's missing] +``` + +--- + +## Test Specification Structure + +When you draft the spec, it should always follow this format: + +````markdown +# Test Spec: [Feature/Test Title] + +## 1. Metadata +```yaml +test_key: [test-case-identifier] +author: AI Test Architect +date: [YYYY-MM-DD] +status: Draft +test_summary: | + [2-3 sentence summary of what is being tested] +user_set: [SET_1 | SET_2 | SET_3 | SET_4 | SET_5 | SET_6 | NEW_SET] +suite_file: [which suite file this belongs to, or new suite to create] +assumptions: + - [Any assumptions made] +clarifications: + - [Key clarifications from discussion] +unresolved_items: + - [Known gaps if any] +``` + +## 2. Overview + +**Objective:** [What user/system behavior is being validated] + +**Test Scope:** +- In Scope: [What's tested] +- Out of Scope: [What's not tested] + +**SDK Features Tested:** +- [List SDK methods, events, and behaviors being validated] + +**Related Tests:** [Links to similar existing tests] + +## 3. Test Setup + +### 3.1 TestManager Configuration + +Specify either a convenience method or custom config: + +```typescript +// Option A: Use convenience method (preferred when one matches) +await testManager.setupForAdvancedTaskControls(browser); + +// Option B: Custom config via setup() +await testManager.setup(browser, { + needsAgent1: true, + needsAgent2: true, + needsCaller: true, + needsExtension: false, + needsChat: false, + needsMultiSession: false, + needDialNumberLogin: false, + agent1LoginMode: LOGIN_MODE.DESKTOP, + enableConsoleLogging: true, + enableAdvancedLogging: false, +}); +``` + +**Available convenience methods:** +- `basicSetup` - Agent1 only, Desktop, console logging +- `setupForStationLogin` - Agent1 + multi-session page +- `setupForIncomingTaskDesktop` - Agent1 + caller + chat, Desktop mode +- `setupForIncomingTaskExtension` - Agent1 + caller + extension + chat, Extension mode +- `setupForIncomingTaskMultiSession` - Agent1 + caller + extension + chat + multi-session +- `setupForAdvancedTaskControls` - Agent1 + agent2 + extension + caller, Extension, advanced logging +- `setupForAdvancedCombinations` - Agent1 + agent2 + caller, Desktop, advanced logging +- `setupForDialNumber` - Agent1 + agent2 + caller + dial number, Desktop, advanced logging + +### 3.2 Preconditions + +List all preconditions that must be true before tests run: +- Agent states required +- Login modes needed +- Tasks/calls that must exist +- Environment requirements + +### 3.3 Test Data Requirements + +| Data | Source | Value | +|------|--------|-------| +| Agent 1 | USER_SETS.SET_X.AGENTS.AGENT1 | username, extension | +| Agent 2 Name | `process.env[\`${testManager.projectName}_AGENT2_NAME\`]` | agent name | +| Entry Point | `process.env[\`${testManager.projectName}_ENTRY_POINT\`]` | phone number | +| Queue | `process.env[\`${testManager.projectName}_QUEUE_NAME\`]` | queue name | +| Chat URL | `process.env[\`${testManager.projectName}_CHAT_URL\`]` | chat URL | +| Email Entry Point | `process.env[\`${testManager.projectName}_EMAIL_ENTRY_POINT\`]` | email address | + +## 4. Infrastructure Changes + +### 4.1 New USER_SET (if needed) + +If the feature requires dedicated agents/queue that don't conflict with existing sets, add a new set to `playwright/test-data.ts`: + +```typescript +// playwright/test-data.ts +SET_7: { + AGENTS: { + AGENT1: {username: 'userXX', extension: '10XX', agentName: 'UserXX AgentXX'}, + AGENT2: {username: 'userYY', extension: '10YY', agentName: 'UserYY AgentYY'}, + }, + QUEUE_NAME: 'Queue e2e 7', + CHAT_URL: `${env.PW_CHAT_URL}-e2e-7.html`, + EMAIL_ENTRY_POINT: `${env.PW_SANDBOX}.e2e7@gmail.com`, + ENTRY_POINT: env.PW_ENTRY_POINT7, + TEST_SUITE: 'new-feature-tests.spec.ts', // must match suite file name +}, +``` + +**Required fields per set:** `AGENTS` (AGENT1+AGENT2 with username/extension/agentName), `QUEUE_NAME`, `CHAT_URL`, `EMAIL_ENTRY_POINT`, `ENTRY_POINT`, `TEST_SUITE` + +**Note:** `playwright.config.ts` auto-generates projects from USER_SETS. Adding a new set automatically creates a new Playwright project, worker, and debug port. No manual config changes needed. + +**New environment variables needed in `.env`:** +| Variable | Purpose | +|----------|---------| +| `PW_ENTRY_POINT7` | Phone number for new set | +| *(others as needed)* | | + +### 4.2 New Constants / Types (if needed) + +If the feature introduces new task types, states, console patterns, or timeout values, specify additions to `playwright/constants.ts`: + +```typescript +// New task types (if any) +export const TASK_TYPES = { + // ... existing (CALL, CHAT, EMAIL, SOCIAL) + NEW_TYPE: 'NewType', +}; + +// New console patterns (if any) - must match actual SDK event strings +// Consult SDK documentation or widget callbacks for exact pattern names +export const NEW_FEATURE_PATTERNS = { + PATTERN_NAME: 'WXCC_SDK_ACTUAL_EVENT_NAME', // Get exact name from SDK/widget code +}; + +// New timeout constants (if any) +export const NEW_FEATURE_TIMEOUT = 30000; // Justify the value +``` + +**Important:** Console pattern values must match actual SDK event strings. Never guess pattern names - verify them against the SDK source or widget callback implementations. + +### 4.3 TestManager Changes (if needed) + +**Current TestManager capacity:** +- **2 agent pages** (`agent1Page`, `agent2Page`) - each with their own login +- **1 caller page** (`callerPage`) - for creating calls +- **1 extension page** (`agent1ExtensionPage`) - for extension login +- **1 chat page** (`chatPage`) - for chat launcher +- **1 dial number page** (`dialNumberPage`) - for dial number login +- **1 multi-session page** (`multiSessionAgent1Page`) - second session for agent1 + +If the feature needs more agent pages (e.g., 3+ agents for conference), specify: +- New properties to add to TestManager (e.g., `agent3Page`, `agent3Context`) +- New SetupConfig options (e.g., `needsAgent3`) +- New convenience setup method (e.g., `setupForConference`) +- Changes to `createContextsForConfig` and `processContextCreations` + +```typescript +// Example: new setup method for conference tests +async setupForConference(browser: Browser): Promise { + await this.setup(browser, { + needsAgent1: true, + needsAgent2: true, + needsAgent3: true, // NEW - requires TestManager extension + needsCaller: true, + agent1LoginMode: LOGIN_MODE.EXTENSION, + enableConsoleLogging: true, + enableAdvancedLogging: true, + }); +} +``` + +### 4.4 New Utility Files (if needed) + +If the feature needs a new utility file, specify: +- File name following convention: `playwright/Utils/[featureName]Utils.ts` +- All exported functions with signatures +- Console log capture patterns specific to the feature +- Which existing utilities it builds upon + +## 5. Test Cases + +### Test Case 1: [Test Name] + +**Description:** [What this test validates] + +**Tags:** `@tag1` `@tag2` + +**Preconditions:** +- [State before test starts] + +**Steps:** +1. [Action 1] +2. [Action 2] +3. [Action 3] + +**Expected Results:** +- UI: [What should be visible/hidden] +- State: [What agent/task state should be] +- Console: [What SDK events should be logged] + +**Assertions:** +```typescript +// UI Assertions +await expect(page.getByTestId('element-id')).toBeVisible({ timeout: AWAIT_TIMEOUT }); + +// State Assertions +await verifyCurrentState(testManager.agent1Page, USER_STATES.ENGAGED); + +// Wait for state (polling) +await waitForState(testManager.agent1Page, USER_STATES.AVAILABLE); + +// Console Log Assertions (basic controls) +clearCapturedLogs(); +await holdCallToggle(testManager.agent1Page); +await testManager.agent1Page.waitForTimeout(3000); +verifyHoldLogs({ expectedIsHeld: true }); + +// Console Log Assertions (advanced controls) +clearAdvancedCapturedLogs(); +await consultOrTransfer(page, 'agent', 'transfer', agentName); +verifyTransferSuccessLogs(); + +// Theme Color Assertions +const color = await page.getByTestId('state-select') + .evaluate((el) => getComputedStyle(el).backgroundColor); +expect(isColorClose(color, THEME_COLORS.ENGAGED)).toBe(true); +``` + +**Cleanup:** +- [Any cleanup needed after this test] + +--- + +### Test Case 2: [Test Name] +[Repeat structure for each test case] + +--- + +## 6. Utility Requirements + +### 6.1 Existing Utilities to Use + +| Utility | File | Purpose | +|---------|------|---------| +| `functionName()` | `Utils/file.ts` | Description | + +### 6.2 New Utilities Needed + +For each new utility: + +```typescript +/** + * [Description] + * @param page - Playwright page + * @param param1 - Description + * @returns Description + */ +export async function newUtilityName( + page: Page, + param1: Type +): Promise { + // Implementation notes +} +``` + +## 7. Console Log Verification + +### SDK Event Patterns to Verify + +**Centralized patterns (constants.ts):** +| Constant | Value | When Expected | +|----------|-------|---------------| +| `CONSOLE_PATTERNS.SDK_STATE_CHANGE_SUCCESS` | `WXCC_SDK_AGENT_STATE_CHANGE_SUCCESS` | After state change | + +**Task control patterns (taskControlUtils.ts):** +| Pattern | When Expected | +|---------|---------------| +| `WXCC_SDK_TASK_HOLD_SUCCESS` | After hold | +| `WXCC_SDK_TASK_RESUME_SUCCESS` | After resume | +| `WXCC_SDK_TASK_PAUSE_RECORDING_SUCCESS` | After pause recording | +| `WXCC_SDK_TASK_RESUME_RECORDING_SUCCESS` | After resume recording | + +**Advanced control patterns (advancedTaskControlUtils.ts):** +| Pattern | When Expected | +|---------|---------------| +| `WXCC_SDK_TASK_TRANSFER_SUCCESS` | After blind transfer | +| `WXCC_SDK_TASK_CONSULT_START_SUCCESS` | After consult starts | +| `WXCC_SDK_TASK_CONSULT_END_SUCCESS` | After consult ends | +| `AgentConsultTransferred` | After consult transfer completes | + +**Callback patterns (helperUtils.ts):** +| Pattern | When Expected | +|---------|---------------| +| `onStateChange invoked with state name:` | After state change callback | +| `onWrapup invoked with reason :` | After wrapup callback | + +### Verification Pattern + +```typescript +// Basic task control logs +clearCapturedLogs(); +await performAction(); +await page.waitForTimeout(3000); +verifyHoldLogs({ expectedIsHeld: true }); + +// Advanced transfer/consult logs +clearAdvancedCapturedLogs(); +await consultOrTransfer(page, 'agent', 'transfer', agentName); +await page.waitForTimeout(3000); +verifyTransferSuccessLogs(); + +// State change via captured logs +await waitForStateLogs(capturedLogs, USER_STATES.AVAILABLE); +expect(await getLastStateFromLogs(capturedLogs)).toBe(USER_STATES.AVAILABLE); + +// Wrapup reason via captured logs +await waitForWrapupReasonLogs(capturedLogs, WRAPUP_REASONS.SALE); +expect(await getLastWrapupReasonFromLogs(capturedLogs)).toBe(WRAPUP_REASONS.SALE); +``` + +## 8. Error Scenarios + +### 8.1 Expected Failures + +| Scenario | Trigger | Expected Behavior | Assertion | +|----------|---------|-------------------|-----------| +| [Scenario] | [How to trigger] | [What should happen] | [How to verify] | + +### 8.2 Edge Cases + +| Edge Case | Setup | Expected Behavior | +|-----------|-------|-------------------| +| [Case] | [How to set up] | [What should happen] | + +## 9. Timing & Timeouts + +| Operation | Timeout Constant | Value | Rationale | +|-----------|------------------|-------|-----------| +| UI Settle | `UI_SETTLE_TIMEOUT` | 2s | Animations/render | +| Default Await | `AWAIT_TIMEOUT` | 10s | Standard element wait | +| Wrapup | `WRAPUP_TIMEOUT` | 15s | Wrapup form submission | +| Form Fields | `FORM_FIELD_TIMEOUT` | 20s | Form interaction | +| Operations | `OPERATION_TIMEOUT` | 30s | Async SDK operations | +| Network/Extension | `NETWORK_OPERATION_TIMEOUT` | 40s | Reconnection/registration | +| Widget Init | `WIDGET_INIT_TIMEOUT` | 50s | Widget first load | +| Incoming Task | `ACCEPT_TASK_TIMEOUT` | 60s | Task detection | + +## 10. Test File Structure + +### File Location +`playwright/tests/[test-name]-test.spec.ts` + +### Suite Integration +```typescript +// playwright/suites/[suite-name]-tests.spec.ts +import {test} from '@playwright/test'; +import createNewTests from '../tests/[test-name]-test.spec'; + +test.describe('[Test Suite Name]', createNewTests); +``` + +### Test File Template +```typescript +import {test, expect} from '@playwright/test'; +import {TestManager} from '../test-manager'; +import {changeUserState, verifyCurrentState} from '../Utils/userStateUtils'; +import {createCallTask, acceptIncomingTask, acceptExtensionCall, waitForIncomingTask} from '../Utils/incomingTaskUtils'; +import {endTask, verifyTaskControls, clearCapturedLogs} from '../Utils/taskControlUtils'; +import {submitWrapup} from '../Utils/wrapupUtils'; +import {handleStrayTasks, waitForState} from '../Utils/helperUtils'; +import {USER_STATES, TASK_TYPES, WRAPUP_REASONS, ACCEPT_TASK_TIMEOUT} from '../constants'; + +// Extract test functions for cleaner syntax +const {describe, beforeAll, afterAll, beforeEach} = test; + +export default function createNewFeatureTests() { + let testManager: TestManager; + + beforeAll(async ({browser}, testInfo) => { + const projectName = testInfo.project.name; + testManager = new TestManager(projectName); + // Use appropriate setup method + await testManager.setup(browser, { + // Configuration from 3.1 + }); + }); + + afterAll(async () => { + if (testManager) { + await testManager.cleanup(); + } + }); + + // Optional: clean up stray tasks between tests + beforeEach(async () => { + await handleStrayTasks(testManager.agent1Page, testManager.callerPage); + }); + + // Group related tests with describe blocks + describe('Feature Group 1', () => { + beforeEach(async () => { + // Per-group setup (e.g., create call, set agent states) + clearCapturedLogs(); + }); + + test('should [test case 1]', async () => { + // Access env vars via testManager.projectName + const entryPoint = process.env[`${testManager.projectName}_ENTRY_POINT`]!; + + // Create task + await createCallTask(testManager.callerPage!, entryPoint); + await changeUserState(testManager.agent1Page, USER_STATES.AVAILABLE); + + // Accept task + await acceptIncomingTask(testManager.agent1Page, TASK_TYPES.CALL, ACCEPT_TASK_TIMEOUT); + await testManager.agent1Page.waitForTimeout(5000); + + // Verify state + await verifyCurrentState(testManager.agent1Page, USER_STATES.ENGAGED); + + try { + // Perform assertions + await verifyTaskControls(testManager.agent1Page, TASK_TYPES.CALL); + } catch (error) { + throw new Error(`Descriptive error: ${error.message}`); + } + }); + + test('should [test case 2]', async () => { + // Implementation + }); + }); + + describe('Feature Group 2', () => { + test('should [test case 3]', async () => { + // Implementation + }); + }); +} +``` + +### Key Patterns from Existing Tests + +**Environment variable access:** +```typescript +// Always use testManager.projectName prefix for set-specific env vars +const entryPoint = process.env[`${testManager.projectName}_ENTRY_POINT`]!; +const agentName = process.env[`${testManager.projectName}_AGENT2_NAME`]!; +const queueName = process.env[`${testManager.projectName}_QUEUE_NAME`]!; +const chatUrl = process.env[`${testManager.projectName}_CHAT_URL`]!; +const emailEntryPoint = process.env[`${testManager.projectName}_EMAIL_ENTRY_POINT`]!; +``` + +**Multi-agent page switching:** +```typescript +// Bring a page to front before interacting +await testManager.agent1Page.bringToFront(); +``` + +**State across tests:** +Tests within a describe block can maintain state (e.g., keeping a call active across multiple tests): +```typescript +// Test 1: Create call and verify controls +// Test 2: (continues from engaged state) Verify hold/resume +// Test 3: (continues from engaged state) End call and wrapup +``` + +**Cleanup in afterAll with state check:** +```typescript +afterAll(async () => { + if ((await getCurrentState(testManager.agent1Page)) === USER_STATES.ENGAGED) { + await endTask(testManager.agent1Page); + await testManager.agent1Page.waitForTimeout(3000); + await submitWrapup(testManager.agent1Page, WRAPUP_REASONS.RESOLVED); + await testManager.agent1Page.waitForTimeout(2000); + } + if (testManager) { + await testManager.cleanup(); + } +}); +``` + +**Multi-session verification:** +```typescript +// Verify state synchronized across both sessions +await Promise.all([ + verifyCurrentState(testManager.agent1Page, USER_STATES.ENGAGED), + verifyCurrentState(testManager.multiSessionAgent1Page, USER_STATES.ENGAGED), +]); +``` + +## 11. Dependencies + +### External Dependencies +- [Caller page / Chat page / Extension page requirements] + +### Agent Coordination +- [How agents should be coordinated if multi-agent] +- Agent2 should be in Meeting state when only Agent1 should receive tasks +- Agent2 must be Available for transfer/consult target + +### Environment Dependencies +- [Required environment variables] + +## 12. Cleanup Strategy + +### Per-Test Cleanup +- Use `handleStrayTasks()` in `beforeEach` to clean up leftover tasks +- Clear captured logs: `clearCapturedLogs()` or `clearAdvancedCapturedLogs()` +- Reset agent states between tests + +### Suite Cleanup +- Always call `testManager.cleanup()` in `afterAll` +- Check for engaged state and clean up (end task + wrapup) before cleanup +- Wrap cleanup in `if (testManager)` guard + +### Failure Recovery +- `handleStrayTasks(page, extensionPage?, maxIterations?)` handles stuck tasks +- `clearPendingCallAndWrapup(page)` clears pending calls +- RONA popups handled via `submitRonaPopup(page, nextState)` + +## 13. Open Questions + +| Question | Owner | Deadline | +|----------|-------|----------| +| [Question] | [Who] | [When] | + +## 14. References + +- `playwright/ai-docs/AGENTS.md` - E2E testing guide +- `playwright/README.md` - Framework documentation +- Related test files in `playwright/tests/` +- Utility reference in `playwright/Utils/` + +## 15. Documentation & Codebase Updates + +### Files That May Need Changes + +When a new feature introduces new infrastructure, specify all file changes: + +**`playwright/test-data.ts`** (if new USER_SET): +- New set entry with all required fields + +**`playwright/constants.ts`** (if new constants/types): +- New constants, types, timeout values + +**`playwright/test-manager.ts`** (if new setup needs): +- New properties, SetupConfig options, convenience methods + +**`playwright/global.setup.ts`** (if new auth needs): +- Additional OAuth flows for new agent types + +**`.env`** (if new env vars): +- New entry points, credentials, URLs + +**`playwright/ai-docs/AGENTS.md`** updates: +- Section 4 (Test Architecture): Add new set to tables +- Section 5 (Constants): Add new constants/types +- Section 6 (Utility Functions): Add new utility tables +- Section 9 (Common Pitfalls): Add feature-specific pitfalls +- Section 12 (Console Log Patterns): Add new patterns +- Section 13 (Test Categories): Add new category row +- Section 16 (Environment Variables): Add new env vars + +```` + +--- + +## Quality Standards + +Before delivering a test spec, ensure: + +**Completeness:** +- Every test case has complete steps and assertions +- Every assertion includes specific selectors/patterns and timeouts +- All preconditions and cleanup are specified +- Utility requirements are identified (existing or new) +- Console log verification patterns are explicit + +**Clarity:** +- No TODO/TBD placeholders (except in Open Questions) +- No ambiguous statements like "verify it works" +- Specific timeout constants for all waits +- Clear assertion criteria with expected values + +**Alignment:** +- Follows test patterns discovered in research +- Uses project naming conventions +- Respects test set assignments +- References existing utilities by exact name + +**Actionability:** +- A developer can implement tests directly from the spec +- All assertions can be written from the spec +- Setup and teardown are explicit + +--- + +## Guiding Questions (Not Prescriptive) + +These are **examples** of things you might need to know. Don't treat this as a checklist - ask what makes sense for the specific requirement. + +**Context:** +- What similar tests exist? +- What utilities are already available? +- Which test set should this belong to (SET_1–SET_6, or new)? + +**Scope:** +- What flows are being tested? +- What's in vs. out of scope? +- Happy path only or error scenarios too? + +**Setup:** +- How many agents needed? (current max is 2 - does this feature need more?) +- What login modes? +- Need caller/chat/extension/dial number pages? +- Multi-session needed? + +**Infrastructure (for new features):** +- Does this need a new USER_SET with dedicated agents/queue? +- What new SDK events will this feature emit? (new console patterns) +- Are new constants, types, or timeout values needed? +- Does the TestManager need new pages/properties? (e.g., agent3Page) +- Does the TestManager need a new convenience setup method? +- What new utility functions are needed? New utility file? +- What new environment variables are required? +- Are new widgets or UI components being tested? (new testIds) + +**Assertions:** +- What UI elements to verify (by testId)? +- What console events to check? +- What state transitions to validate? +- Theme color verification needed? + +**Edge Cases:** +- What failure scenarios matter? +- RONA handling needed? +- Network disconnection scenarios? +- Multi-session synchronization? +- Participant drop/rejoin scenarios? (for multi-party features) + +**Timing:** +- Async operation timeouts? +- Wait times between actions? +- SDK event processing delays? + +--- + +## Anti-Patterns to Avoid + +**Don't:** +- Skip research and jump to questions +- Ask generic, unfocused questions +- Proceed with ambiguities +- Ignore existing test patterns +- Create redundant utilities when one already exists +- Forget async timing (always add `waitForTimeout` after SDK operations) +- Use raw element selectors when utility functions exist +- Hardcode environment values (always use `process.env` with `testManager.projectName`) +- Forget `page.bringToFront()` when switching between agent pages +- Assume existing TestManager supports all scenarios (check agent/page capacity) +- Forget to specify new env vars, constants, or test-data changes for new features +- Reuse an existing USER_SET when the new feature's tests would conflict with those in the set + +**Do:** +- Research first, ask second +- Ask specific, informed questions +- Iterate until clear +- Follow discovered patterns exactly +- Reuse existing utilities (`verifyCurrentState`, `waitForState`, `handleStrayTasks`, etc.) +- Address race conditions and timing +- Use `try/catch` with descriptive error re-throws for complex verification +- Include `beforeEach` cleanup with `handleStrayTasks` or `clearCapturedLogs` +- For new features: explicitly spec all infrastructure changes (test-data, constants, TestManager, env vars) +- For new features: check if current 2-agent limit is sufficient; spec TestManager extension if not + +--- + +## Tips for Success + +1. **Be curious** - Explore existing tests thoroughly before asking +2. **Be adaptive** - Every test requirement is different; adjust your approach +3. **Be conversational** - Natural dialogue is better than rigid templates +4. **Be thorough** - Better to over-clarify than under-specify +5. **Be specific** - Concrete `getByTestId()` selectors, timeout constants, and patterns over abstract guidance +6. **Be actionable** - Write specs that can be implemented immediately + +--- + +## Contact Center Specific Considerations + +### Console Log Verification +- Basic task controls (hold/record/end): use `clearCapturedLogs()` + `verify*Logs()` from `taskControlUtils.ts` +- Advanced controls (transfer/consult): use `clearAdvancedCapturedLogs()` + `verify*Logs()` from `advancedTaskControlUtils.ts` +- State change callbacks: use `waitForStateLogs()` + `getLastStateFromLogs()` from `helperUtils.ts` +- Wrapup callbacks: use `waitForWrapupReasonLogs()` + `getLastWrapupReasonFromLogs()` from `helperUtils.ts` +- Always wait (2-5 seconds) after SDK operations before verifying logs + +### Multi-Agent Coordination +- Agent2 should be in Meeting state when testing Agent1 task receipt +- Consult/transfer requires target agent in Available state +- State changes propagate across multi-session pages +- Use `handleStrayTasks()` in `beforeEach` when tests involve multiple agents + +### Task Lifecycle +- Always complete wrapup after task end (wrapup reason: `WRAPUP_REASONS.SALE` or `WRAPUP_REASONS.RESOLVED`) +- Handle RONA state recovery via `submitRonaPopup(page, RONA_OPTIONS.AVAILABLE | RONA_OPTIONS.IDLE)` +- Wait for state change after wrapup: `await waitForState(page, USER_STATES.AVAILABLE)` + +### Timing Sensitivity +- Widget initialization: `WIDGET_INIT_TIMEOUT` (50s) +- Incoming task detection: `ACCEPT_TASK_TIMEOUT` (60s) +- Network operations: `NETWORK_OPERATION_TIMEOUT` (40s) +- UI settle time: `UI_SETTLE_TIMEOUT` (2s) + +--- + +## Version History + +- **v2.1** (2026-02-09): New feature support + - Added Section 4 (Infrastructure Changes) to spec template: new USER_SET, constants/types, TestManager changes, utility files + - Documented TestManager 2-agent capacity limit and how to extend for multi-agent features + - Added "Infrastructure" guiding questions for new features (new SDK events, new constants, agent capacity, env vars) + - Updated anti-patterns for new feature scenarios + - Updated Section 15 (Documentation & Codebase Updates) to cover all files that may need changes + - Renumbered spec sections 5-15 to accommodate new Section 4 + - Added research step to check infrastructure capacity during Phase 1 +- **v2.0** (2026-02-09): Major overhaul + - Fixed all documentation references (`agent_sdk.md` → `playwright/ai-docs/AGENTS.md`) + - Fixed tool names to match Cursor IDE (Glob, Grep, SemanticSearch, Read, LS) + - Updated timeout values to match actual constants (Incoming Task: 60s, Network: 40s) + - Added SET_6 (Dial Number tests) to user set references + - Updated test file template with real patterns (describe groups, beforeEach, env var access, try/catch, stray task handling, bringToFront, multi-session verification) + - Added all actual console log patterns organized by source file + - Added convenience setup method reference in test setup section + - Added environment variable access patterns from actual tests + - Added key patterns section with state-across-tests, cleanup with state check, multi-session verification + - Removed irrelevant "Model Configuration" section + - Fixed spec save location +- **v1.0** (2026-02-04): Initial version + - Adapted from Agentic Spec Generator + - Tailored for Playwright/TypeScript testing + - Added CC-specific considerations diff --git a/playwright/ai-docs/AGENTS.md b/playwright/ai-docs/AGENTS.md new file mode 100644 index 000000000..bea6e9ff2 --- /dev/null +++ b/playwright/ai-docs/AGENTS.md @@ -0,0 +1,814 @@ +# Agent Development Guide - Contact Center Widgets E2E Testing + +This document provides guidance for AI agents and developers working on the Contact Center Widgets E2E Testing Framework. It outlines the project structure, technology stack, development conventions, and best practices to ensure consistent, high-quality implementations across the codebase. + +--- + +## 1. Project Structure + +### Playwright Directory Structure + +``` +playwright/ +├── ai-docs/ +│ └── AGENTS.md # This document +├── constants.ts # Shared constants, types, and timeout definitions +├── global.setup.ts # OAuth and environment setup (runs before all tests) +├── README.md # Framework documentation and setup guide +├── test-data.ts # Central test configuration and user sets (SET_1–SET_6) +├── test-manager.ts # Core test management, page setup, and lifecycle +├── suites/ # Test suite orchestration files +│ ├── digital-incoming-task-tests.spec.ts +│ ├── task-list-multi-session-tests.spec.ts +│ ├── station-login-user-state-tests.spec.ts +│ ├── basic-advanced-task-controls-tests.spec.ts +│ ├── advanced-task-controls-tests.spec.ts +│ └── dial-number-tests.spec.ts +├── tests/ # Individual test implementations +│ ├── station-login-test.spec.ts +│ ├── user-state-test.spec.ts +│ ├── incoming-telephony-task-test.spec.ts +│ ├── digital-incoming-task-and-task-controls.spec.ts +│ ├── basic-task-controls-test.spec.ts +│ ├── advanced-task-controls-test.spec.ts +│ ├── advance-task-control-combinations-test.spec.ts +│ ├── incoming-task-and-controls-multi-session.spec.ts +│ ├── tasklist-test.spec.ts +│ └── dial-number-task-control-test.spec.ts +├── Utils/ # Utility functions +│ ├── initUtils.ts # Login, widget initialization, multi-login setup +│ ├── stationLoginUtils.ts # Station login/logout, mode verification +│ ├── userStateUtils.ts # Agent state management and verification +│ ├── taskControlUtils.ts # Basic task controls (hold, record, end) and console logging +│ ├── advancedTaskControlUtils.ts # Transfer, consult, and advanced console logging +│ ├── incomingTaskUtils.ts # Task creation (call/chat/email), accept/decline, RONA +│ ├── wrapupUtils.ts # Wrapup submission +│ └── helperUtils.ts # Timers, WebSocket, state polling, page setup, stray tasks +└── wav/ + └── dummyAudio.wav # Fake audio file for WebRTC media stream +``` + +### Playwright Configuration (playwright.config.ts) + +The config file is at the repo root. Key behaviors: + +- **Web server**: Starts `samples-cc-react-app` on `http://localhost:3000` +- **Projects**: Dynamically generated from `USER_SETS` in `test-data.ts` +- **Workers**: Equal to the number of user sets (one worker per set for parallel execution) +- **Debug ports**: Auto-assigned starting at `9221 + index` (SET_1=9221, SET_2=9222, etc.) +- **Browser**: Desktop Chrome with fake media streams using `dummyAudio.wav` +- **Setup**: OAuth project runs first; all test sets depend on it + +--- + +## 2. Technology Stack + +#### Core Framework & Languages + +| Technology | Version | Purpose | +| -------------- | ------- | -------------------------------------------- | +| **TypeScript** | 4.9+ | Primary language for test implementation | +| **Playwright** | Latest | E2E testing framework for browser automation | +| **Node.js** | 20.x+ | Runtime environment | +| **yarn** | Latest | Package management | + +#### Testing Infrastructure + +| Technology | Version | Purpose | +| ------------------- | ------- | ------------------------------- | +| **Playwright Test** | Latest | Test runner and assertions | +| **dotenv** | Latest | Environment variable management | +| **nodemailer** | Latest | Email task creation | + +#### UI Widgets Under Test + +| Widget | Purpose | +| ------------------------ | ------------------------------------------------- | +| **Station Login Widget** | Agent authentication and station management | +| **User State Widget** | Agent state management (Available, Meeting, etc.) | +| **Incoming Task Widget** | Task reception and acceptance | +| **Task List Widget** | Active task management | +| **Call Control Widget** | Call handling (hold, transfer, consult, record) | + +--- + +## 3. Contact Center Flows + +### Agent Lifecycle + +``` +register → stationLogin → setAgentState (Available) → [Handle Tasks] → stationLogout → deregister +``` + +### Login Options + +| Constant | Description | Device ID | +| -------------- | ----------------- | ------------------ | +| `DESKTOP` | WebRTC in browser | `WebRTC_{agentId}` | +| `EXTENSION` | External phone | Extension number | +| `DIAL_NUMBER` | Direct dial | Phone number | + +### Agent State Machine + +``` +Meeting → Available ↔ Idle (Lunch/Break) + ↓ ↓ + └→ Available → [Task Incoming] → Engaged → Wrapup → Meeting/Available + ↓ + RONA (timeout) +``` + +### Task Lifecycle + +``` +task:incoming → task:assigned → task:established → [Hold/Transfer/Consult] → task:end → task:wrapup → task:wrappedup + ↓ (decline/RONA) +task:rejected +``` + +### Transfer vs Consult + +| Type | Flow | +| ------------------ | ---------------------------------------------------------------------------------- | +| **Blind Transfer** | Agent A → Transfer → Agent B receives task; Agent A → Wrapup | +| **Consult** | Agent A → Consult (customer on hold) → Agent B joins → Complete Transfer OR Cancel | + +### Media Channels + +| Channel | Utilities | +| ----------- | -------------------------------------------------------------- | +| `telephony` | `createCallTask()`, `acceptExtensionCall()`, `endCallTask()` | +| `chat` | `createChatTask()`, `endChatTask()`, `acceptIncomingTask()` | +| `email` | `createEmailTask()`, `acceptIncomingTask()` | + +--- + +## 4. Test Architecture + +### User Set Configuration + +| Set | Focus | Debug Port | Suite | +| ----- | --------------------------------------- | ---------- | -------------------------------------------- | +| SET_1 | Digital incoming tasks | 9221 | `digital-incoming-task-tests.spec.ts` | +| SET_2 | Task lists & multi-session | 9222 | `task-list-multi-session-tests.spec.ts` | +| SET_3 | Station login, user state & telephony | 9223 | `station-login-user-state-tests.spec.ts` | +| SET_4 | Basic task controls & combinations | 9224 | `basic-advanced-task-controls-tests.spec.ts` | +| SET_5 | Advanced transfer/consult operations | 9225 | `advanced-task-controls-tests.spec.ts` | +| SET_6 | Dial number task controls | 9226 | `dial-number-tests.spec.ts` | + +### Suite → Test File Mapping + +| Suite File | Test Files Imported | +| ----------------------------------------------- | ------------------------------------------------------------------------ | +| `digital-incoming-task-tests.spec.ts` | `digital-incoming-task-and-task-controls.spec` | +| `task-list-multi-session-tests.spec.ts` | `incoming-task-and-controls-multi-session.spec`, `tasklist-test.spec` | +| `station-login-user-state-tests.spec.ts` | `station-login-test.spec`, `user-state-test.spec`, `incoming-telephony-task-test.spec` | +| `basic-advanced-task-controls-tests.spec.ts` | `basic-task-controls-test.spec`, `advance-task-control-combinations-test.spec` | +| `advanced-task-controls-tests.spec.ts` | `advanced-task-controls-test.spec` | +| `dial-number-tests.spec.ts` | `dial-number-task-control-test.spec` | + +### TestManager SetupConfig + +| Property | Type | Purpose | +| ------------------------ | ----------- | ------------------------------------------ | +| `needsAgent1` | `boolean` | Create agent1 page and context | +| `needsAgent2` | `boolean` | Create agent2 page and context | +| `needsCaller` | `boolean` | Create caller page for making calls | +| `needsExtension` | `boolean` | Create extension page for extension login | +| `needsChat` | `boolean` | Create chat page for chat tasks | +| `needsMultiSession` | `boolean` | Enable multi-login session page | +| `needDialNumberLogin` | `boolean` | Create dial number page and login | +| `agent1LoginMode` | `LoginMode` | Login mode for agent1 (Desktop/Extension/Dial Number) | +| `enableConsoleLogging` | `boolean` | Capture console messages from agent pages | +| `enableAdvancedLogging` | `boolean` | Capture advanced transfer/consult logs | + +### TestManager Convenience Setup Methods + +| Method | Config Summary | +| ----------------------------------- | ------------------------------------------------------------------------------- | +| `setup(browser, config)` | Universal setup with any config | +| `basicSetup(browser)` | Agent1 only, Desktop mode, console logging | +| `setupForStationLogin(browser)` | Agent1 + multi-session page for login tests | +| `setupForIncomingTaskDesktop(browser)` | Agent1 + caller + chat, Desktop mode | +| `setupForIncomingTaskExtension(browser)` | Agent1 + caller + extension + chat, Extension mode | +| `setupForIncomingTaskMultiSession(browser)` | Agent1 + caller + extension + chat + multi-session, Extension mode | +| `setupForAdvancedTaskControls(browser)` | Agent1 + agent2 + extension + caller, Extension mode, advanced logging | +| `setupForAdvancedCombinations(browser)` | Agent1 + agent2 + caller, Desktop mode, advanced logging | +| `setupForDialNumber(browser)` | Agent1 + agent2 + caller + dial number, Desktop mode, advanced logging | + +### TestManager Key Properties + +| Property | Type | Description | +| ------------------------- | ----------------- | -------------------------------- | +| `agent1Page` | `Page` | Primary agent widget page | +| `agent2Page` | `Page` | Secondary agent widget page | +| `callerPage` | `Page` | Webex calling page | +| `agent1ExtensionPage` | `Page` | Extension login page | +| `chatPage` | `Page` | Chat launcher page | +| `dialNumberPage` | `Page` | Dial number login page | +| `multiSessionAgent1Page` | `Page` | Multi-login session page | +| `consoleMessages` | `string[]` | Captured console log messages | +| `projectName` | `string` | Current project/set name | +| `maxRetries` | `number` | Max retries for setup operations | + +--- + +## 5. Constants + +### Core Constants + +```typescript +export const BASE_URL = 'http://localhost:3000'; + +export const USER_STATES = { + MEETING: 'Meeting', + AVAILABLE: 'Available', + LUNCH: 'Lunch Break', + RONA: 'RONA', + ENGAGED: 'Engaged', + AGENT_DECLINED: 'Agent_Declined', +}; + +export const THEME_COLORS = { + AVAILABLE: 'rgb(206, 245, 235)', + MEETING: 'rgba(0, 0, 0, 0.11)', + ENGAGED: 'rgb(255, 235, 194)', + RONA: 'rgb(250, 233, 234)', +}; + +export const LOGIN_MODE = {DESKTOP: 'Desktop', EXTENSION: 'Extension', DIAL_NUMBER: 'Dial Number'}; +export const TASK_TYPES = {CALL: 'Call', CHAT: 'Chat', EMAIL: 'Email', SOCIAL: 'Social'}; +export const WRAPUP_REASONS = {SALE: 'Sale', RESOLVED: 'Resolved'}; +export const RONA_OPTIONS = {AVAILABLE: 'Available', IDLE: 'Idle'}; + +export const PAGE_TYPES = { + AGENT1: 'agent1', AGENT2: 'agent2', CALLER: 'caller', + EXTENSION: 'extension', CHAT: 'chat', MULTI_SESSION: 'multiSession', DIAL_NUMBER: 'dialNumber', +}; + +export const CALL_URL = 'https://web-sdk.webex.com/samples/calling/'; + +export const TEST_DATA = { + CHAT_NAME: 'Playwright Test', + CHAT_EMAIL: 'playwright@test.com', + EMAIL_TEXT: '--This Email is generated due to playwright automation test for incoming Tasks---', + EXTENSION_CALL_INDICATOR: 'Ringing...', +}; +``` + +### Timeout Constants + +| Constant | Value | Purpose | +| ------------------------------ | ------- | ---------------------------------- | +| `AWAIT_TIMEOUT` | 10000 | Universal await timeout | +| `DEFAULT_TIMEOUT` | 5000 | TestManager default timeout | +| `DEFAULT_MAX_RETRIES` | 3 | TestManager default retry count | +| `UI_SETTLE_TIMEOUT` | 2000 | Wait for UI animations/settle | +| `DROPDOWN_SETTLE_TIMEOUT` | 200 | Wait for dropdown to settle | +| `FORM_FIELD_TIMEOUT` | 20000 | Form field interaction timeout | +| `WRAPUP_TIMEOUT` | 15000 | Wrapup submission timeout | +| `OPERATION_TIMEOUT` | 30000 | Standard async operation timeout | +| `NETWORK_OPERATION_TIMEOUT` | 40000 | Network reconnection timeout | +| `EXTENSION_REGISTRATION_TIMEOUT` | 40000 | Extension registration wait | +| `WIDGET_INIT_TIMEOUT` | 50000 | Widget initialization timeout | +| `CHAT_LAUNCHER_TIMEOUT` | 60000 | Chat launcher load timeout | +| `ACCEPT_TASK_TIMEOUT` | 60000 | Incoming task detection timeout | + +### Console Patterns (in constants.ts) + +```typescript +export const CONSOLE_PATTERNS = { + SDK_STATE_CHANGE_SUCCESS: 'WXCC_SDK_AGENT_STATE_CHANGE_SUCCESS', + ON_STATE_CHANGE_REGEX: /onStateChange invoked with state name:\s*(.+)/i, + ON_STATE_CHANGE_KEYWORDS: ['onstatechange', 'invoked'], +}; +``` + +### Exported Types + +```typescript +export type userState = (typeof USER_STATES)[keyof typeof USER_STATES]; +export type ThemeColor = (typeof THEME_COLORS)[keyof typeof THEME_COLORS]; +export type LoginMode = (typeof LOGIN_MODE)[keyof typeof LOGIN_MODE]; +export type PageType = (typeof PAGE_TYPES)[keyof typeof PAGE_TYPES]; +export type TaskType = (typeof TASK_TYPES)[keyof typeof TASK_TYPES]; +export type WrapupReason = (typeof WRAPUP_REASONS)[keyof typeof WRAPUP_REASONS]; +export type RonaOption = (typeof RONA_OPTIONS)[keyof typeof RONA_OPTIONS]; +``` + +--- + +## 6. Utility Functions + +### initUtils.ts + +| Function | Purpose | +| ---------------------------------------------- | ------------------------------------ | +| `loginViaAccessToken(page, accessToken)` | Login with access token | +| `oauthLogin(page, username, customPassword?)` | OAuth login flow | +| `enableAllWidgets(page)` | Enable all CC widgets | +| `enableMultiLogin(page)` | Enable multi-login checkbox | +| `disableMultiLogin(page)` | Disable multi-login checkbox | +| `initialiseWidgets(page)` | Init widgets and wait for ready | +| `agentRelogin(page)` | Re-login after logout | +| `setupMultiLoginPage(context)` | Create a new page for multi-session | + +### stationLoginUtils.ts + +| Function | Purpose | +| ------------------------------------------------- | ------------------------------------ | +| `desktopLogin(page)` | Browser/Desktop mode login | +| `extensionLogin(page, extensionNumber?)` | Extension mode login | +| `dialLogin(page, dialNumber?)` | Dial Number mode login | +| `stationLogout(page, throwOnFailure?)` | Station logout | +| `telephonyLogin(page, mode, number?)` | Generic telephony login by mode | +| `verifyLoginMode(page, expectedMode)` | Verify current login mode | +| `ensureUserStateVisible(page, loginMode, number?)` | Ensure user state widget visible after login | +| `verifyDesktopOptionVisibility(page, shouldBeVisible)` | Verify Desktop option toggle | + +### userStateUtils.ts + +| Function | Purpose | +| ---------------------------------------------------------- | ------------------------------------ | +| `changeUserState(page, userState)` | Change agent state | +| `getCurrentState(page)` | Get current state text | +| `verifyCurrentState(page, expectedState)` | Assert current state matches | +| `getStateElapsedTime(page)` | Get elapsed time string | +| `validateConsoleStateChange(page, state, consoleMessages)` | Validate state change in console | +| `checkCallbackSequence(page, expectedState, consoleMessages)` | Verify callback order | + +### taskControlUtils.ts + +| Function | Purpose | +| --------------------------------------------------- | ------------------------------------ | +| `callTaskControlCheck(page)` | Verify call task control buttons | +| `chatTaskControlCheck(page)` | Verify chat task control buttons | +| `emailTaskControlCheck(page)` | Verify email task control buttons | +| `verifyTaskControls(page, taskType)` | Verify controls by task type | +| `holdCallToggle(page)` | Toggle hold on/off | +| `recordCallToggle(page)` | Toggle recording on/off | +| `verifyHoldTimer(page, {shouldBeVisible, verifyContent?})` | Verify hold timer visibility | +| `verifyHoldButtonIcon(page, {expectedIsHeld})` | Verify hold button icon state | +| `verifyRecordButtonIcon(page, {expectedIsRecording})` | Verify record button icon state | +| `setupConsoleLogging(page)` | Setup console log capture (returns cleanup fn) | +| `clearCapturedLogs()` | Clear captured basic logs | +| `verifyHoldLogs({expectedIsHeld})` | Verify hold/resume console logs | +| `verifyRecordingLogs({expectedIsRecording})` | Verify recording console logs | +| `verifyEndLogs()` | Verify end task console logs | +| `verifyRemoteAudioTracks(page)` | Verify remote audio tracks exist | +| `verifyHoldMusicElement(page)` | Verify hold music audio element | +| `endTask(page)` | End current task | + +### advancedTaskControlUtils.ts + +| Function | Purpose | +| --------------------------------------------------------------------------- | --------------------------------- | +| `setupAdvancedConsoleLogging(page)` | Setup advanced log capture (returns cleanup fn) | +| `clearAdvancedCapturedLogs()` | Clear captured advanced logs | +| `verifyTransferSuccessLogs()` | Verify transfer success logs | +| `verifyConsultStartSuccessLogs()` | Verify consult start success logs | +| `verifyConsultEndSuccessLogs()` | Verify consult end success logs | +| `verifyConsultTransferredLogs()` | Verify consult transferred logs | +| `consultOrTransfer(page, type, action, value)` | Perform consult or transfer | +| `cancelConsult(page)` | Cancel active consult | + +**`consultOrTransfer` parameters:** +- `type`: `'agent'` | `'queue'` | `'dialNumber'` | `'entryPoint'` +- `action`: `'consult'` | `'transfer'` + +### incomingTaskUtils.ts + +| Function | Purpose | +| ------------------------------------------------- | ------------------------------------------ | +| `createCallTask(page, number)` | Create a telephony call via caller page | +| `endCallTask(page, isCaller?)` | End a call task | +| `createChatTask(page, chatURL)` | Create a chat task via chat launcher | +| `endChatTask(page)` | End a chat task | +| `createEmailTask(to)` | Create an email task via nodemailer | +| `getIncomingTaskLocator(page, type)` | Get locator for incoming task by type | +| `waitForIncomingTask(page, type, timeout?)` | Wait for incoming task to appear | +| `acceptIncomingTask(page, type, timeout?)` | Accept an incoming task | +| `declineIncomingTask(page, type)` | Decline an incoming task | +| `acceptExtensionCall(page)` | Accept call on extension page | +| `declineExtensionCall(page)` | Decline call on extension page | +| `endExtensionCall(page)` | End call on extension page | +| `loginExtension(page, token)` | Login on extension page with token | +| `submitRonaPopup(page, nextState)` | Handle RONA popup (choose Available/Idle) | + +### wrapupUtils.ts + +| Function | Purpose | +| --------------------------------- | ------------------------------ | +| `submitWrapup(page, reason)` | Submit wrapup with reason | + +**Note:** `reason` is of type `WrapupReason` (`'Sale'` | `'Resolved'`). + +### helperUtils.ts + +| Function | Purpose | +| ------------------------------------------------------------------ | -------------------------------------------- | +| `parseTimeString(timeString)` | Parse time string to seconds | +| `waitForWebSocketDisconnection(consoleMessages, timeoutMs?)` | Wait for WebSocket disconnect in logs | +| `waitForWebSocketReconnection(consoleMessages, timeoutMs?)` | Wait for WebSocket reconnect in logs | +| `waitForState(page, expectedState)` | Poll until agent reaches expected state | +| `getLastStateFromLogs(capturedLogs)` | Extract last state from console logs | +| `waitForStateLogs(capturedLogs, expectedState, timeoutMs?)` | Wait for state change to appear in logs | +| `waitForWrapupReasonLogs(capturedLogs, expectedReason, timeoutMs?)` | Wait for wrapup reason in logs | +| `getLastWrapupReasonFromLogs(capturedLogs)` | Extract last wrapup reason from logs | +| `isColorClose(receivedColor, expectedColor, tolerance?)` | Compare RGB colors with tolerance | +| `handleStrayTasks(page, extensionPage?, maxIterations?)` | Clean up stray/leftover tasks | +| `clearPendingCallAndWrapup(page)` | Clear pending call and submit wrapup | +| `pageSetup(page, loginMode, accessToken, extensionPage?, extensionNumber?, isMultiSession?)` | Full page setup flow | +| `dismissOverlays(page)` | Dismiss any blocking overlays/popovers | + +--- + +## 7. Test Patterns + +### Standard Test Structure + +```typescript +export default function createMyTests() { + let testManager: TestManager; + + test.beforeAll(async ({browser}, testInfo) => { + testManager = new TestManager(testInfo.project.name); + await testManager.setup(browser, {needsAgent1: true, enableConsoleLogging: true}); + }); + + test.afterAll(async () => { + await testManager.cleanup(); + }); + + test('should perform action @tag', async () => { + /* implementation */ + }); +} +``` + +### Suite Orchestration + +```typescript +// suites/my-tests.spec.ts +import createMyTests from '../tests/my-test.spec'; +test.describe('My Test Suite', createMyTests); +``` + +### Multiple Tests in One Suite + +```typescript +// suites/combined-tests.spec.ts +import createTestA from '../tests/test-a.spec'; +import createTestB from '../tests/test-b.spec'; +test.describe('Test A', createTestA); +test.describe('Test B', createTestB); +``` + +--- + +## 8. Naming Conventions + +| Type | Pattern | Example | +| ------------- | ------------------------------ | ---------------------------------------- | +| Test Files | `*-test.spec.ts` | `station-login-test.spec.ts` | +| Suite Files | `*-tests.spec.ts` | `station-login-user-state-tests.spec.ts` | +| Utility Files | `*Utils.ts` | `stationLoginUtils.ts` | +| Actions | `verbNoun` | `changeUserState`, `createCallTask` | +| Verification | `verify*` | `verifyCurrentState` | +| Getters | `get*` | `getCurrentState` | +| Test Names | `should ` | `'should login with Desktop mode'` | +| Pages | `*Page` | `agent1Page`, `callerPage` | +| TestIDs | `widget-name`, `action-button` | `station-login-widget`, `login-button` | + +--- + +## 9. Common Pitfalls + +### Playwright Pitfalls + +1. **Missing Timeouts** - Always use explicit timeouts (`AWAIT_TIMEOUT`, `OPERATION_TIMEOUT`) +2. **Race Conditions** - Wait for elements before interacting; clear console logs before capturing +3. **Stale Elements** - Re-query after navigation/reload +4. **Iframe Handling** - Use `.contentFrame()`; wait for visibility first +5. **Network Simulation** - Use `page.context().setOffline()`; wait for disconnect/reconnect detection + +### Test Design Pitfalls + +6. **Test Interdependence** - Each test should be independent with proper setup/teardown +7. **Hardcoded Values** - Use environment variables and `testManager.projectName` +8. **Missing Error Handling** - Provide context in error messages +9. **Console Log Timing** - Clear before operation; wait for async events to arrive +10. **Parallel Conflicts** - Each set uses different agents/queues; don't share state + +### SDK-Specific Pitfalls + +11. **Widget Init Failures** - Wait for visibility; retry on failure +12. **State Transition Timing** - Wait for callback confirmation before proceeding +13. **Multi-Session Sync** - Enable multi-login first; state/timer should sync +14. **Task Lifecycle** - Complete wrapup; wait for `task:wrappedup` before state change +15. **WebSocket Reconnection** - State persists; some timers may reset +16. **Call Control State** - Hold timer appears on hold; consult requires hold first + +### Contact Center Flow Pitfalls + +17. **RONA** - Agent must change state after RONA; timeout is 15-30 seconds +18. **Queue Routing** - Verify agent in correct queue; tasks may timeout if no agents +19. **Consult vs Transfer** - Blind=immediate handoff; Consult=3-way then transfer/cancel +20. **Extension Login** - Must be registered; calls require separate acceptance +21. **Wrapup Requirements** - Reason required; has configurable timeout +22. **Multi-Agent Coordination** - Agent2 unavailable for Agent1 tests; target must be available for transfer + +--- + +## 10. Best Practices + +### Test Organization + +- Export factory functions for test definitions +- Use `beforeAll` for login/widget init; `afterAll` for cleanup +- Clear console before capturing; reset UI between tests +- Use specific TestIDs; verify both UI and console events + +### Code Organization + +- Single responsibility per utility function +- Return meaningful values or throw descriptive errors +- Use TypeScript types for parameters and returns + +### Console Log Capture Pattern + +```typescript +testManager.consoleMessages.length = 0; +await performOperation(); +await page.waitForTimeout(3000); +const logs = testManager.consoleMessages.filter((msg) => msg.includes('PATTERN')); +expect(logs.length).toBeGreaterThan(0); +``` + +### Advanced Console Logging Pattern + +```typescript +// For transfer/consult operations (uses separate log buffer) +clearAdvancedCapturedLogs(); +await consultOrTransfer(page, 'agent', 'transfer', agentName); +verifyTransferSuccessLogs(); +``` + +--- + +## 11. Implementation Guardrails + +### Requirements + +| Category | Requirements | +| --------------- | ---------------------------------------------------------------- | +| **Setup** | Export factory function; use TestManager; verify widget init | +| **Cleanup** | Call `cleanup()` in afterAll; handle stray tasks; close contexts | +| **Assertions** | Use Playwright `expect`; include timeouts; verify UI and events | +| **Environment** | Credentials via env vars; never commit secrets | + +### Timeout Guidelines + +| Operation | Timeout | Constant | +| ------------------------- | ------- | ------------------------------ | +| UI Settle | 2s | `UI_SETTLE_TIMEOUT` | +| Default Await | 10s | `AWAIT_TIMEOUT` | +| Wrapup Submission | 15s | `WRAPUP_TIMEOUT` | +| Form Fields | 20s | `FORM_FIELD_TIMEOUT` | +| Standard Operations | 30s | `OPERATION_TIMEOUT` | +| Network/Extension | 40s | `NETWORK_OPERATION_TIMEOUT` | +| Widget Initialization | 50s | `WIDGET_INIT_TIMEOUT` | +| Incoming Task / Chat | 60s | `ACCEPT_TASK_TIMEOUT` | +| Test Timeout (global) | 180s | Set in `playwright.config.ts` | + +### Architectural Boundaries + +- Each USER_SET operates independently with dedicated agents/queues +- Tests interact through UI, not SDK directly +- Verify SDK events through console logs +- Tests run against sandbox; never use production credentials + +--- + +## 12. Console Log Patterns Used in Tests + +### Centralized Patterns (constants.ts) + +| Constant | Value | Used For | +| ------------------------------ | ------------------------------------------ | ----------------- | +| `SDK_STATE_CHANGE_SUCCESS` | `WXCC_SDK_AGENT_STATE_CHANGE_SUCCESS` | State changes | +| `ON_STATE_CHANGE_REGEX` | `/onStateChange invoked with state name:\s*(.+)/i` | Parse state | +| `ON_STATE_CHANGE_KEYWORDS` | `['onstatechange', 'invoked']` | Filter logs | + +### Patterns in taskControlUtils.ts (local to captured logs) + +| Pattern | Purpose | +| --------------------------------------- | ----------------------- | +| `WXCC_SDK_TASK_HOLD_SUCCESS` | Hold success | +| `WXCC_SDK_TASK_RESUME_SUCCESS` | Resume from hold | +| `WXCC_SDK_TASK_PAUSE_RECORDING_SUCCESS` | Recording paused | +| `WXCC_SDK_TASK_RESUME_RECORDING_SUCCESS`| Recording resumed | +| `onHoldResume invoked` | Hold/resume callback | +| `onRecordingToggle invoked` | Recording callback | +| `onEnd invoked` | End task callback | + +### Patterns in advancedTaskControlUtils.ts (local to captured logs) + +| Pattern | Purpose | +| ---------------------------------------- | ----------------------- | +| `WXCC_SDK_TASK_TRANSFER_SUCCESS` | Blind transfer success | +| `WXCC_SDK_TASK_CONSULT_START_SUCCESS` | Consult started | +| `WXCC_SDK_TASK_CONSULT_END_SUCCESS` | Consult ended | +| `AgentConsultTransferred` | Consult transfer done | + +### Patterns in helperUtils.ts + +| Pattern | Purpose | +| ---------------------------------------- | ----------------------- | +| `onStateChange invoked with state name:` | State change callback | +| `onWrapup invoked with reason :` | Wrapup callback | + +--- + +## 13. Test Categories + +| Category | Sets | Focus | +| --------------------- | ------------ | -------------------------------------------------------------------- | +| **Station Login** | SET_3 | Desktop/Extension/Dial Number login, multi-login, reload, network | +| **User State** | SET_3 | Transitions, timer, callback verification, multi-session sync | +| **Incoming Telephony**| SET_3 | Desktop/Extension call accept/decline, RONA, customer disconnect | +| **Digital Incoming** | SET_1 | Chat/Email accept/decline, RONA, multi-task, disconnect | +| **Task List** | SET_2 | Call/Chat/Email task list verification, multiple tasks | +| **Multi-Session** | SET_2 | Multi-login call/chat/email sync, control synchronization | +| **Basic Controls** | SET_4 | Hold, recording, audio tracks, end call, wrapup | +| **Combinations** | SET_4 | Transfer chains, multi-stage consult-transfer between agents | +| **Advanced Controls** | SET_5 | Blind transfer (agent/queue), consult (agent/queue/entry point) | +| **Dial Number** | SET_6 | Dial number consult/transfer, search, multi-hop transfers | + +--- + +## 14. Adding New Tests + +1. **Create test file** in `tests/` exporting a factory function (e.g., `createMyTests`) +2. **Add to suite** in `suites/` using `test.describe('Name', createMyTests)` +3. **(Optional) Add new set** in `test-data.ts` if the feature needs dedicated agents/queue (see Section 17) + +--- + +## 14a. Extending the Framework for New Features + +When a new feature (e.g., multi-party conference) requires infrastructure changes beyond just adding test files, use this section as a guide. + +### Adding a New USER_SET + +Each set needs dedicated agents and queue to avoid conflicts with other parallel sets. Add to `playwright/test-data.ts`: + +```typescript +SET_7: { + AGENTS: { + AGENT1: {username: 'userXX', extension: '10XX', agentName: 'UserXX AgentXX'}, + AGENT2: {username: 'userYY', extension: '10YY', agentName: 'UserYY AgentYY'}, + }, + QUEUE_NAME: 'Queue e2e 7', + CHAT_URL: `${env.PW_CHAT_URL}-e2e-7.html`, + EMAIL_ENTRY_POINT: `${env.PW_SANDBOX}.e2e7@gmail.com`, + ENTRY_POINT: env.PW_ENTRY_POINT7, + TEST_SUITE: 'new-feature-tests.spec.ts', +}, +``` + +**Required fields:** `AGENTS` (AGENT1 + AGENT2, each with `username`, `extension`, `agentName`), `QUEUE_NAME`, `CHAT_URL`, `EMAIL_ENTRY_POINT`, `ENTRY_POINT`, `TEST_SUITE` + +**Automatic behaviors when a set is added:** +- `playwright.config.ts` auto-generates a new Playwright project, worker, and debug port (9221 + index) +- `global.setup.ts` auto-runs OAuth for all agents in the set and writes access tokens to `.env` +- No manual changes needed in either config file + +**New `.env` variables needed:** +- `PW_ENTRY_POINT7` (or whichever number) - the phone number for the new set's entry point +- The agents must be pre-provisioned in the sandbox with the correct queue assignment + +### Extending TestManager for More Agents + +**Current capacity:** TestManager supports exactly 2 agent pages (`agent1Page`, `agent2Page`). If a feature needs 3+ agents (e.g., multi-party conference with Agent A, Agent B, and Agent C), the TestManager must be extended. + +**What to add:** +1. New properties in `TestManager` class: + ```typescript + public agent3Page: Page; + public agent3Context: BrowserContext; + ``` +2. New `SetupConfig` option: + ```typescript + needsAgent3?: boolean; + ``` +3. New `PAGE_TYPES` entry in `constants.ts`: + ```typescript + AGENT3: 'agent3', + ``` +4. Add AGENT3 to the USER_SET in `test-data.ts`: + ```typescript + AGENTS: { + AGENT1: {...}, + AGENT2: {...}, + AGENT3: {username: 'userZZ', extension: '10ZZ', agentName: 'UserZZ AgentZZ'}, + }, + ``` +5. Extend `createContextsForConfig`, `processContextCreations`, and add a `setupAgent3` method following the pattern of `setupAgent2`. +6. Extend `global.setup.ts` OAuth loop (it already iterates over all agents in each set, so adding AGENT3 to the AGENTS object is sufficient). +7. New convenience setup method: + ```typescript + async setupForNewFeature(browser: Browser): Promise { + await this.setup(browser, { + needsAgent1: true, + needsAgent2: true, + needsAgent3: true, + needsCaller: true, + agent1LoginMode: LOGIN_MODE.EXTENSION, + enableConsoleLogging: true, + enableAdvancedLogging: true, + }); + } + ``` + +### Adding New Constants and Types + +When a new feature introduces new SDK events, task types, or timeout requirements, add to `constants.ts`: + +- **New task types:** Add to `TASK_TYPES` object and `TaskType` type will auto-derive +- **New page types:** Add to `PAGE_TYPES` object if new page roles are needed +- **New console patterns:** Create a new constant object (feature-scoped) or add to `CONSOLE_PATTERNS` if universally applicable. Pattern values must match actual SDK event strings - verify against the widget or SDK source code +- **New timeout constants:** Add with a descriptive comment explaining the rationale and value +- **New state constants:** Only if the feature introduces new agent states + +### Adding New Utility Files + +Follow the existing convention: + +- **File name:** `playwright/Utils/[featureName]Utils.ts` (camelCase + `Utils.ts`) +- **Pattern:** Export async functions that take `Page` as first parameter +- **Console logging:** If the feature has its own SDK events, create dedicated `setup*ConsoleLogging(page)` and `clear*CapturedLogs()` functions following the pattern in `taskControlUtils.ts` and `advancedTaskControlUtils.ts` +- **Verification:** Create `verify*Logs()` functions for each SDK event pattern +- **Update this document:** Add the new utility's function table to Section 6 + +### Adding New Environment Variables + +- Add to `.env` file (see Section 16 for existing patterns) +- If the variable is needed per-set, use `global.setup.ts` pattern (it reads from USER_SETS and writes to `.env`) +- If the variable is optional (feature-gated), guard usage with `if (process.env.VAR_NAME)` and `test.skip()` when not set +- Document in Section 16 of this file + +--- + +## 15. Running Tests + +```bash +yarn test:e2e # All tests +yarn test:e2e suites/station-login-user-state-tests.spec.ts # Specific suite +yarn test:e2e --project=SET_3 # Specific set +yarn test:e2e --debug | --ui | --headed # Debug modes +``` + +--- + +## 16. Environment Variables + +```env +# Sandbox +PW_SANDBOX=your-sandbox-name +PW_SANDBOX_PASSWORD=sandbox-password + +# Entry Points (one per user set) +PW_ENTRY_POINT1=+1234567890 +PW_ENTRY_POINT2=+1234567891 +PW_ENTRY_POINT3=+1234567892 +PW_ENTRY_POINT4=+1234567893 +PW_ENTRY_POINT5=+1234567894 +PW_ENTRY_POINT6=+1234567895 + +# URLs +PW_CHAT_URL=https://your-chat-base-url + +# Email (for nodemailer) +PW_SENDER_EMAIL=sender@gmail.com +PW_SENDER_EMAIL_PASSWORD=app-password + +# Dial Number Login (optional - enables dial number tests) +PW_DIAL_NUMBER_LOGIN_USERNAME=dial-user +PW_DIAL_NUMBER_LOGIN_PASSWORD=dial-password +PW_DIAL_NUMBER_NAME=Dial Number Agent + +# Entry Point Name (optional - enables entry point consult tests) +PW_ENTRYPOINT_NAME=EntryPointName + +# Auto-generated by global.setup.ts (DO NOT set manually): +# SET_1_AGENT1_ACCESS_TOKEN, SET_1_AGENT2_ACCESS_TOKEN, ... +# SET_6_AGENT1_ACCESS_TOKEN, SET_6_AGENT2_ACCESS_TOKEN +# DIAL_NUMBER_LOGIN_ACCESS_TOKEN +``` + +--- + +**Document Version**: 1.4.0 +**Last Updated**: February 9, 2026 +**Maintained By**: Contact Center Widgets Testing Team From c998f855d22cdf16ac49e16d55634b646d2f65c2 Mon Sep 17 00:00:00 2001 From: Ravi Chandra Sekhar Sarika Date: Tue, 17 Feb 2026 15:02:44 +0530 Subject: [PATCH 2/2] docs: update playwright AGENTS and multiparty conference spec --- AGENTS.md | 12 +- .../playright-test-spec-generator.md | 140 ++- playwright/ai-docs/AGENTS.md | 926 ++++-------------- .../specs/multiparty-conference.spec.md | 131 +++ 4 files changed, 418 insertions(+), 791 deletions(-) create mode 100644 playwright/ai-docs/specs/multiparty-conference.spec.md diff --git a/AGENTS.md b/AGENTS.md index 35c07cda0..ee33da8b2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -51,7 +51,7 @@ If the developer's message contains multiple distinct task types (for example, " **E. Understanding Architecture** - Developer needs to understand how something works - **Read:** Package's `ai-docs/AGENTS.md` (usage) and `ai-docs/ARCHITECTURE.md` (technical details) -- **Available for:** station-login, user-state, store, cc-components, cc-widgets, ui-logging, test-fixtures +- **Available for:** station-login, user-state, store, cc-components, cc-widgets, ui-logging, test-fixtures, playwright --- @@ -183,6 +183,10 @@ Once provided, I'll analyze it and generate the widget accordingly. **If working with metrics/logging:** - Read: `packages/contact-center/ui-logging/ai-docs/AGENTS.md` +**If working with Playwright E2E tests/specs:** +- Read: `playwright/ai-docs/AGENTS.md` +- Read relevant specs in: `playwright/ai-docs/specs/` + --- ## Step 3: SDK API Consultation (Before Code Generation) @@ -448,6 +452,10 @@ yarn build **If architecture changed:** - Update: Relevant architecture documentation as needed +**If Playwright E2E framework/docs changed:** +- Update: `playwright/ai-docs/AGENTS.md` +- Update relevant spec files in: `playwright/ai-docs/specs/` + --- ## Step 7: Validation & Review @@ -495,7 +503,7 @@ ccWidgets/ │ └── cc/ │ ├── samples-cc-react-app/ # React sample │ └── samples-cc-wc-app/ # Web Component sample -├── playwright/ # E2E tests +├── playwright/ # E2E tests with ai-docs/ (AGENTS.md + specs/) └── ai-docs/ ├── AGENTS.md # This file ├── RULES.md # Repository rules diff --git a/ai-docs/templates/Playright/playright-test-spec-generator.md b/ai-docs/templates/Playright/playright-test-spec-generator.md index fff190a4f..b2348cfa5 100644 --- a/ai-docs/templates/Playright/playright-test-spec-generator.md +++ b/ai-docs/templates/Playright/playright-test-spec-generator.md @@ -1,4 +1,4 @@ -# Contact Center Widgets Test Spec Generator for Playwright E2E Testing +# Contact Center Widgets Playwright Test Spec Generator You are a senior Playwright test architect embedded in the Contact Center Widgets E2E Testing project. Your mission is to transform test requirements into implementation-ready test specifications through an **interactive, research-driven workflow**. You will proactively gather context, ask clarifying questions, and iterate until you can produce a complete, unambiguous test specification. @@ -12,6 +12,7 @@ You are a senior Playwright test architect embedded in the Contact Center Widget 4. **Never Assume** - If information is missing or ambiguous, ask; if you make assumptions, state them explicitly 5. **Follow Existing Patterns** - Align with established test architecture and conventions you discover in the codebase 6. **Be Implementation-Ready** - Every spec must be directly implementable with zero ambiguity +7. **No History Framing in Specs** - Generated specs must read like fresh documents; do not include version-history/changelog sections or wording like "replaces", "rewritten", or migration history notes --- @@ -100,7 +101,7 @@ Engage in **natural, conversational clarification**: **Prioritize these:** - `playwright/ai-docs/AGENTS.md` - Test architecture, patterns, utilities, SDK events, pitfalls, constants - `playwright/README.md` - Framework setup, running tests, environment configuration -- `playwright/test-data.ts` - User sets (SET_1–SET_6), agent configurations, entry points +- `playwright/test-data.ts` - User sets (SET_1–SET_7), agent configurations, entry points - `playwright/test-manager.ts` - TestManager class, SetupConfig options, convenience setup methods - `playwright/constants.ts` - USER_STATES, LOGIN_MODE, TASK_TYPES, WRAPUP_REASONS, RONA_OPTIONS, timeouts, types @@ -168,11 +169,12 @@ I've researched the test codebase and found several relevant patterns: ## Test Specification Structure When you draft the spec, it should always follow this format: +- Use plain heading names (no numeric prefixes like `## 1.` or `### 3.2`). ````markdown -# Test Spec: [Feature/Test Title] +# [Feature/Test Title] E2E Spec -## 1. Metadata +## Metadata ```yaml test_key: [test-case-identifier] author: AI Test Architect @@ -180,7 +182,7 @@ date: [YYYY-MM-DD] status: Draft test_summary: | [2-3 sentence summary of what is being tested] -user_set: [SET_1 | SET_2 | SET_3 | SET_4 | SET_5 | SET_6 | NEW_SET] +user_set: [SET_1 | SET_2 | SET_3 | SET_4 | SET_5 | SET_6 | SET_7 | NEW_SET] suite_file: [which suite file this belongs to, or new suite to create] assumptions: - [Any assumptions made] @@ -190,7 +192,7 @@ unresolved_items: - [Known gaps if any] ``` -## 2. Overview +## Purpose and Scope **Objective:** [What user/system behavior is being validated] @@ -203,9 +205,9 @@ unresolved_items: **Related Tests:** [Links to similar existing tests] -## 3. Test Setup +## Test Setup -### 3.1 TestManager Configuration +### TestManager Configuration Specify either a convenience method or custom config: @@ -238,7 +240,7 @@ await testManager.setup(browser, { - `setupForAdvancedCombinations` - Agent1 + agent2 + caller, Desktop, advanced logging - `setupForDialNumber` - Agent1 + agent2 + caller + dial number, Desktop, advanced logging -### 3.2 Preconditions +### Preconditions List all preconditions that must be true before tests run: - Agent states required @@ -246,7 +248,7 @@ List all preconditions that must be true before tests run: - Tasks/calls that must exist - Environment requirements -### 3.3 Test Data Requirements +### Test Data Requirements | Data | Source | Value | |------|--------|-------| @@ -257,9 +259,9 @@ List all preconditions that must be true before tests run: | Chat URL | `process.env[\`${testManager.projectName}_CHAT_URL\`]` | chat URL | | Email Entry Point | `process.env[\`${testManager.projectName}_EMAIL_ENTRY_POINT\`]` | email address | -## 4. Infrastructure Changes +## Infrastructure Changes -### 4.1 New USER_SET (if needed) +### New USER_SET (if needed) If the feature requires dedicated agents/queue that don't conflict with existing sets, add a new set to `playwright/test-data.ts`: @@ -288,7 +290,7 @@ SET_7: { | `PW_ENTRY_POINT7` | Phone number for new set | | *(others as needed)* | | -### 4.2 New Constants / Types (if needed) +### New Constants / Types (if needed) If the feature introduces new task types, states, console patterns, or timeout values, specify additions to `playwright/constants.ts`: @@ -311,19 +313,19 @@ export const NEW_FEATURE_TIMEOUT = 30000; // Justify the value **Important:** Console pattern values must match actual SDK event strings. Never guess pattern names - verify them against the SDK source or widget callback implementations. -### 4.3 TestManager Changes (if needed) +### TestManager Changes (if needed) **Current TestManager capacity:** -- **2 agent pages** (`agent1Page`, `agent2Page`) - each with their own login +- **4 agent pages** (`agent1Page`, `agent2Page`, `agent3Page`, `agent4Page`) - each with their own login - **1 caller page** (`callerPage`) - for creating calls - **1 extension page** (`agent1ExtensionPage`) - for extension login - **1 chat page** (`chatPage`) - for chat launcher - **1 dial number page** (`dialNumberPage`) - for dial number login - **1 multi-session page** (`multiSessionAgent1Page`) - second session for agent1 -If the feature needs more agent pages (e.g., 3+ agents for conference), specify: -- New properties to add to TestManager (e.g., `agent3Page`, `agent3Context`) -- New SetupConfig options (e.g., `needsAgent3`) +If the feature needs more than 4 dedicated agent pages, specify: +- New properties to add to TestManager (e.g., `agent5Page`, `agent5Context`) +- New SetupConfig options (e.g., `needsAgent5`) - New convenience setup method (e.g., `setupForConference`) - Changes to `createContextsForConfig` and `processContextCreations` @@ -333,16 +335,17 @@ async setupForConference(browser: Browser): Promise { await this.setup(browser, { needsAgent1: true, needsAgent2: true, - needsAgent3: true, // NEW - requires TestManager extension + needsAgent3: true, + needsAgent4: true, needsCaller: true, - agent1LoginMode: LOGIN_MODE.EXTENSION, + agent1LoginMode: LOGIN_MODE.DESKTOP, enableConsoleLogging: true, enableAdvancedLogging: true, }); } ``` -### 4.4 New Utility Files (if needed) +### New Utility Files (if needed) If the feature needs a new utility file, specify: - File name following convention: `playwright/Utils/[featureName]Utils.ts` @@ -350,7 +353,7 @@ If the feature needs a new utility file, specify: - Console log capture patterns specific to the feature - Which existing utilities it builds upon -## 5. Test Cases +## Test Cases ### Test Case 1: [Test Name] @@ -409,15 +412,15 @@ expect(isColorClose(color, THEME_COLORS.ENGAGED)).toBe(true); --- -## 6. Utility Requirements +## Utility Requirements -### 6.1 Existing Utilities to Use +### Existing Utilities to Use | Utility | File | Purpose | |---------|------|---------| | `functionName()` | `Utils/file.ts` | Description | -### 6.2 New Utilities Needed +### New Utilities Needed For each new utility: @@ -436,7 +439,7 @@ export async function newUtilityName( } ``` -## 7. Console Log Verification +## Console Log Verification ### SDK Event Patterns to Verify @@ -491,21 +494,21 @@ await waitForWrapupReasonLogs(capturedLogs, WRAPUP_REASONS.SALE); expect(await getLastWrapupReasonFromLogs(capturedLogs)).toBe(WRAPUP_REASONS.SALE); ``` -## 8. Error Scenarios +## Error Scenarios -### 8.1 Expected Failures +### Expected Failures | Scenario | Trigger | Expected Behavior | Assertion | |----------|---------|-------------------|-----------| | [Scenario] | [How to trigger] | [What should happen] | [How to verify] | -### 8.2 Edge Cases +### Edge Cases | Edge Case | Setup | Expected Behavior | |-----------|-------|-------------------| | [Case] | [How to set up] | [What should happen] | -## 9. Timing & Timeouts +## Timing & Timeouts | Operation | Timeout Constant | Value | Rationale | |-----------|------------------|-------|-----------| @@ -518,7 +521,7 @@ expect(await getLastWrapupReasonFromLogs(capturedLogs)).toBe(WRAPUP_REASONS.SALE | Widget Init | `WIDGET_INIT_TIMEOUT` | 50s | Widget first load | | Incoming Task | `ACCEPT_TASK_TIMEOUT` | 60s | Task detection | -## 10. Test File Structure +## Test File Structure ### File Location `playwright/tests/[test-name]-test.spec.ts` @@ -617,6 +620,7 @@ export default function createNewFeatureTests() { **Environment variable access:** ```typescript // Always use testManager.projectName prefix for set-specific env vars +const agent1Name = process.env[`${testManager.projectName}_AGENT1_NAME`]!; const entryPoint = process.env[`${testManager.projectName}_ENTRY_POINT`]!; const agentName = process.env[`${testManager.projectName}_AGENT2_NAME`]!; const queueName = process.env[`${testManager.projectName}_QUEUE_NAME`]!; @@ -624,6 +628,9 @@ const chatUrl = process.env[`${testManager.projectName}_CHAT_URL`]!; const emailEntryPoint = process.env[`${testManager.projectName}_EMAIL_ENTRY_POINT`]!; ``` +**Routing-sensitive naming rule:** +- Avoid generic placeholder fallbacks (for example, `'Agent 1'`) for consult/transfer targets; require concrete agent display names from env/set data to prevent false negatives. + **Multi-agent page switching:** ```typescript // Bring a page to front before interacting @@ -662,7 +669,7 @@ await Promise.all([ ]); ``` -## 11. Dependencies +## Dependencies ### External Dependencies - [Caller page / Chat page / Extension page requirements] @@ -675,7 +682,7 @@ await Promise.all([ ### Environment Dependencies - [Required environment variables] -## 12. Cleanup Strategy +## Cleanup Strategy ### Per-Test Cleanup - Use `handleStrayTasks()` in `beforeEach` to clean up leftover tasks @@ -692,20 +699,20 @@ await Promise.all([ - `clearPendingCallAndWrapup(page)` clears pending calls - RONA popups handled via `submitRonaPopup(page, nextState)` -## 13. Open Questions +## Open Questions | Question | Owner | Deadline | |----------|-------|----------| | [Question] | [Who] | [When] | -## 14. References +## References - `playwright/ai-docs/AGENTS.md` - E2E testing guide - `playwright/README.md` - Framework documentation - Related test files in `playwright/tests/` - Utility reference in `playwright/Utils/` -## 15. Documentation & Codebase Updates +## Documentation & Codebase Updates ### Files That May Need Changes @@ -721,19 +728,17 @@ When a new feature introduces new infrastructure, specify all file changes: - New properties, SetupConfig options, convenience methods **`playwright/global.setup.ts`** (if new auth needs): -- Additional OAuth flows for new agent types +- Keep OAuth data-driven by `USER_SETS`; avoid hardcoded per-agent login flows +- Preserve serial chunked setup and extended setup timeout for reliability **`.env`** (if new env vars): - New entry points, credentials, URLs **`playwright/ai-docs/AGENTS.md`** updates: -- Section 4 (Test Architecture): Add new set to tables -- Section 5 (Constants): Add new constants/types -- Section 6 (Utility Functions): Add new utility tables -- Section 9 (Common Pitfalls): Add feature-specific pitfalls -- Section 12 (Console Log Patterns): Add new patterns -- Section 13 (Test Categories): Add new category row -- Section 16 (Environment Variables): Add new env vars +- Update architecture/test-set coverage tables. +- Update constants and utility references. +- Update common pitfalls and console log pattern guidance. +- Update test category and environment variable guidance. ```` @@ -776,7 +781,7 @@ These are **examples** of things you might need to know. Don't treat this as a c **Context:** - What similar tests exist? - What utilities are already available? -- Which test set should this belong to (SET_1–SET_6, or new)? +- Which test set should this belong to (SET_1–SET_7, or new)? **Scope:** - What flows are being tested? @@ -784,7 +789,7 @@ These are **examples** of things you might need to know. Don't treat this as a c - Happy path only or error scenarios too? **Setup:** -- How many agents needed? (current max is 2 - does this feature need more?) +- How many agents needed? (current max is 4 - does this feature need more?) - What login modes? - Need caller/chat/extension/dial number pages? - Multi-session needed? @@ -834,6 +839,7 @@ These are **examples** of things you might need to know. Don't treat this as a c - Assume existing TestManager supports all scenarios (check agent/page capacity) - Forget to specify new env vars, constants, or test-data changes for new features - Reuse an existing USER_SET when the new feature's tests would conflict with those in the set +- Add version-history/changelog sections or rewrite/migration language in generated spec files **Do:** - Research first, ask second @@ -845,7 +851,7 @@ These are **examples** of things you might need to know. Don't treat this as a c - Use `try/catch` with descriptive error re-throws for complex verification - Include `beforeEach` cleanup with `handleStrayTasks` or `clearCapturedLogs` - For new features: explicitly spec all infrastructure changes (test-data, constants, TestManager, env vars) -- For new features: check if current 2-agent limit is sufficient; spec TestManager extension if not +- For new features: check if current 4-agent limit is sufficient; spec TestManager extension if not --- @@ -867,11 +873,17 @@ These are **examples** of things you might need to know. Don't treat this as a c - Advanced controls (transfer/consult): use `clearAdvancedCapturedLogs()` + `verify*Logs()` from `advancedTaskControlUtils.ts` - State change callbacks: use `waitForStateLogs()` + `getLastStateFromLogs()` from `helperUtils.ts` - Wrapup callbacks: use `waitForWrapupReasonLogs()` + `getLastWrapupReasonFromLogs()` from `helperUtils.ts` +- For conference participant lifecycle checks, allow either task-event patterns (`task:participantJoined` / `task:participantLeft`) or their corresponding conference success metrics when task events are absent in runtime logs +- For conference end flows, prioritize state-transition assertions as the hard pass criteria; treat end-event console metrics as optional when runtime does not emit them for owner end-call paths. +- For consult-lobby disconnect scenarios, prefer direct `call-control:end-call` interaction over generalized helpers that assume hold/resume controls are present. +- If consult-lobby disconnect controls are unavailable, simulate primary disconnect with `page.context().setOffline(true)` and validate downstream agent states; restore connectivity after assertions. - Always wait (2-5 seconds) after SDK operations before verifying logs ### Multi-Agent Coordination - Agent2 should be in Meeting state when testing Agent1 task receipt - Consult/transfer requires target agent in Available state +- For owner-transfer scenarios, keep only the intended receiver Available before inbound call, then set consult target Available immediately before consult +- For shared setup helpers, keep only one receiver Available for the first inbound task, then switch the consult target to Available before `consultAndMerge` - State changes propagate across multi-session pages - Use `handleStrayTasks()` in `beforeEach` when tests involve multiple agents @@ -885,32 +897,12 @@ These are **examples** of things you might need to know. Don't treat this as a c - Incoming task detection: `ACCEPT_TASK_TIMEOUT` (60s) - Network operations: `NETWORK_OPERATION_TIMEOUT` (40s) - UI settle time: `UI_SETTLE_TIMEOUT` (2s) +- For post-transfer ownership checks, prefer `waitForState(..., USER_STATES.ENGAGED)` over immediate state snapshots. +- For entry-point consult routing scenarios, use a longer incoming-task wait on the consulted agent (for example, 120s) because EP routing can be slower than direct consult. ---- +### OAuth Setup Reliability +- OAuth setup is chunked into serial setup tests (`OAuth chunk 1..3`) plus optional dial-number OAuth +- OAuth setup timeout is intentionally higher (`setup.setTimeout(600000)`) to handle identity-provider slowness +- Specs that introduce new sets should keep OAuth generation within the shared `USER_SETS`-driven flow -## Version History - -- **v2.1** (2026-02-09): New feature support - - Added Section 4 (Infrastructure Changes) to spec template: new USER_SET, constants/types, TestManager changes, utility files - - Documented TestManager 2-agent capacity limit and how to extend for multi-agent features - - Added "Infrastructure" guiding questions for new features (new SDK events, new constants, agent capacity, env vars) - - Updated anti-patterns for new feature scenarios - - Updated Section 15 (Documentation & Codebase Updates) to cover all files that may need changes - - Renumbered spec sections 5-15 to accommodate new Section 4 - - Added research step to check infrastructure capacity during Phase 1 -- **v2.0** (2026-02-09): Major overhaul - - Fixed all documentation references (`agent_sdk.md` → `playwright/ai-docs/AGENTS.md`) - - Fixed tool names to match Cursor IDE (Glob, Grep, SemanticSearch, Read, LS) - - Updated timeout values to match actual constants (Incoming Task: 60s, Network: 40s) - - Added SET_6 (Dial Number tests) to user set references - - Updated test file template with real patterns (describe groups, beforeEach, env var access, try/catch, stray task handling, bringToFront, multi-session verification) - - Added all actual console log patterns organized by source file - - Added convenience setup method reference in test setup section - - Added environment variable access patterns from actual tests - - Added key patterns section with state-across-tests, cleanup with state check, multi-session verification - - Removed irrelevant "Model Configuration" section - - Fixed spec save location -- **v1.0** (2026-02-04): Initial version - - Adapted from Agentic Spec Generator - - Tailored for Playwright/TypeScript testing - - Added CC-specific considerations +--- diff --git a/playwright/ai-docs/AGENTS.md b/playwright/ai-docs/AGENTS.md index bea6e9ff2..96a9d1796 100644 --- a/playwright/ai-docs/AGENTS.md +++ b/playwright/ai-docs/AGENTS.md @@ -1,814 +1,310 @@ -# Agent Development Guide - Contact Center Widgets E2E Testing +# Playwright E2E Testing (`widgets/playwright`) -This document provides guidance for AI agents and developers working on the Contact Center Widgets E2E Testing Framework. It outlines the project structure, technology stack, development conventions, and best practices to ensure consistent, high-quality implementations across the codebase. +## Overview ---- - -## 1. Project Structure - -### Playwright Directory Structure - -``` -playwright/ -├── ai-docs/ -│ └── AGENTS.md # This document -├── constants.ts # Shared constants, types, and timeout definitions -├── global.setup.ts # OAuth and environment setup (runs before all tests) -├── README.md # Framework documentation and setup guide -├── test-data.ts # Central test configuration and user sets (SET_1–SET_6) -├── test-manager.ts # Core test management, page setup, and lifecycle -├── suites/ # Test suite orchestration files -│ ├── digital-incoming-task-tests.spec.ts -│ ├── task-list-multi-session-tests.spec.ts -│ ├── station-login-user-state-tests.spec.ts -│ ├── basic-advanced-task-controls-tests.spec.ts -│ ├── advanced-task-controls-tests.spec.ts -│ └── dial-number-tests.spec.ts -├── tests/ # Individual test implementations -│ ├── station-login-test.spec.ts -│ ├── user-state-test.spec.ts -│ ├── incoming-telephony-task-test.spec.ts -│ ├── digital-incoming-task-and-task-controls.spec.ts -│ ├── basic-task-controls-test.spec.ts -│ ├── advanced-task-controls-test.spec.ts -│ ├── advance-task-control-combinations-test.spec.ts -│ ├── incoming-task-and-controls-multi-session.spec.ts -│ ├── tasklist-test.spec.ts -│ └── dial-number-task-control-test.spec.ts -├── Utils/ # Utility functions -│ ├── initUtils.ts # Login, widget initialization, multi-login setup -│ ├── stationLoginUtils.ts # Station login/logout, mode verification -│ ├── userStateUtils.ts # Agent state management and verification -│ ├── taskControlUtils.ts # Basic task controls (hold, record, end) and console logging -│ ├── advancedTaskControlUtils.ts # Transfer, consult, and advanced console logging -│ ├── incomingTaskUtils.ts # Task creation (call/chat/email), accept/decline, RONA -│ ├── wrapupUtils.ts # Wrapup submission -│ └── helperUtils.ts # Timers, WebSocket, state polling, page setup, stray tasks -└── wav/ - └── dummyAudio.wav # Fake audio file for WebRTC media stream -``` - -### Playwright Configuration (playwright.config.ts) +The `playwright` directory contains the end-to-end testing framework for Contact Center widgets in this monorepo. It provides reusable setup/teardown orchestration, shared utilities for agent and task flows, and dynamic project generation by user set. -The config file is at the repo root. Key behaviors: +**Package:** `playwright` (internal test framework directory) -- **Web server**: Starts `samples-cc-react-app` on `http://localhost:3000` -- **Projects**: Dynamically generated from `USER_SETS` in `test-data.ts` -- **Workers**: Equal to the number of user sets (one worker per set for parallel execution) -- **Debug ports**: Auto-assigned starting at `9221 + index` (SET_1=9221, SET_2=9222, etc.) -- **Browser**: Desktop Chrome with fake media streams using `dummyAudio.wav` -- **Setup**: OAuth project runs first; all test sets depend on it +**Version:** See [root package.json](../../package.json) --- -## 2. Technology Stack +## Why and What is This Used For? -#### Core Framework & Languages +### Purpose -| Technology | Version | Purpose | -| -------------- | ------- | -------------------------------------------- | -| **TypeScript** | 4.9+ | Primary language for test implementation | -| **Playwright** | Latest | E2E testing framework for browser automation | -| **Node.js** | 20.x+ | Runtime environment | -| **yarn** | Latest | Package management | +This framework validates real widget behavior in browser-driven flows such as station login, user state transitions, incoming tasks, task controls, transfer/consult operations, and dial-number login. It centralizes environment setup and cleanup through `TestManager` so test files can focus on behavior assertions. It also reduces duplication by exposing utility modules for common interactions and verification patterns. -#### Testing Infrastructure +### Key Capabilities -| Technology | Version | Purpose | -| ------------------- | ------- | ------------------------------- | -| **Playwright Test** | Latest | Test runner and assertions | -| **dotenv** | Latest | Environment variable management | -| **nodemailer** | Latest | Email task creation | - -#### UI Widgets Under Test - -| Widget | Purpose | -| ------------------------ | ------------------------------------------------- | -| **Station Login Widget** | Agent authentication and station management | -| **User State Widget** | Agent state management (Available, Meeting, etc.) | -| **Incoming Task Widget** | Task reception and acceptance | -| **Task List Widget** | Active task management | -| **Call Control Widget** | Call handling (hold, transfer, consult, record) | +- **Dynamic project generation** - Playwright projects are built from `playwright/test-data.ts` (`USER_SETS`). +- **Reusable test setup** - `TestManager` provisions contexts/pages and performs login/widget initialization. +- **Flow-specific utilities** - Shared helpers for station login, user state, incoming tasks, task controls, and wrapup. +- **Parallel execution model** - Worker count scales with the number of configured user sets. +- **Deterministic cleanup and retries** - Built-in retry and cleanup patterns reduce flaky state carry-over. --- -## 3. Contact Center Flows - -### Agent Lifecycle - -``` -register → stationLogin → setAgentState (Available) → [Handle Tasks] → stationLogout → deregister -``` - -### Login Options +## Examples and Use Cases -| Constant | Description | Device ID | -| -------------- | ----------------- | ------------------ | -| `DESKTOP` | WebRTC in browser | `WebRTC_{agentId}` | -| `EXTENSION` | External phone | Extension number | -| `DIAL_NUMBER` | Direct dial | Phone number | +### Getting Started -### Agent State Machine - -``` -Meeting → Available ↔ Idle (Lunch/Break) - ↓ ↓ - └→ Available → [Task Incoming] → Engaged → Wrapup → Meeting/Available - ↓ - RONA (timeout) -``` - -### Task Lifecycle - -``` -task:incoming → task:assigned → task:established → [Hold/Transfer/Consult] → task:end → task:wrapup → task:wrappedup - ↓ (decline/RONA) -task:rejected -``` - -### Transfer vs Consult - -| Type | Flow | -| ------------------ | ---------------------------------------------------------------------------------- | -| **Blind Transfer** | Agent A → Transfer → Agent B receives task; Agent A → Wrapup | -| **Consult** | Agent A → Consult (customer on hold) → Agent B joins → Complete Transfer OR Cancel | - -### Media Channels - -| Channel | Utilities | -| ----------- | -------------------------------------------------------------- | -| `telephony` | `createCallTask()`, `acceptExtensionCall()`, `endCallTask()` | -| `chat` | `createChatTask()`, `endChatTask()`, `acceptIncomingTask()` | -| `email` | `createEmailTask()`, `acceptIncomingTask()` | - ---- - -## 4. Test Architecture - -### User Set Configuration - -| Set | Focus | Debug Port | Suite | -| ----- | --------------------------------------- | ---------- | -------------------------------------------- | -| SET_1 | Digital incoming tasks | 9221 | `digital-incoming-task-tests.spec.ts` | -| SET_2 | Task lists & multi-session | 9222 | `task-list-multi-session-tests.spec.ts` | -| SET_3 | Station login, user state & telephony | 9223 | `station-login-user-state-tests.spec.ts` | -| SET_4 | Basic task controls & combinations | 9224 | `basic-advanced-task-controls-tests.spec.ts` | -| SET_5 | Advanced transfer/consult operations | 9225 | `advanced-task-controls-tests.spec.ts` | -| SET_6 | Dial number task controls | 9226 | `dial-number-tests.spec.ts` | - -### Suite → Test File Mapping - -| Suite File | Test Files Imported | -| ----------------------------------------------- | ------------------------------------------------------------------------ | -| `digital-incoming-task-tests.spec.ts` | `digital-incoming-task-and-task-controls.spec` | -| `task-list-multi-session-tests.spec.ts` | `incoming-task-and-controls-multi-session.spec`, `tasklist-test.spec` | -| `station-login-user-state-tests.spec.ts` | `station-login-test.spec`, `user-state-test.spec`, `incoming-telephony-task-test.spec` | -| `basic-advanced-task-controls-tests.spec.ts` | `basic-task-controls-test.spec`, `advance-task-control-combinations-test.spec` | -| `advanced-task-controls-tests.spec.ts` | `advanced-task-controls-test.spec` | -| `dial-number-tests.spec.ts` | `dial-number-task-control-test.spec` | - -### TestManager SetupConfig - -| Property | Type | Purpose | -| ------------------------ | ----------- | ------------------------------------------ | -| `needsAgent1` | `boolean` | Create agent1 page and context | -| `needsAgent2` | `boolean` | Create agent2 page and context | -| `needsCaller` | `boolean` | Create caller page for making calls | -| `needsExtension` | `boolean` | Create extension page for extension login | -| `needsChat` | `boolean` | Create chat page for chat tasks | -| `needsMultiSession` | `boolean` | Enable multi-login session page | -| `needDialNumberLogin` | `boolean` | Create dial number page and login | -| `agent1LoginMode` | `LoginMode` | Login mode for agent1 (Desktop/Extension/Dial Number) | -| `enableConsoleLogging` | `boolean` | Capture console messages from agent pages | -| `enableAdvancedLogging` | `boolean` | Capture advanced transfer/consult logs | - -### TestManager Convenience Setup Methods - -| Method | Config Summary | -| ----------------------------------- | ------------------------------------------------------------------------------- | -| `setup(browser, config)` | Universal setup with any config | -| `basicSetup(browser)` | Agent1 only, Desktop mode, console logging | -| `setupForStationLogin(browser)` | Agent1 + multi-session page for login tests | -| `setupForIncomingTaskDesktop(browser)` | Agent1 + caller + chat, Desktop mode | -| `setupForIncomingTaskExtension(browser)` | Agent1 + caller + extension + chat, Extension mode | -| `setupForIncomingTaskMultiSession(browser)` | Agent1 + caller + extension + chat + multi-session, Extension mode | -| `setupForAdvancedTaskControls(browser)` | Agent1 + agent2 + extension + caller, Extension mode, advanced logging | -| `setupForAdvancedCombinations(browser)` | Agent1 + agent2 + caller, Desktop mode, advanced logging | -| `setupForDialNumber(browser)` | Agent1 + agent2 + caller + dial number, Desktop mode, advanced logging | - -### TestManager Key Properties - -| Property | Type | Description | -| ------------------------- | ----------------- | -------------------------------- | -| `agent1Page` | `Page` | Primary agent widget page | -| `agent2Page` | `Page` | Secondary agent widget page | -| `callerPage` | `Page` | Webex calling page | -| `agent1ExtensionPage` | `Page` | Extension login page | -| `chatPage` | `Page` | Chat launcher page | -| `dialNumberPage` | `Page` | Dial number login page | -| `multiSessionAgent1Page` | `Page` | Multi-login session page | -| `consoleMessages` | `string[]` | Captured console log messages | -| `projectName` | `string` | Current project/set name | -| `maxRetries` | `number` | Max retries for setup operations | - ---- - -## 5. Constants - -### Core Constants - -```typescript -export const BASE_URL = 'http://localhost:3000'; - -export const USER_STATES = { - MEETING: 'Meeting', - AVAILABLE: 'Available', - LUNCH: 'Lunch Break', - RONA: 'RONA', - ENGAGED: 'Engaged', - AGENT_DECLINED: 'Agent_Declined', -}; - -export const THEME_COLORS = { - AVAILABLE: 'rgb(206, 245, 235)', - MEETING: 'rgba(0, 0, 0, 0.11)', - ENGAGED: 'rgb(255, 235, 194)', - RONA: 'rgb(250, 233, 234)', -}; - -export const LOGIN_MODE = {DESKTOP: 'Desktop', EXTENSION: 'Extension', DIAL_NUMBER: 'Dial Number'}; -export const TASK_TYPES = {CALL: 'Call', CHAT: 'Chat', EMAIL: 'Email', SOCIAL: 'Social'}; -export const WRAPUP_REASONS = {SALE: 'Sale', RESOLVED: 'Resolved'}; -export const RONA_OPTIONS = {AVAILABLE: 'Available', IDLE: 'Idle'}; - -export const PAGE_TYPES = { - AGENT1: 'agent1', AGENT2: 'agent2', CALLER: 'caller', - EXTENSION: 'extension', CHAT: 'chat', MULTI_SESSION: 'multiSession', DIAL_NUMBER: 'dialNumber', -}; - -export const CALL_URL = 'https://web-sdk.webex.com/samples/calling/'; - -export const TEST_DATA = { - CHAT_NAME: 'Playwright Test', - CHAT_EMAIL: 'playwright@test.com', - EMAIL_TEXT: '--This Email is generated due to playwright automation test for incoming Tasks---', - EXTENSION_CALL_INDICATOR: 'Ringing...', -}; -``` - -### Timeout Constants - -| Constant | Value | Purpose | -| ------------------------------ | ------- | ---------------------------------- | -| `AWAIT_TIMEOUT` | 10000 | Universal await timeout | -| `DEFAULT_TIMEOUT` | 5000 | TestManager default timeout | -| `DEFAULT_MAX_RETRIES` | 3 | TestManager default retry count | -| `UI_SETTLE_TIMEOUT` | 2000 | Wait for UI animations/settle | -| `DROPDOWN_SETTLE_TIMEOUT` | 200 | Wait for dropdown to settle | -| `FORM_FIELD_TIMEOUT` | 20000 | Form field interaction timeout | -| `WRAPUP_TIMEOUT` | 15000 | Wrapup submission timeout | -| `OPERATION_TIMEOUT` | 30000 | Standard async operation timeout | -| `NETWORK_OPERATION_TIMEOUT` | 40000 | Network reconnection timeout | -| `EXTENSION_REGISTRATION_TIMEOUT` | 40000 | Extension registration wait | -| `WIDGET_INIT_TIMEOUT` | 50000 | Widget initialization timeout | -| `CHAT_LAUNCHER_TIMEOUT` | 60000 | Chat launcher load timeout | -| `ACCEPT_TASK_TIMEOUT` | 60000 | Incoming task detection timeout | - -### Console Patterns (in constants.ts) +#### Basic Usage (Suite + TestManager) ```typescript -export const CONSOLE_PATTERNS = { - SDK_STATE_CHANGE_SUCCESS: 'WXCC_SDK_AGENT_STATE_CHANGE_SUCCESS', - ON_STATE_CHANGE_REGEX: /onStateChange invoked with state name:\s*(.+)/i, - ON_STATE_CHANGE_KEYWORDS: ['onstatechange', 'invoked'], -}; -``` - -### Exported Types - -```typescript -export type userState = (typeof USER_STATES)[keyof typeof USER_STATES]; -export type ThemeColor = (typeof THEME_COLORS)[keyof typeof THEME_COLORS]; -export type LoginMode = (typeof LOGIN_MODE)[keyof typeof LOGIN_MODE]; -export type PageType = (typeof PAGE_TYPES)[keyof typeof PAGE_TYPES]; -export type TaskType = (typeof TASK_TYPES)[keyof typeof TASK_TYPES]; -export type WrapupReason = (typeof WRAPUP_REASONS)[keyof typeof WRAPUP_REASONS]; -export type RonaOption = (typeof RONA_OPTIONS)[keyof typeof RONA_OPTIONS]; -``` - ---- +import {test} from '@playwright/test'; +import {TestManager} from '../test-manager'; -## 6. Utility Functions - -### initUtils.ts - -| Function | Purpose | -| ---------------------------------------------- | ------------------------------------ | -| `loginViaAccessToken(page, accessToken)` | Login with access token | -| `oauthLogin(page, username, customPassword?)` | OAuth login flow | -| `enableAllWidgets(page)` | Enable all CC widgets | -| `enableMultiLogin(page)` | Enable multi-login checkbox | -| `disableMultiLogin(page)` | Disable multi-login checkbox | -| `initialiseWidgets(page)` | Init widgets and wait for ready | -| `agentRelogin(page)` | Re-login after logout | -| `setupMultiLoginPage(context)` | Create a new page for multi-session | - -### stationLoginUtils.ts - -| Function | Purpose | -| ------------------------------------------------- | ------------------------------------ | -| `desktopLogin(page)` | Browser/Desktop mode login | -| `extensionLogin(page, extensionNumber?)` | Extension mode login | -| `dialLogin(page, dialNumber?)` | Dial Number mode login | -| `stationLogout(page, throwOnFailure?)` | Station logout | -| `telephonyLogin(page, mode, number?)` | Generic telephony login by mode | -| `verifyLoginMode(page, expectedMode)` | Verify current login mode | -| `ensureUserStateVisible(page, loginMode, number?)` | Ensure user state widget visible after login | -| `verifyDesktopOptionVisibility(page, shouldBeVisible)` | Verify Desktop option toggle | - -### userStateUtils.ts - -| Function | Purpose | -| ---------------------------------------------------------- | ------------------------------------ | -| `changeUserState(page, userState)` | Change agent state | -| `getCurrentState(page)` | Get current state text | -| `verifyCurrentState(page, expectedState)` | Assert current state matches | -| `getStateElapsedTime(page)` | Get elapsed time string | -| `validateConsoleStateChange(page, state, consoleMessages)` | Validate state change in console | -| `checkCallbackSequence(page, expectedState, consoleMessages)` | Verify callback order | - -### taskControlUtils.ts - -| Function | Purpose | -| --------------------------------------------------- | ------------------------------------ | -| `callTaskControlCheck(page)` | Verify call task control buttons | -| `chatTaskControlCheck(page)` | Verify chat task control buttons | -| `emailTaskControlCheck(page)` | Verify email task control buttons | -| `verifyTaskControls(page, taskType)` | Verify controls by task type | -| `holdCallToggle(page)` | Toggle hold on/off | -| `recordCallToggle(page)` | Toggle recording on/off | -| `verifyHoldTimer(page, {shouldBeVisible, verifyContent?})` | Verify hold timer visibility | -| `verifyHoldButtonIcon(page, {expectedIsHeld})` | Verify hold button icon state | -| `verifyRecordButtonIcon(page, {expectedIsRecording})` | Verify record button icon state | -| `setupConsoleLogging(page)` | Setup console log capture (returns cleanup fn) | -| `clearCapturedLogs()` | Clear captured basic logs | -| `verifyHoldLogs({expectedIsHeld})` | Verify hold/resume console logs | -| `verifyRecordingLogs({expectedIsRecording})` | Verify recording console logs | -| `verifyEndLogs()` | Verify end task console logs | -| `verifyRemoteAudioTracks(page)` | Verify remote audio tracks exist | -| `verifyHoldMusicElement(page)` | Verify hold music audio element | -| `endTask(page)` | End current task | - -### advancedTaskControlUtils.ts - -| Function | Purpose | -| --------------------------------------------------------------------------- | --------------------------------- | -| `setupAdvancedConsoleLogging(page)` | Setup advanced log capture (returns cleanup fn) | -| `clearAdvancedCapturedLogs()` | Clear captured advanced logs | -| `verifyTransferSuccessLogs()` | Verify transfer success logs | -| `verifyConsultStartSuccessLogs()` | Verify consult start success logs | -| `verifyConsultEndSuccessLogs()` | Verify consult end success logs | -| `verifyConsultTransferredLogs()` | Verify consult transferred logs | -| `consultOrTransfer(page, type, action, value)` | Perform consult or transfer | -| `cancelConsult(page)` | Cancel active consult | - -**`consultOrTransfer` parameters:** -- `type`: `'agent'` | `'queue'` | `'dialNumber'` | `'entryPoint'` -- `action`: `'consult'` | `'transfer'` - -### incomingTaskUtils.ts - -| Function | Purpose | -| ------------------------------------------------- | ------------------------------------------ | -| `createCallTask(page, number)` | Create a telephony call via caller page | -| `endCallTask(page, isCaller?)` | End a call task | -| `createChatTask(page, chatURL)` | Create a chat task via chat launcher | -| `endChatTask(page)` | End a chat task | -| `createEmailTask(to)` | Create an email task via nodemailer | -| `getIncomingTaskLocator(page, type)` | Get locator for incoming task by type | -| `waitForIncomingTask(page, type, timeout?)` | Wait for incoming task to appear | -| `acceptIncomingTask(page, type, timeout?)` | Accept an incoming task | -| `declineIncomingTask(page, type)` | Decline an incoming task | -| `acceptExtensionCall(page)` | Accept call on extension page | -| `declineExtensionCall(page)` | Decline call on extension page | -| `endExtensionCall(page)` | End call on extension page | -| `loginExtension(page, token)` | Login on extension page with token | -| `submitRonaPopup(page, nextState)` | Handle RONA popup (choose Available/Idle) | - -### wrapupUtils.ts - -| Function | Purpose | -| --------------------------------- | ------------------------------ | -| `submitWrapup(page, reason)` | Submit wrapup with reason | - -**Note:** `reason` is of type `WrapupReason` (`'Sale'` | `'Resolved'`). - -### helperUtils.ts - -| Function | Purpose | -| ------------------------------------------------------------------ | -------------------------------------------- | -| `parseTimeString(timeString)` | Parse time string to seconds | -| `waitForWebSocketDisconnection(consoleMessages, timeoutMs?)` | Wait for WebSocket disconnect in logs | -| `waitForWebSocketReconnection(consoleMessages, timeoutMs?)` | Wait for WebSocket reconnect in logs | -| `waitForState(page, expectedState)` | Poll until agent reaches expected state | -| `getLastStateFromLogs(capturedLogs)` | Extract last state from console logs | -| `waitForStateLogs(capturedLogs, expectedState, timeoutMs?)` | Wait for state change to appear in logs | -| `waitForWrapupReasonLogs(capturedLogs, expectedReason, timeoutMs?)` | Wait for wrapup reason in logs | -| `getLastWrapupReasonFromLogs(capturedLogs)` | Extract last wrapup reason from logs | -| `isColorClose(receivedColor, expectedColor, tolerance?)` | Compare RGB colors with tolerance | -| `handleStrayTasks(page, extensionPage?, maxIterations?)` | Clean up stray/leftover tasks | -| `clearPendingCallAndWrapup(page)` | Clear pending call and submit wrapup | -| `pageSetup(page, loginMode, accessToken, extensionPage?, extensionNumber?, isMultiSession?)` | Full page setup flow | -| `dismissOverlays(page)` | Dismiss any blocking overlays/popovers | - ---- - -## 7. Test Patterns - -### Standard Test Structure - -```typescript -export default function createMyTests() { +export default function createStationLoginTests() { let testManager: TestManager; test.beforeAll(async ({browser}, testInfo) => { testManager = new TestManager(testInfo.project.name); - await testManager.setup(browser, {needsAgent1: true, enableConsoleLogging: true}); + await testManager.setupForStationLogin(browser); }); test.afterAll(async () => { await testManager.cleanup(); }); - test('should perform action @tag', async () => { - /* implementation */ + test('should render station login widget', async () => { + await testManager.agent1Page.getByTestId('station-login-widget').isVisible(); }); } ``` -### Suite Orchestration - -```typescript -// suites/my-tests.spec.ts -import createMyTests from '../tests/my-test.spec'; -test.describe('My Test Suite', createMyTests); -``` - -### Multiple Tests in One Suite - -```typescript -// suites/combined-tests.spec.ts -import createTestA from '../tests/test-a.spec'; -import createTestB from '../tests/test-b.spec'; -test.describe('Test A', createTestA); -test.describe('Test B', createTestB); -``` +#### Running Tests ---- +```bash +# Run all configured sets -## 8. Naming Conventions +yarn test:e2e -| Type | Pattern | Example | -| ------------- | ------------------------------ | ---------------------------------------- | -| Test Files | `*-test.spec.ts` | `station-login-test.spec.ts` | -| Suite Files | `*-tests.spec.ts` | `station-login-user-state-tests.spec.ts` | -| Utility Files | `*Utils.ts` | `stationLoginUtils.ts` | -| Actions | `verbNoun` | `changeUserState`, `createCallTask` | -| Verification | `verify*` | `verifyCurrentState` | -| Getters | `get*` | `getCurrentState` | -| Test Names | `should ` | `'should login with Desktop mode'` | -| Pages | `*Page` | `agent1Page`, `callerPage` | -| TestIDs | `widget-name`, `action-button` | `station-login-widget`, `login-button` | +# Run one suite ---- +yarn test:e2e playwright/suites/station-login-user-state-tests.spec.ts -## 9. Common Pitfalls +# Run one project (set) -### Playwright Pitfalls +yarn test:e2e --project=SET_3 +``` -1. **Missing Timeouts** - Always use explicit timeouts (`AWAIT_TIMEOUT`, `OPERATION_TIMEOUT`) -2. **Race Conditions** - Wait for elements before interacting; clear console logs before capturing -3. **Stale Elements** - Re-query after navigation/reload -4. **Iframe Handling** - Use `.contentFrame()`; wait for visibility first -5. **Network Simulation** - Use `page.context().setOffline()`; wait for disconnect/reconnect detection +### Common Use Cases -### Test Design Pitfalls +#### 1. Incoming Telephony Task Validation -6. **Test Interdependence** - Each test should be independent with proper setup/teardown -7. **Hardcoded Values** - Use environment variables and `testManager.projectName` -8. **Missing Error Handling** - Provide context in error messages -9. **Console Log Timing** - Clear before operation; wait for async events to arrive -10. **Parallel Conflicts** - Each set uses different agents/queues; don't share state +```typescript +import {createCallTask, acceptIncomingTask, endCallTask} from '../Utils/incomingTaskUtils'; +import {TASK_TYPES} from '../constants'; -### SDK-Specific Pitfalls +await createCallTask(testManager.callerPage, process.env[`${testInfo.project.name}_ENTRY_POINT`]!); +await acceptIncomingTask(testManager.agent1Page, TASK_TYPES.CALL); +await endCallTask(testManager.agent1Page); +``` -11. **Widget Init Failures** - Wait for visibility; retry on failure -12. **State Transition Timing** - Wait for callback confirmation before proceeding -13. **Multi-Session Sync** - Enable multi-login first; state/timer should sync -14. **Task Lifecycle** - Complete wrapup; wait for `task:wrappedup` before state change -15. **WebSocket Reconnection** - State persists; some timers may reset -16. **Call Control State** - Hold timer appears on hold; consult requires hold first +**Key Points:** +- Use `TestManager.setupForIncomingTaskDesktop()` or `setupForIncomingTaskExtension()`. +- Prefer constants from `constants.ts` for task and state values. +- Always clean up call state in teardown. -### Contact Center Flow Pitfalls +#### 2. State Transition Assertions -17. **RONA** - Agent must change state after RONA; timeout is 15-30 seconds -18. **Queue Routing** - Verify agent in correct queue; tasks may timeout if no agents -19. **Consult vs Transfer** - Blind=immediate handoff; Consult=3-way then transfer/cancel -20. **Extension Login** - Must be registered; calls require separate acceptance -21. **Wrapup Requirements** - Reason required; has configurable timeout -22. **Multi-Agent Coordination** - Agent2 unavailable for Agent1 tests; target must be available for transfer +```typescript +import {changeUserState, verifyCurrentState} from '../Utils/userStateUtils'; +import {USER_STATES} from '../constants'; ---- +await changeUserState(testManager.agent1Page, USER_STATES.AVAILABLE); +await verifyCurrentState(testManager.agent1Page, USER_STATES.AVAILABLE); +``` -## 10. Best Practices +**Key Points:** +- Use shared helpers instead of direct selector logic. +- Keep test assertions tied to domain constants. -### Test Organization +#### 3. Advanced Consult/Transfer Flow -- Export factory functions for test definitions -- Use `beforeAll` for login/widget init; `afterAll` for cleanup -- Clear console before capturing; reset UI between tests -- Use specific TestIDs; verify both UI and console events +```typescript +import {consultOrTransfer, verifyTransferSuccessLogs} from '../Utils/advancedTaskControlUtils'; -### Code Organization +await consultOrTransfer(testManager.agent1Page, 'agent', 'transfer', process.env[`${testInfo.project.name}_AGENT2_NAME`]!); +verifyTransferSuccessLogs(); +``` -- Single responsibility per utility function -- Return meaningful values or throw descriptive errors -- Use TypeScript types for parameters and returns +**Key Points:** +- Use `setupForAdvancedTaskControls()` for extension and second-agent context. +- Validate both UI state and captured console metrics/log patterns. -### Console Log Capture Pattern +#### 4. Multi-Session Setup ```typescript -testManager.consoleMessages.length = 0; -await performOperation(); -await page.waitForTimeout(3000); -const logs = testManager.consoleMessages.filter((msg) => msg.includes('PATTERN')); -expect(logs.length).toBeGreaterThan(0); +await testManager.setupForIncomingTaskMultiSession(browser); + +// Validate secondary session page behavior +await testManager.multiSessionAgent1Page.getByTestId('station-login-widget').isVisible(); ``` -### Advanced Console Logging Pattern +**Key Points:** +- Multi-session tests require `needsMultiSession` flow. +- Keep both sessions in sync with deterministic setup and cleanup. + +#### 5. Defensive Cleanup in Failure Paths ```typescript -// For transfer/consult operations (uses separate log buffer) -clearAdvancedCapturedLogs(); -await consultOrTransfer(page, 'agent', 'transfer', agentName); -verifyTransferSuccessLogs(); +try { + // test actions +} finally { + await testManager.softCleanup(); +} ``` ---- +**Key Points:** +- Use `softCleanup()` between heavy scenarios. +- Use full `cleanup()` only at end-of-suite boundaries. -## 11. Implementation Guardrails +### Integration Patterns -### Requirements +#### Pattern 1: Add a New Test File to an Existing Suite -| Category | Requirements | -| --------------- | ---------------------------------------------------------------- | -| **Setup** | Export factory function; use TestManager; verify widget init | -| **Cleanup** | Call `cleanup()` in afterAll; handle stray tasks; close contexts | -| **Assertions** | Use Playwright `expect`; include timeouts; verify UI and events | -| **Environment** | Credentials via env vars; never commit secrets | - -### Timeout Guidelines +```typescript +// playwright/suites/station-login-user-state-tests.spec.ts +import createMyNewTest from '../tests/my-new-test.spec'; -| Operation | Timeout | Constant | -| ------------------------- | ------- | ------------------------------ | -| UI Settle | 2s | `UI_SETTLE_TIMEOUT` | -| Default Await | 10s | `AWAIT_TIMEOUT` | -| Wrapup Submission | 15s | `WRAPUP_TIMEOUT` | -| Form Fields | 20s | `FORM_FIELD_TIMEOUT` | -| Standard Operations | 30s | `OPERATION_TIMEOUT` | -| Network/Extension | 40s | `NETWORK_OPERATION_TIMEOUT` | -| Widget Initialization | 50s | `WIDGET_INIT_TIMEOUT` | -| Incoming Task / Chat | 60s | `ACCEPT_TASK_TIMEOUT` | -| Test Timeout (global) | 180s | Set in `playwright.config.ts` | +test.describe('My New Test', createMyNewTest); +``` -### Architectural Boundaries +#### Pattern 2: Add a New User Set (Project) -- Each USER_SET operates independently with dedicated agents/queues -- Tests interact through UI, not SDK directly -- Verify SDK events through console logs -- Tests run against sandbox; never use production credentials +```typescript +// playwright/test-data.ts +export const USER_SETS = { + // ...existing sets + SET_7: { + AGENTS: { + AGENT1: {username: 'user25', extension: '1025', agentName: 'User25 Agent25'}, + AGENT2: {username: 'user26', extension: '1026', agentName: 'User26 Agent26'}, + }, + QUEUE_NAME: 'Queue e2e 7', + CHAT_URL: `${env.PW_CHAT_URL}-e2e-7.html`, + EMAIL_ENTRY_POINT: `${env.PW_SANDBOX}.e2e7@gmail.com`, + ENTRY_POINT: env.PW_ENTRY_POINT7, + TEST_SUITE: 'my-new-suite.spec.ts', + }, +}; +``` --- -## 12. Console Log Patterns Used in Tests - -### Centralized Patterns (constants.ts) +## Dependencies -| Constant | Value | Used For | -| ------------------------------ | ------------------------------------------ | ----------------- | -| `SDK_STATE_CHANGE_SUCCESS` | `WXCC_SDK_AGENT_STATE_CHANGE_SUCCESS` | State changes | -| `ON_STATE_CHANGE_REGEX` | `/onStateChange invoked with state name:\s*(.+)/i` | Parse state | -| `ON_STATE_CHANGE_KEYWORDS` | `['onstatechange', 'invoked']` | Filter logs | +**Note:** Exact versions are in [root package.json](../../package.json). -### Patterns in taskControlUtils.ts (local to captured logs) +### Runtime Dependencies -| Pattern | Purpose | -| --------------------------------------- | ----------------------- | -| `WXCC_SDK_TASK_HOLD_SUCCESS` | Hold success | -| `WXCC_SDK_TASK_RESUME_SUCCESS` | Resume from hold | -| `WXCC_SDK_TASK_PAUSE_RECORDING_SUCCESS` | Recording paused | -| `WXCC_SDK_TASK_RESUME_RECORDING_SUCCESS`| Recording resumed | -| `onHoldResume invoked` | Hold/resume callback | -| `onRecordingToggle invoked` | Recording callback | -| `onEnd invoked` | End task callback | +| Package | Purpose | +|---------|---------| +| `@playwright/test` | Browser automation, assertions, and test runner | +| `dotenv` | Loads test environment variables from `.env` | +| `nodemailer` | Creates inbound email tasks for email-channel scenarios | -### Patterns in advancedTaskControlUtils.ts (local to captured logs) +### Peer Dependencies -| Pattern | Purpose | -| ---------------------------------------- | ----------------------- | -| `WXCC_SDK_TASK_TRANSFER_SUCCESS` | Blind transfer success | -| `WXCC_SDK_TASK_CONSULT_START_SUCCESS` | Consult started | -| `WXCC_SDK_TASK_CONSULT_END_SUCCESS` | Consult ended | -| `AgentConsultTransferred` | Consult transfer done | +| Package | Purpose | +|---------|---------| +| `Node.js 20+` | Runtime required by tooling and scripts | +| `yarn 4+` | Workspace-aware dependency and script runner | -### Patterns in helperUtils.ts +### Development Dependencies -| Pattern | Purpose | -| ---------------------------------------- | ----------------------- | -| `onStateChange invoked with state name:` | State change callback | -| `onWrapup invoked with reason :` | Wrapup callback | +Key tooling lives in the root workspace: +- TypeScript +- Jest (unit/tooling checks) +- ESLint/style tooling --- -## 13. Test Categories - -| Category | Sets | Focus | -| --------------------- | ------------ | -------------------------------------------------------------------- | -| **Station Login** | SET_3 | Desktop/Extension/Dial Number login, multi-login, reload, network | -| **User State** | SET_3 | Transitions, timer, callback verification, multi-session sync | -| **Incoming Telephony**| SET_3 | Desktop/Extension call accept/decline, RONA, customer disconnect | -| **Digital Incoming** | SET_1 | Chat/Email accept/decline, RONA, multi-task, disconnect | -| **Task List** | SET_2 | Call/Chat/Email task list verification, multiple tasks | -| **Multi-Session** | SET_2 | Multi-login call/chat/email sync, control synchronization | -| **Basic Controls** | SET_4 | Hold, recording, audio tracks, end call, wrapup | -| **Combinations** | SET_4 | Transfer chains, multi-stage consult-transfer between agents | -| **Advanced Controls** | SET_5 | Blind transfer (agent/queue), consult (agent/queue/entry point) | -| **Dial Number** | SET_6 | Dial number consult/transfer, search, multi-hop transfers | +## API Reference + +### Core Class: `TestManager` + +| Method | Parameters | Returns | Description | +|--------|------------|---------|-------------| +| `new TestManager()` | `projectName: string, maxRetries?: number` | `TestManager` | Creates manager bound to a Playwright project/set name | +| `setup()` | `browser: Browser, config?: SetupConfig` | `Promise` | Universal context/page setup with configurable resources | +| `basicSetup()` | `browser: Browser` | `Promise` | Agent1-only desktop setup | +| `setupForStationLogin()` | `browser: Browser, isDesktopMode?: boolean` | `Promise` | Setup specialized for station login flows | +| `setupForIncomingTaskDesktop()` | `browser: Browser` | `Promise` | Setup for desktop incoming task flows | +| `setupForIncomingTaskExtension()` | `browser: Browser` | `Promise` | Setup for extension incoming task flows | +| `setupForIncomingTaskMultiSession()` | `browser: Browser` | `Promise` | Setup for extension + multi-session flows | +| `setupForAdvancedTaskControls()` | `browser: Browser` | `Promise` | Setup for consult/transfer flows with advanced logging | +| `setupForAdvancedCombinations()` | `browser: Browser` | `Promise` | Setup for advanced mixed control combinations | +| `setupForDialNumber()` | `browser: Browser` | `Promise` | Setup for dial-number login task flows | +| `setupMultiSessionPage()` | none | `Promise` | Initializes multi-session page when already provisioned | +| `softCleanup()` | none | `Promise` | Clears stray tasks without full logout/context teardown | +| `cleanup()` | none | `Promise` | Full cleanup: stray tasks, logout, close pages/contexts | + +### `SetupConfig` (for `TestManager.setup`) + +| Property | Type | Required | Default | Description | +|----------|------|----------|---------|-------------| +| `needsAgent1` | `boolean` | No | `true` | Create/setup primary agent page | +| `needsAgent2` | `boolean` | No | `false` | Create/setup secondary agent page | +| `needsCaller` | `boolean` | No | `false` | Create/setup caller page | +| `needsExtension` | `boolean` | No | `false` | Create/setup extension page | +| `needsChat` | `boolean` | No | `false` | Create/setup chat launcher page | +| `needsMultiSession` | `boolean` | No | `false` | Create/setup second session for agent1 | +| `needDialNumberLogin` | `boolean` | No | `false` | Create/setup dial-number login page | +| `agent1LoginMode` | `LoginMode` | No | `LOGIN_MODE.DESKTOP` | Login mode for agent1 setup | +| `enableConsoleLogging` | `boolean` | No | `true` | Capture page console logs | +| `enableAdvancedLogging` | `boolean` | No | `false` | Capture advanced transfer/consult log patterns | + +### Data Configuration: `USER_SETS` + +| Field | Type | Description | +|-------|------|-------------| +| `AGENTS.AGENT1/AGENT2.username` | `string` | Sandbox username for each agent | +| `AGENTS.AGENT1/AGENT2.extension` | `string` | Extension value for extension-mode tests | +| `AGENTS.AGENT1/AGENT2.agentName` | `string` | Display name used in assertions/transfers | +| `QUEUE_NAME` | `string` | Queue for routing validations | +| `CHAT_URL` | `string` | Chat launcher URL for digital task tests | +| `EMAIL_ENTRY_POINT` | `string` | Email target for inbound email task creation | +| `ENTRY_POINT` | `string \| undefined` | Entry point number used for inbound telephony routing | +| `TEST_SUITE` | `string` | Suite file under `playwright/suites/` mapped to the set | + +### Utility Modules (Selected) + +| Module | Function(s) | Description | +|--------|-------------|-------------| +| `Utils/initUtils.ts` | `loginViaAccessToken`, `oauthLogin`, `initialiseWidgets` | Auth and widget bootstrapping | +| `Utils/stationLoginUtils.ts` | `desktopLogin`, `extensionLogin`, `dialLogin`, `stationLogout` | Station login/logout actions | +| `Utils/userStateUtils.ts` | `changeUserState`, `verifyCurrentState` | Agent state changes and assertions | +| `Utils/incomingTaskUtils.ts` | `createCallTask`, `createChatTask`, `acceptIncomingTask`, `submitRonaPopup` | Incoming task lifecycle utilities | +| `Utils/taskControlUtils.ts` | `holdCallToggle`, `recordCallToggle`, `endTask`, log verifiers | Basic task control and logging checks | +| `Utils/advancedTaskControlUtils.ts` | `consultOrTransfer`, `cancelConsult`, log verifiers | Advanced consult/transfer controls | +| `Utils/helperUtils.ts` | `waitForState`, `handleStrayTasks`, `pageSetup`, `dismissOverlays` | Polling, cleanup, and setup helpers | +| `Utils/wrapupUtils.ts` | `submitWrapup` | Wrapup submission helper | --- -## 14. Adding New Tests - -1. **Create test file** in `tests/` exporting a factory function (e.g., `createMyTests`) -2. **Add to suite** in `suites/` using `test.describe('Name', createMyTests)` -3. **(Optional) Add new set** in `test-data.ts` if the feature needs dedicated agents/queue (see Section 17) +## Installation ---- - -## 14a. Extending the Framework for New Features +This framework is part of the repository and is not published as a standalone npm package. -When a new feature (e.g., multi-party conference) requires infrastructure changes beyond just adding test files, use this section as a guide. +```bash +yarn install +``` -### Adding a New USER_SET +### Required Environment Variables -Each set needs dedicated agents and queue to avoid conflicts with other parallel sets. Add to `playwright/test-data.ts`: +Set these in the root `.env` file: -```typescript -SET_7: { - AGENTS: { - AGENT1: {username: 'userXX', extension: '10XX', agentName: 'UserXX AgentXX'}, - AGENT2: {username: 'userYY', extension: '10YY', agentName: 'UserYY AgentYY'}, - }, - QUEUE_NAME: 'Queue e2e 7', - CHAT_URL: `${env.PW_CHAT_URL}-e2e-7.html`, - EMAIL_ENTRY_POINT: `${env.PW_SANDBOX}.e2e7@gmail.com`, - ENTRY_POINT: env.PW_ENTRY_POINT7, - TEST_SUITE: 'new-feature-tests.spec.ts', -}, +```env +PW_CHAT_URL= +PW_SANDBOX= +PW_SANDBOX_PASSWORD= +PW_ENTRY_POINT1= +PW_ENTRY_POINT2= +PW_ENTRY_POINT3= +PW_ENTRY_POINT4= +PW_ENTRY_POINT5= +PW_ENTRY_POINT6= ``` -**Required fields:** `AGENTS` (AGENT1 + AGENT2, each with `username`, `extension`, `agentName`), `QUEUE_NAME`, `CHAT_URL`, `EMAIL_ENTRY_POINT`, `ENTRY_POINT`, `TEST_SUITE` - -**Automatic behaviors when a set is added:** -- `playwright.config.ts` auto-generates a new Playwright project, worker, and debug port (9221 + index) -- `global.setup.ts` auto-runs OAuth for all agents in the set and writes access tokens to `.env` -- No manual changes needed in either config file - -**New `.env` variables needed:** -- `PW_ENTRY_POINT7` (or whichever number) - the phone number for the new set's entry point -- The agents must be pre-provisioned in the sandbox with the correct queue assignment - -### Extending TestManager for More Agents - -**Current capacity:** TestManager supports exactly 2 agent pages (`agent1Page`, `agent2Page`). If a feature needs 3+ agents (e.g., multi-party conference with Agent A, Agent B, and Agent C), the TestManager must be extended. - -**What to add:** -1. New properties in `TestManager` class: - ```typescript - public agent3Page: Page; - public agent3Context: BrowserContext; - ``` -2. New `SetupConfig` option: - ```typescript - needsAgent3?: boolean; - ``` -3. New `PAGE_TYPES` entry in `constants.ts`: - ```typescript - AGENT3: 'agent3', - ``` -4. Add AGENT3 to the USER_SET in `test-data.ts`: - ```typescript - AGENTS: { - AGENT1: {...}, - AGENT2: {...}, - AGENT3: {username: 'userZZ', extension: '10ZZ', agentName: 'UserZZ AgentZZ'}, - }, - ``` -5. Extend `createContextsForConfig`, `processContextCreations`, and add a `setupAgent3` method following the pattern of `setupAgent2`. -6. Extend `global.setup.ts` OAuth loop (it already iterates over all agents in each set, so adding AGENT3 to the AGENTS object is sufficient). -7. New convenience setup method: - ```typescript - async setupForNewFeature(browser: Browser): Promise { - await this.setup(browser, { - needsAgent1: true, - needsAgent2: true, - needsAgent3: true, - needsCaller: true, - agent1LoginMode: LOGIN_MODE.EXTENSION, - enableConsoleLogging: true, - enableAdvancedLogging: true, - }); - } - ``` - -### Adding New Constants and Types - -When a new feature introduces new SDK events, task types, or timeout requirements, add to `constants.ts`: - -- **New task types:** Add to `TASK_TYPES` object and `TaskType` type will auto-derive -- **New page types:** Add to `PAGE_TYPES` object if new page roles are needed -- **New console patterns:** Create a new constant object (feature-scoped) or add to `CONSOLE_PATTERNS` if universally applicable. Pattern values must match actual SDK event strings - verify against the widget or SDK source code -- **New timeout constants:** Add with a descriptive comment explaining the rationale and value -- **New state constants:** Only if the feature introduces new agent states - -### Adding New Utility Files - -Follow the existing convention: - -- **File name:** `playwright/Utils/[featureName]Utils.ts` (camelCase + `Utils.ts`) -- **Pattern:** Export async functions that take `Page` as first parameter -- **Console logging:** If the feature has its own SDK events, create dedicated `setup*ConsoleLogging(page)` and `clear*CapturedLogs()` functions following the pattern in `taskControlUtils.ts` and `advancedTaskControlUtils.ts` -- **Verification:** Create `verify*Logs()` functions for each SDK event pattern -- **Update this document:** Add the new utility's function table to Section 6 - -### Adding New Environment Variables - -- Add to `.env` file (see Section 16 for existing patterns) -- If the variable is needed per-set, use `global.setup.ts` pattern (it reads from USER_SETS and writes to `.env`) -- If the variable is optional (feature-gated), guard usage with `if (process.env.VAR_NAME)` and `test.skip()` when not set -- Document in Section 16 of this file +Project-scoped OAuth tokens/user values are generated and consumed by `global.setup.ts` + project naming conventions. --- -## 15. Running Tests +## Additional Resources -```bash -yarn test:e2e # All tests -yarn test:e2e suites/station-login-user-state-tests.spec.ts # Specific suite -yarn test:e2e --project=SET_3 # Specific set -yarn test:e2e --debug | --ui | --headed # Debug modes -``` - ---- +For detailed framework behavior, project mapping, and troubleshooting, see [playwright README](../README.md). -## 16. Environment Variables +For conference test planning and assumptions, see [multiparty conference spec](./specs/multiparty-conference.spec.md). -```env -# Sandbox -PW_SANDBOX=your-sandbox-name -PW_SANDBOX_PASSWORD=sandbox-password - -# Entry Points (one per user set) -PW_ENTRY_POINT1=+1234567890 -PW_ENTRY_POINT2=+1234567891 -PW_ENTRY_POINT3=+1234567892 -PW_ENTRY_POINT4=+1234567893 -PW_ENTRY_POINT5=+1234567894 -PW_ENTRY_POINT6=+1234567895 - -# URLs -PW_CHAT_URL=https://your-chat-base-url - -# Email (for nodemailer) -PW_SENDER_EMAIL=sender@gmail.com -PW_SENDER_EMAIL_PASSWORD=app-password - -# Dial Number Login (optional - enables dial number tests) -PW_DIAL_NUMBER_LOGIN_USERNAME=dial-user -PW_DIAL_NUMBER_LOGIN_PASSWORD=dial-password -PW_DIAL_NUMBER_NAME=Dial Number Agent - -# Entry Point Name (optional - enables entry point consult tests) -PW_ENTRYPOINT_NAME=EntryPointName - -# Auto-generated by global.setup.ts (DO NOT set manually): -# SET_1_AGENT1_ACCESS_TOKEN, SET_1_AGENT2_ACCESS_TOKEN, ... -# SET_6_AGENT1_ACCESS_TOKEN, SET_6_AGENT2_ACCESS_TOKEN -# DIAL_NUMBER_LOGIN_ACCESS_TOKEN -``` +For implementation-level details, read: +- [playwright.config.ts](../../playwright.config.ts) +- [playwright/test-manager.ts](../test-manager.ts) +- [playwright/test-data.ts](../test-data.ts) --- -**Document Version**: 1.4.0 -**Last Updated**: February 9, 2026 -**Maintained By**: Contact Center Widgets Testing Team +_Last Updated: 2026-02-17_ diff --git a/playwright/ai-docs/specs/multiparty-conference.spec.md b/playwright/ai-docs/specs/multiparty-conference.spec.md new file mode 100644 index 000000000..407b5f328 --- /dev/null +++ b/playwright/ai-docs/specs/multiparty-conference.spec.md @@ -0,0 +1,131 @@ +# Multi-Party Conference Spec + +Implementation spec based on: +- `Multi-Party Conference Feature Test Matrix` +- `TRANSFER CONFERENCE SCENARIOS` +- `Switch Conference — Test Plan` + +## Metadata +```yaml +test_key: conference-transfer-switch +author: Contact Center QA Automation +date: 2026-02-17 +status: Implemented and Stabilized +source_page: + title: CC Widgets Test Plan + url: https://confluence-eng-gpk2.cisco.com/conf/spaces/WSDK/pages/604864061/CC+Widgets+Test+Plan + page_id: 604864061 +source_sections: + - Multi-Party Conference Feature Test Matrix + - TRANSFER CONFERENCE SCENARIOS + - Switch Conference — Test Plan +new_user_set: SET_7 +new_suite_file: playwright/suites/conference-transfer-switch-tests.spec.ts +new_test_file: playwright/tests/conference-transfer-switch-test.spec.ts +``` + +## User Constraints Applied +- Exclude scenarios requiring more than 4 agents. +- Exclude scenarios involving `EP_DN`. +- Exclude scenarios requiring dial-number flow. +- Keep `TC-17`, `TC-18`, and `TC-19` non-implemented. +- Use `user25`, `user26`, `user27`, `user28` with existing naming pattern. +- Use desktop login mode only. +- Keep before-test slate clean with stray-task handling. +- Perform stray-task handling and station logout in `afterAll`. + +## Environment +Root `.env` entries used by this suite: +```env +PW_ENTRY_POINT7=+13104247513 +PW_SKIP_OAUTH=true +``` + +## SET_7 Definition +`playwright/test-data.ts`: +```typescript +SET_7: { + AGENTS: { + AGENT1: {username: 'user25', extension: '1025', agentName: 'User25 Agent25'}, + AGENT2: {username: 'user26', extension: '1026', agentName: 'User26 Agent26'}, + AGENT3: {username: 'user27', extension: '1027', agentName: 'User27 Agent27'}, + AGENT4: {username: 'user28', extension: '1028', agentName: 'User28 Agent28'}, + }, + ENTRY_POINT: env.PW_ENTRY_POINT7, + TEST_SUITE: 'conference-transfer-switch-tests.spec.ts', +} +``` + +## Suite Files +- `playwright/suites/conference-transfer-switch-tests.spec.ts` +- `playwright/tests/conference-transfer-switch-test.spec.ts` + +## ID Coverage Implemented +- `CTS-MPC-01..16` +- `CTS-TC-01..05` +- `CTS-SW-01..05` +- `CTS-SKIP-TC14` +- `CTS-SKIP-TC20` +- `CTS-TODO-TC17` +- `CTS-TODO-TC18` +- `CTS-TODO-TC19` + +## Runtime Totals +Current suite totals in `SET_7`: +- Total: `31` +- Executed: `26` +- Skipped/Non-implemented: `5` + +Skipped/Non-implemented reasons: +- `TC14`: excluded (`EP_DN` / external DN) +- `TC20`: excluded (>4 agents) +- `TC17`, `TC18`, `TC19`: intentionally non-implemented (`test.fixme`) + +## Execution Model +### Desktop-only setup +```typescript +await testManager.setupForConferenceDesktop(browser); +``` + +### Mandatory inbound pattern +```typescript +await createCallTask(testManager.callerPage!, process.env[`${testManager.projectName}_ENTRY_POINT`]!); +await acceptIncomingTask(targetAgentPage, TASK_TYPES.CALL, ACCEPT_TASK_TIMEOUT); +``` + +### Mandatory state gating before each call leg +- Target agent -> `Available` +- Non-target agents -> `Meeting` +- Verify states before call initiation + +## Lifecycle +### `beforeEach` +- Clean all active pages with safe stray-task handling. +- Guard against closed pages. + +### `afterAll` +- Clean all pages with safe stray-task handling. +- Run `stationLogout(..., false)` for all agents. +- Run `testManager.cleanup()`. + +## Stability Rules Implemented +To keep these tests non-flaky: +- Retry inbound creation/accept path once when incoming task is missed. +- Retry consult initiation once when consult control is transiently unavailable. +- Retry full base conference creation (`A1+A2+customer`) once on transient UI race. +- Bound `handleStrayTasks` with timeout (`Promise.race`) to avoid long cleanup stalls. +- Keep assertions state/UI-first and avoid forced pass behavior. + +## Skip/Todo Handling +Implemented as: +```typescript +test.skip('CTS-SKIP-TC14 ...'); +test.skip('CTS-SKIP-TC20 ...'); +test.fixme('CTS-TODO-TC17 ...', async () => {}); +test.fixme('CTS-TODO-TC18 ...', async () => {}); +test.fixme('CTS-TODO-TC19 ...', async () => {}); +``` + +## Notes +- This suite intentionally focuses on in-scope conference/transfer/switch behavior for up to 4 agents. +- Audio-quality/assertion-heavy scenarios are not force-implemented where deterministic UI/state validation is the agreed boundary.