213 lines
6.8 KiB
TypeScript
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);
|
|
});
|
|
});
|