mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-11 17:51:39 -05:00
418 lines
14 KiB
TypeScript
418 lines
14 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
import { TestHelpers } from './fixtures/test-helpers';
|
|
|
|
test.describe('Trips', () => {
|
|
let helpers: TestHelpers;
|
|
|
|
test.beforeEach(async ({ page }) => {
|
|
helpers = new TestHelpers(page);
|
|
await helpers.loginAsDemo();
|
|
});
|
|
|
|
test.describe('Trips List', () => {
|
|
test('should display trips page correctly', async ({ page }) => {
|
|
await helpers.navigateTo('Trips');
|
|
|
|
// Check page title and elements
|
|
await expect(page).toHaveTitle(/Trips.*Dawarich/);
|
|
await expect(page.getByRole('heading', { name: 'Trips' })).toBeVisible();
|
|
|
|
// Should show "New trip" button
|
|
await expect(page.getByRole('link', { name: 'New trip' })).toBeVisible();
|
|
});
|
|
|
|
test('should show trips list or empty state', async ({ page }) => {
|
|
await helpers.navigateTo('Trips');
|
|
|
|
// Check for either trips grid or empty state
|
|
const tripsGrid = page.locator('.grid');
|
|
const emptyState = page.getByText('Hello there!');
|
|
|
|
if (await tripsGrid.isVisible()) {
|
|
await expect(tripsGrid).toBeVisible();
|
|
} else {
|
|
// Should show empty state with create link
|
|
await expect(emptyState).toBeVisible();
|
|
await expect(page.getByRole('link', { name: 'create one' })).toBeVisible();
|
|
}
|
|
});
|
|
|
|
test('should display trip statistics if trips exist', async ({ page }) => {
|
|
await helpers.navigateTo('Trips');
|
|
|
|
// Look for trip cards
|
|
const tripCards = page.locator('.card[data-trip-id]');
|
|
const cardCount = await tripCards.count();
|
|
|
|
if (cardCount > 0) {
|
|
// Should show distance info in first trip card
|
|
const firstCard = tripCards.first();
|
|
await expect(firstCard.getByText(/\d+\s*(km|miles)/)).toBeVisible();
|
|
}
|
|
});
|
|
|
|
test('should navigate to new trip page', async ({ page }) => {
|
|
await helpers.navigateTo('Trips');
|
|
|
|
// Click "New trip" button
|
|
await page.getByRole('link', { name: 'New trip' }).click();
|
|
|
|
// Should navigate to new trip page
|
|
await expect(page).toHaveURL(/\/trips\/new/);
|
|
await expect(page.getByRole('heading', { name: 'New trip' })).toBeVisible();
|
|
});
|
|
});
|
|
|
|
test.describe('Trip Creation', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await helpers.navigateTo('Trips');
|
|
await page.getByRole('link', { name: 'New trip' }).click();
|
|
});
|
|
|
|
test('should show trip creation form', async ({ page }) => {
|
|
// Should have form fields
|
|
await expect(page.getByLabel('Name')).toBeVisible();
|
|
await expect(page.getByLabel('Started at')).toBeVisible();
|
|
await expect(page.getByLabel('Ended at')).toBeVisible();
|
|
|
|
// Should have submit button
|
|
await expect(page.getByRole('button', { name: 'Create trip' })).toBeVisible();
|
|
|
|
// Should have map container
|
|
await expect(page.locator('#map')).toBeVisible();
|
|
});
|
|
|
|
test('should create trip with valid data', async ({ page }) => {
|
|
// Fill form fields
|
|
await page.getByLabel('Name').fill('Test Trip');
|
|
await page.getByLabel('Started at').fill('2024-01-01T10:00');
|
|
await page.getByLabel('Ended at').fill('2024-01-01T18:00');
|
|
|
|
// Submit form
|
|
await page.getByRole('button', { name: 'Create trip' }).click();
|
|
|
|
// Should redirect to trip show page
|
|
await page.waitForLoadState('networkidle');
|
|
await expect(page).toHaveURL(/\/trips\/\d+/);
|
|
});
|
|
|
|
test('should validate required fields', async ({ page }) => {
|
|
// Try to submit empty form
|
|
await page.getByRole('button', { name: 'Create trip' }).click();
|
|
|
|
// Should show validation errors
|
|
await expect(page.getByText(/can't be blank|is required/i)).toBeVisible();
|
|
});
|
|
|
|
test('should validate date range', async ({ page }) => {
|
|
// Fill with invalid date range (end before start)
|
|
await page.getByLabel('Name').fill('Invalid Trip');
|
|
await page.getByLabel('Started at').fill('2024-01-02T10:00');
|
|
await page.getByLabel('Ended at').fill('2024-01-01T18:00');
|
|
|
|
// Submit form
|
|
await page.getByRole('button', { name: 'Create trip' }).click();
|
|
|
|
// Should show validation error (if backend validates this)
|
|
await page.waitForLoadState('networkidle');
|
|
// Note: This test assumes backend validation exists
|
|
});
|
|
});
|
|
|
|
test.describe('Trip Details', () => {
|
|
test('should display trip details when clicked', async ({ page }) => {
|
|
await helpers.navigateTo('Trips');
|
|
|
|
// Look for trip cards
|
|
const tripCards = page.locator('.card[data-trip-id]');
|
|
const cardCount = await tripCards.count();
|
|
|
|
if (cardCount > 0) {
|
|
// Click on first trip card
|
|
await tripCards.first().click();
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
// Should show trip name as heading
|
|
await expect(page.locator('h1, h2, h3').first()).toBeVisible();
|
|
|
|
// Should show distance info
|
|
const distanceText = page.getByText(/\d+\s*(km|miles)/);
|
|
if (await distanceText.count() > 0) {
|
|
await expect(distanceText.first()).toBeVisible();
|
|
}
|
|
}
|
|
});
|
|
|
|
test('should show trip map', async ({ page }) => {
|
|
await helpers.navigateTo('Trips');
|
|
|
|
const tripCards = page.locator('.card[data-trip-id]');
|
|
const cardCount = await tripCards.count();
|
|
|
|
if (cardCount > 0) {
|
|
await tripCards.first().click();
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
// Should show map container
|
|
const mapContainer = page.locator('#map');
|
|
if (await mapContainer.isVisible()) {
|
|
await expect(mapContainer).toBeVisible();
|
|
await helpers.waitForMap();
|
|
}
|
|
}
|
|
});
|
|
|
|
test('should show trip timeline info', async ({ page }) => {
|
|
await helpers.navigateTo('Trips');
|
|
|
|
const tripCards = page.locator('.card[data-trip-id]');
|
|
const cardCount = await tripCards.count();
|
|
|
|
if (cardCount > 0) {
|
|
await tripCards.first().click();
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
// Should show date/time information
|
|
const dateInfo = page.getByText(/\d{1,2}\s+(January|February|March|April|May|June|July|August|September|October|November|December)/);
|
|
if (await dateInfo.count() > 0) {
|
|
await expect(dateInfo.first()).toBeVisible();
|
|
}
|
|
}
|
|
});
|
|
|
|
test('should allow trip editing', async ({ page }) => {
|
|
await helpers.navigateTo('Trips');
|
|
|
|
const tripCards = page.locator('.card[data-trip-id]');
|
|
const cardCount = await tripCards.count();
|
|
|
|
if (cardCount > 0) {
|
|
await tripCards.first().click();
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
// Look for edit link/button
|
|
const editLink = page.getByRole('link', { name: /edit/i });
|
|
if (await editLink.isVisible()) {
|
|
await editLink.click();
|
|
|
|
// Should show edit form
|
|
await expect(page.getByLabel('Name')).toBeVisible();
|
|
await expect(page.getByLabel('Started at')).toBeVisible();
|
|
await expect(page.getByLabel('Ended at')).toBeVisible();
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
test.describe('Trip Visualization', () => {
|
|
test('should show trip on map', async ({ page }) => {
|
|
await helpers.navigateTo('Trips');
|
|
|
|
const tripCards = page.locator('.card[data-trip-id]');
|
|
const cardCount = await tripCards.count();
|
|
|
|
if (cardCount > 0) {
|
|
await tripCards.first().click();
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
// Check if map is present
|
|
const mapContainer = page.locator('#map');
|
|
if (await mapContainer.isVisible()) {
|
|
await helpers.waitForMap();
|
|
|
|
// Should have map controls
|
|
await expect(page.getByRole('button', { name: 'Zoom in' })).toBeVisible();
|
|
await expect(page.getByRole('button', { name: 'Zoom out' })).toBeVisible();
|
|
}
|
|
}
|
|
});
|
|
|
|
test('should display trip route', async ({ page }) => {
|
|
await helpers.navigateTo('Trips');
|
|
|
|
const tripCards = page.locator('.card[data-trip-id]');
|
|
const cardCount = await tripCards.count();
|
|
|
|
if (cardCount > 0) {
|
|
await tripCards.first().click();
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
const mapContainer = page.locator('#map');
|
|
if (await mapContainer.isVisible()) {
|
|
await helpers.waitForMap();
|
|
|
|
// Look for route polylines
|
|
const routeElements = page.locator('.leaflet-interactive[stroke]');
|
|
if (await routeElements.count() > 0) {
|
|
await expect(routeElements.first()).toBeVisible();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
test('should show trip points', async ({ page }) => {
|
|
await helpers.navigateTo('Trips');
|
|
|
|
const tripCards = page.locator('.card[data-trip-id]');
|
|
const cardCount = await tripCards.count();
|
|
|
|
if (cardCount > 0) {
|
|
await tripCards.first().click();
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
const mapContainer = page.locator('#map');
|
|
if (await mapContainer.isVisible()) {
|
|
await helpers.waitForMap();
|
|
|
|
// Look for point markers
|
|
const pointMarkers = page.locator('.leaflet-marker-icon');
|
|
if (await pointMarkers.count() > 0) {
|
|
await expect(pointMarkers.first()).toBeVisible();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
test('should allow map interaction', async ({ page }) => {
|
|
await helpers.navigateTo('Trips');
|
|
|
|
const tripCards = page.locator('.card[data-trip-id]');
|
|
const cardCount = await tripCards.count();
|
|
|
|
if (cardCount > 0) {
|
|
await tripCards.first().click();
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
const mapContainer = page.locator('#map');
|
|
if (await mapContainer.isVisible()) {
|
|
await helpers.waitForMap();
|
|
|
|
// Test zoom controls
|
|
const zoomIn = page.getByRole('button', { name: 'Zoom in' });
|
|
const zoomOut = page.getByRole('button', { name: 'Zoom out' });
|
|
|
|
await zoomIn.click();
|
|
await page.waitForTimeout(500);
|
|
await zoomOut.click();
|
|
await page.waitForTimeout(500);
|
|
|
|
// Map should still be functional
|
|
await expect(mapContainer).toBeVisible();
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
test.describe('Trip Management', () => {
|
|
test('should show trip actions', async ({ page }) => {
|
|
await helpers.navigateTo('Trips');
|
|
|
|
const tripCards = page.locator('.card[data-trip-id]');
|
|
const cardCount = await tripCards.count();
|
|
|
|
if (cardCount > 0) {
|
|
await tripCards.first().click();
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
// Look for edit/delete/export options
|
|
const editLink = page.getByRole('link', { name: /edit/i });
|
|
const deleteButton = page.getByRole('button', { name: /delete/i }).or(page.getByRole('link', { name: /delete/i }));
|
|
|
|
// At least edit should be available
|
|
if (await editLink.isVisible()) {
|
|
await expect(editLink).toBeVisible();
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
test.describe('Mobile Trips Experience', () => {
|
|
test('should work on mobile viewport', async ({ page }) => {
|
|
await page.setViewportSize({ width: 375, height: 667 });
|
|
await helpers.navigateTo('Trips');
|
|
|
|
// Page should load correctly on mobile
|
|
await expect(page.getByRole('heading', { name: 'Trips' })).toBeVisible();
|
|
await expect(page.getByRole('link', { name: 'New trip' })).toBeVisible();
|
|
|
|
// Grid should adapt to mobile
|
|
const tripsGrid = page.locator('.grid');
|
|
if (await tripsGrid.isVisible()) {
|
|
await expect(tripsGrid).toBeVisible();
|
|
}
|
|
});
|
|
|
|
test('should handle mobile trip details', async ({ page }) => {
|
|
await page.setViewportSize({ width: 375, height: 667 });
|
|
await helpers.navigateTo('Trips');
|
|
|
|
const tripCards = page.locator('.card[data-trip-id]');
|
|
const cardCount = await tripCards.count();
|
|
|
|
if (cardCount > 0) {
|
|
await tripCards.first().click();
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
// Should show trip info on mobile
|
|
await expect(page.locator('h1, h2, h3').first()).toBeVisible();
|
|
|
|
// Map should be responsive if present
|
|
const mapContainer = page.locator('#map');
|
|
if (await mapContainer.isVisible()) {
|
|
await expect(mapContainer).toBeVisible();
|
|
}
|
|
}
|
|
});
|
|
|
|
test('should handle mobile map interactions', async ({ page }) => {
|
|
await page.setViewportSize({ width: 375, height: 667 });
|
|
await helpers.navigateTo('Trips');
|
|
|
|
const tripCards = page.locator('.card[data-trip-id]');
|
|
const cardCount = await tripCards.count();
|
|
|
|
if (cardCount > 0) {
|
|
await tripCards.first().click();
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
const mapContainer = page.locator('#map');
|
|
if (await mapContainer.isVisible()) {
|
|
await helpers.waitForMap();
|
|
|
|
// Test touch interaction
|
|
await mapContainer.click();
|
|
await page.waitForTimeout(300);
|
|
|
|
// Map should remain functional
|
|
await expect(mapContainer).toBeVisible();
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
test.describe('Trip Performance', () => {
|
|
test('should load trips page within reasonable time', async ({ page }) => {
|
|
const startTime = Date.now();
|
|
|
|
await helpers.navigateTo('Trips');
|
|
|
|
const loadTime = Date.now() - startTime;
|
|
const maxLoadTime = await helpers.isMobileViewport() ? 15000 : 10000;
|
|
|
|
expect(loadTime).toBeLessThan(maxLoadTime);
|
|
});
|
|
|
|
test('should handle large numbers of trips', async ({ page }) => {
|
|
await helpers.navigateTo('Trips');
|
|
|
|
// Page should load without timing out
|
|
await page.waitForLoadState('networkidle', { timeout: 30000 });
|
|
|
|
// Should show either trips or empty state
|
|
const tripsGrid = page.locator('.grid');
|
|
const emptyState = page.getByText('Hello there!');
|
|
|
|
expect(await tripsGrid.isVisible() || await emptyState.isVisible()).toBe(true);
|
|
});
|
|
});
|
|
});
|