import { test, expect } from '@playwright/test'; import { TEST_USERS } from './setup/test-users.js'; import { loginAsLocalUser, ensureSelfProfile } from './helpers/auth.js'; import { addPackingList, createTrip, openAddToTripMenuItem, uniqueSuffix } from './helpers/trip.js'; function formatDate(offsetDays: number): string { const date = new Date(); date.setDate(date.getDate() + offsetDays); return date.toISOString().slice(0, 10); } async function addDestination( page: import('@playwright/test').Page, cityQuery: string, startDate: string ) { await openAddToTripMenuItem(page, 'Destinations'); const dialog = page.getByRole('dialog', { name: 'Add destination' }); await expect(dialog).toBeVisible(); await dialog.getByLabel('City', { exact: false }).fill(cityQuery); const cityOption = dialog.locator('ul button').filter({ hasText: cityQuery }).first(); await expect(cityOption).toBeVisible(); await cityOption.click(); await dialog.getByLabel('Arrival').fill(startDate); await dialog.getByRole('button', { name: 'Add to trip' }).click(); await expect(dialog).toBeHidden(); } async function addActivity( page: import('@playwright/test').Page, values: { name: string; startDate: string; startTime: string } ) { await openAddToTripMenuItem(page, 'Attractions & Activities'); const dialog = page .locator('[role="dialog"]') .filter({ has: page.getByRole('heading', { name: /Attraction & activity/i }) }) .first(); await expect(dialog).toBeVisible(); await dialog.getByLabel('Name', { exact: false }).fill(values.name); await dialog.getByLabel('Start date').fill(values.startDate); await dialog.getByLabel('Start time', { exact: true }).fill(values.startTime); await dialog.getByRole('button', { name: 'Add' }).click(); await expect(dialog).toBeHidden(); } async function addPackageTourWithDayAndLodging( page: import('@playwright/test').Page, values: { operatorName: string; tourName: string; startDate: string; dayTitle: string } ) { await openAddToTripMenuItem(page, 'Package Tours'); const dialog = page.getByRole('dialog', { name: 'Add package tour' }); await expect(dialog).toBeVisible(); await dialog.getByLabel('Tour operator', { exact: false }).fill(values.operatorName); await dialog.getByLabel('Tour name', { exact: false }).fill(values.tourName); await dialog.locator('input[name="start_date"]').fill(values.startDate); await dialog.getByRole('button', { name: 'Add tour' }).click(); await expect(dialog).toBeHidden(); await expect(page.getByText(values.operatorName)).toBeVisible(); await page.getByRole('button', { name: 'Add day' }).click(); const addDayForm = page.locator('form[action="?/addTourDay"]'); await expect(addDayForm).toBeVisible(); await addDayForm.getByPlaceholder(/Day title/i).fill(values.dayTitle); await addDayForm.getByRole('button', { name: 'Add day' }).click(); const dayRow = page .locator('div.mb-2.overflow-hidden.rounded-lg.border.border-gray-100') .filter({ hasText: `Day 1` }) .filter({ hasText: values.dayTitle }) .first(); await expect(dayRow).toBeVisible(); } test.beforeEach(async ({ context }) => { await context.clearCookies(); }); test('timeline view shows scheduled and unscheduled plans with tour days', async ({ page }) => { const suffix = uniqueSuffix(); const startDate = formatDate(10); const activityDate = formatDate(11); const destinationDate = formatDate(12); const tourStartDate = formatDate(13); const tripName = `E2E Timeline Trip ${suffix}`; const activityName = `Waterfall hike ${suffix}`; const destinationName = 'Tokyo'; const packingListName = `Timeline essentials ${suffix}`; const tourOperator = `Trailblazer ${suffix}`; const tourName = `Jungle Trek ${suffix}`; const tourDayTitle = `Rainforest ${suffix}`; await loginAsLocalUser(page, TEST_USERS.regular.username, TEST_USERS.regular.password); await ensureSelfProfile(page); await createTrip(page, { name: tripName, startDate, description: 'Timeline view coverage' }); await addDestination(page, destinationName, destinationDate); await addActivity(page, { name: activityName, startDate: activityDate, startTime: '09:00' }); await addPackingList(page, { name: packingListName, items: ['Passport', 'Sunscreen'] }); await addPackageTourWithDayAndLodging(page, { operatorName: tourOperator, tourName, startDate: tourStartDate, dayTitle: tourDayTitle }); await page.getByRole('button', { name: 'Timeline' }).click(); await expect(page.getByRole('button', { name: 'Timeline' })).toHaveAttribute( 'aria-pressed', 'true' ); await expect(page.getByText(activityName)).toBeVisible(); await expect(page.getByText(destinationName, { exact: false })).toBeVisible(); await expect(page.getByText('09:00').first()).toBeVisible(); await expect(page.getByText(`Day 1 — ${tourDayTitle}`)).toBeVisible(); await expect(page.getByText('Unscheduled')).toBeVisible(); await expect(page.getByText(packingListName)).toBeVisible(); });