Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 72 additions & 1 deletion .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,78 @@ This workspace uses the following MCP (Model Context Protocol) tools:
- Let the user interact with the browser after navigation or testing
- Only use `browser_close` when the user specifically requests it

### 🏥 WebChart Testing Workflow
### � Creating Demo Videos with Playwright

This project uses Playwright to create automated demonstration videos of WebChart features. Videos should be under 5 minutes and include overlay annotations.

#### Video Creation Workflow

**1. Authentication Setup (One-Time)**
- Create an `auth-setup.spec.ts` in the `scripts/` directory
- Script should handle "Standard Login" button click, then username/password login
- Save authentication state to `.auth/webchart-session.json` using `storageState`
- This allows tests to skip login and start pre-authenticated

**2. Create Demo Script**
- Create test file in `scripts/` directory (e.g., `feature-name.spec.ts`)
- Use saved authentication: `test.use({ storageState: path.join(__dirname, '../.auth/webchart-session.json') })`
- Navigate directly to feature URLs when possible to avoid UI navigation delays
- Include overlay annotations using helper functions:
```typescript
async function showOverlay(page, text, duration) {
await page.evaluate(({ text, duration }) => {
const overlay = document.createElement('div');
overlay.style.cssText = 'position:fixed;top:20px;left:50%;transform:translateX(-50%);...';
overlay.textContent = text;
document.body.appendChild(overlay);
setTimeout(() => overlay.remove(), duration);
}, { text, duration });
}
```

**3. Video Configuration** (in `playwright.config.ts`)
- Set `video: { mode: 'on', size: { width: 1920, height: 1080 } }`
- Configure `outputDir: './scripts/videos'` for video artifacts
- Set viewport to match video size: `viewport: { width: 1920, height: 1080 }`
- Use single worker: `workers: 1` for sequential execution

**4. Running Video Creation**
```bash
# First time: Run authentication setup
npx playwright test scripts/auth-setup.spec.ts --headed

# Then: Run demo script to generate video
npx playwright test scripts/feature-name.spec.ts --headed
```

**5. Git LFS for Videos**
- Videos are tracked in Git LFS (see `.gitattributes`)
- Patterns: `scripts/videos/*.webm` and `scripts/videos/*.mp4`
- Videos output to `scripts/videos/` directory
- Directory is in `.gitignore` but files tracked via LFS

#### Video Best Practices

- **No login shown**: Use pre-authenticated sessions via `storageState`
- **Direct navigation**: Navigate to feature URLs (`/webchart.cgi?f=chart&s=pat&t=FeatureName&pat_id=TEST-10019`) to skip UI clicks
- **Overlays**: Add text overlays to guide viewers through each step
- **Duration**: Keep under 5 minutes; create separate "quick demo" version if needed
- **Timing**: Add `waitForTimeout()` calls to let actions be visible (500-2000ms)
- **Test patient**: Use TEST-10019 (Hart, William S.) for consistency

#### File Structure
```
scripts/
├── auth-setup.spec.ts # One-time login, saves session
├── feature-name.spec.ts # Demo script with overlays
├── demographics.md # Video script outline
├── videos/ # Generated videos (gitignored, LFS tracked)
└── README.md # Instructions for running tests
.auth/
└── webchart-session.json # Saved authentication state (gitignored)
```

### �🏥 WebChart Testing Workflow

When testing WebChart features, documentation, or web pages, follow this standardized procedure:

Expand Down
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,11 @@ config/_default/menu.en.json
.hugo_build.lock
.idea
.playwright-mcp/

# Playwright & Testing
.env
.auth/
scripts/videos/
test-results/
playwright-report/
playwright/.cache/
66 changes: 66 additions & 0 deletions playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { defineConfig, devices } from '@playwright/test';

/**
* Playwright configuration for Demographics video demonstrations
* Videos are automatically recorded and saved to scripts/videos/ directory
*/
export default defineConfig({
testDir: './scripts',

// Maximum time one test can run for
timeout: 60 * 1000,

// Run tests in files in parallel
fullyParallel: false,

// Fail the build on CI if you accidentally left test.only in the source code
forbidOnly: !!process.env.CI,

// Retry on CI only
retries: process.env.CI ? 2 : 0,

// Use single worker to ensure tests run sequentially
workers: 1,

// Reporter to use
reporter: 'html',

// Shared settings for all the projects below
use: {
// Base URL to use in actions like `await page.goto('/')`
baseURL: 'https://masterdaily.dev.webchart.app',

// Collect trace when retrying the failed test
trace: 'on-first-retry',

// Record video on all tests
video: {
mode: 'on',
size: { width: 1920, height: 1080 }
},

// Set viewport size
viewport: { width: 1920, height: 1080 },

// Screenshot settings
screenshot: 'only-on-failure',
},

// Configure projects for major browsers
projects: [
{
name: 'chromium',
use: {
...devices['Desktop Chrome'],
// Store videos in scripts/videos directory
video: {
mode: 'on',
size: { width: 1920, height: 1080 }
},
},
},
],

// Output folder for videos and screenshots
outputDir: './scripts/videos',
});
87 changes: 87 additions & 0 deletions scripts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Demographics Tab Video Script Tests

Automated Playwright tests for creating demonstration videos of the WebChart Demographics tab functionality.

## Setup

1. **Install dependencies** (if not already done):
```bash
npm install
```

2. **Configure credentials** in `.env` file:
```
WEBCHART_URL=https://masterdaily.dev.webchart.app/
WEBCHART_USERNAME=dave
WEBCHART_PASSWORD=dave
```

## Running the Tests

### Step 1: Authenticate and Save Session

Before running the demonstration tests, you need to establish an authenticated session:

```bash
npx playwright test scripts/auth-setup.spec.ts --headed
```

This will:
- Log into WebChart with the credentials from `.env`
- Save the authentication state to `.auth/webchart-session.json`
- Allow subsequent tests to skip the login process

**Note**: Run this setup whenever:
- Running tests for the first time
- Session expires
- Switching between different WebChart environments

### Step 2: Run Demographics Demonstration

```bash
npx playwright test scripts/demographics.spec.ts --headed --timeout=60000
```

This will run two test scenarios and **automatically record videos**:

1. **Complete Demographics Tab Walkthrough** (4-5 minutes)
- Full demonstration covering all 10 chapters from the script
- Shows all sections: demographics, employment, contacts, insurance, duplicates

2. **Quick Demographics Navigation Demo** (2-3 minutes)
- Condensed version focusing on key highlights
- Faster navigation through main sections

**Videos are automatically saved to**: `scripts/videos/`

Each test run creates a uniquely named video file with timestamp.

## Test Features

- **Pre-authenticated**: Tests use saved session state, no login shown in videos
- **Overlay Annotations**: Each step displays overlay text explaining the action
- **Smooth Navigation**: Automatic scrolling and waiting for proper timing
- **Chapter-based**: Aligned with the demographics.md script structure

## Files

- `auth-setup.spec.ts` - Authentication setup (run once before tests)
- `demographics.spec.ts` - Main demonstration tests
- `demographics.md` - Original video script with 10 chapters
- `.auth/webchart-session.json` - Saved authentication state (git-ignored)
- `videos/` - Recorded video files (git-ignored, automatically created)
- `../playwright.config.ts` - Playwright configuration with video settings

## Troubleshooting

**Session expired**: Re-run the auth-setup script
```bash
npx playwright test scripts/auth-setup.spec.ts --headed
```

**Test timing issues**: Adjust timeout values in the test or use:
```bash
npx playwright test scripts/demographics.spec.ts --headed --timeout=120000
```

**Element not found**: Check that WebChart selectors haven't changed and update test accordingly
111 changes: 111 additions & 0 deletions scripts/auth-setup.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/**
* Authentication Setup Script
*
* This script logs into WebChart and saves the authentication state
* so that tests can skip the login process and start already authenticated.
*
* Run this before running tests:
* npx playwright test scripts/auth-setup.ts
*/

import { test as setup } from '@playwright/test';
import * as dotenv from 'dotenv';
import * as path from 'path';

// Load environment variables
dotenv.config({ path: path.resolve(__dirname, '../.env') });

const WEBCHART_URL = process.env.WEBCHART_URL || 'https://masterdaily.dev.webchart.app/';
const USERNAME = process.env.WEBCHART_USERNAME || 'dave';
const PASSWORD = process.env.WEBCHART_PASSWORD || 'dave';

const authFile = path.join(__dirname, '../.auth/webchart-session.json');

setup('authenticate to WebChart', async ({ page }) => {
console.log('Logging into WebChart...');

// Navigate to WebChart
await page.goto(WEBCHART_URL);
await page.waitForLoadState('domcontentloaded');
await page.waitForTimeout(2000);

// First, check if "Standard Login" button exists
const standardLoginButton = await page.getByRole('button', { name: 'Standard Login' }).isVisible().catch(() => false);

if (standardLoginButton) {
console.log('Clicking Standard Login button...');
await page.getByRole('button', { name: 'Standard Login' }).click();
await page.waitForLoadState('domcontentloaded');
await page.waitForTimeout(2000);
}

// Now check if login form is present - look for the username textbox
const usernameField = page.getByRole('textbox', { name: /Username/ });
const loginFormVisible = await usernameField.isVisible().catch(() => false);

if (loginFormVisible) {
console.log('Login form found, entering credentials...');

// Fill in credentials using the textbox role
await usernameField.fill(USERNAME);
await page.waitForTimeout(500);
await page.getByRole('textbox', { name: /Password/ }).fill(PASSWORD);
await page.waitForTimeout(500);

// Submit login - click the Next button (first time)
console.log('Looking for Next button...');
await page.getByRole('button', { name: 'Next' }).click();
console.log('First Next button clicked');
await page.waitForTimeout(2000);

// Check if there's a second Next button (two-step login process)
const secondNextButton = page.getByRole('button', { name: 'Next' });
const secondNextVisible = await secondNextButton.isVisible().catch(() => false);

if (secondNextVisible) {
console.log('Second Next button found (two-step login), clicking...');
await secondNextButton.click();
await page.waitForLoadState('networkidle', { timeout: 30000 });
await page.waitForTimeout(3000);
} else {
console.log('No second Next button, waiting for navigation...');
await page.waitForLoadState('networkidle', { timeout: 30000 });
await page.waitForTimeout(3000);
}

console.log(`Final URL after login: ${page.url()}`);
console.log('Login completed!');
} else {
console.log('Already logged in or on main page');
}

// Wait for page to fully load
await page.waitForLoadState('networkidle');
await page.waitForTimeout(3000);

// Verify we're logged in by checking for any main page element
const pageLoaded = await page.locator('body').isVisible();
if (pageLoaded) {
console.log('Page loaded successfully, saving authentication state...');

// Log cookies to debug
const cookies = await page.context().cookies();
console.log(`Found ${cookies.length} cookies to save`);

// Check localStorage for tokens
const localStorage = await page.evaluate(() => {
return JSON.stringify(window.localStorage);
});
console.log(`LocalStorage contents: ${localStorage}`);

// Check if we see user-specific content to verify login worked
const bodyText = await page.locator('body').textContent();
console.log(`Page contains "dave": ${bodyText?.includes('dave')}`);
} else {
throw new Error('Page did not load correctly');
}

// Save the authentication state
await page.context().storageState({ path: authFile });
console.log(`Authentication state saved to: ${authFile}`);
});
Loading
Loading