mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage
synced 2026-04-11 18:28:15 +00:00
feat: Global E2E tests, multi-agent fixes, SIP agent tracing
- 13 Global Hospital smoke tests (CC Agent + Supervisor) - Auto-unlock agent session in test setup via maint API - agent-status-toggle sends agentId from localStorage (was missing) - maint-otp-modal injects agentId from localStorage into all calls - SIP manager logs agent identity on connect/disconnect/state changes - seed-data.ts: added CC agent + marketing users, idempotent member creation, cleanup phase before seeding - .gitignore: exclude test-results/ and playwright-report/ Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,14 @@ import { fileURLToPath } from 'url';
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const authFile = path.join(__dirname, '.auth/agent.json');
|
||||
|
||||
setup('login as CC Agent', async ({ page }) => {
|
||||
setup('login as CC Agent', async ({ page, request, baseURL }) => {
|
||||
// Clear any stale session lock before login
|
||||
const url = baseURL ?? 'https://ramaiah.engage.healix360.net';
|
||||
await request.post(`${url}/api/maint/unlock-agent`, {
|
||||
headers: { 'Content-Type': 'application/json', 'x-maint-otp': '400168' },
|
||||
data: { agentId: 'ramaiahadmin' },
|
||||
}).catch(() => {});
|
||||
|
||||
await page.goto('/login');
|
||||
|
||||
await page.locator('input[type="email"], input[name="email"], input[placeholder*="@"]').first().fill('ccagent@ramaiahcare.com');
|
||||
|
||||
25
e2e/global-setup.ts
Normal file
25
e2e/global-setup.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { test as setup, expect } from '@playwright/test';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const authFile = path.join(__dirname, '.auth/global-agent.json');
|
||||
|
||||
setup('login as Global CC Agent', async ({ page, request }) => {
|
||||
// Clear any stale session lock before login
|
||||
await request.post('https://global.engage.healix360.net/api/maint/unlock-agent', {
|
||||
headers: { 'Content-Type': 'application/json', 'x-maint-otp': '400168' },
|
||||
data: { agentId: 'global' },
|
||||
}).catch(() => {});
|
||||
|
||||
await page.goto('https://global.engage.healix360.net/login');
|
||||
|
||||
await page.locator('input[type="email"], input[placeholder*="@"]').first().fill('rekha.cc@globalcare.com');
|
||||
await page.locator('input[type="password"]').first().fill('Global@123');
|
||||
await page.getByRole('button', { name: 'Sign in', exact: true }).click();
|
||||
|
||||
await expect(page).not.toHaveURL(/\/login/, { timeout: 20_000 });
|
||||
await expect(page.locator('aside').first()).toBeVisible({ timeout: 10_000 });
|
||||
|
||||
await page.context().storageState({ path: authFile });
|
||||
});
|
||||
120
e2e/global-smoke.spec.ts
Normal file
120
e2e/global-smoke.spec.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* Global Hospital — happy-path smoke tests.
|
||||
*
|
||||
* Uses saved auth state from global-setup.ts (same pattern as Ramaiah).
|
||||
* Last test signs out to release the agent session.
|
||||
*/
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { loginAs, waitForApp } from './helpers';
|
||||
|
||||
const BASE = 'https://global.engage.healix360.net';
|
||||
|
||||
test.describe('Global — CC Agent', () => {
|
||||
|
||||
test('landing page loads', async ({ page }) => {
|
||||
await page.goto(BASE + '/');
|
||||
await waitForApp(page);
|
||||
await expect(page.locator('aside').first()).toBeVisible();
|
||||
});
|
||||
|
||||
test('Call History page loads', async ({ page }) => {
|
||||
await page.goto(BASE + '/call-history');
|
||||
await waitForApp(page);
|
||||
await expect(page.locator('text="Call History"').first()).toBeVisible();
|
||||
});
|
||||
|
||||
test('Patients page loads', async ({ page }) => {
|
||||
await page.goto(BASE + '/patients');
|
||||
await waitForApp(page);
|
||||
const search = page.getByPlaceholder(/search/i).or(page.getByLabel(/search/i));
|
||||
await expect(search.first()).toBeVisible();
|
||||
});
|
||||
|
||||
test('Appointments page loads', async ({ page }) => {
|
||||
await page.goto(BASE + '/appointments');
|
||||
await waitForApp(page);
|
||||
await expect(
|
||||
page.locator('text=/Appointment|Schedule|No appointment/i').first(),
|
||||
).toBeVisible({ timeout: 10_000 });
|
||||
});
|
||||
|
||||
test('My Performance page loads', async ({ page }) => {
|
||||
await page.goto(BASE + '/my-performance');
|
||||
await waitForApp(page);
|
||||
await expect(page.getByRole('button', { name: 'Today' })).toBeVisible();
|
||||
});
|
||||
|
||||
test('sidebar has CC Agent nav items', async ({ page }) => {
|
||||
await page.goto(BASE + '/');
|
||||
await waitForApp(page);
|
||||
const sidebar = page.locator('aside').first();
|
||||
for (const item of ['Call Desk', 'Call History', 'Patients', 'Appointments', 'My Performance']) {
|
||||
await expect(sidebar.locator(`text="${item}"`)).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
// Last test — sign out to release session
|
||||
test('sign-out completes', async ({ page }) => {
|
||||
await page.goto(BASE + '/');
|
||||
await waitForApp(page);
|
||||
|
||||
const sidebar = page.locator('aside').first();
|
||||
const accountArea = sidebar.locator('[class*="account"], [class*="avatar"]').last();
|
||||
if (await accountArea.isVisible()) await accountArea.click();
|
||||
|
||||
const signOutBtn = page.locator('button, [role="menuitem"]').filter({ hasText: /sign out/i }).first();
|
||||
if (await signOutBtn.isVisible({ timeout: 5_000 }).catch(() => false)) {
|
||||
await signOutBtn.click();
|
||||
const modal = page.locator('[role="dialog"]');
|
||||
await expect(modal).toBeVisible({ timeout: 5_000 });
|
||||
await modal.getByRole('button', { name: /sign out/i }).click();
|
||||
await expect(page).toHaveURL(/\/login/, { timeout: 15_000 });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Global — Supervisor', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto(BASE + '/login');
|
||||
await page.locator('input[type="email"], input[placeholder*="@"]').first().fill('dr.ramesh@globalcare.com');
|
||||
await page.locator('input[type="password"]').first().fill('Global@123');
|
||||
await page.getByRole('button', { name: 'Sign in', exact: true }).click();
|
||||
await expect(page).not.toHaveURL(/\/login/, { timeout: 20_000 });
|
||||
await waitForApp(page);
|
||||
});
|
||||
|
||||
test('landing page loads', async ({ page }) => {
|
||||
await expect(page.locator('aside').first()).toBeVisible();
|
||||
});
|
||||
|
||||
test('Patients page loads', async ({ page }) => {
|
||||
await page.goto(BASE + '/patients');
|
||||
await waitForApp(page);
|
||||
const search = page.getByPlaceholder(/search/i).or(page.getByLabel(/search/i));
|
||||
await expect(search.first()).toBeVisible();
|
||||
});
|
||||
|
||||
test('Appointments page loads', async ({ page }) => {
|
||||
await page.goto(BASE + '/appointments');
|
||||
await waitForApp(page);
|
||||
await expect(
|
||||
page.locator('text=/Appointment|Schedule|No appointment/i').first(),
|
||||
).toBeVisible({ timeout: 10_000 });
|
||||
});
|
||||
|
||||
test('Campaigns page loads', async ({ page }) => {
|
||||
await page.goto(BASE + '/campaigns');
|
||||
await waitForApp(page);
|
||||
await expect(
|
||||
page.locator('text=/Campaign|No campaign/i').first(),
|
||||
).toBeVisible({ timeout: 10_000 });
|
||||
});
|
||||
|
||||
test('Settings page loads', async ({ page }) => {
|
||||
await page.goto(BASE + '/settings');
|
||||
await waitForApp(page);
|
||||
await expect(
|
||||
page.locator('text=/Settings|Configuration/i').first(),
|
||||
).toBeVisible({ timeout: 10_000 });
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user