bilhej/frontend/e2e/admin-dashboard.spec.ts
Joakim Mörling 1c9269699e
Some checks failed
CI / Lint, type check, unit tests, coverage (pull_request) Failing after 1m50s
CI / E2E browser tests (pull_request) Failing after 1m38s
Add admin order fulfillment tracking.
Register PostNord shipments, admin notes, and guarded status transitions
with customer emails. Expandable admin UI, V11 migration, serial E2E suite,
and AGENTS.md Docker-only E2E guidance.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-27 12:21:17 +02:00

150 lines
5.3 KiB
TypeScript

import { test, expect } from '@playwright/test'
const SEEDED_ORDER_ID = 'c1eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'
const SEEDED_ORDER_SHORT_ID = SEEDED_ORDER_ID.slice(0, 8)
const PROCESSING_PLATE = 'JKL012'
function rowByPlate(page: import('@playwright/test').Page, plate: string) {
return page.locator('.admin__row').filter({
has: page.locator('.admin__plate', { hasText: plate }),
})
}
test.describe('Admin dashboard', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/logga-in')
await page.getByLabel('E-postadress').fill('admin@bilhalsning.se')
await page.getByLabel('Lösenord').fill('test1234')
await page.getByRole('button', { name: 'Logga in' }).click()
await page.waitForURL('/')
})
test('admin can navigate to admin page', async ({ page }) => {
await page.goto('/admin')
await expect(
page.getByRole('heading', { name: 'Administration' }),
).toBeVisible()
})
test('non-admin user is redirected away from admin', async ({ page }) => {
await page.evaluate(() => localStorage.clear())
await page.goto('/logga-in')
await page.getByLabel('E-postadress').fill('test@bilhej.se')
await page.getByLabel('Lösenord').fill('test1234')
await page.getByRole('button', { name: 'Logga in' }).click()
await page.waitForURL('/')
await page.goto('/admin')
await expect(page).toHaveURL('/')
})
test('shows orders table with columns', async ({ page }) => {
await page.goto('/admin')
await expect(page.getByRole('columnheader', { name: 'Datum' })).toBeVisible()
await expect(page.getByRole('columnheader', { name: 'ID' })).toBeVisible()
await expect(page.getByRole('columnheader', { name: 'E-post' })).toBeVisible()
await expect(page.getByRole('columnheader', { name: 'Regnr' })).toBeVisible()
await expect(page.getByRole('columnheader', { name: 'Status' })).toBeVisible()
})
test('shows seeded order data', async ({ page }) => {
await page.goto('/admin')
await expect(page.locator('.admin__plate').first()).toBeVisible()
await expect(page.getByText('DEF456').first()).toBeVisible()
await expect(page.getByText('GHI789').first()).toBeVisible()
})
test('show message button opens modal with full letter text', async ({
page,
}) => {
await page.goto('/admin')
await page.locator('#admin-order-search').fill(SEEDED_ORDER_SHORT_ID)
const row = page.locator('.admin__row', { hasText: SEEDED_ORDER_SHORT_ID })
await row.getByRole('button', { name: 'Visa meddelande' }).click()
const dialog = page.getByRole('dialog', { name: 'Brevtext' })
await expect(dialog).toBeVisible()
await expect(dialog).toContainText('fin bil')
await dialog.getByRole('button', { name: 'Stäng' }).click()
await expect(dialog).not.toBeVisible()
})
test('click row shows tracking section', async ({ page }) => {
await page.goto('/admin')
await expect(page.locator('.admin__loading')).toBeHidden({ timeout: 30_000 })
await rowByPlate(page, PROCESSING_PLATE).click()
await expect(page.getByText('Registrera utskick').first()).toBeVisible()
})
test('click row again collapses it', async ({ page }) => {
await page.goto('/admin')
await expect(page.locator('.admin__loading')).toBeHidden({ timeout: 30_000 })
const row = rowByPlate(page, PROCESSING_PLATE)
await row.click()
await expect(page.locator('.admin__tracking-input').first()).toBeVisible()
await row.click()
await expect(page.locator('.admin__tracking-input').first()).not.toBeVisible()
})
test('status dropdown changes update order status for sent orders', async ({
page,
}) => {
await page.goto('/admin')
await page.locator('#admin-order-search').fill(SEEDED_ORDER_SHORT_ID)
const row = page.locator('.admin__row', { hasText: SEEDED_ORDER_SHORT_ID })
const select = row.locator('.admin__status-select')
await select.selectOption('delivered')
await expect(select).toHaveValue('delivered')
})
test('admin cannot access admin page without auth', async ({ page }) => {
await page.evaluate(() => localStorage.clear())
await page.goto('/admin')
await expect(page).toHaveURL(/\/logga-in\?redirect=\/admin/)
})
test('expanded row shows tracking input and save button', async ({ page }) => {
await page.goto('/admin')
await expect(page.locator('.admin__loading')).toBeHidden({ timeout: 30_000 })
await rowByPlate(page, PROCESSING_PLATE).click()
await expect(page.getByText('Registrera utskick').first()).toBeVisible()
await expect(page.locator('.admin__tracking-input')).toBeVisible()
await expect(
page.getByRole('button', { name: 'Registrera utskick' }),
).toBeVisible()
})
test('shows PostNord link when trackingId exists', async ({ page }) => {
await page.goto('/admin')
await page.locator('.admin__row').last().click()
const trackingLink = page.locator('.admin__tracking-link')
await expect(trackingLink).toBeVisible()
await expect(trackingLink).toHaveAttribute('href', /postnord/)
})
test('hides PostNord link when trackingId is null', async ({ page }) => {
await page.goto('/admin')
const defRow = page.locator('.admin__row', { hasText: 'DEF456' }).first()
await defRow.click()
const trackingLink = page.locator('.admin__tracking-link')
await expect(trackingLink).not.toBeVisible()
})
})