import { expect, type Page, test } from '@playwright/test' async function useAdminSession (page: Page) { await page.addInitScript(() => { sessionStorage.setItem('bolts-session', JSON.stringify({ username: 'admin', role: 'admin', token: 'admin-token', })) }) } test('admin opens a user file and views a linked entity record', async ({ page }) => { let projectTitle = 'Website refresh' const projects: Record[] = [{ id: 42, title: 'Website refresh', owner: 7 }] const tasks: Record[] = [] const notes: Record[] = [] const milestones: Record[] = [] const projectResponse = () => ({ entity: { id: 3, name: 'Project', identifier: 'project', fields: [ { id: 11, name: 'Title', identifier: 'title', type: 'TEXT' }, { id: 12, name: 'Owner', identifier: 'owner', type: 'USER' }, { id: 13, name: 'Milestones', identifier: 'milestones', type: 'RELATIONSHIP', targetEntityId: 6, relationshipType: 'ONE_TO_MANY', }, { id: 14, name: 'Tasks', identifier: 'tasks', type: 'RELATIONSHIP', targetEntityId: 4, relationshipType: 'ONE_TO_MANY', }, ], }, values: { id: 42, title: projectTitle, owner: 7 }, children: [{ entity: { id: 4, name: 'Task', identifier: 'task', fields: [ { id: 20, name: 'Description', identifier: 'description', type: 'TEXT' }, { id: 22, name: 'Notes', identifier: 'notes', type: 'RELATIONSHIP', targetEntityId: 5, relationshipType: 'ONE_TO_MANY', }, ], }, relationshipField: { id: 14, name: 'Tasks', identifier: 'tasks', type: 'RELATIONSHIP', targetEntityId: 4, relationshipType: 'ONE_TO_MANY', }, records: tasks, }, { entity: { id: 6, name: 'Milestone', identifier: 'milestone', fields: [{ id: 40, name: 'Label', identifier: 'label', type: 'TEXT' }], }, relationshipField: { id: 13, name: 'Milestones', identifier: 'milestones', type: 'RELATIONSHIP', targetEntityId: 6, relationshipType: 'ONE_TO_MANY', }, records: milestones, }], }) await useAdminSession(page) await page.route('**/api/users', route => route.fulfill({ json: [{ id: 7, username: 'alex', role: 'user' }], })) await page.route('**/api/users/7/file', route => route.fulfill({ json: { user: { id: 7, username: 'alex', role: 'user' }, linkedEntities: [{ entity: { id: 3, name: 'Project', identifier: 'project', fields: [ { id: 11, name: 'Title', identifier: 'title', type: 'TEXT' }, { id: 12, name: 'Owner', identifier: 'owner', type: 'USER' }, ], }, relationshipField: { id: 12, name: 'Owner', identifier: 'owner', type: 'USER' }, records: projects, }], }, })) await page.route('**/api/users/7/children/Project/12', async route => { const values = new URLSearchParams(route.request().postData() ?? '') const created = { id: 43, title: values.get('title'), owner: 7 } projects.push(created) await route.fulfill({ status: 201, json: { entity: projectResponse().entity, values: created, children: [] }, }) }) await page.route('**/api/users/7/entities/Project/records/42', async route => { if (route.request().method() === 'PATCH') { const values = new URLSearchParams(route.request().postData() ?? '') projectTitle = values.get('title') ?? projectTitle } await route.fulfill({ json: projectResponse() }) }) await page.route('**/api/users/7/entities/Project/records/42/children/Task/14', async route => { const values = new URLSearchParams(route.request().postData() ?? '') const created = { id: 55, description: values.get('description'), notes: null } tasks.push(created) await route.fulfill({ status: 201, json: { entity: projectResponse().children.at(0)!.entity, values: created, children: [], }, }) }) await page.route('**/api/users/7/entities/Project/records/42/children/Milestone/13', async route => { const values = new URLSearchParams(route.request().postData() ?? '') const created = { id: 60, label: values.get('label') } milestones.push(created) await route.fulfill({ status: 201, json: { entity: projectResponse().children.at(1)!.entity, values: created, children: [] }, }) }) await page.route('**/api/users/7/entities/Task/records/55', route => route.fulfill({ json: { entity: projectResponse().children.at(0)!.entity, values: tasks.at(0), children: [{ entity: { id: 5, name: 'Note', identifier: 'note', fields: [ { id: 30, name: 'Contents', identifier: 'contents', type: 'TEXT' }, ], }, relationshipField: { id: 22, name: 'Notes', identifier: 'notes', type: 'RELATIONSHIP', targetEntityId: 5, relationshipType: 'ONE_TO_MANY', }, records: notes, }], }, })) await page.route('**/api/users/7/entities/Task/records/55/children/Note/22', async route => { const values = new URLSearchParams(route.request().postData() ?? '') const created = { id: 56, contents: values.get('contents') } notes.push(created) await route.fulfill({ status: 201, json: { entity: { id: 5, name: 'Note', fields: [] }, values: created, children: [] }, }) }) await page.goto('/users') await page.getByRole('link', { name: 'alex' }).click() await expect(page.getByRole('heading', { name: 'alex' })).toBeVisible() await expect(page.getByRole('heading', { name: 'Project' })).toBeVisible() await expect(page.getByRole('row').filter({ hasText: 'Website refresh' })).toContainText('7') await page.getByRole('button', { name: 'Add Project' }).click() const projectForm = page.getByRole('form', { name: 'Add Project' }) await projectForm.getByLabel('Title').fill('Mobile application') await projectForm.getByRole('button', { name: 'Add Project' }).click() await expect(page.getByRole('row').filter({ hasText: 'Mobile application' })).toContainText('7') await page.getByRole('link', { name: 'View Project record 42' }).click() await expect(page).toHaveURL('/users/7/entities/Project/records/42') await expect(page.getByRole('heading', { name: 'Project #42' })).toBeVisible() await expect(page.getByText('Website refresh')).toBeVisible() await expect(page.getByText('Owner')).toBeVisible() await page.getByRole('button', { name: 'Add Milestone' }).click() const milestoneForm = page.getByRole('form', { name: 'Add Milestone' }) await milestoneForm.getByLabel('Label').fill('Public beta') await milestoneForm.getByRole('button', { name: 'Add Milestone' }).click() await expect(page.getByRole('row').filter({ hasText: 'Public beta' })).toBeVisible() await page.getByRole('button', { name: 'Edit record' }).click() const editForm = page.getByRole('form', { name: 'Edit record' }) await editForm.getByLabel('Title').fill('Mobile application') await editForm.getByRole('button', { name: 'Save changes' }).click() await expect(page.getByText('Mobile application')).toBeVisible() await page.getByRole('button', { name: 'Add Task' }).click() const childForm = page.getByRole('form', { name: 'Add Task' }) await childForm.getByLabel('Description').fill('Prepare launch') await childForm.getByRole('button', { name: 'Add Task' }).click() await expect(page.getByRole('row').filter({ hasText: 'Prepare launch' })).toBeVisible() await page.getByRole('link', { name: 'View Task record 55' }).click() await expect(page.getByRole('heading', { name: 'Task #55' })).toBeVisible() await page.getByRole('button', { name: 'Add Note' }).click() const noteForm = page.getByRole('form', { name: 'Add Note' }) await noteForm.getByLabel('Contents').fill('Nested child') await noteForm.getByRole('button', { name: 'Add Note' }).click() await expect(page.getByRole('row').filter({ hasText: 'Nested child' })).toBeVisible() })