Add E2E tests for waypoint notes and nearby POI snap; archive waypoint-notes
- E2E: type a note, blur, verify it persists and appears in GPX <desc> on <wpt> - E2E: mock Overpass, select waypoint, verify Nearby list, snap to POI, verify note prefix prepended - Sync waypoint-notes delta spec → openspec/specs/waypoint-notes/spec.md - Archive waypoint-notes change Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
763aa475ea
commit
41217ef658
7 changed files with 149 additions and 2 deletions
|
|
@ -469,4 +469,105 @@ test.describe("Planner", () => {
|
|||
const panelText = await page.getByText("Drinking water").textContent();
|
||||
expect(panelText).toBeTruthy();
|
||||
});
|
||||
|
||||
test("waypoint note persists and appears in GPX export", async ({ page, request }) => {
|
||||
const sessionResp = await request.post("/api/sessions", { data: {} });
|
||||
const { url } = await sessionResp.json();
|
||||
|
||||
await mockBRouter(page);
|
||||
|
||||
await page.goto(`${url}?waypoints=${encodeURIComponent(JSON.stringify([
|
||||
{ lat: 52.520, lon: 13.405, name: "Berlin" },
|
||||
{ lat: 52.515, lon: 13.351, name: "Spandau" },
|
||||
]))}`);
|
||||
|
||||
await expect(page.locator(".leaflet-container")).toBeVisible({ timeout: 10000 });
|
||||
await expect(page.getByText("Connected")).toBeVisible({ timeout: 15000 });
|
||||
await expect(page.getByText("Waypoints (2)")).toBeVisible({ timeout: 5000 });
|
||||
|
||||
const sidebar = page.locator("aside");
|
||||
|
||||
// Click on the note placeholder for the first waypoint
|
||||
const firstRow = sidebar.locator("li").filter({ has: page.locator("span.rounded-full").first() }).first();
|
||||
await firstRow.locator("p.italic").click();
|
||||
|
||||
// Type a note in the textarea
|
||||
const textarea = firstRow.locator("textarea");
|
||||
await expect(textarea).toBeVisible({ timeout: 3000 });
|
||||
await textarea.fill("Refill water here");
|
||||
|
||||
// Blur to save
|
||||
await textarea.blur();
|
||||
|
||||
// Note should now be displayed (no longer placeholder)
|
||||
await expect(firstRow.getByText("Refill water here")).toBeVisible({ timeout: 3000 });
|
||||
|
||||
// Export GPX and verify <desc> appears inside <wpt>
|
||||
const [download] = await Promise.all([
|
||||
page.waitForEvent("download"),
|
||||
page.getByRole("button", { name: "Export GPX" }).click(),
|
||||
]);
|
||||
const gpxStream = await download.createReadStream();
|
||||
const chunks: Buffer[] = [];
|
||||
for await (const chunk of gpxStream) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
||||
const gpxText = Buffer.concat(chunks).toString("utf-8");
|
||||
|
||||
// The <desc> should be inside the first <wpt> block
|
||||
const wptBlock = gpxText.match(/<wpt[^>]*lat="52\.52[^"]*"[^>]*>[\s\S]*?<\/wpt>/)?.[0] ?? "";
|
||||
expect(wptBlock).toContain("<desc>Refill water here</desc>");
|
||||
});
|
||||
|
||||
test("nearby POI snap moves waypoint and prepends note prefix", async ({ page, request }) => {
|
||||
const sessionResp = await request.post("/api/sessions", { data: {} });
|
||||
const { url } = await sessionResp.json();
|
||||
|
||||
await mockBRouter(page);
|
||||
|
||||
// Mock the Overpass proxy to return a nearby POI
|
||||
await page.route("**/api/overpass", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({
|
||||
elements: [
|
||||
{
|
||||
type: "node",
|
||||
id: 99001,
|
||||
lat: 52.521,
|
||||
lon: 13.406,
|
||||
tags: { amenity: "drinking_water", name: "Stadtbrunnen" },
|
||||
},
|
||||
],
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
await page.goto(`${url}?waypoints=${encodeURIComponent(JSON.stringify([
|
||||
{ lat: 52.520, lon: 13.405, name: "Start" },
|
||||
{ lat: 52.515, lon: 13.351, name: "End" },
|
||||
]))}`);
|
||||
|
||||
await expect(page.locator(".leaflet-container")).toBeVisible({ timeout: 10000 });
|
||||
await expect(page.getByText("Connected")).toBeVisible({ timeout: 15000 });
|
||||
await expect(page.getByText("Waypoints (2)")).toBeVisible({ timeout: 5000 });
|
||||
|
||||
const sidebar = page.locator("aside");
|
||||
|
||||
// Click the first waypoint row to select it (triggers nearby POI fetch)
|
||||
const firstRow = sidebar.locator("li").filter({ has: page.locator("span.rounded-full").first() }).first();
|
||||
await firstRow.click();
|
||||
|
||||
// Wait for the Nearby section to appear with the mock POI
|
||||
await expect(sidebar.getByText("Nearby")).toBeVisible({ timeout: 5000 });
|
||||
await expect(sidebar.getByText("Stadtbrunnen")).toBeVisible({ timeout: 5000 });
|
||||
|
||||
// Click the snap button for that POI
|
||||
const snapButton = sidebar.locator("li").filter({ hasText: "Stadtbrunnen" }).getByRole("button", { name: /snap/i });
|
||||
await snapButton.click();
|
||||
|
||||
// The waypoint note should now contain the POI prefix (water emoji + name)
|
||||
await expect(firstRow.locator("p.italic")).not.toHaveText(/Add a note/);
|
||||
const noteText = await firstRow.locator("p.italic").textContent();
|
||||
expect(noteText).toContain("Stadtbrunnen");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
## 6. Testing (Notes)
|
||||
|
||||
- [x] 6.1 Unit tests: per-waypoint `<desc>` in GPX generation; `<desc>` inside `<wpt>` parsed into `note`; verify no collision with `metadata > desc`
|
||||
- [ ] 6.2 E2E test: type a note in sidebar, blur, verify note persists; verify GPX export contains `<desc>` inside `<wpt>`
|
||||
- [x] 6.2 E2E test: type a note in sidebar, blur, verify note persists; verify GPX export contains `<desc>` inside `<wpt>`
|
||||
|
||||
## 7. POI Data Layer (per-waypoint)
|
||||
|
||||
|
|
@ -62,4 +62,4 @@
|
|||
- [x] 11.2 POI cache unit tests — `poi-cache.test.ts` already covers this
|
||||
- [x] 11.3 Unit tests for `fetchNearbyPois`: correct bbox from lat/lon/radius, category filtering
|
||||
- [x] 11.4 Unit tests for snap: coords updated, name set, note prefix prepended, existing note preserved, all in one Yjs transaction
|
||||
- [ ] 11.5 E2E test: mock Overpass via route handler, select a waypoint, verify Nearby list appears, click snap, verify waypoint moved and note prefixed
|
||||
- [x] 11.5 E2E test: mock Overpass via route handler, select a waypoint, verify Nearby list appears, click snap, verify waypoint moved and note prefixed
|
||||
46
openspec/specs/waypoint-notes/spec.md
Normal file
46
openspec/specs/waypoint-notes/spec.md
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
## ADDED Requirements
|
||||
|
||||
### Requirement: Per-waypoint text notes
|
||||
Each waypoint SHALL support an optional plain-text note synced via Yjs.
|
||||
|
||||
#### Scenario: Add note to waypoint
|
||||
- **WHEN** a user clicks the note area under a waypoint in the sidebar and types text
|
||||
- **THEN** the note is stored in the waypoint's Y.Map as a `note` string field
|
||||
- **AND** auto-saves on blur
|
||||
|
||||
#### Scenario: Note syncs to participants
|
||||
- **WHEN** a user adds or edits a waypoint note
|
||||
- **THEN** all other participants see the update in real-time via Yjs
|
||||
|
||||
### Requirement: Map note indicators
|
||||
Waypoint markers with notes SHALL show a visual indicator on the map.
|
||||
|
||||
#### Scenario: Note icon on marker
|
||||
- **WHEN** a waypoint has a note
|
||||
- **THEN** its map marker shows a small note icon
|
||||
|
||||
#### Scenario: Note tooltip
|
||||
- **WHEN** a user hovers or taps a marker with a note
|
||||
- **THEN** the note text appears in a tooltip
|
||||
|
||||
### Requirement: Notes in GPX export
|
||||
Waypoint notes SHALL be exported as `<desc>` elements in GPX output.
|
||||
|
||||
#### Scenario: Export notes
|
||||
- **WHEN** a user exports a plan with waypoint notes
|
||||
- **THEN** each waypoint's note appears as a `<desc>` element in the GPX file
|
||||
|
||||
### Requirement: Nearby POI display
|
||||
When a waypoint is selected, nearby POIs from OpenStreetMap SHALL be shown on the map and in the sidebar.
|
||||
|
||||
#### Scenario: POI lookup
|
||||
- **WHEN** a user selects a waypoint
|
||||
- **THEN** nearby POIs are fetched from the Overpass API and displayed as small markers on the map and as a list in the sidebar
|
||||
|
||||
### Requirement: Snap waypoint to POI
|
||||
Users SHALL be able to move a waypoint to a nearby POI's exact coordinates.
|
||||
|
||||
#### Scenario: Snap to POI
|
||||
- **WHEN** a user clicks a nearby POI
|
||||
- **THEN** the waypoint moves to the POI's coordinates
|
||||
- **AND** the POI's name and type are added as a note prefix (e.g., "Campsite - Waldcamp Fichtelberg")
|
||||
Loading…
Add table
Add a link
Reference in a new issue