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:
2026-04-11 12:12:22 +05:30
parent f09250f3ef
commit cb4894ddc3
9 changed files with 247 additions and 8 deletions

View File

@@ -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
View 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
View 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 });
});
});