# QA Test Plan *Branch: experimental-polar-steps. Tester role: Senior Staff QA Engineer.* --- ## Scope All features implemented in Phase 4 (Milestones 1โ€“4): - M1: Entry enrichment (location badge, weather badge, photo gallery, hero image) - M2: Interactive map page - M3: Statistics page - M4: Mini-map on tracker feed Test URLs: - Desktop: http://localhost:8081 - Mobile: http://100.96.115.96:8081 (Tailscale โ€” requires physical phone) --- ## Milestone 1 โ€” Entry Enrichment ### TC-1.1: Location badge on entry page | Step | Action | Expected Result | |---|---|---| | 1 | Open http://localhost:8081/tracker/2026-06-17.entry | Entry page loads (200) | | 2 | Look at entry header | `๐Ÿ“ Amsterdam, Netherlands` visible below date | | 3 | Inspect HTML | `

` present with city and country | **Automation:** grep for `.entry-location` and "Amsterdam" in curl output --- ### TC-1.2: Weather badge on entry page | Step | Action | Expected Result | |---|---|---| | 1 | Open http://localhost:8081/tracker/2026-06-17.entry | Entry page loads | | 2 | Look at entry header | `โ›… Partly cloudy ยท 19ยฐC` visible | | 3 | Inspect HTML | `

` present | **Automation:** grep for `.entry-weather` and "Partly cloudy" and "19ยฐC" --- ### TC-1.3: Location badge hidden when fields empty | Step | Action | Expected Result | |---|---|---| | 1 | Create test entry with no location_city/location_country | โ€” | | 2 | Open that entry | No `๐Ÿ“` badge shown, no empty `

` rendered | **Automation:** Check example entry before fields were added (not needed โ€” fields are now set); create a second test entry without location --- ### TC-1.4: Weather badge hidden when fields empty | Step | Action | Expected Result | |---|---|---| | 1 | Entry with no weather fields | No weather section in HTML | **Automation:** grep for `entry-weather` in HTML โ€” should only appear if value present --- ### TC-1.5: Hero image on tracker feed card | Step | Action | Expected Result | |---|---|---| | 1 | Open http://localhost:8081/tracker | Feed loads | | 2 | Entry card for 2026-06-17 | No image shown (example entry has no photos) | | 3 | Upload a photo to the entry via Admin media manager | โ€” | | 4 | Reload tracker | Hero image shows as 16:9 thumbnail | **Manual verification required:** Photo upload requires browser Admin interaction --- ### TC-1.6: Location badge on tracker feed card | Step | Action | Expected Result | |---|---|---| | 1 | Open http://localhost:8081/tracker | Feed loads | | 2 | Entry card | `๐Ÿ“ Amsterdam, Netherlands` visible | **Automation:** grep feed HTML for `entry-location--card` and "Amsterdam" --- ### TC-1.7: Photo gallery renders on entry page (with photos) | Step | Action | Expected Result | |---|---|---| | 1 | Upload 3 photos to the example entry via Admin | โ€” | | 2 | Open entry page | Gallery grid appears below entry body | | 3 | Count thumbnails | 3 thumbnails in 2-col (mobile) / 3-col (desktop) grid | | 4 | Click a thumbnail | Lightbox overlay opens with full-size image | | 5 | Press Escape | Lightbox closes | | 6 | Click left/right arrow buttons | Navigates between images | | 7 | Click outside lightbox | Lightbox closes | **Manual verification required:** Photo upload and interactive lightbox require browser --- ### TC-1.8: Post form has location and weather fields | Step | Action | Expected Result | |---|---|---| | 1 | Open http://localhost:8081/post (logged in) | Post form renders | | 2 | Inspect form | `City` and `Country` text inputs present | | 3 | Inspect form | `๐Ÿ“ Get Current Location` and `๐ŸŒค Get Weather` buttons present | **Automation:** grep /post HTML for `location_city`, `location_country`, `get-location`, `get-weather` --- ### TC-1.9: Get Weather button fills fields | Step | Action | Expected Result | |---|---|---| | 1 | Open /post on phone | Post form loads | | 2 | Tap "Get Current Location" | Lat/lng fields fill with coordinates | | 3 | Tap "Get Weather" | Status shows "๐ŸŒค Weather set: [desc] ยท [temp]ยฐC" | | 4 | Submit form | New entry created with weather in frontmatter | | 5 | Open entry in Admin | weather_temp_c and weather_desc fields populated | **Manual verification required:** Geolocation and form submission require mobile browser --- ## Milestone 2 โ€” Interactive Map ### TC-2.1: Map page loads | Step | Action | Expected Result | |---|---|---| | 1 | GET http://localhost:8081/map | HTTP 200 | | 2 | Inspect HTML | `

` present | | 3 | Inspect HTML | Leaflet CSS and JS from CDN present | **Automation:** curl + HTTP status check; grep for "trip-map" and "leaflet" --- ### TC-2.2: Entry with GPS appears in ENTRIES JSON | Step | Action | Expected Result | |---|---|---| | 1 | curl http://localhost:8081/map | Map page HTML | | 2 | grep for `var ENTRIES` | Array contains Amsterdam entry with lat 52.3676 | | 3 | Check entry has title, date, url | All fields present | **Automation:** grep output for ENTRIES and lat value --- ### TC-2.3: Map renders marker and route in browser | Step | Action | Expected Result | |---|---|---| | 1 | Open /map in browser | Map tiles load, marker visible | | 2 | Click marker | Popup opens with "The Journey Begins" title and "Read entry โ†’" link | | 3 | Click "Read entry โ†’" | Navigates to entry page | **Manual verification required:** Leaflet rendering requires browser --- ### TC-2.4: Map navigation link in header | Step | Action | Expected Result | |---|---|---| | 1 | Open any page | Header shows Journal, Map, Stats nav links | | 2 | Click Map | Navigates to /map | **Automation:** grep base template output for "/map" nav link --- ### TC-2.5: Empty state (no GPS entries) | Step | Action | Expected Result | |---|---|---| | 1 | Remove lat/lng from test entry temporarily | โ€” | | 2 | Visit /map | Map at world zoom, "No locations yet" message shown | | 3 | Restore lat/lng | โ€” | **Manual verification required:** Requires temporarily editing entry --- ### TC-2.6: Map page is full-height on mobile | Step | Action | Expected Result | |---|---|---| | 1 | Open /map on mobile browser | Map fills screen below header | | 2 | Pinch to zoom | Map zooms without page scrolling | | 3 | Pan with finger | Map pans without page scrolling | **Manual verification required:** Touch interaction requires physical device --- ## Milestone 3 โ€” Statistics Page ### TC-3.1: Stats page loads | Step | Action | Expected Result | |---|---|---| | 1 | GET http://localhost:8081/stats | HTTP 200 | | 2 | Inspect HTML | Four stat blocks present | **Automation:** curl + HTTP status + grep for "stat-block" --- ### TC-3.2: Days on the road count | Step | Action | Expected Result | |---|---|---| | 1 | curl /stats | Page HTML | | 2 | grep for "days" | Shows "1 day on the road" (entry date: 2026-06-17, today: 2026-06-18) | **Automation:** grep stat-value output and compare to expected day count --- ### TC-3.3: Entries count | Step | Action | Expected Result | |---|---|---| | 1 | curl /stats | grep for "entry posted" | Shows "1 entry posted" | **Automation:** grep for "entry posted" --- ### TC-3.4: Countries visited | Step | Action | Expected Result | |---|---|---| | 1 | curl /stats | grep for "Netherlands" | "Netherlands" appears in countries list | | 2 | grep for "country visited" | Shows "1 country visited" | **Automation:** grep output --- ### TC-3.5: Distance shows "โ€”" for single GPS point | Step | Action | Expected Result | |---|---|---| | 1 | curl /stats | grep for GPS_POINTS | One point in array | | 2 | In browser, check stat-distance | Shows "โ€”" (JS computes, needs browser) | **Automation:** grep GPS_POINTS array length from page source --- ### TC-3.6: Stats navigation link | Step | Action | Expected Result | |---|---|---| | 1 | Open any page header | "Stats" link present in nav | | 2 | Click Stats | Navigates to /stats | **Automation:** grep any page HTML for "/stats" in nav --- ## Milestone 4 โ€” Mini-map on Tracker Feed ### TC-4.1: Mini-map appears on tracker feed | Step | Action | Expected Result | |---|---|---| | 1 | GET http://localhost:8081/tracker | HTTP 200 | | 2 | grep for "feed-map" | Mini-map div present | | 3 | grep for "FEED_ENTRIES" | JSON array with Amsterdam entry | | 4 | grep for "View full map โ†’" | Link to /map present | **Automation:** curl + grep --- ### TC-4.2: Mini-map hidden when no GPS entries | Step | Action | Expected Result | |---|---|---| | 1 | Remove lat/lng from example entry | โ€” | | 2 | curl /tracker | No "feed-map" div in output | | 3 | Restore lat/lng | โ€” | **Manual verification:** Requires temporarily editing entry --- ### TC-4.3: Marker click navigates to entry (mobile) | Step | Action | Expected Result | |---|---|---| | 1 | Open /tracker on phone | Mini-map renders above entry list | | 2 | Tap Amsterdam marker | Navigates to /tracker/2026-06-17.entry | **Manual verification required:** Touch interaction requires browser --- ### TC-4.4: Entry list still visible below mini-map | Step | Action | Expected Result | |---|---|---| | 1 | Open /tracker | Mini-map shows, scroll down | Entry cards visible below map | **Manual verification required:** Visual layout check --- ## Post Submission Flow These scenarios cover the full round-trip: filling the form โ†’ saving โ†’ verifying values in the UI and on disk. Use the exact test values specified so that each assertion can be precise. **Test data (use verbatim):** | Field | Value | |---|---| | Title | `QA Test Entry` | | Date & Time | `2026-06-18 10:00` | | Content | `This is the QA test body. Second sentence for length.` | | City | `Tokyo` | | Country | `Japan` | | Latitude | `35.689487` | | Longitude | `139.691711` | | Photos | none (keep simple for first run) | --- ### TC-P.1: Post form requires authentication | Step | Action | Expected Result | |---|---|---| | 1 | Open private/incognito tab (no session) | โ€” | | 2 | GET http://100.96.115.96:8081/post | Page loads at /post URL (no redirect) but renders the login form inline | | 3 | Inspect page content | Login form fields (username, password) visible; post form fields absent | **Automation:** curl /post without auth; assert `login-form-nonce` present AND `data[title]` absent --- ### TC-P.2: Post form renders all fields | Step | Action | Expected Result | |---|---|---| | 1 | Log in at /login | Redirected to /tracker | | 2 | Navigate to /post | Post form page loads (200) | | 3 | Check form fields present | Title, Date & Time, description textarea, Photos upload | | 4 | Check location fields | Latitude, Longitude, City, Country inputs visible | | 5 | Check action buttons | `๐Ÿ“ Get Current Location` and `๐ŸŒค Get Weather` buttons visible | | 6 | Check submit button | `Post Entry` button visible | | 7 | Check date field default | Pre-filled with today's date and time (not blank) | **Automation:** curl /post with auth; grep for `data[title]`, `data[lat]`, `data[location_city]`, `get-location`, `get-weather` --- ### TC-P.3: Required field validation | Step | Action | Expected Result | |---|---|---| | 1 | Log in and open /post | Form loads | | 2 | Leave Title blank, fill in only the description | โ€” | | 3 | Submit form | Page reloads with validation error on Title | | 4 | Error message | Indicates title is required | | 5 | Fill in Title, clear Description/Content, submit | Validation error on Content field | | 6 | Confirm | No new entry file created in pages/01.tracker/ during failed submissions | **Manual verification required:** Validation feedback requires browser --- ### TC-P.4: Successful post submission โ€” all fields | Step | Action | Expected Result | |---|---|---| | 1 | Log in and open /post | Form loads | | 2 | Enter Title: `QA Test Entry` | โ€” | | 3 | Set Date to `2026-06-18 10:00` | โ€” | | 4 | Enter Content: `This is the QA test body. Second sentence for length.` | โ€” | | 5 | Enter City: `Tokyo`, Country: `Japan` | โ€” | | 6 | Enter Latitude: `35.689487`, Longitude: `139.691711` | โ€” | | 7 | Leave Photos empty | โ€” | | 8 | Click `Post Entry` | Form submits (POST to /post) | | 9 | Observe result | Success message `Entry posted successfully!` shown on page | | 10 | Form state | Form is reset / fields cleared | **Manual verification required:** Form submission and success message require browser --- ### TC-P.5: Entry file created on disk with correct values | Step | Action | Expected Result | |---|---|---| | 1 | After TC-P.4 completes | โ€” | | 2 | Check directory `user/pages/01.tracker/` | Folder `2026-06-18.entry/` exists (add-page-by-form appends template name per `physical_template_name: true`) | | 3 | Read `user/pages/01.tracker/2026-06-18.entry/entry.md` | File exists | | 4 | Verify frontmatter `title` | Equals `QA Test Entry` | | 5 | Verify frontmatter `date` | Equals `2026-06-18 10:00` | | 6 | Verify frontmatter `location_city` | Equals `Tokyo` | | 7 | Verify frontmatter `location_country` | Equals `Japan` | | 8 | Verify frontmatter `lat` | Equals `35.689487` | | 9 | Verify frontmatter `lng` | Equals `139.691711` | | 10 | Verify frontmatter `template` | Equals `entry` | | 11 | Verify frontmatter `published` | Equals `true` | | 12 | Verify page body | Contains `This is the QA test body. Second sentence for length.` | **Automation:** Read file from filesystem; parse YAML frontmatter; assert each field value exactly --- ### TC-P.6: Entry appears in tracker feed | Step | Action | Expected Result | |---|---|---| | 1 | BUG-001 fixed โ€” no manual cache clear needed | โ€” | | 2 | GET http://100.96.115.96:8081/tracker | Page loads (200) | | 3 | Entry card present | Card with title `QA Test Entry` visible | | 4 | Date shown on card | `18 Jun 2026` | | 5 | Location badge on card | `๐Ÿ“ Tokyo, Japan` visible | | 6 | Entry card link | `href` points to `/tracker/2026-06-18.entry` | | 7 | Excerpt shown | Partial text of the body content visible | **Automation:** curl /tracker; grep for "QA Test Entry", "18 Jun 2026", "Tokyo", "Japan", "/tracker/2026-06-18.entry" --- ### TC-P.7: Entry detail page shows correct values | Step | Action | Expected Result | |---|---|---| | 1 | GET http://100.96.115.96:8081/tracker/2026-06-18.entry | Page loads (200) | | 2 | Page title | `QA Test Entry` in `

` | | 3 | Date header | `Thursday, 18 June 2026` (or locale equivalent) | | 4 | Location badge | `๐Ÿ“ Tokyo, Japan` | | 5 | Body content | Full text `This is the QA test body. Second sentence for length.` rendered | | 6 | No gallery | Photo gallery section absent (no photos were uploaded) | | 7 | Back link | `โ† Back to journal` link present, points to /tracker | **Automation:** curl /tracker/2026-06-18.entry; grep for "QA Test Entry", "Tokyo", "Japan", "This is the QA test body", "Back to journal" --- ### TC-P.8: Entry appears on map and mini-map | Step | Action | Expected Result | |---|---|---| | 1 | GET http://100.96.115.96:8081/tracker | Mini-map section visible | | 2 | Inspect FEED_ENTRIES JSON | Contains entry with `lat: "35.689487"`, `lng: "139.691711"`, `title: "QA Test Entry"` | | 3 | GET http://100.96.115.96:8081/map | Map page loads | | 4 | Inspect ENTRIES JSON | Contains same entry | **Automation:** curl /tracker and /map; grep FEED_ENTRIES and ENTRIES JSON for lat/lng values --- ### TC-P.9: Entry appears in stats | Step | Action | Expected Result | |---|---|---| | 1 | GET http://100.96.115.96:8081/stats | Page loads (200) | | 2 | Entries count | Shows `2` entries (existing test entry + new QA entry) | | 3 | Countries list | `Japan` and `Netherlands` both listed | **Automation:** curl /stats; grep entry count and country names --- ### TC-P.10: Duplicate date handling | Step | Action | Expected Result | |---|---|---| | 1 | Submit a second post with the same date `2026-06-18 10:00` | โ€” | | 2 | Observe result | Either: error shown, OR new entry created at a different slug | | 3 | Check filesystem | No silent data loss โ€” original entry intact | **Note:** `overwrite_mode: false` on add-page-by-form plugin should prevent overwrite. Behavior on conflict is to be documented here after first run. **Manual verification required:** Requires two submissions with same date --- ## Cross-cutting Tests ### TC-X.1: Nav links present on all pages | Page | Expected nav links | |---|---| | /tracker | Journal, Map, Stats | | /map | Journal, Map, Stats | | /stats | Journal, Map, Stats | | /tracker/2026-06-17.entry | Journal, Map, Stats | **Automation:** curl each page, grep for all three links --- ### TC-X.2: All pages return 200 | Page | Expected HTTP status | |---|---| | / (redirects to /tracker) | 200 or 302โ†’200 | | /tracker | 200 | | /tracker/2026-06-17.entry | 200 | | /map | 200 | | /stats | 200 | | /post | 200 (after login) or 302 (login redirect) | **Automation:** curl HTTP status checks --- ### TC-X.3: Mobile touch targets โ‰ฅ44px | Element | Expected min height/width | |---|---| | Nav links | 44px height | | Gallery thumbnails | 44px on shortest side | | Lightbox close/prev/next buttons | 44px | | Post form buttons | 44px height | | "Get Location" button | 44px height | | "Get Weather" button | 44px height | **Manual verification required:** Inspect computed CSS or measure visually on device --- ### TC-X.4: No JS errors in browser console | Page | Expected | |---|---| | /tracker | No console errors | | /map | No console errors (may have tile 404s for tiles not in viewport โ€” acceptable) | | /stats | No console errors | | /tracker/2026-06-17.entry | No console errors | **Manual verification required:** Open browser DevTools ---