Rename /admin/series-management to /admin/series so it follows the /admin/<section> convention; the breadcrumb's auto-derived parent link is now a real route (was a dead /admin/series link). Add an /admin/tags page to review pending TagSuggestions — list, approve (creates the Tag), reject — backed by new admin endpoints and a tagSuggestionReviewSchema. Resolves the dead /admin/tags alert link.
65 lines
2.6 KiB
JavaScript
65 lines
2.6 KiB
JavaScript
import { test, expect } from './helpers/fixtures.js'
|
|
|
|
test.describe('Admin series management page', () => {
|
|
test('series list loads for admin', async ({ adminPage }) => {
|
|
await adminPage.goto('/admin/series')
|
|
await expect(adminPage.getByRole('heading', { name: 'Series', level: 1 })).toBeVisible({
|
|
timeout: 15000,
|
|
})
|
|
await expect(adminPage.getByRole('link', { name: 'Create Series' })).toBeVisible()
|
|
})
|
|
})
|
|
|
|
test.describe('Admin series access control', () => {
|
|
test('non-admin redirect', async ({ page }) => {
|
|
await page.goto('/admin/series')
|
|
await page.waitForURL((url) => !url.pathname.startsWith('/admin'))
|
|
expect(page.url()).not.toContain('/admin/series')
|
|
})
|
|
})
|
|
|
|
test.describe('Admin series CRUD', () => {
|
|
test('create and edit a series', async ({ adminPage }) => {
|
|
const suffix = Date.now().toString().slice(-6)
|
|
const title = `e2e-series-${suffix}`
|
|
const description = 'e2e test series description'
|
|
const editedDescription = 'e2e test series description edited'
|
|
|
|
// --- Create ---
|
|
await adminPage.goto('/admin/series/create')
|
|
await expect(adminPage.locator('h1')).toContainText('Create New Series')
|
|
|
|
await adminPage
|
|
.getByPlaceholder('e.g., Cooperative Game Development Fundamentals')
|
|
.fill(title)
|
|
|
|
await adminPage
|
|
.getByPlaceholder('Describe what the series covers and its goals')
|
|
.fill(description)
|
|
|
|
await adminPage.getByRole('button', { name: 'Create Series' }).click()
|
|
|
|
await adminPage.waitForURL('**/admin/series', { timeout: 15000 })
|
|
|
|
const card = adminPage.locator('.series-card', { hasText: title })
|
|
await expect(card).toBeVisible({ timeout: 10000 })
|
|
await expect(card).toContainText(description)
|
|
|
|
// --- Edit (in-page modal) ---
|
|
await card.getByRole('button', { name: 'Edit' }).click()
|
|
await expect(adminPage.getByRole('heading', { name: 'Edit Series' })).toBeVisible()
|
|
|
|
const descInput = adminPage.locator('textarea[placeholder="Brief description of this series"]')
|
|
await descInput.fill(editedDescription)
|
|
await adminPage.getByRole('button', { name: 'Save Changes' }).click()
|
|
|
|
const editedCard = adminPage.locator('.series-card', { hasText: title })
|
|
await expect(editedCard).toContainText(editedDescription, { timeout: 10000 })
|
|
})
|
|
|
|
// Delete is skipped: the series-management page's "Delete" button only
|
|
// unlinks events from the series via PUT /api/admin/events/:id; it does
|
|
// not call DELETE /api/admin/series/:id, so the series record remains.
|
|
// No UI affordance currently exists to remove an empty series.
|
|
test.skip('delete a series', async () => {})
|
|
})
|