|
| 1 | +# Test Fixtures - Mock Data for Testing |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +Test Fixtures is a utility package that provides comprehensive mock data for testing contact center widgets. It includes mock objects for the Contact Center SDK, tasks, profiles, agents, queues, and address books. These fixtures enable isolated unit testing without requiring actual SDK connections. |
| 6 | + |
| 7 | +**Package:** `@webex/test-fixtures` |
| 8 | + |
| 9 | +**Version:** See [package.json](../package.json) |
| 10 | + |
| 11 | +--- |
| 12 | + |
| 13 | +## Why and What is This Package Used For? |
| 14 | + |
| 15 | +### Purpose |
| 16 | + |
| 17 | +Test Fixtures provides realistic mock data for testing widgets and components. It: |
| 18 | +- **Provides mock SDK instance** - IContactCenter mock with jest functions |
| 19 | +- **Supplies mock data** - Tasks, profiles, agents, queues, address books |
| 20 | +- **Enables isolated testing** - Test widgets without backend dependencies |
| 21 | +- **Ensures consistency** - Same mock data across all tests |
| 22 | +- **Supports customization** - Easy to extend or override fixtures |
| 23 | + |
| 24 | +### Key Capabilities |
| 25 | + |
| 26 | +- **SDK Mock**: Mock SDK methods to be used in testing |
| 27 | +- **Task Fixtures**: Mock tasks with various states and media types |
| 28 | +- **Profile Data**: Mock agent profiles with teams, dial plans, idle codes |
| 29 | +- **Address Book**: Mock contact entries and search results |
| 30 | +- **Queue Data**: Mock queue configurations and statistics |
| 31 | +- **Agent Data**: Mock agent lists for buddy agents/transfers |
| 32 | +- **Type-Safe**: All fixtures match actual SDK TypeScript types |
| 33 | + |
| 34 | +--- |
| 35 | + |
| 36 | +## Examples and Use Cases |
| 37 | + |
| 38 | +### Getting Started |
| 39 | + |
| 40 | +#### Basic Widget Test |
| 41 | + |
| 42 | +```typescript |
| 43 | +import { render } from '@testing-library/react'; |
| 44 | +import { StationLogin } from '@webex/cc-station-login'; |
| 45 | +import { mockCC, mockProfile } from '@webex/test-fixtures'; |
| 46 | +import store from '@webex/cc-store'; |
| 47 | + |
| 48 | +// Mock the store |
| 49 | +jest.mock('@webex/cc-store', () => ({ |
| 50 | + cc: mockCC, |
| 51 | + teams: mockProfile.teams, |
| 52 | + loginOptions: mockProfile.loginVoiceOptions, |
| 53 | + logger: mockCC.LoggerProxy, |
| 54 | + isAgentLoggedIn: false, |
| 55 | +})); |
| 56 | + |
| 57 | +describe('station login', () => { |
| 58 | + it('renders station login', () => { |
| 59 | + const { getByText } = render(<StationLogin profileMode={false} />); |
| 60 | + expect(getByText('Login')).toBeInTheDocument(); |
| 61 | + }) |
| 62 | +}); |
| 63 | +``` |
| 64 | + |
| 65 | +#### Using Mock Task |
| 66 | + |
| 67 | +```typescript |
| 68 | +import { render } from '@testing-library/react'; |
| 69 | +import { CallControl } from '@webex/cc-task'; |
| 70 | +import { mockTask } from '@webex/test-fixtures'; |
| 71 | + |
| 72 | +it('renders call control for active task', () => { |
| 73 | + const { getByRole } = render( |
| 74 | + <CallControl task={mockTask} /> |
| 75 | + ); |
| 76 | + |
| 77 | + expect(getByRole('button', { name: /hold/i })).toBeInTheDocument(); |
| 78 | + expect(getByRole('button', { name: /end/i })).toBeInTheDocument(); |
| 79 | +}); |
| 80 | +``` |
| 81 | + |
| 82 | +### Common Use Cases |
| 83 | + |
| 84 | +#### 1. Mocking Contact Center SDK |
| 85 | + |
| 86 | +```typescript |
| 87 | +import { mockCC } from '@webex/test-fixtures'; |
| 88 | + |
| 89 | +// Use in tests |
| 90 | +it('calls SDK stationLogin method', async () => { |
| 91 | + const loginSpy = jest.spyOn(mockCC, 'stationLogin') |
| 92 | + .mockResolvedValue({ success: true }); |
| 93 | + |
| 94 | + await mockCC.stationLogin({ |
| 95 | + teamId: 'team1', |
| 96 | + loginOption: 'BROWSER', |
| 97 | + dialNumber: '' |
| 98 | + }); |
| 99 | + |
| 100 | + expect(loginSpy).toHaveBeenCalledWith({ |
| 101 | + teamId: 'team1', |
| 102 | + loginOption: 'BROWSER', |
| 103 | + dialNumber: '' |
| 104 | + }); |
| 105 | +}); |
| 106 | +``` |
| 107 | + |
| 108 | +#### 2. Customizing Mock Profile |
| 109 | + |
| 110 | +```typescript |
| 111 | +import { mockProfile } from '@webex/test-fixtures'; |
| 112 | + |
| 113 | +it('handles agent with custom idle codes', () => { |
| 114 | + // Customize fixture |
| 115 | + const customProfile = { |
| 116 | + ...mockProfile, |
| 117 | + idleCodes: [ |
| 118 | + { id: 'break', name: 'Break', isSystem: true, isDefault: false }, |
| 119 | + { id: 'lunch', name: 'Lunch', isSystem: false, isDefault: false }, |
| 120 | + { id: 'meeting', name: 'Meeting', isSystem: false, isDefault: true }, |
| 121 | + ] |
| 122 | + }; |
| 123 | + |
| 124 | + // Use in test |
| 125 | + store.setIdleCodes(customProfile.idleCodes); |
| 126 | + // ... test logic |
| 127 | +}); |
| 128 | +``` |
| 129 | + |
| 130 | +#### 3. Testing Task Operations |
| 131 | + |
| 132 | +```typescript |
| 133 | +import { mockTask } from '@webex/test-fixtures'; |
| 134 | + |
| 135 | +it('can hold and resume task', async () => { |
| 136 | + // Task has pre-configured jest mocks |
| 137 | + |
| 138 | + const holdSpy = jest.spyOn(mockTask,'hold') |
| 139 | + const resumeSpy = jest.spyOn(mockTask,'resume') |
| 140 | + |
| 141 | + await mockTask.hold() |
| 142 | + await mockTask.resume() |
| 143 | + await mockTask.hold() |
| 144 | + |
| 145 | + expect(holdSpy).toHaveBeenCalledTimes(2) |
| 146 | + expect(resumeSpy).toHaveBeenCalledTimes(1) |
| 147 | +}); |
| 148 | + |
| 149 | +it('can end task with wrapup', async () => { |
| 150 | + const mockData = { success: true } |
| 151 | + const wrapupSpy = jest.spyOn(mockTask, 'wrapup') |
| 152 | + .mockResolvedValue(mockData); |
| 153 | + |
| 154 | + const res = await mockTask.wrapup(); |
| 155 | + expect(wrapupSpy).toHaveBeenCalled(); |
| 156 | + expect(res).toEqual(mockData) |
| 157 | +}); |
| 158 | +``` |
| 159 | + |
| 160 | +#### 4. Testing with Mock Agents |
| 161 | + |
| 162 | +```typescript |
| 163 | +import { mockAgents } from '@webex/test-fixtures'; |
| 164 | + |
| 165 | +it('displays buddy agents for transfer', () => { |
| 166 | + const { getByText } = render( |
| 167 | + <BuddyAgentList agents={mockAgents} /> |
| 168 | + ); |
| 169 | + |
| 170 | + expect(getByText('Agent1')).toBeInTheDocument(); |
| 171 | + expect(getByText('Agent2')).toBeInTheDocument(); |
| 172 | +}); |
| 173 | +``` |
| 174 | + |
| 175 | +#### 5. Testing Queue Selection |
| 176 | + |
| 177 | +```typescript |
| 178 | +import { mockQueueDetails } from '@webex/test-fixtures'; |
| 179 | + |
| 180 | +it('allows selecting transfer queue', () => { |
| 181 | + const { getByRole } = render( |
| 182 | + <QueueSelector queues={mockQueueDetails} /> |
| 183 | + ); |
| 184 | + |
| 185 | + const queue1 = getByRole('option', { name: /Queue1/i }); |
| 186 | + expect(queue1).toBeInTheDocument(); |
| 187 | +}); |
| 188 | +``` |
| 189 | + |
| 190 | +#### 6. Custom Address Book Mock |
| 191 | + |
| 192 | +```typescript |
| 193 | +import { makeMockAddressBook } from '@webex/test-fixtures'; |
| 194 | + |
| 195 | +it('searches address book entries', async () => { |
| 196 | + const mockGetEntries = jest.fn().mockResolvedValue({ |
| 197 | + data: [ |
| 198 | + { id: 'c1', name: 'John', number: '123' }, |
| 199 | + { id: 'c2', name: 'Jane', number: '456' }, |
| 200 | + ], |
| 201 | + meta: { page: 0, pageSize: 25, totalPages: 1 } |
| 202 | + }); |
| 203 | + |
| 204 | + const addressBook = makeMockAddressBook(mockGetEntries); |
| 205 | + |
| 206 | + const result = await addressBook.getEntries({ search: 'John' }); |
| 207 | + |
| 208 | + expect(mockGetEntries).toHaveBeenCalledWith({ search: 'John' }); |
| 209 | + expect(result.data).toHaveLength(2); |
| 210 | +}); |
| 211 | +``` |
| 212 | + |
| 213 | +### Integration Patterns |
| 214 | + |
| 215 | +#### Complete Widget Test Setup |
| 216 | + |
| 217 | +```typescript |
| 218 | +import { render } from '@testing-library/react'; |
| 219 | +import { UserState } from '@webex/cc-user-state'; |
| 220 | +import { mockCC, mockProfile } from '@webex/test-fixtures'; |
| 221 | +import store from '@webex/cc-store'; |
| 222 | + |
| 223 | +// Mock store module |
| 224 | +jest.mock('@webex/cc-store', () => ({ |
| 225 | + cc: mockCC, |
| 226 | + idleCodes: mockProfile.idleCodes, |
| 227 | + agentId: mockProfile.agentId, |
| 228 | + currentState: 'Available', |
| 229 | + lastStateChangeTimestamp: 'mock-date', |
| 230 | + customState: null, |
| 231 | + logger: mockCC.LoggerProxy, |
| 232 | + setCurrentState: jest.fn(), |
| 233 | + setLastStateChangeTimestamp: jest.fn(), |
| 234 | + setLastIdleCodeChangeTimestamp: jest.fn(), |
| 235 | +})); |
| 236 | + |
| 237 | +it('user state widget', () => { |
| 238 | + const onStateChange = jest.fn(); |
| 239 | + |
| 240 | + render(<UserState onStateChange={onStateChange} />); |
| 241 | + |
| 242 | + // Test interactions |
| 243 | + // ... |
| 244 | +}); |
| 245 | +``` |
| 246 | + |
| 247 | +#### Snapshot Testing |
| 248 | + |
| 249 | +```typescript |
| 250 | +import { render } from '@testing-library/react'; |
| 251 | +import { TaskList } from '@webex/cc-task'; |
| 252 | +import { mockTask } from '@webex/test-fixtures'; |
| 253 | + |
| 254 | +it('task list matches snapshot', async() => { |
| 255 | + const { container } = await render( |
| 256 | + <TaskList |
| 257 | + tasks={[mockTask]} |
| 258 | + selectedTaskId={mockTask.data.interactionId} |
| 259 | + /> |
| 260 | + ); |
| 261 | + |
| 262 | + expect(container.firstChild).toMatchSnapshot(); |
| 263 | +}); |
| 264 | +``` |
| 265 | + |
| 266 | +--- |
| 267 | + |
| 268 | +## Dependencies |
| 269 | + |
| 270 | +**Note:** For exact versions, see [package.json](../package.json) |
| 271 | + |
| 272 | +### Runtime Dependencies |
| 273 | + |
| 274 | +| Package | Purpose | |
| 275 | +|---------|---------| |
| 276 | +| `@webex/cc-store` | Store types and interfaces | |
| 277 | +| `typescript` | TypeScript support | |
| 278 | +| `@webex/contact-center` | Types import from SDK | |
| 279 | + |
| 280 | +### Development Dependencies |
| 281 | + |
| 282 | +Key development tools (see [package.json](../package.json) for versions): |
| 283 | +- TypeScript |
| 284 | +- Webpack (bundling) |
| 285 | +- Babel (transpilation) |
| 286 | +- ESLint (linting) |
| 287 | + |
| 288 | +**Note:** This package has no peer dependencies since it's only used in tests. |
| 289 | + |
| 290 | +--- |
| 291 | + |
| 292 | +## Available Fixtures |
| 293 | + |
| 294 | +### Core Fixtures |
| 295 | + |
| 296 | +| Export | Type | Purpose | |
| 297 | +|--------|------|---------| |
| 298 | +| `mockCC` | `IContactCenter` | Complete SDK instance mock with jest functions | |
| 299 | +| `mockProfile` | `Profile` | Agent profile with teams, idle codes, wrapup codes | |
| 300 | +| `mockTask` | `ITask` | Active task with telephony interaction | |
| 301 | +| `mockQueueDetails` | `Array<QueueDetails>` | Queue configurations | |
| 302 | +| `mockAgents` | `Array<Agent>` | Buddy agent list | |
| 303 | +| `mockEntryPointsResponse` | `EntryPointListResponse` | Entry points for outdial | |
| 304 | +| `mockAddressBookEntriesResponse` | `AddressBookEntriesResponse` | Address book contacts | |
| 305 | +| `makeMockAddressBook` | `Function` | Factory for custom address book mock | |
| 306 | +| `mockIncomingTaskData` | `Record<string, IncomingTaskData>` | Incoming task data variants for incoming task tests | |
| 307 | +| `mockTaskData` | `Record<string, Record<string, TaskListItemData>>` | Task list item data variants for task list tests | |
| 308 | +| `mockOutdialCallProps` | `OutdialCallComponentProps` | Outdial call component props mock with jest functions | |
| 309 | +| `mockAniEntries` | `Array<OutdialAniEntry>` | Outdial ANI entries list | |
| 310 | +| `mockCCWithAni` | `IContactCenter` | CC mock with outdial ANI configured | |
| 311 | + |
| 312 | +### Importing Fixtures |
| 313 | + |
| 314 | +```typescript |
| 315 | +// Import all fixtures |
| 316 | +import { |
| 317 | + mockCC, |
| 318 | + mockProfile, |
| 319 | + mockTask, |
| 320 | + mockQueueDetails, |
| 321 | + mockAgents, |
| 322 | + mockEntryPointsResponse, |
| 323 | + mockAddressBookEntriesResponse, |
| 324 | + makeMockAddressBook, |
| 325 | +} from '@webex/test-fixtures'; |
| 326 | +
|
| 327 | +// Use in tests |
| 328 | +it('example', () => { |
| 329 | + expect(mockCC.stationLogin).toBeDefined(); |
| 330 | + expect(mockProfile.teams).toHaveLength(1); |
| 331 | + expect(mockTask.data.interactionId).toBe('interaction123'); |
| 332 | +}); |
| 333 | +``` |
| 334 | + |
| 335 | +--- |
| 336 | + |
| 337 | +## Installation |
| 338 | + |
| 339 | +```bash |
| 340 | +# Install as dev dependency |
| 341 | +yarn add -D @webex/test-fixtures |
| 342 | +
|
| 343 | +# Usually already included in widget package devDependencies |
| 344 | +``` |
| 345 | + |
| 346 | +--- |
| 347 | + |
| 348 | +## Additional Resources |
| 349 | + |
| 350 | +For detailed fixture structure, customization patterns, and testing strategies, see [architecture.md](./architecture.md). |
| 351 | + |
| 352 | +--- |
| 353 | + |
| 354 | +_Last Updated: 2025-11-26_ |
| 355 | + |
0 commit comments