Pre-production security fixes to prevent cross-hospital data leaks: - Standards API: add get_queryset() filtering by department__hospital - Reports service: add user param with hospital filtering to all querysets - RCA views: replace is_superuser with tenant_hospital pattern, add access checks to all 11 mutation views - Notifications views: replace is_superuser patterns with _get_notification_hospital helper across all 5 settings functions - Appreciation API: add tenant_hospital fallback to AppreciationViewSet, AppreciationStatsViewSet, and LeaderboardView - AI Analytics: add tenant_hospital fallback in ExecutiveSummaryGenerator and ActionRecommendationEngine - SourceUserRestrictionMiddleware: remove None from ALLOWED_URL_NAMES - Complaint export: fix nullable patient/due_at/description crashes in CSV and Excel export, fix invalid get_category_display/get_source_display calls E2E test updates: - Update isolation gap tests to actively assert hospital filtering - Fix CSV export test to use API context for download handling - Switch clinical-staff tests to serial mode to prevent race conditions
186 lines
5.8 KiB
TypeScript
186 lines
5.8 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
import { RoleAuthHelper } from '../../helpers/helpers';
|
|
|
|
test.describe('Physician Role', () => {
|
|
test.describe.configure({ mode: 'serial' });
|
|
|
|
test('login succeeds and goes to dashboard', async ({ page }) => {
|
|
const auth = new RoleAuthHelper(page);
|
|
await auth.login('physician');
|
|
|
|
expect(page.url()).not.toContain('login');
|
|
expect(page.url()).not.toContain('select-hospital');
|
|
});
|
|
|
|
test('cannot access config dashboard', async ({ page }) => {
|
|
const auth = new RoleAuthHelper(page);
|
|
await auth.login('physician');
|
|
|
|
await page.goto('/config/');
|
|
const blocked = page.url().includes('command-center') || page.url().includes('analytics') || page.url().toContain('login');
|
|
expect(blocked).toBeTruthy();
|
|
});
|
|
|
|
test('can view complaints list', async ({ page }) => {
|
|
const auth = new RoleAuthHelper(page);
|
|
await auth.login('physician');
|
|
|
|
const response = await page.goto('/complaints/');
|
|
expect(response?.status()).toBeLessThan(400);
|
|
expect(page.url()).not.toContain('login');
|
|
});
|
|
|
|
test('can view physician ratings', async ({ page }) => {
|
|
const auth = new RoleAuthHelper(page);
|
|
await auth.login('physician');
|
|
|
|
const response = await page.goto('/physicians/');
|
|
expect(response?.status()).toBeLessThan(400);
|
|
expect(page.url()).not.toContain('login');
|
|
});
|
|
|
|
test('can access dashboard', async ({ page }) => {
|
|
const auth = new RoleAuthHelper(page);
|
|
await auth.login('physician');
|
|
|
|
const response = await page.goto('/');
|
|
expect(response?.status()).toBeLessThan(400);
|
|
expect(page.url()).not.toContain('login');
|
|
});
|
|
});
|
|
|
|
test.describe('Nurse Role', () => {
|
|
test.describe.configure({ mode: 'serial' });
|
|
|
|
test('login succeeds and goes to dashboard', async ({ page }) => {
|
|
const auth = new RoleAuthHelper(page);
|
|
await auth.login('nurse');
|
|
|
|
expect(page.url()).not.toContain('login');
|
|
expect(page.url()).not.toContain('select-hospital');
|
|
});
|
|
|
|
test('cannot access config dashboard', async ({ page }) => {
|
|
const auth = new RoleAuthHelper(page);
|
|
await auth.login('nurse');
|
|
|
|
await page.goto('/config/');
|
|
const blocked = page.url().includes('command-center') || page.url().includes('analytics') || page.url().toContain('login');
|
|
expect(blocked).toBeTruthy();
|
|
});
|
|
|
|
test('can view dashboard', async ({ page }) => {
|
|
const auth = new RoleAuthHelper(page);
|
|
await auth.login('nurse');
|
|
|
|
const response = await page.goto('/');
|
|
expect(response?.status()).toBeLessThan(400);
|
|
expect(page.url()).not.toContain('login');
|
|
});
|
|
|
|
test('can view complaints', async ({ page }) => {
|
|
const auth = new RoleAuthHelper(page);
|
|
await auth.login('nurse');
|
|
|
|
const response = await page.goto('/complaints/');
|
|
expect(response?.status()).toBeLessThan(400);
|
|
expect(page.url()).not.toContain('login');
|
|
});
|
|
});
|
|
|
|
test.describe('Staff Role', () => {
|
|
test.describe.configure({ mode: 'serial' });
|
|
|
|
test('login succeeds and goes to dashboard', async ({ page }) => {
|
|
const auth = new RoleAuthHelper(page);
|
|
await auth.login('staff');
|
|
|
|
expect(page.url()).not.toContain('login');
|
|
expect(page.url()).not.toContain('select-hospital');
|
|
});
|
|
|
|
test('cannot access config dashboard', async ({ page }) => {
|
|
const auth = new RoleAuthHelper(page);
|
|
await auth.login('staff');
|
|
|
|
await page.goto('/config/');
|
|
const blocked = page.url().includes('command-center') || page.url().includes('analytics') || page.url().toContain('login');
|
|
expect(blocked).toBeTruthy();
|
|
});
|
|
|
|
test('can view dashboard', async ({ page }) => {
|
|
const auth = new RoleAuthHelper(page);
|
|
await auth.login('staff');
|
|
|
|
const response = await page.goto('/');
|
|
expect(response?.status()).toBeLessThan(400);
|
|
expect(page.url()).not.toContain('login');
|
|
});
|
|
|
|
test('can view complaints', async ({ page }) => {
|
|
const auth = new RoleAuthHelper(page);
|
|
await auth.login('staff');
|
|
|
|
const response = await page.goto('/complaints/');
|
|
expect(response?.status()).toBeLessThan(400);
|
|
expect(page.url()).not.toContain('login');
|
|
});
|
|
});
|
|
|
|
test.describe('Viewer Role', () => {
|
|
test.describe.configure({ mode: 'serial' });
|
|
|
|
test('login succeeds and goes to dashboard', async ({ page }) => {
|
|
const auth = new RoleAuthHelper(page);
|
|
await auth.login('viewer');
|
|
|
|
expect(page.url()).not.toContain('login');
|
|
expect(page.url()).not.toContain('select-hospital');
|
|
});
|
|
|
|
test('cannot access config dashboard', async ({ page }) => {
|
|
const auth = new RoleAuthHelper(page);
|
|
await auth.login('viewer');
|
|
|
|
await page.goto('/config/');
|
|
const blocked = page.url().includes('command-center') || page.url().includes('analytics') || page.url().toContain('login');
|
|
expect(blocked).toBeTruthy();
|
|
});
|
|
|
|
test('can view dashboard', async ({ page }) => {
|
|
const auth = new RoleAuthHelper(page);
|
|
await auth.login('viewer');
|
|
|
|
const response = await page.goto('/');
|
|
expect(response?.status()).toBeLessThan(400);
|
|
expect(page.url()).not.toContain('login');
|
|
});
|
|
|
|
test('can view complaints (read-only)', async ({ page }) => {
|
|
const auth = new RoleAuthHelper(page);
|
|
await auth.login('viewer');
|
|
|
|
const response = await page.goto('/complaints/');
|
|
expect(response?.status()).toBeLessThan(400);
|
|
expect(page.url()).not.toContain('login');
|
|
});
|
|
|
|
test('can view surveys instances', async ({ page }) => {
|
|
const auth = new RoleAuthHelper(page);
|
|
await auth.login('viewer');
|
|
|
|
const response = await page.goto('/surveys/instances/');
|
|
expect(response?.status()).toBeLessThan(400);
|
|
expect(page.url()).not.toContain('login');
|
|
});
|
|
|
|
test('can view reports', async ({ page }) => {
|
|
const auth = new RoleAuthHelper(page);
|
|
await auth.login('viewer');
|
|
|
|
const response = await page.goto('/reports/');
|
|
expect(response?.status()).toBeLessThan(400);
|
|
expect(page.url()).not.toContain('login');
|
|
});
|
|
});
|