import { http, HttpResponse } from 'msw' import { test, expect } from './msw-setup' import type { StoredEvent } from '../src/composables/useEventStorage' const STORAGE_KEY = 'fete:events' const fullEvent = { eventToken: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', title: 'Summer BBQ', description: 'Bring your own drinks!', dateTime: '2026-03-15T20:00:00+01:00', timezone: 'Europe/Berlin', location: 'Central Park, NYC', attendeeCount: 12, cancelled: false, cancellationReason: null, } const organizerToken = '550e8400-e29b-41d4-a716-446655440001' function seedEvents(events: StoredEvent[]): string { return `window.localStorage.setItem('${STORAGE_KEY}', ${JSON.stringify(JSON.stringify(events))})` } function organizerSeed(): StoredEvent { return { eventToken: fullEvent.eventToken, organizerToken, title: fullEvent.title, dateTime: fullEvent.dateTime, } } test.describe('US1: Organizer cancels event with reason', () => { test('organizer opens cancel bottom sheet, enters reason, confirms — event shows as cancelled on reload', async ({ page, network, }) => { let cancelled = false network.use( http.get('*/api/events/:token', () => { if (cancelled) { return HttpResponse.json({ ...fullEvent, cancelled: true, cancellationReason: 'Venue closed', }) } return HttpResponse.json(fullEvent) }), http.patch('*/api/events/:token', ({ request }) => { const url = new URL(request.url) const token = url.searchParams.get('organizerToken') if (token === organizerToken) { cancelled = true return new HttpResponse(null, { status: 204 }) } return HttpResponse.json( { type: 'urn:problem-type:invalid-organizer-token', title: 'Forbidden', status: 403 }, { status: 403 }, ) }), ) await page.addInitScript(seedEvents([organizerSeed()])) await page.goto(`/events/${fullEvent.eventToken}`) // Open kebab menu, then cancel event const kebabBtn = page.getByRole('button', { name: /Event actions/i }) await expect(kebabBtn).toBeVisible() await kebabBtn.click() const cancelItem = page.getByRole('menuitem', { name: /Cancel event/i }) await expect(cancelItem).toBeVisible() await cancelItem.click() // Fill in reason const reasonField = page.getByLabel(/reason/i) await expect(reasonField).toBeVisible() await reasonField.fill('Venue closed') // Confirm cancellation await page.getByRole('button', { name: /Confirm cancellation/i }).click() // Event should show as cancelled await expect(page.getByText(/This event has been cancelled/i)).toBeVisible() await expect(page.getByText('Venue closed')).toBeVisible() // Kebab menu should be gone (event is cancelled) await expect(kebabBtn).not.toBeVisible() }) }) test.describe('US1: Organizer cancels event without reason', () => { test('organizer cancels without reason — event shows as cancelled', async ({ page, network, }) => { let cancelled = false network.use( http.get('*/api/events/:token', () => { if (cancelled) { return HttpResponse.json({ ...fullEvent, cancelled: true, cancellationReason: null, }) } return HttpResponse.json(fullEvent) }), http.patch('*/api/events/:token', ({ request }) => { const url = new URL(request.url) const token = url.searchParams.get('organizerToken') if (token === organizerToken) { cancelled = true return new HttpResponse(null, { status: 204 }) } return HttpResponse.json({}, { status: 403 }) }), ) await page.addInitScript(seedEvents([organizerSeed()])) await page.goto(`/events/${fullEvent.eventToken}`) await page.getByRole('button', { name: /Event actions/i }).click() await page.getByRole('menuitem', { name: /Cancel event/i }).click() // Don't fill in reason, just confirm await page.getByRole('button', { name: /Confirm cancellation/i }).click() // Event should show as cancelled without reason text await expect(page.getByText(/This event has been cancelled/i)).toBeVisible() }) }) test.describe('US1: Cancel API failure', () => { test('cancel API fails — error displayed in bottom sheet, button re-enabled for retry', async ({ page, network, }) => { network.use( http.get('*/api/events/:token', () => HttpResponse.json(fullEvent)), http.patch('*/api/events/:token', () => { return HttpResponse.json( { type: 'about:blank', title: 'Internal Server Error', status: 500, detail: 'Something went wrong', }, { status: 500, headers: { 'Content-Type': 'application/problem+json' } }, ) }), ) await page.addInitScript(seedEvents([organizerSeed()])) await page.goto(`/events/${fullEvent.eventToken}`) await page.getByRole('button', { name: /Event actions/i }).click() await page.getByRole('menuitem', { name: /Cancel event/i }).click() await page.getByRole('button', { name: /Confirm cancellation/i }).click() // Error message in bottom sheet await expect(page.getByText(/Could not cancel event/i)).toBeVisible() // Confirm button should be re-enabled await expect(page.getByRole('button', { name: /Confirm cancellation/i })).toBeEnabled() }) })