feat: add E2E smoke tests, architecture docs, and operations runbook

- 27 Playwright E2E tests covering login (3 roles), CC Agent pages
  (call desk, call history, patients, appointments, my performance,
  sidebar, sign-out), and Supervisor pages (all 11 pages + sidebar)
- Tests run against live EC2 at ramaiah.engage.healix360.net
- Last test completes sign-out to release agent session for next run
- Architecture doc with updated Mermaid diagram including telephony
  dispatcher, service discovery, and multi-tenant topology
- Operations runbook with SSH access (VPS + EC2), accounts, container
  reference, deploy steps, Redis ops, and troubleshooting guide

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-10 20:54:20 +05:30
parent a1598716ee
commit 1cdb7fe9e7
11 changed files with 1056 additions and 0 deletions

56
e2e/agent-login.spec.ts Normal file
View File

@@ -0,0 +1,56 @@
/**
* Login feature tests — covers multiple roles.
*
* These run WITHOUT saved auth state (fresh browser).
*/
import { test, expect } from '@playwright/test';
import { waitForApp } from './helpers';
const SUPERVISOR = { email: 'supervisor@ramaiahcare.com', password: 'MrRamaiah@2026' };
test.describe('Login', () => {
test('login page renders with branding', async ({ page }) => {
await page.goto('/login');
await expect(page.locator('img[alt]').first()).toBeVisible();
await expect(page.locator('h1').first()).toBeVisible();
await expect(page.locator('form')).toBeVisible();
await expect(page.locator('input[type="email"], input[placeholder*="@"]').first()).toBeVisible();
await expect(page.locator('input[type="password"]').first()).toBeVisible();
await expect(page.getByRole('button', { name: 'Sign in', exact: true })).toBeVisible();
});
test('invalid credentials show error', async ({ page }) => {
await page.goto('/login');
await page.locator('input[type="email"], input[placeholder*="@"]').first().fill('bad@bad.com');
await page.locator('input[type="password"]').first().fill('wrongpassword');
await page.getByRole('button', { name: 'Sign in', exact: true }).click();
await expect(
page.locator('text=/not found|invalid|incorrect|failed|error|unauthorized/i').first(),
).toBeVisible({ timeout: 10_000 });
await expect(page).toHaveURL(/\/login/);
});
test('Supervisor login → lands on app', async ({ page }) => {
await page.goto('/login');
await page.locator('input[type="email"], input[placeholder*="@"]').first().fill(SUPERVISOR.email);
await page.locator('input[type="password"]').first().fill(SUPERVISOR.password);
await page.getByRole('button', { name: 'Sign in', exact: true }).click();
await expect(page).not.toHaveURL(/\/login/, { timeout: 20_000 });
await waitForApp(page);
// Sidebar should be visible
await expect(page.locator('aside').first()).toBeVisible();
});
test('unauthenticated user redirected to login', async ({ page }) => {
await page.context().clearCookies();
await page.goto('/patients');
await expect(page).toHaveURL(/\/login/, { timeout: 10_000 });
});
});