import { http, HttpResponse } from 'msw' import { test, expect } from './msw-setup' 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, expired: false, } test.describe('US1: RSVP submission flow', () => { test('submits RSVP, updates attendee count, and persists in localStorage', async ({ page, network }) => { network.use( http.get('*/api/events/:token', () => { return HttpResponse.json(fullEvent) }), http.post('*/api/events/:token/rsvps', () => { return HttpResponse.json( { rsvpToken: 'd4e5f6a7-b8c9-0123-4567-890abcdef012', name: 'Max Mustermann' }, { status: 201 }, ) }), ) await page.goto(`/events/${fullEvent.eventToken}`) // CTA is visible const cta = page.getByRole('button', { name: "I'm attending" }) await expect(cta).toBeVisible() // Open bottom sheet await cta.click() const dialog = page.getByRole('dialog', { name: 'RSVP' }) await expect(dialog).toBeVisible() // Fill name and submit await dialog.getByLabel('Your name').fill('Max Mustermann') await dialog.getByRole('button', { name: 'Count me in' }).click() // Bottom sheet closes, status bar appears await expect(dialog).not.toBeVisible() await expect(page.getByText("You're attending!")).toBeVisible() await expect(cta).not.toBeVisible() // Attendee count incremented await expect(page.getByText('13')).toBeVisible() // Verify localStorage const stored = await page.evaluate(() => { const raw = localStorage.getItem('fete:events') return raw ? JSON.parse(raw) : null }) expect(stored).toEqual( expect.arrayContaining([ expect.objectContaining({ eventToken: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', rsvpToken: 'd4e5f6a7-b8c9-0123-4567-890abcdef012', rsvpName: 'Max Mustermann', }), ]), ) }) test('shows validation error when name is empty', async ({ page, network }) => { network.use( http.get('*/api/events/:token', () => { return HttpResponse.json(fullEvent) }), ) await page.goto(`/events/${fullEvent.eventToken}`) await page.getByRole('button', { name: "I'm attending" }).click() const dialog = page.getByRole('dialog', { name: 'RSVP' }) await dialog.getByRole('button', { name: 'Count me in' }).click() await expect(page.getByText('Please enter your name.')).toBeVisible() }) test('restores RSVP status from localStorage on page load', async ({ page, network }) => { network.use( http.get('*/api/events/:token', () => { return HttpResponse.json(fullEvent) }), ) // Pre-seed localStorage await page.goto('/') await page.evaluate(() => { localStorage.setItem( 'fete:events', JSON.stringify([ { eventToken: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', title: 'Summer BBQ', dateTime: '2026-03-15T20:00:00+01:00', expiryDate: '', rsvpToken: 'existing-rsvp-token', rsvpName: 'Anna', }, ]), ) }) await page.goto(`/events/${fullEvent.eventToken}`) // Status bar should show, not CTA await expect(page.getByText("You're attending!")).toBeVisible() await expect(page.getByRole('button', { name: "I'm attending" })).not.toBeVisible() }) test('shows error when server is unreachable during RSVP', async ({ page, network }) => { network.use( http.get('*/api/events/:token', () => { return HttpResponse.json(fullEvent) }), http.post('*/api/events/:token/rsvps', () => { return HttpResponse.json( { type: 'about:blank', title: 'Bad Request', status: 400 }, { status: 400, headers: { 'Content-Type': 'application/problem+json' } }, ) }), ) await page.goto(`/events/${fullEvent.eventToken}`) await page.getByRole('button', { name: "I'm attending" }).click() const dialog = page.getByRole('dialog', { name: 'RSVP' }) await dialog.getByLabel('Your name').fill('Max') await dialog.getByRole('button', { name: 'Count me in' }).click() await expect(page.getByText('Could not submit RSVP. Please try again.')).toBeVisible() }) test('does not show RSVP bar for organizer', async ({ page, network }) => { network.use( http.get('*/api/events/:token', () => { return HttpResponse.json(fullEvent) }), ) // Pre-seed localStorage with organizer token await page.goto('/') await page.evaluate(() => { localStorage.setItem( 'fete:events', JSON.stringify([ { eventToken: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', organizerToken: 'org-token-123', title: 'Summer BBQ', dateTime: '2026-03-15T20:00:00+01:00', expiryDate: '', }, ]), ) }) await page.goto(`/events/${fullEvent.eventToken}`) // Event content should load await expect(page.getByText('Summer BBQ')).toBeVisible() // But no RSVP bar await expect(page.getByRole('button', { name: "I'm attending" })).not.toBeVisible() await expect(page.getByText("You're attending!")).not.toBeVisible() }) test('does not show RSVP bar on expired event', async ({ page, network }) => { network.use( http.get('*/api/events/:token', () => { return HttpResponse.json({ ...fullEvent, expired: true }) }), ) await page.goto(`/events/${fullEvent.eventToken}`) await expect(page.getByText('This event has ended.')).toBeVisible() await expect(page.getByRole('button', { name: "I'm attending" })).not.toBeVisible() }) })