HH/e2e/tests/api/api-security.spec.ts
2026-04-08 17:13:35 +03:00

213 lines
6.8 KiB
TypeScript

import { test, expect } from '@playwright/test';
import { ApiHelper } from '../../helpers/api-helper';
test.describe('JWT Authentication', () => {
test('obtain JWT token pair', async ({ page }) => {
const resp = await page.request.post('/accounts/token/', {
data: {
email: 'e2e-hospital-admin@px360.test',
password: 'Dev@123456',
},
});
expect(resp.status()).toBe(200);
const body = await resp.json();
expect(body.access).toBeTruthy();
expect(body.refresh).toBeTruthy();
});
test('reject invalid credentials', async ({ page }) => {
const resp = await page.request.post('/accounts/token/', {
data: {
email: 'invalid@test.com',
password: 'wrongpass',
},
});
expect(resp.status()).toBe(401);
});
test('access protected API with valid JWT', async ({ page }) => {
const api = new ApiHelper(page);
await api.authenticate('hospital_admin');
const resp = await api.get('/accounts/users/me/');
expect(resp.status()).toBe(200);
const body = await resp.json();
expect(body.email).toBe('e2e-hospital-admin@px360.test');
});
test('access protected API with no token returns 401', async ({ page }) => {
const resp = await page.request.get('/complaints/api/complaints/');
expect(resp.status()).toBe(401);
});
test('refresh token works', async ({ page }) => {
const resp = await page.request.post('/accounts/token/', {
data: {
email: 'e2e-hospital-admin@px360.test',
password: 'Dev@123456',
},
});
const body = await resp.json();
const refreshResp = await page.request.post('/accounts/token/refresh/', {
data: { refresh: body.refresh },
});
expect(refreshResp.status()).toBe(200);
const refreshBody = await refreshResp.json();
expect(refreshBody.access).toBeTruthy();
});
test('PX Admin can create user via API', async ({ page }) => {
const api = new ApiHelper(page);
await api.authenticate('px_admin');
const resp = await api.get('/accounts/users/');
expect(resp.status()).toBe(200);
const body = await resp.json();
expect(Array.isArray(body.results || body)).toBeTruthy();
});
test('Hospital Admin cannot create user via API', async ({ page }) => {
const api = new ApiHelper(page);
await api.authenticate('hospital_admin');
const resp = await api.post('/accounts/users/', {
email: 'e2e-blocked@test.com',
password: 'Test@123456',
});
expect(resp.status()).toBe(403);
});
});
test.describe('Critical API Endpoints', () => {
test('list complaints with JWT returns data', async ({ page }) => {
const api = new ApiHelper(page);
await api.authenticate('hospital_admin');
const resp = await api.get('/complaints/api/complaints/');
expect(resp.status()).toBe(200);
const body = await resp.json();
expect(body.results || body).toBeTruthy();
});
test('create complaint via API', async ({ page }) => {
const api = new ApiHelper(page);
await api.authenticate('hospital_admin');
const { response, body } = await api.createComplaint();
expect([201, 400]).toContain(response.status());
if (response.status() === 201) {
expect(body.reference_number).toMatch(/^CMP-/);
}
});
test('get complaint detail via API', async ({ page }) => {
const api = new ApiHelper(page);
await api.authenticate('hospital_admin');
const listResp = await api.get('/complaints/api/complaints/?page_size=1');
const listBody = await listResp.json();
const results = listBody.results || listBody;
if (results.length === 0) {
test.skip();
return;
}
const pk = results[0].id;
const detailResp = await api.get(`/complaints/api/complaints/${pk}/`);
expect(detailResp.status()).toBe(200);
const detail = await detailResp.json();
expect(detail.id).toBe(pk);
});
test('list inquiries via API', async ({ page }) => {
const api = new ApiHelper(page);
await api.authenticate('hospital_admin');
const resp = await api.get('/complaints/api/inquiries/');
expect(resp.status()).toBe(200);
});
test('list hospitals respects permissions', async ({ page }) => {
const api = new ApiHelper(page);
await api.authenticate('hospital_admin');
const resp = await api.get('/organizations/hospitals/');
expect(resp.status()).toBe(200);
});
test('list survey instances via API', async ({ page }) => {
const api = new ApiHelper(page);
await api.authenticate('hospital_admin');
const resp = await api.get('/surveys/api/instances/');
expect(resp.status()).toBe(200);
});
test('list PX actions via API', async ({ page }) => {
const api = new ApiHelper(page);
await api.authenticate('hospital_admin');
const resp = await api.get('/actions/api/actions/');
expect(resp.status()).toBe(200);
});
test('survey analytics engagement stats via API', async ({ page }) => {
const api = new ApiHelper(page);
await api.authenticate('hospital_admin');
const resp = await api.get('/surveys/api/analytics/engagement_stats/');
expect(resp.status()).toBe(200);
});
test('list physicians via API', async ({ page }) => {
const api = new ApiHelper(page);
await api.authenticate('hospital_admin');
const resp = await api.get('/physicians/api/physicians/');
expect(resp.status()).toBe(200);
});
test('standards API returns data (known isolation gap)', async ({ page }) => {
const api = new ApiHelper(page);
await api.authenticate('hospital_admin');
const resp = await api.get('/standards/api/standards/');
expect(resp.status()).toBe(200);
});
});
test.describe('Public Endpoint Security', () => {
test('API docs accessible without auth', async ({ page }) => {
const resp = await page.request.get('/api/docs/');
expect(resp.status()).toBe(200);
});
test('public complaint submit endpoint exists', async ({ page }) => {
await page.goto('/complaints/public/submit/');
await page.waitForLoadState('domcontentloaded');
await page.waitForSelector('#public_complaint_form, form', { timeout: 10000 });
expect(true).toBeTruthy();
});
test('invalid survey token handled gracefully', async ({ page }) => {
const resp = await page.request.get('/surveys/s/invalid-token/');
expect(resp.status()).not.toBe(500);
});
test('location dropdowns are public', async ({ page }) => {
const resp = await page.request.get('/organizations/locations/');
expect([200, 404]).toContain(resp.status());
});
test('API schema is accessible', async ({ page }) => {
const resp = await page.request.get('/api/schema/');
expect([200, 404, 500]).toContain(resp.status());
});
test('simulator health endpoint is public', async ({ page }) => {
const resp = await page.request.get('/api/simulator/health/');
expect(resp.status()).toBe(200);
});
});