import type { Page, Route } from '@playwright/test'; import { expect, test } from '@playwright/test'; const templateId = '01M00000000000000000000210'; const readonlyTemplateId = '01M00000000000000000000211'; const documentId = '01M00000000000000000000212'; function template(overrides: Record = {}) { return { publicId: templateId, formType: 'OA-01', templateVersion: 1, name: '项目立项申请', groupCode: 'PROJECT_PREPARATION', groupName: '项目准备', purpose: '形成项目基础资料', initiatorRoles: ['PROJECT_MANAGER'], status: 'ACTIVE', publishedAt: '2026-08-15T08:00:00Z', myDraftCount: 1, myPendingCount: 0, canCreate: true, fields: [], ...overrides, }; } function sourceForm() { return { publicId: documentId, businessNo: 'OA01-E2E-001', formType: 'OA-01', formName: '项目立项申请', templateVersion: 1, sourceSystem: 'MANUAL', sourceNo: 'SRC-OA01-E2E-001', sourceVersion: '1', company: { publicId: '01M00000000000000000000213', name: '凯迪测试公司' }, project: { publicId: '01M00000000000000000000214', name: '表单中心验收项目' }, applicantName: '项目经办人', businessDate: '2026-08-15', status: 'DRAFT', currentNodeCode: null, currentNodeName: null, version: 0, createdByName: '项目经办人', createdAt: '2026-08-15T08:00:00Z', updatedAt: '2026-08-15T08:00:00Z', allowedActions: ['EDIT', 'VALIDATE', 'SUBMIT', 'VOID'], }; } function session() { return { authenticated: true, user: { publicId: '01M00000000000000000000215', username: 'forms-e2e', displayName: '表单验收用户', departmentName: '项目部', mustChangePassword: false, }, roles: [{ code: 'PROJECT_MANAGER', name: '项目管理人员', workbenchRoute: '/workbench/project' }], activeRole: 'PROJECT_MANAGER', permissions: ['source:template:view', 'source:form:view', 'source:form:create', 'source:form:validate'], }; } async function installFormCenterFixture( page: Page, validateRequests: Array>, formQueries: URLSearchParams[] = [], ) { const userSession = session(); await page.route('**/api/v1/**', async (route: Route) => { const request = route.request(); const pathname = new URL(request.url()).pathname; if (pathname === '/api/v1/auth/session') { await route.fulfill({ json: { data: userSession, requestId: '01M00000000000000000000216' } }); return; } if (pathname === '/api/v1/auth/profile') { await route.fulfill({ json: { data: userSession.user, requestId: '01M00000000000000000000217' } }); return; } if (pathname === '/api/v1/auth/roles') { await route.fulfill({ json: { data: userSession.roles, requestId: '01M00000000000000000000218' } }); return; } if (pathname === '/api/v1/auth/csrf') { await route.fulfill({ headers: { 'set-cookie': 'XSRF-TOKEN=forms-e2e-csrf; Path=/' }, json: { data: { token: 'forms-e2e-csrf' }, requestId: '01M00000000000000000000219' }, }); return; } if (request.method() === 'GET' && pathname === '/api/v1/source/templates') { await route.fulfill({ json: { data: [ template(), template({ publicId: readonlyTemplateId, formType: 'OA-02', name: '供应商准入申请', purpose: '形成供应商准入资料', initiatorRoles: ['FINANCE_MANAGER'], myDraftCount: 0, canCreate: false, }), template({ publicId: '01M00000000000000000000224', formType: 'OA-05', templateVersion: 2, name: '收款确认申请', groupCode: 'INCOME_EXPENSE', groupName: '收支执行', }), ], requestId: '01M00000000000000000000220', }, }); return; } if (request.method() === 'GET' && pathname === '/api/v1/source/forms') { formQueries.push(new URL(request.url()).searchParams); await route.fulfill({ json: { data: [sourceForm()], meta: { page: 1, size: 20, totalElements: 1, totalPages: 1 }, requestId: '01M00000000000000000000221', }, }); return; } if (request.method() === 'POST' && pathname === `/api/v1/source/forms/${documentId}/validate`) { validateRequests.push((request.postDataJSON() || {}) as Record); await route.fulfill({ json: { data: { documentId, version: 0, valid: true, canSubmit: true, errors: [], warnings: [], validatedAt: '2026-08-15T08:01:00Z', }, requestId: '01M00000000000000000000222', }, }); return; } if (request.method() === 'GET') { await route.fulfill({ json: { data: [], meta: { page: 1, size: 20, totalElements: 0, totalPages: 0 }, requestId: '01M00000000000000000000223', }, }); return; } await route.fulfill({ status: 204 }); }); } test('PAGE-09 shows initiator roles, respects create rights and validates a draft', async ({ page }) => { const validateRequests: Array> = []; await installFormCenterFixture(page, validateRequests); await page.goto('/forms'); await expect(page.getByRole('heading', { name: '表单中心', exact: true })).toBeVisible(); const editableCard = page.locator('.t-card').filter({ hasText: 'OA-01' }); await expect(editableCard.getByText('项目管理人员', { exact: true })).toBeVisible(); await expect(editableCard.getByRole('button', { name: '在线填写', exact: true })).toBeVisible(); await expect(editableCard.getByRole('button', { name: '导入', exact: true })).toBeVisible(); const readonlyCard = page.locator('.t-card').filter({ hasText: 'OA-02' }); await expect(readonlyCard.getByText('财务管理人员', { exact: true })).toBeVisible(); await expect(readonlyCard.getByRole('button', { name: '在线填写', exact: true })).toHaveCount(0); await expect(readonlyCard.getByRole('button', { name: '导入', exact: true })).toHaveCount(0); await page.getByText('校验', { exact: true }).click(); await expect.poll(() => validateRequests.length).toBe(1); expect(validateRequests[0]).toEqual({}); await expect(page.getByText('表单校验通过', { exact: true })).toBeVisible(); await editableCard.getByRole('button', { name: '在线填写', exact: true }).click(); await expect(page).toHaveURL(/\/forms\/OA-01\?mode=online/); }); test('PAGE-09 sends group, version, creation date and sort filters and keeps them in the URL', async ({ page }) => { const formQueries: URLSearchParams[] = []; await installFormCenterFixture(page, [], formQueries); await page.goto( '/forms?groupCode=INCOME_EXPENSE&formType=OA-05&templateVersion=2' + '&createdDateFrom=2026-08-01&createdDateTo=2026-08-15&sort=createdAt%2Casc', ); await expect(page.getByRole('heading', { name: '表单中心', exact: true })).toBeVisible(); await expect.poll(() => formQueries.length).toBeGreaterThan(0); const initial = formQueries.at(-1)!; expect(initial.get('groupCode')).toBe('INCOME_EXPENSE'); expect(initial.get('formType')).toBe('OA-05'); expect(initial.get('templateVersion')).toBe('2'); expect(initial.get('createdDateFrom')).toBe('2026-08-01'); expect(initial.get('createdDateTo')).toBe('2026-08-15'); expect(initial.get('sort')).toBe('createdAt,asc'); await expect(page).toHaveURL(/groupCode=INCOME_EXPENSE/); await expect(page).toHaveURL(/templateVersion=2/); const requestCount = formQueries.length; await page.getByText('项目准备', { exact: true }).click(); await expect.poll(() => formQueries.length).toBeGreaterThan(requestCount); expect(formQueries.at(-1)!.get('groupCode')).toBe('PROJECT_PREPARATION'); await expect(page).toHaveURL(/groupCode=PROJECT_PREPARATION/); });