Skip to content

Commit e5dc28e

Browse files
committed
Update test README
1 parent 45c8814 commit e5dc28e

1 file changed

Lines changed: 119 additions & 46 deletions

File tree

src/tests/README.md

Lines changed: 119 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ This project uses **Playwright** for all testing needs, with a focused test suit
77
## Test Results
88

99
```bash
10-
7 passing tests (15s)
10+
12 passing tests (~22s)
1111
- 3 unit tests (pure utility functions)
12-
- 4 integration tests (complete user flows)
12+
- 9 integration tests (complete user flows)
1313
```
1414

1515
## Architecture
@@ -74,6 +74,18 @@ The main integration test (`complete-flow.test.ts`) provides **high confidence**
7474
- Verifies `useZendeskIframeStyles` hook injects custom styles
7575
- Confirms `<style data-zendesk-custom-styles="true">` exists in iframe
7676

77+
**6. ✅ Clear Conversation Data Flow**
78+
79+
- Tests the "Clear Conversation Data" button functionality
80+
- Verifies confirmation dialog appears with proper content
81+
- Tests dialog cancellation (storage preserved, dialog closes)
82+
- Confirms storage (localStorage/sessionStorage) is cleared on confirmation
83+
- Verifies user returns to consent screen after clearing
84+
- Tests dialog keyboard interactions (Escape key, Tab navigation, focus management)
85+
- Tests overlay click to close dialog
86+
- Verifies widget is not rendered after state reset
87+
- Verifies button visibility based on widget state
88+
7789
### Example Test Output
7890

7991
```
@@ -94,6 +106,9 @@ The main integration test (`complete-flow.test.ts`) provides **high confidence**
94106
- https://improving.duckduckgo.com/t/subscriptionsupport_helplink_getting-started
95107
- https://improving.duckduckgo.com/t/subscriptionsupport_link_ticket
96108
- https://improving.duckduckgo.com/t/subscriptionsupport_helpful_yes
109+
110+
✅ Storage cleared and widget not rendered
111+
✅ Dialog cancelled and storage preserved
97112
```
98113

99114
## Running Tests
@@ -227,6 +242,7 @@ zE('messenger', 'render', { mode: 'embedded', widget: { targetElement: '#id' } }
227242
zE('messenger:on', 'unreadMessages', callback)
228243
zE('messenger:set', 'cookies', 'functional')
229244
zE('messenger:set', 'customization', { theme: {...} })
245+
zE('messenger', 'resetWidget', callback) // Resets widget and calls callback
230246
```
231247

232248
Creates actual iframe structure:
@@ -243,6 +259,12 @@ Includes realistic content:
243259
- Yes/No feedback buttons for testing click handlers
244260
- Bot messages and conversation structure
245261

262+
**Mock Features:**
263+
264+
- `resetWidget` support - Resets widget state, removes iframes, and calls callback
265+
- Proper iframe structure matching production Zendesk widget
266+
- Realistic timing for callbacks and rendering
267+
246268
This ensures tests verify actual hook behavior, not simulations.
247269

248270
## Test Types Explained
@@ -309,6 +331,9 @@ test('complete flow', async ({ page }) => {
309331
- Style injection via `useZendeskIframeStyles` hook
310332
- Pixel event tracking to `improving.duckduckgo.com`
311333
- Message sending and user interactions
334+
- Clear conversation data flow with dialog confirmation
335+
- Storage clearing (localStorage/sessionStorage)
336+
- State reset and return to consent screen
312337

313338
## Writing New Tests
314339

@@ -334,37 +359,22 @@ test.describe('myUtility', () => {
334359

335360
### Adding an Integration Test
336361

337-
For testing user flows with Zendesk:
362+
For testing user flows with Zendesk, use the helper functions defined in `complete-flow.test.ts` for cleaner, more maintainable tests:
338363

339364
```typescript
340365
import { test, expect } from '@playwright/test';
341-
import { readFileSync } from 'fs';
342-
import { join } from 'path';
366+
// Helper functions are defined at the top of complete-flow.test.ts
367+
// They can be reused within that file or copied to new test files
343368
344369
test('new user flow', async ({ page }) => {
345-
// Load Zendesk mock
346-
const mockScript = readFileSync(
347-
join(__dirname, '../fixtures/zendesk-mock.js'),
348-
'utf-8',
349-
);
350-
351-
await page.route('https://static.zdassets.com/ekr/snippet.js*', (route) => {
352-
route.fulfill({
353-
status: 200,
354-
contentType: 'application/javascript',
355-
body: mockScript,
356-
});
357-
});
370+
// Set up Zendesk mock (helper function)
371+
await setupZendeskMock(page);
358372
359-
// Optionally intercept pixel events
360-
const pixelRequests: string[] = [];
361-
await page.route('https://improving.duckduckgo.com/t/*', (route) => {
362-
pixelRequests.push(route.request().url());
363-
route.fulfill({ status: 200, body: '' });
364-
});
373+
// Optionally intercept pixel events (helper function)
374+
const pixelRequests = await setupPixelInterception(page);
365375
366-
// Test your flow
367-
await page.goto('/');
376+
// Load widget and wait for it to be ready (helper function)
377+
await loadWidget(page);
368378
369379
// ... your test steps ...
370380
@@ -373,6 +383,14 @@ test('new user flow', async ({ page }) => {
373383
});
374384
```
375385

386+
**Helper Functions Available in `complete-flow.test.ts`:**
387+
388+
- `setupZendeskMock(page)` - Sets up the Zendesk script mock route (mock script loaded once at module level)
389+
- `loadWidget(page)` - Navigates to page, clicks consent button, waits for widget ready (~1500ms)
390+
- `setupPixelInterception(page)` - Sets up pixel request interception, returns requests array
391+
392+
These helpers eliminate code duplication and ensure consistent test setup. The mock script is loaded once at module level for better performance.
393+
376394
## Troubleshooting
377395

378396
### Tests are slow
@@ -420,6 +438,7 @@ test('new user flow', async ({ page }) => {
420438
- Intercept and verify network requests (pixel events)
421439
- Use the same selectors as your hooks (e.g., `ZENDESK_ARTICLE_LINK_SELECTOR`) for consistency
422440
- Use `data-testid` attributes for stable element selection
441+
- Test IDs available: `LOAD_ZD_BUTTON_TEST_ID`, `DELETE_DATA_BUTTON_TEST_ID`, `CONFIRM_DELETE_DATA_BUTTON_TEST_ID`, `CANCEL_DELETE_DATA_BUTTON_TEST_ID`
423442
- Wait for specific conditions with `waitForSelector()` instead of arbitrary timeouts
424443
- Test in the real Next.js app environment
425444

@@ -430,7 +449,7 @@ test('new user flow', async ({ page }) => {
430449
- Don't mock what you're testing - only mock external dependencies
431450
- Don't test implementation details - test user-visible behavior
432451
- Don't use brittle CSS class selectors - use semantic selectors
433-
- Don't duplicate test setup - use shared fixtures and helpers
452+
- Don't duplicate test setup - use shared fixtures and helper functions (`setupZendeskMock`, `loadWidget`, `setupPixelInterception`)
434453

435454
## Maintenance
436455

@@ -506,9 +525,9 @@ When you create a new hook that modifies the widget:
506525

507526
```typescript
508527
test('should verify new hook behavior', async ({ page }) => {
509-
// Setup (mock, goto, click button)
510-
// Wait for hooks to activate
511-
await page.waitForTimeout(1500);
528+
// Use helper functions for setup
529+
await setupZendeskMock(page);
530+
await loadWidget(page);
512531
513532
// Verify hook's DOM changes
514533
const result = await page.evaluate(() => {
@@ -522,12 +541,58 @@ When you create a new hook that modifies the widget:
522541
});
523542
```
524543

544+
### Testing Clear Conversation Data Flow
545+
546+
When testing the clear conversation data functionality:
547+
548+
```typescript
549+
test('should clear conversation data', async ({ page }) => {
550+
await setupZendeskMock(page);
551+
await loadWidget(page);
552+
553+
// Pre-populate storage
554+
await page.evaluate(() => {
555+
localStorage.setItem('test-key', 'test-value');
556+
sessionStorage.setItem('test-session-key', 'test-session-value');
557+
});
558+
559+
// Click clear button
560+
const clearButton = page.getByTestId(DELETE_DATA_BUTTON_TEST_ID);
561+
await clearButton.click();
562+
563+
// Verify dialog appears
564+
const dialog = page.getByRole('dialog');
565+
await expect(dialog).toBeVisible();
566+
567+
// Confirm deletion
568+
const confirmButton = page.getByTestId(CONFIRM_DELETE_DATA_BUTTON_TEST_ID);
569+
await confirmButton.click();
570+
571+
// Wait for reload
572+
await page.waitForLoadState('networkidle');
573+
574+
// Verify storage is cleared
575+
const storageState = await page.evaluate(() => ({
576+
localStorage: Object.keys(localStorage).length,
577+
sessionStorage: Object.keys(sessionStorage).length,
578+
}));
579+
expect(storageState.sessionStorage).toBe(0);
580+
});
581+
```
582+
525583
## Key Files
526584

527585
**Tests:**
528586

529-
- `src/tests/integration/complete-flow.test.ts` - Comprehensive integration tests (4 tests)
587+
- `src/tests/integration/complete-flow.test.ts` - Comprehensive integration tests (9 tests)
588+
- Complete widget flow with pixel tracking
589+
- Custom styles injection verification
590+
- Article link click tracking
591+
- Yes/No button click tracking
592+
- Clear conversation data flow
593+
- Dialog cancellation flow
530594
- `src/tests/unit/build-article-url.test.ts` - Unit tests for utilities (3 tests)
595+
- `src/tests/unit/get-slug-from-url.test.ts` - Unit tests for utilities (3 tests)
531596

532597
**Fixtures:**
533598

@@ -542,37 +607,35 @@ When you create a new hook that modifies the widget:
542607

543608
### How Integration Tests Work
544609

545-
1. **Mock Setup**
610+
1. **Mock Setup** (using helper functions)
546611

547612
```typescript
548-
// Load the mock script
549-
const mockScript = readFileSync('zendesk-mock.js', 'utf-8');
613+
// Set up Zendesk mock (helper function handles script loading)
614+
await setupZendeskMock(page);
550615
551-
// Intercept Zendesk CDN request
552-
await page.route('https://static.zdassets.com/ekr/snippet.js*', (route) => {
553-
route.fulfill({ body: mockScript });
554-
});
616+
// Optionally set up pixel interception
617+
const pixelRequests = await setupPixelInterception(page);
555618
```
556619

557-
2. **User Action**
620+
2. **User Action** (using helper functions)
558621

559622
```typescript
560-
// Navigate and click button
561-
await page.goto('/');
562-
await page.getByTestId('load-zd-button').click();
623+
// Load widget (helper function handles navigation, consent click, and waiting)
624+
await loadWidget(page);
563625
```
564626

565627
3. **Widget Renders**
566628

567629
```typescript
568-
// Mock creates iframes
569-
await page.waitForSelector('#messaging-container iframe');
630+
// Widget is ready after loadWidget() completes
631+
// Mock creates iframes automatically
570632
```
571633

572634
4. **Hooks Activate**
573635

574636
```typescript
575-
// Wait for hooks (zendeskReady + callbacks)
637+
// Hooks activate automatically (loadWidget waits for them)
638+
// Additional waits may be needed for specific hook effects
576639
await page.waitForTimeout(1500);
577640
```
578641

@@ -584,6 +647,16 @@ When you create a new hook that modifies the widget:
584647
await expect(link).toHaveAttribute('href', /duckduckgo\.com/);
585648
```
586649

650+
**Helper Functions:**
651+
652+
The test suite includes optimized helper functions to reduce code duplication:
653+
654+
- `setupZendeskMock(page)` - Loads and routes the Zendesk mock script (loaded once at module level)
655+
- `loadWidget(page)` - Navigates to page, clicks consent, waits for widget ready (~1500ms)
656+
- `setupPixelInterception(page)` - Sets up pixel request interception, returns requests array
657+
658+
These helpers make tests more maintainable and consistent.
659+
587660
### Why 1500ms Wait?
588661

589662
The integration tests wait 1500ms for hooks to activate because:
@@ -606,4 +679,4 @@ For issues or questions:
606679

607680
---
608681

609-
**Summary:** A focused test suite providing high confidence for CI deployment. Tests the complete user journey with realistic mocks, verifying iframe rendering, link swapping, message sending, and pixel tracking.
682+
**Summary:** A focused test suite providing high confidence for CI deployment. Tests the complete user journey with realistic mocks, verifying iframe rendering, link swapping, message sending, pixel tracking, and the clear conversation data flow. Uses optimized helper functions to reduce duplication and improve maintainability.

0 commit comments

Comments
 (0)