bilhej/frontend/e2e/deferred-payment-admin.spec.ts
Joakim Mörling 4d3beeffb4
Some checks failed
CI / Lint, type check, unit tests, coverage (pull_request) Successful in 2m22s
CI / E2E browser tests (pull_request) Failing after 1m6s
Stabilize deferred-payment admin E2E search assertions.
CI intermittently failed when searching admin orders by registration
number because the table was queried before data and filters settled.
Wait for the admin list to load, clear the search field between queries,
and use a longer timeout when expecting the matching row.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 13:16:11 +02:00

164 lines
5.9 KiB
TypeScript

import { test, expect } from '@playwright/test'
test.describe.configure({ mode: 'serial' })
function uniquePlate(prefix: string): string {
const digits = String((Date.now() % 90) + 10)
return `${prefix}${digits}E`
}
test.describe('Deferred payment and admin lookup', () => {
const plate = uniquePlate('LAT')
const letterText = 'E2E-test: betalar senare från orderhistoriken.'
let orderId = ''
let shortOrderId = ''
async function loginAsTestUser(page: import('@playwright/test').Page) {
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('/')
}
async function loginAsAdmin(page: import('@playwright/test').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('/')
}
async function completeSwishPayment(page: import('@playwright/test').Page) {
await page.getByRole('button', { name: 'Jag har betalat' }).click()
await page.getByRole('button', { name: 'Ja, jag har betalat' }).click()
}
async function openAdminTodoBoard(page: import('@playwright/test').Page) {
await page.goto('/admin')
await expect(page.locator('.admin__loading')).toBeHidden({ timeout: 30_000 })
await page.getByRole('button', { name: /Att göra/ }).click()
}
async function searchAdminOrders(
page: import('@playwright/test').Page,
query: string,
) {
const search = page.locator('#admin-order-search')
await search.clear()
await search.fill(query)
await expect(search).toHaveValue(query)
}
async function expectAdminOrderRow(
page: import('@playwright/test').Page,
options: { shortOrderId: string; plate: string; todo?: boolean },
) {
const row = page.locator('.admin__row', { hasText: options.shortOrderId })
await expect(row).toBeVisible({ timeout: 15_000 })
await expect(row.locator('.admin__plate')).toHaveText(options.plate)
if (options.todo) {
await expect(row).toHaveClass(/admin__row--todo/)
}
}
test('user creates order, leaves payment, and pays later from orders', async ({
page,
}) => {
await loginAsTestUser(page)
await page.goto(`/compose?plate=${plate}`)
await page.getByLabel('Ditt meddelande').fill(letterText)
await page.getByRole('button', { name: 'Fortsätt till betalning' }).click()
await page.waitForURL(/\/betalning\/[a-f0-9-]+/i)
const match = page.url().match(/\/betalning\/([a-f0-9-]+)/i)
expect(match).not.toBeNull()
orderId = match![1]
shortOrderId = orderId.slice(0, 8)
await expect(page.locator('.payment__order-id')).toHaveText(orderId)
await page.goto('/')
await page.getByRole('link', { name: 'Mina beställningar' }).click()
await expect(page).toHaveURL('/orders')
const orderCard = page.locator('.orders__card', { hasText: orderId })
await expect(orderCard.getByText(plate)).toBeVisible()
await expect(orderCard.locator('.badge')).toHaveText('Väntar på betalning')
await expect(orderCard.getByRole('link', { name: 'Betala 49 kr' })).toBeVisible()
await orderCard.getByRole('link', { name: 'Betala 49 kr' }).click()
await expect(page).toHaveURL(new RegExp(`/betalning/${orderId}`))
await completeSwishPayment(page)
await expect(page).toHaveURL('/orders')
await expect(orderCard.locator('.badge')).toHaveText('Hanteras')
await expect(orderCard.getByRole('link', { name: 'Betala 49 kr' })).not.toBeVisible()
})
test('admin finds paid order under Att göra when searching partial order id', async ({
page,
}) => {
await loginAsAdmin(page)
await openAdminTodoBoard(page)
await searchAdminOrders(page, shortOrderId)
await expectAdminOrderRow(page, {
shortOrderId,
plate,
todo: true,
})
const row = page.locator('.admin__row', { hasText: shortOrderId })
await expect(row.locator('.admin__order-id')).toHaveText(shortOrderId)
})
test('admin finds paid order when searching full order id', async ({ page }) => {
await loginAsAdmin(page)
await openAdminTodoBoard(page)
await searchAdminOrders(page, orderId)
await expectAdminOrderRow(page, { shortOrderId, plate })
const row = page.locator('.admin__row', { hasText: shortOrderId })
await expect(row.locator('.admin__order-id')).toHaveText(shortOrderId)
})
test('admin finds paid order when searching registration number', async ({
page,
}) => {
await loginAsAdmin(page)
await openAdminTodoBoard(page)
await searchAdminOrders(page, plate)
await expectAdminOrderRow(page, { shortOrderId, plate })
})
test('admin does not show unpaid order under Att göra before payment', async ({
page,
}) => {
await loginAsTestUser(page)
const unpaidPlate = uniquePlate('UNP')
await page.goto(`/compose?plate=${unpaidPlate}`)
await page.getByLabel('Ditt meddelande').fill('E2E-test: ska ligga under Väntar.')
await page.getByRole('button', { name: 'Fortsätt till betalning' }).click()
await page.waitForURL(/\/betalning\/([a-f0-9-]+)/i)
const unpaidMatch = page.url().match(/\/betalning\/([a-f0-9-]+)/i)
const unpaidOrderId = unpaidMatch![1]
const unpaidShortId = unpaidOrderId.slice(0, 8)
await page.goto('/orders')
await page.evaluate(() => localStorage.clear())
await loginAsAdmin(page)
await openAdminTodoBoard(page)
const unpaidRow = page.locator('.admin__row', { hasText: unpaidShortId })
await expect(unpaidRow).not.toBeVisible()
await page.getByRole('button', { name: /Väntar/ }).click()
await searchAdminOrders(page, unpaidPlate)
await expect(unpaidRow).toBeVisible()
await expect(unpaidRow.locator('.admin__plate')).toHaveText(unpaidPlate)
})
})