trips) add dashboard overview (#54)
All checks were successful
Build and Push Image / docker-build-and-push (push) Successful in 2m14s

Reviewed-on: #54
Co-authored-by: AI Agent <ai-agent@campbellwireless.net>
Co-committed-by: AI Agent <ai-agent@campbellwireless.net>
This commit was merged in pull request #54.
This commit is contained in:
2026-02-24 21:23:54 +00:00
committed by shaun
parent 4aabf47108
commit ebc8f80bb5
4 changed files with 721 additions and 2 deletions

75
e2e/dashboard.test.ts Normal file
View File

@@ -0,0 +1,75 @@
import { test, expect, type Page } from '@playwright/test';
import { TEST_USERS } from './setup/test-users.js';
import { loginAsLocalUser } from './helpers/auth.js';
import { 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: Page, cityQuery: string, arrivalDate?: string): Promise<void> {
await openAddToTripMenuItem(page, 'Destinations');
const dialog = page.getByRole('dialog', { name: 'Add destination' });
await expect(dialog).toBeVisible();
await dialog.getByLabel(/City/).fill(cityQuery);
const cityOption = dialog.locator('ul button').filter({ hasText: cityQuery }).first();
await expect(cityOption).toBeVisible();
await cityOption.click();
if (arrivalDate) {
await dialog.getByLabel('Arrival').fill(arrivalDate);
}
await dialog.getByRole('button', { name: 'Add to trip' }).click();
await expect(dialog).toBeHidden();
}
test.beforeEach(async ({ context }) => {
await context.clearCookies();
});
test('dashboard surfaces map stops, stats, and trip status', async ({ page }) => {
const suffix = uniqueSuffix();
const pastStart = formatDate(-18);
const pastEnd = formatDate(-15);
const currentStart = formatDate(-2);
const currentEnd = formatDate(4);
const futureStart = formatDate(28);
const futureEnd = formatDate(34);
const pastTripName = `E2E Past Trip ${suffix}`;
const currentTripName = `E2E Current Trip ${suffix}`;
const futureTripName = `E2E Future Trip ${suffix}`;
await loginAsLocalUser(page, TEST_USERS.regular.username, TEST_USERS.regular.password);
await createTrip(page, { name: pastTripName, startDate: pastStart, endDate: pastEnd });
await addDestination(page, 'London', pastStart);
await createTrip(page, { name: currentTripName, startDate: currentStart, endDate: currentEnd });
await addDestination(page, 'New York', currentStart);
await createTrip(page, { name: futureTripName, startDate: futureStart, endDate: futureEnd });
await addDestination(page, 'Tokyo', futureStart);
await page.goto('/trips/dashboard');
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
const map = page.getByTestId('trip-map');
await expect(map).toBeVisible();
await expect(map.locator('[data-testid="map-stop"][data-status="past"]')).toHaveCount(1);
await expect(map.locator('[data-testid="map-stop"][data-status="current"]')).toHaveCount(1);
await expect(map.locator('[data-testid="map-stop"][data-status="future"]')).toHaveCount(1);
await expect(page.getByRole('heading', { name: 'Trips in progress' })).toBeVisible();
await expect(page.getByText(currentTripName)).toBeVisible();
await expect(page.getByRole('heading', { name: 'Trips being planned' })).toBeVisible();
await expect(page.getByText(futureTripName)).toBeVisible();
await expect(page.getByTestId('stat-past-trips')).toHaveText('1');
await expect(page.getByTestId('stat-countries')).toHaveText('1');
});