feat: v0.4.0 — self-host OFM styles/fonts/sprites (tiles stay remote) + top-bar style switcher defaulting to Fiord
This commit is contained in:
+77
-7
@@ -72,13 +72,11 @@ test('clicking an airport marker opens a popup with name and ICAO', async ({ pag
|
||||
});
|
||||
|
||||
test('wheel zoom is clamped between min and max zoom', async ({ page }) => {
|
||||
// Zoom clamping is pure camera behavior, so block basemap tile fetches (the
|
||||
// style JSON still loads): it keeps the headless main thread idle and makes the
|
||||
// test fast and independent of tile-server latency.
|
||||
await page.route('**://*.openfreemap.org/**', (route) => {
|
||||
if (route.request().url().includes('/styles/')) return route.continue();
|
||||
return route.abort();
|
||||
});
|
||||
// Zoom clamping is pure camera behavior, so block basemap tile fetches: it keeps
|
||||
// the headless main thread idle and makes the test fast and independent of
|
||||
// tile-server latency. Styles/fonts/sprites are self-hosted now — anything from
|
||||
// openfreemap.org is a tile request, so abort all of them.
|
||||
await page.route('**://*.openfreemap.org/**', (route) => route.abort());
|
||||
await page.goto(APP_URL);
|
||||
|
||||
const getZoom = () => page.evaluate(() => (window as any).__flightMap?.getZoom() ?? -1);
|
||||
@@ -144,3 +142,75 @@ test('wheel zoom is clamped between min and max zoom', async ({ page }) => {
|
||||
expect(zoom).toBeGreaterThanOrEqual(MIN_ZOOM);
|
||||
expect(zoom).toBeLessThanOrEqual(MAX_ZOOM);
|
||||
});
|
||||
|
||||
test('style switcher defaults to Fiord, switches styles, and keeps the airports layer', async ({ page }) => {
|
||||
// Styles/fonts/sprites are self-hosted; only tiles come from openfreemap — abort
|
||||
// them for speed (the GeoJSON airport layer renders without basemap tiles).
|
||||
await page.route('**://*.openfreemap.org/**', (route) => route.abort());
|
||||
await page.goto(APP_URL);
|
||||
|
||||
const select = page.getByTestId('style-switch');
|
||||
await expect(select).toBeVisible();
|
||||
await expect(select.locator('option')).toHaveCount(5);
|
||||
// Fiord is the default style.
|
||||
await expect(select).toHaveValue('fiord');
|
||||
|
||||
await waitForAirportCount(page);
|
||||
|
||||
const renderedCircles = () =>
|
||||
page.evaluate(
|
||||
() =>
|
||||
(window as any).__flightMap?.queryRenderedFeatures(undefined, {
|
||||
layers: ['airports-circles'],
|
||||
})?.length ?? 0,
|
||||
);
|
||||
await expect.poll(renderedCircles, { timeout: 15_000 }).toBeGreaterThan(0);
|
||||
|
||||
const layerIds = () =>
|
||||
page.evaluate(() => (window as any).__flightMap?.getStyle()?.layers?.map((l: { id: string }) => l.id) ?? []);
|
||||
const before = await layerIds();
|
||||
expect(before.length).toBeGreaterThan(0);
|
||||
|
||||
// Switch to Dark.
|
||||
await select.selectOption('dark');
|
||||
await expect(select).toHaveValue('dark');
|
||||
|
||||
// The applied style must actually change (each OFM style has a different layer set).
|
||||
await expect.poll(layerIds, { timeout: 15_000 }).not.toEqual(before);
|
||||
|
||||
// Regression guard for the setStyle-wipes-layers bug: map.setStyle() removes every
|
||||
// source/layer not in the new style, so the airports layer must be re-established —
|
||||
// count still shown and markers rendered again.
|
||||
await expect(page.getByTestId('airport-count')).toContainText(/EU airports/);
|
||||
await expect.poll(renderedCircles, { timeout: 15_000 }).toBeGreaterThan(0);
|
||||
|
||||
// Clicking a marker after the switch opens exactly one popup (the click handler is
|
||||
// re-wired idempotently — no duplicate listeners).
|
||||
const pt = await page.evaluate(() => {
|
||||
const map = (window as any).__flightMap;
|
||||
const p = map.project([30.894699, 50.345001]); // UKBB Boryspil
|
||||
const rect = map.getContainer().getBoundingClientRect();
|
||||
return { x: rect.left + p.x, y: rect.top + p.y };
|
||||
});
|
||||
await page.mouse.click(pt.x, pt.y);
|
||||
const popups = page.getByTestId('airport-popup');
|
||||
await expect(popups.first()).toBeVisible();
|
||||
await expect(popups).toHaveCount(1);
|
||||
});
|
||||
|
||||
test('style choice persists across reloads via localStorage', async ({ page }) => {
|
||||
await page.route('**://*.openfreemap.org/**', (route) => route.abort());
|
||||
await page.goto(APP_URL);
|
||||
|
||||
const select = page.getByTestId('style-switch');
|
||||
await expect(select).toHaveValue('fiord');
|
||||
|
||||
await select.selectOption('positron');
|
||||
const stored = await page.evaluate(() => localStorage.getItem('flight-ops-style'));
|
||||
expect(stored).toBe('positron');
|
||||
|
||||
// Reload: the persisted choice is restored after mount (SSR-safe path — server and
|
||||
// first paint use the default, then the effect applies the saved style).
|
||||
await page.reload();
|
||||
await expect(select).toHaveValue('positron');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user