Fix test failures and workload/websocket behavior

This commit is contained in:
beabigegg
2026-01-11 08:37:21 +08:00
parent 3bdc6ff1c9
commit f5f870da56
49 changed files with 3006 additions and 1132 deletions

View File

@@ -0,0 +1,252 @@
import path from 'path'
import { fileURLToPath } from 'url'
import { expect, test, Page } from 'playwright/test'
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const runId = new Date().toISOString().replace(/[-:.TZ]/g, '')
const spaceName = `E2E Space ${runId}`
const projectName = `E2E Project ${runId}`
const taskOneTitle = `E2E Task One ${runId}`
const taskTwoTitle = `E2E Task Two ${runId}`
const subtaskTitle = `E2E Subtask ${runId}`
const commentText = `E2E Comment ${runId}`
const customNumberField = `sp_${runId}`
const customFormulaField = `double_sp_${runId}`
const attachmentPath = path.join(__dirname, 'fixtures', 'attachment.txt')
const formatDateInput = (date: Date) => {
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
}
const setEnglishLocale = async (page: Page) => {
await page.addInitScript(() => {
localStorage.setItem('i18nextLng', 'en')
})
}
const openProjectFromSpaces = async (page: Page) => {
await page.goto('/spaces')
await expect(page.getByRole('heading', { name: 'Spaces' })).toBeVisible()
await page.getByRole('button', { name: `Spaces: ${spaceName}` }).click()
await expect(page.getByRole('heading', { name: 'Projects' })).toBeVisible()
await page.getByRole('button', { name: `Projects: ${projectName}` }).click()
await expect(page.getByRole('heading', { name: 'Tasks' })).toBeVisible()
}
test.describe.serial('admin e2e flow', () => {
test.beforeEach(async ({ page }) => {
await setEnglishLocale(page)
})
test('login and dashboard', async ({ page }) => {
await page.goto('/')
await expect(page.getByRole('heading', { name: /Welcome back/i })).toBeVisible()
await expect(page.getByRole('heading', { name: 'Quick Actions' })).toBeVisible()
})
test('create space and project', async ({ page }) => {
await page.goto('/spaces')
await expect(page.getByRole('heading', { name: 'Spaces' })).toBeVisible()
await page.getByRole('button', { name: /Create Space/i }).click()
const spaceModal = page.getByRole('dialog', { name: 'Create Space' })
await spaceModal.getByLabel('Name').fill(spaceName)
await spaceModal.getByLabel('Description').fill('E2E space description')
await spaceModal.getByRole('button', { name: 'Create' }).click()
await expect(page.getByRole('button', { name: `Spaces: ${spaceName}` })).toBeVisible()
await page.getByRole('button', { name: `Spaces: ${spaceName}` }).click()
await expect(page.getByRole('heading', { name: 'Projects' })).toBeVisible()
await page.getByRole('button', { name: /New Project/i }).click()
const projectModal = page.getByRole('dialog', { name: 'Create Project' })
await projectModal.getByText('Blank Project', { exact: true }).click()
await projectModal.locator('#project-title').fill(projectName)
await projectModal.locator('#project-description').fill('E2E project description')
await projectModal.getByRole('button', { name: 'Create' }).click()
await expect(page.getByRole('button', { name: `Projects: ${projectName}` })).toBeVisible()
await page.getByRole('button', { name: `Projects: ${projectName}` }).click()
await expect(page.getByRole('heading', { name: 'Tasks' })).toBeVisible()
})
test('project settings: members and custom fields', async ({ page }) => {
await openProjectFromSpaces(page)
await page.getByRole('button', { name: 'Settings' }).click()
await expect(page.getByRole('heading', { name: 'Project Settings' })).toBeVisible()
await page.getByRole('button', { name: 'Members' }).click()
await expect(page.getByText('Member Management')).toBeVisible()
await expect(page.getByText('User')).toBeVisible()
await page.getByRole('button', { name: 'Custom Fields' }).click()
await expect(page.getByRole('button', { name: /Add Field/i })).toBeVisible()
await page.getByRole('button', { name: /Add Field/i }).click()
const customModal = page.getByRole('dialog', { name: 'Create Field' })
await customModal.getByPlaceholder('e.g., Story Points, Sprint Number').fill(customNumberField)
await customModal.getByText('Number', { exact: true }).click()
await customModal.getByRole('button', { name: 'Create Field' }).click()
await expect(page.getByText(customNumberField)).toBeVisible()
await page.getByRole('button', { name: /Add Field/i }).click()
const formulaModal = page.getByRole('dialog', { name: 'Create Field' })
await formulaModal.getByPlaceholder('e.g., Story Points, Sprint Number').fill(customFormulaField)
await formulaModal.getByText('Formula', { exact: true }).click()
await formulaModal.getByPlaceholder('e.g., {time_spent} / {original_estimate} * 100')
.fill(`{${customNumberField}} * 2`)
await formulaModal.getByRole('button', { name: 'Create Field' }).click()
await expect(page.getByText(customFormulaField)).toBeVisible()
})
test('tasks flow: create, views, detail, attachments, comments, subtasks, dependencies', async ({ page }) => {
await openProjectFromSpaces(page)
const today = new Date()
const startDate = formatDateInput(today)
const dueDate = formatDateInput(new Date(today.getTime() + 3 * 24 * 60 * 60 * 1000))
await page.getByRole('button', { name: /Create Task/i }).click()
const createModal = page.getByRole('dialog', { name: 'Create Task' })
await createModal.locator('#task-title').fill(taskOneTitle)
await createModal.locator('#task-description').fill('E2E task description')
await createModal.locator('select').first().selectOption('low')
const dateInputs = createModal.locator('input[type="date"]')
await dateInputs.nth(0).fill(startDate)
await dateInputs.nth(1).fill(dueDate)
const customFieldContainer = createModal.locator('label', { hasText: customNumberField }).locator('..')
await customFieldContainer.locator('input[type="number"]').fill('5')
await createModal.getByRole('button', { name: 'Create' }).click()
await expect(page.getByText(taskOneTitle)).toBeVisible()
await page.getByRole('button', { name: /Create Task/i }).click()
const createModalTwo = page.getByRole('dialog', { name: 'Create Task' })
await createModalTwo.locator('#task-title').fill(taskTwoTitle)
await createModalTwo.locator('#task-description').fill('E2E task description 2')
const dateInputsTwo = createModalTwo.locator('input[type="date"]')
await dateInputsTwo.nth(0).fill(startDate)
await dateInputsTwo.nth(1).fill(dueDate)
await createModalTwo.getByRole('button', { name: 'Create' }).click()
await expect(page.getByText(taskTwoTitle)).toBeVisible()
await expect(page.getByText(`${customNumberField}: 5`, { exact: true })).toBeVisible()
await page.getByRole('button', { name: 'Kanban' }).click()
await expect(page.getByText(taskOneTitle)).toBeVisible()
await page.getByRole('button', { name: 'Calendar' }).click()
await expect(page.getByText(new RegExp(taskOneTitle))).toBeVisible()
await page.getByRole('button', { name: 'Gantt' }).click()
await expect(page.getByText('Task Dependencies')).toBeVisible()
await page.getByRole('button', { name: 'Manage Dependencies' }).first().click()
const depsHeading = page.getByRole('heading', {
name: /Manage Dependencies for/i,
})
await expect(depsHeading).toBeVisible()
const depsDialog = depsHeading.locator('..')
const dependencySelect = depsDialog.locator('select').first()
await dependencySelect.selectOption({ index: 1 })
await depsDialog.getByRole('button', { name: 'Add Dependency' }).click()
await expect(page.locator('text=Depends on:').first()).toBeVisible()
await page.getByRole('button', { name: 'List' }).click()
await page.getByText(taskOneTitle).first().click()
const taskModal = page.getByRole('dialog', { name: taskOneTitle })
await expect(taskModal.getByRole('heading', { name: taskOneTitle })).toBeVisible()
await page.getByRole('button', { name: 'Edit' }).click()
const descriptionField = page.locator('label', { hasText: 'Description' }).locator('..').locator('textarea')
await descriptionField.fill('Updated task description')
await page.getByRole('button', { name: 'Save' }).click()
await expect(page.getByText('Updated task description')).toBeVisible()
await page.getByPlaceholder('Add a comment... Use @name to mention someone').fill(commentText)
await page.getByRole('button', { name: 'Post Comment' }).click()
await expect(page.getByText(commentText)).toBeVisible()
await page.locator('input[type="file"]').setInputFiles(attachmentPath)
await expect(page.getByText('attachment.txt')).toBeVisible()
await page.getByRole('button', { name: /Add Subtask/i }).click()
await page.locator('#new-subtask-title').fill(subtaskTitle)
await page.getByRole('button', { name: 'Add' }).click()
await expect(page.getByText(subtaskTitle)).toBeVisible()
await page.getByLabel('Close').click()
})
test('notifications and my settings', async ({ page }) => {
await page.goto('/')
await page.getByRole('button', { name: 'Notifications' }).click()
await expect(page.getByRole('heading', { name: 'Notifications' })).toBeVisible()
await page.goto('/my-settings')
await expect(page.getByRole('heading', { name: 'My Settings' })).toBeVisible()
const capacityInput = page.locator('input[type="number"]').first()
const currentCapacity = await capacityInput.inputValue()
const nextCapacity = String((Number(currentCapacity) || 40) + 1)
await capacityInput.fill(nextCapacity)
await page.getByRole('button', { name: 'Save' }).click()
await capacityInput.fill(currentCapacity || '40')
await page.getByRole('button', { name: 'Save' }).click()
const weeklyCard = page.getByRole('heading', { name: 'Weekly Report' }).locator('..')
const subscriptionToggle = weeklyCard.locator('input[type="checkbox"]')
await expect(subscriptionToggle).toBeEnabled()
const isChecked = await subscriptionToggle.isChecked()
await subscriptionToggle.click()
if (isChecked) {
await expect(subscriptionToggle).not.toBeChecked()
} else {
await expect(subscriptionToggle).toBeChecked()
}
await subscriptionToggle.click()
})
test('workload, project health, audit pages', async ({ page }) => {
await page.goto('/workload')
await expect(page.getByRole('heading', { name: 'Workload' })).toBeVisible()
await page.getByRole('button', { name: 'Next week' }).click()
await page.goto('/project-health')
await expect(page.getByRole('heading', { name: 'Project Health Dashboard' })).toBeVisible()
await page.getByLabel('Sort by:').selectOption('name')
await page.goto('/audit')
await expect(page.getByRole('heading', { name: 'Audit Log' })).toBeVisible()
})
test('cleanup: delete project and space', async ({ page }) => {
await page.goto('/spaces')
await expect(page.getByRole('heading', { name: 'Spaces' })).toBeVisible()
await page.getByRole('button', { name: `Spaces: ${spaceName}` }).click()
await expect(page.getByRole('heading', { name: 'Projects' })).toBeVisible()
const projectCard = page.getByRole('button', { name: `Projects: ${projectName}` })
await projectCard.getByRole('button', { name: 'Delete Project' }).click()
const deleteProjectModal = page.getByRole('dialog', { name: 'Delete Project' })
await deleteProjectModal.getByRole('button', { name: 'Delete' }).click()
await expect(page.getByRole('button', { name: `Projects: ${projectName}` })).toHaveCount(0)
await page.goto('/spaces')
await expect(page.getByRole('heading', { name: 'Spaces' })).toBeVisible()
const spaceCard = page.getByRole('button', { name: `Spaces: ${spaceName}` })
await spaceCard.getByRole('button', { name: 'Delete Space' }).click()
const deleteSpaceModal = page.getByRole('dialog', { name: 'Delete Space' })
await deleteSpaceModal.getByRole('button', { name: 'Delete' }).click()
await expect(page.getByRole('button', { name: `Spaces: ${spaceName}` })).toHaveCount(0)
})
})