import { expect, test } from '@playwright/test'; const adminEmail = 'e2e-admin@example.com'; const adminPassword = 'e2e-pass-123'; test.describe.configure({ mode: 'serial' }); /** * @param {import('@playwright/test').APIRequestContext} request * @param {string} email * @param {string} template */ async function latestLink(request, email, template) { const response = await request.get( `http://127.0.0.1:4000/api/dev/outbox?email=${encodeURIComponent(email)}&template=${template}`, ); expect(response.ok()).toBeTruthy(); const rows = await response.json(); const last = rows.at(-1); expect(last?.url).toBeTruthy(); const url = new URL(last.url); url.protocol = 'http:'; url.host = '127.0.0.1:5173'; return url.toString(); } /** * @param {import('@playwright/test').Page} page * @param {string} registration */ async function fillAgreement(page, registration, email) { await expect(page.locator('#agreement_date')).not.toHaveValue(''); await page.locator('#email').fill(email); await page.locator('#full_name').fill('E2E Physician'); await page.locator('#age').fill('42'); await page.locator('#address').fill('Pune'); await page.locator('#registration_no').fill(registration); await page.locator('#medical_council').fill('Maharashtra Medical Council'); await page.locator('#pan').fill('ABCDE1234F'); await page.locator('#bank_name').fill('State Bank of India'); await page.locator('#account_holder').fill('E2E Physician'); await page.locator('#account_number').fill('123456789012'); await page.locator('#ifsc').fill('SBIN0001234'); await page.locator('#accepted').check(); await page.getByRole('button', { name: 'Continue to review' }).click(); await expect(page.getByRole('heading', { name: 'Review agreement' })).toBeVisible(); } /** * @param {import('@playwright/test').Page} page */ async function signAgreement(page) { await page.getByRole('button', { name: 'Proceed to sign' }).click(); await page.getByRole('tab', { name: 'Type instead' }).click(); await page.locator('#typed-name').fill('E2E Physician'); await page.getByRole('button', { name: 'Submit signature' }).click(); await expect(page.getByRole('heading', { name: 'Agreement submitted' })).toBeVisible(); } /** * @param {import('@playwright/test').Page} page * @param {string} registration */ async function openApplication(page, registration) { await page.goto('/admin/login'); await page.locator('#admin-email').fill(adminEmail); await page.locator('#admin-password').fill(adminPassword); await page.getByRole('button', { name: 'Sign in' }).click(); await expect(page.getByRole('link', { name: 'Applications' })).toBeVisible(); await page.goto('/admin/applications'); await page.getByLabel('Search').fill(registration); await page .getByRole('row', { name: new RegExp(registration) }) .getByRole('link') .click(); await expect(page.getByRole('heading', { name: 'E2E Physician' })).toBeVisible(); } /** * @param {import('@playwright/test').Page} page */ async function fillSurveySection(page) { const numbers = page.locator('section input[type="number"]'); const numberCount = await numbers.count(); for (let index = 0; index < numberCount; index += 1) { await numbers.nth(index).fill('25'); } const texts = page.locator('section input[type="text"], section textarea'); const textCount = await texts.count(); for (let index = 0; index < textCount; index += 1) { if (!(await texts.nth(index).inputValue())) { await texts.nth(index).fill('Pune clinic'); } } const radios = page.locator('section input[type="radio"]'); const seen = new Set(); const radioCount = await radios.count(); for (let index = 0; index < radioCount; index += 1) { const name = await radios.nth(index).getAttribute('name'); if (name && !seen.has(name)) { seen.add(name); await radios.nth(index).check(); } } const boxes = page.locator('section input[type="checkbox"]'); if ((await boxes.count()) > 0) { await boxes.first().check(); } } /** * @param {import('@playwright/test').Page} page */ async function completeSurvey(page) { await expect(page.locator('section h2').first()).toBeVisible(); for (let step = 0; step < 24; step += 1) { const title = await page.locator('section h2').first().innerText(); if (title === 'Review') { break; } await fillSurveySection(page); const progress = await page.getByRole('progressbar').getAttribute('aria-valuenow'); await page.getByRole('button', { name: 'Next' }).click(); await expect(page.getByRole('progressbar')).not.toHaveAttribute( 'aria-valuenow', progress ?? '', ); } await page.getByRole('button', { name: 'Submit', exact: true }).click(); await page.getByRole('dialog').getByRole('button', { name: 'Submit' }).click(); await expect(page.getByRole('heading', { name: 'Thank you' })).toBeVisible(); } test('completes the agreement and refuses a second survey', async ({ page, request }) => { const email = `e2e-approve-${Date.now()}@example.com`; const registration = `MMC-E2E-${Date.now()}`; await page.goto('/'); await fillAgreement(page, registration, email); await page.getByRole('button', { name: 'Edit details' }).click(); await expect(page.locator('#full_name')).toHaveValue('E2E Physician'); await expect(page.locator('#agreement_date')).not.toHaveValue(''); await page.locator('#address').fill('Pune clinic'); await page.getByRole('button', { name: 'Continue to review' }).click(); await expect(page.getByRole('heading', { name: 'Review agreement' })).toBeVisible(); await signAgreement(page); await openApplication(page, registration); await page.getByRole('button', { name: 'Approve', exact: true }).click(); await page.getByRole('button', { name: 'Approve', exact: true }).last().click(); await expect(page.getByText('APPROVED', { exact: true })).toBeVisible(); await page.goto(await latestLink(request, email, 'approved')); await completeSurvey(page); await page.reload(); await expect(page.getByRole('heading', { name: 'Already submitted' })).toBeVisible(); }); test('returns a rejected agreement for a new signature and approval', async ({ page, request }) => { const email = `e2e-reject-${Date.now()}@example.com`; const registration = `MMC-REJ-${Date.now()}`; await page.goto('/'); await fillAgreement(page, registration, email); await signAgreement(page); await openApplication(page, registration); await page.getByRole('button', { name: 'Reject', exact: true }).click(); await page.locator('#reject-reason').fill('Please correct the clinic address.'); await page.getByRole('button', { name: 'Reject' }).last().click(); await expect(page.getByText('REJECTED', { exact: true })).toBeVisible(); await page.goto(await latestLink(request, email, 'rejected')); await page.getByRole('button', { name: 'Edit and resubmit' }).click(); await expect(page.locator('#full_name')).toHaveValue('E2E Physician'); await expect(page.locator('#agreement_date')).not.toHaveValue(''); await page.locator('#address').fill('Corrected Pune clinic'); await page.locator('#accepted').check(); await page.getByRole('button', { name: 'Continue to review' }).click(); await expect(page.getByRole('heading', { name: 'Review agreement' })).toBeVisible(); await signAgreement(page); await openApplication(page, registration); await page.getByRole('button', { name: 'Approve', exact: true }).click(); await page.getByRole('button', { name: 'Approve', exact: true }).last().click(); await expect(page.getByText('APPROVED', { exact: true })).toBeVisible(); });