import { test, expect } from '@playwright/test' import { closeOnboardingModal } from '../../../helpers/navigation.js' import { navigateToMapsV2WithDate, waitForMapLibre, waitForLoadingComplete, hasLayer, getLayerVisibility, getRoutesSourceData } from '../../helpers/setup.js' test.describe('Routes Layer', () => { test.beforeEach(async ({ page }) => { await page.goto('/map/v2?start_at=2025-10-15T00:00&end_at=2025-10-15T23:59') await closeOnboardingModal(page) await waitForMapLibre(page) await waitForLoadingComplete(page) await page.waitForTimeout(1500) }) test.describe('Layer Existence', () => { test('routes layer exists on map', async ({ page }) => { await page.waitForFunction(() => { const element = document.querySelector('[data-controller*="maps--maplibre"]') if (!element) return false const app = window.Stimulus || window.Application if (!app) return false const controller = app.getControllerForElementAndIdentifier(element, 'maps--maplibre') return controller?.map?.getLayer('routes') !== undefined }, { timeout: 10000 }).catch(() => false) const hasRoutesLayer = await hasLayer(page, 'routes') expect(hasRoutesLayer).toBe(true) }) }) test.describe('Data Source', () => { test('routes source has data', async ({ page }) => { await page.waitForFunction(() => { const element = document.querySelector('[data-controller*="maps--maplibre"]') if (!element) return false const app = window.Stimulus || window.Application if (!app) return false const controller = app.getControllerForElementAndIdentifier(element, 'maps--maplibre') return controller?.map?.getSource('routes-source') !== undefined }, { timeout: 20000 }) const { hasSource, featureCount } = await getRoutesSourceData(page) expect(hasSource).toBe(true) expect(featureCount).toBeGreaterThanOrEqual(0) }) test('routes have LineString geometry', async ({ page }) => { const { features } = await getRoutesSourceData(page) if (features.length > 0) { features.forEach(feature => { expect(feature.geometry.type).toBe('LineString') expect(feature.geometry.coordinates.length).toBeGreaterThan(1) }) } }) test('routes have distance properties', async ({ page }) => { const { features } = await getRoutesSourceData(page) if (features.length > 0) { features.forEach(feature => { expect(feature.properties).toHaveProperty('distance') expect(typeof feature.properties.distance).toBe('number') expect(feature.properties.distance).toBeGreaterThanOrEqual(0) }) } }) test('routes connect points chronologically', async ({ page }) => { const { features } = await getRoutesSourceData(page) if (features.length > 0) { features.forEach(feature => { expect(feature.properties).toHaveProperty('startTime') expect(feature.properties).toHaveProperty('endTime') expect(feature.properties.endTime).toBeGreaterThanOrEqual(feature.properties.startTime) expect(feature.properties).toHaveProperty('pointCount') expect(feature.properties.pointCount).toBeGreaterThan(1) }) } }) }) test.describe('Styling', () => { test('routes have solid color', async ({ page }) => { await page.waitForFunction(() => { const element = document.querySelector('[data-controller*="maps--maplibre"]') if (!element) return false const app = window.Stimulus || window.Application if (!app) return false const controller = app.getControllerForElementAndIdentifier(element, 'maps--maplibre') return controller?.map?.getLayer('routes') !== undefined }, { timeout: 20000 }) const routeLayerInfo = await page.evaluate(() => { const element = document.querySelector('[data-controller*="maps--maplibre"]') if (!element) return null const app = window.Stimulus || window.Application if (!app) return null const controller = app.getControllerForElementAndIdentifier(element, 'maps--maplibre') if (!controller?.map) return null const layer = controller.map.getLayer('routes') if (!layer) return null const lineColor = controller.map.getPaintProperty('routes', 'line-color') return { exists: !!lineColor, isArray: Array.isArray(lineColor), value: lineColor } }) expect(routeLayerInfo).toBeTruthy() expect(routeLayerInfo.exists).toBe(true) // Route color is now a MapLibre expression that supports dynamic colors // Format: ['case', ['has', 'color'], ['get', 'color'], '#0000ff'] if (routeLayerInfo.isArray) { // It's a MapLibre expression, check the default color (last element) expect(routeLayerInfo.value[routeLayerInfo.value.length - 1]).toBe('#0000ff') } else { // Solid color (fallback) expect(routeLayerInfo.value).toBe('#0000ff') } }) }) test.describe('Layer Order', () => { test('routes layer renders below points layer', async ({ page }) => { await page.waitForFunction(() => { const element = document.querySelector('[data-controller*="maps--maplibre"]') const app = window.Stimulus || window.Application const controller = app?.getControllerForElementAndIdentifier(element, 'maps--maplibre') return controller?.map?.getLayer('routes') !== undefined && controller?.map?.getLayer('points') !== undefined }, { timeout: 10000 }) const layerOrder = await page.evaluate(() => { const element = document.querySelector('[data-controller*="maps--maplibre"]') if (!element) return null const app = window.Stimulus || window.Application if (!app) return null const controller = app.getControllerForElementAndIdentifier(element, 'maps--maplibre') if (!controller?.map) return null const style = controller.map.getStyle() const layers = style.layers || [] const routesIndex = layers.findIndex(l => l.id === 'routes') const pointsIndex = layers.findIndex(l => l.id === 'points') return { routesIndex, pointsIndex } }) expect(layerOrder).toBeTruthy() if (layerOrder.routesIndex >= 0 && layerOrder.pointsIndex >= 0) { expect(layerOrder.routesIndex).toBeLessThan(layerOrder.pointsIndex) } }) }) test.describe('Persistence', () => { test('date navigation preserves routes layer', async ({ page }) => { // Wait for routes layer to be added to the map await page.waitForFunction(() => { const element = document.querySelector('[data-controller*="maps--maplibre"]') if (!element) return false const app = window.Stimulus || window.Application if (!app) return false const controller = app.getControllerForElementAndIdentifier(element, 'maps--maplibre') return controller?.map?.getLayer('routes') !== undefined }, { timeout: 10000 }) const initialRoutes = await hasLayer(page, 'routes') expect(initialRoutes).toBe(true) await navigateToMapsV2WithDate(page, '2025-10-16T00:00', '2025-10-16T23:59') await closeOnboardingModal(page) await waitForMapLibre(page) await waitForLoadingComplete(page) await page.waitForTimeout(1500) const hasRoutesLayer = await hasLayer(page, 'routes') expect(hasRoutesLayer).toBe(true) }) }) })