Skip to content

Latest commit

 

History

History
195 lines (138 loc) · 11.4 KB

File metadata and controls

195 lines (138 loc) · 11.4 KB

Tests

Map date visibility and eyelid blink

Browser checks against a fresh production build cover desktop and mobile layouts, independent Future/Past/Other visibility, Show all, Hide all, and clearing filters. Hiding the last category starts the full-viewport CSS eyelids: all categories remain hidden through the closed pause, then only the last hidden category returns as the eyes reopen. Hide all restores the last currently visible category in display order. Check each category as the last hidden one, repeat the animation, verify keyboard focus stays on the trigger, and confirm Escape restores visibility immediately. Format/activity choices must survive the blink. Reduced motion uses an opacity fade without moving eyelids. Leaving the tab finishes the blink, and unmounting clears timers and keyboard/visibility listeners.

Forum sidebar

File: .github/scripts/forum-topics.test.mjs Run: node --test .github/scripts/forum-topics.test.mjs

Covers recent-activity sorting, feed limits, both Discourse tag formats, malformed responses, fixed-origin topic links, reply totals, avatar resolution, and relative timestamps. Browser checks should cover runtime loading, errors/retry, empty feeds, and square map layout.

Event list

File: .github/scripts/event-list.test.mjs Run: node --test .github/scripts/event-list.test.mjs

Covers calendar boundaries, Today/Tomorrow headings, ongoing and undated events, combined confirmation criteria, placeholder exclusion, and accent-insensitive multi-word search. Included in scripts/run-tests.sh.

Browser storage safety

File: .github/scripts/safe-storage.test.mjs Run: node --test .github/scripts/safe-storage.test.mjs Requires: Node built-ins only — no install needed.

These tests verify that safeStorage passes available localStorage reads and writes through while returning safe defaults when browser privacy settings make the localStorage property itself throw.


Event issue helpers

File: .github/scripts/event-issue-helpers.test.mjs Run: node --test .github/scripts/event-issue-helpers.test.mjs Requires: Node built-ins only — no install needed.

These tests cover the shared pure functions extracted into event-issue-helpers.mjs, which are used by both the new-event and edit-event intake scripts.

Function Cases
parseIssueSections Normal sections, _No response_ cleaning, empty body, \r\n normalization
isValidDate Valid date, missing leading zero, non-ISO format, out-of-range month/day, empty string
isValidTime Valid time, midnight, hour 25, missing colon, minute 60
isValidEmail Valid email, missing @, missing TLD, empty string
isValidHttpUrl http/https valid, ftp rejected, non-URL string, empty string
slugify Accent removal, lowercase+space→dash, leading/trailing dash strip, multiple dash collapse, special char removal
parseActivities Checked boxes, all unchecked, unknown activity filtered, case-insensitive [X]
parseOrganizers Plain names, name <email> suffix stripped, blank lines ignored, empty input
generateUniqueUid Length 7, hex chars only, not in existing set, added to set, multiple unique in sequence

New event intake script

File: .github/scripts/process-new-event-issue.test.mjs Run: node --test .github/scripts/process-new-event-issue.test.mjs Requires: Node built-ins + open-location-code at pcd-website/node_modules/. Runs the script as a child process against a real temp filesystem.

Case Expected
Valid new-event issue body valid=true, writes metadata.json with all fields including uid (7 hex chars)
Event page URL field present Value appears in metadata.json as event_page_url (regression for the Event website field-name bug)
Duplicate event directory valid=false, validation comment mentions the generated id
Issue body contains ### Event canonical ID heading valid=skip (guard against running on edit-event template)
Edit-event issue body (contains ### Event canonical ID and ### Plus Code (for map placement)) valid=skip (regression: edit-event body must not be processed as new event)
Issue body missing ### Plus Code (for map placement) and no ### Event canonical ID valid=skip (unrecognized template)

Edit event intake script

File: .github/scripts/process-edit-event-issue.test.mjs Run: node --test .github/scripts/process-edit-event-issue.test.mjs Requires: Node built-ins + open-location-code at pcd-website/node_modules/. Runs the script as a child process; sets up a real test event directory in the repo's events folder with beforeEach/afterEach cleanup.

Case Expected
Valid edit issue, event exists valid=true, pr_label=edit event, action_verb=updated on, metadata updated, uid and intake preserved
Blank full_description Existing content.md unchanged
All activities unchecked Existing event_activities preserved (checkbox prefill limitation)
Some activities checked event_activities overwritten with checked values
Event directory does not exist valid=false, validation comment mentions the missing event id
Missing ### Event canonical ID heading valid=skip (guard against running on new-event template)

data.json build output

File: .github/scripts/data-json.test.mjs Run: node --test .github/scripts/data-json.test.mjs Requires: npm run build must be run from pcd-website/ first — this test reads pcd-website/dist/data.json.

Case Expected
File exists and is valid JSON Passes without error
Top-level keys schema_version, generated_at, event_count, events all present
event_count vs events.length Equal
No primary_contact in any event Omitted (privacy)
No placeholder in any event Omitted (all feed entries are confirmed)
canonical_url shape Exactly https://day.processing.org/event/${id}-${uid}/
lat and lng Finite numbers on every event

Zines

Files: .github/scripts/zines.test.mjs, .github/scripts/zine-build.test.mjs, .github/scripts/process-new-zine-issue.test.mjs Run: node --test .github/scripts/zines.test.mjs, node --test .github/scripts/zine-build.test.mjs, and node --test .github/scripts/process-new-zine-issue.test.mjs Requires: The metadata suite uses the locally installed Astro dependency. The build suite owns a temporary fixture zine, builds the site, verifies emitted cover/PDF URLs and cleans up its fixture.

Suite Cases
zines.test.mjs Generic download schema, optional covers/languages, manual external downloads, identity/id uniqueness, and root-cover versus downloads/ asset validation
zine-build.test.mjs Published cards, ordering, emitted cover and mixed-format downloads, including same-named root/download images and downloadable JSON assets
process-new-zine-issue.test.mjs Attachment-only URL rules, GitHub HTML image embeds and signature-derived cover filenames, namespace-aware filename normalisation/collisions, size boundaries and limits, redirect allowlisting/hop limits, binary signatures, UTF-8/JSON validation, publication-ready file generation, metadata and maintainer-note preservation, order assignment/reuse, slug conflicts, template skipping, authoritative branch shape, and invalid/successful PR label transitions

Single-command test run

Run ./scripts/run-tests.sh from the repo root after installing dependencies (pcd-website already has node_modules/ from npm install). The script executes the helper, event and zine intake, plus-code, and zine metadata suites; runs the zine fixture build; then builds the Astro site (npm run build inside pcd-website/) before running data-json.test.mjs. Use this single command whenever you want to verify the full test battery end to end.


Plus Code functions

File: .github/scripts/plus-code.test.mjs Run: node --test .github/scripts/plus-code.test.mjs Requires: open-location-code — available locally at pcd-website/node_modules/open-location-code/ (no install needed). In CI it is installed to /tmp/script-deps/.

These tests cover isValidPlusCode and resolvePlusCode from .github/scripts/plus-code.mjs, which are used by the new-event intake script to validate and recover Plus Codes submitted via GitHub Issues.

isValidPlusCode

Pure function — no mocking needed.

Input Expected Reason
'8FW4V9H4+MC' true Valid full global code
'8FW4V9H4+MC7' true Valid 3-char suffix variant
'8FW4V9H4+MC ' true Trailing spaces are normalized
'8fw4v9h4+mc' true Lowercase is normalized
'V9H4+MC' false Short code — not a full global code
'NOTACODE' false No Plus Code structure
'' false Empty string

resolvePlusCode — fast path

Input is already a valid full code; no Nominatim call is made.

Input Expected
('8FW4V9H4+MC', '', '') { code: '8FW4V9H4+MC', note: null }
('8FW4V9H4+MC ', '', '') { code: '8FW4V9H4+MC', note: null } — spaces stripped
('8fw4v9h4+mc', '', '') { code: '8FW4V9H4+MC', note: null } — uppercased

resolvePlusCode — short code recovery

Nominatim is mocked to return Paris coordinates (~48.879188, 2.356063). The reference full code is 8FW4V9H4+MC (short form V9H4+MC, near 145 rue La Fayette, Paris).

Recovery tests assert:

  1. result.code === '8FW4V9H4+MC'
  2. result.note is non-null
  3. The decoded center lat/lon is within 0.001° of the Paris reference
Input Expected
('V9H4+MC', 'Paris', 'France') Recovers — city/country form fields used as location ref
('V9H4+MC,PARIS', '', '') Recovers — comma-separated city extracted from value
('V9H4+MC,PARIS,FRANCE', '', '') Recovers — comma-separated city and country extracted
('V9H4+MC, Paris, France', '', '') Recovers — spaces around commas stripped before extraction
('My code: V9H4+MC,PARIS', '', '') Recovers — arbitrary prefix text is ignored
('V9H4+MC', '', '') { code: null, note: null } — short code with no location reference

resolvePlusCode — ambiguous input

When a city name starts with OLC-valid characters (e.g. P in PARIS), the extraction regex cannot cleanly separate the short code from the city. This is a documented limitation.

Input Behavior
('V9H4+MCPARIS', '', '') V9H4+MCP is extracted (P absorbed into suffix). No location hint follows, so the result is not the correct Paris code.
('V9H4+MCPARIS,FRANCE', '', '') V9H4+MCP is extracted, FRANCE used as hint. Recovery may succeed but produces a code at the wrong location — not 8FW4V9H4+MC.

Supported formats to avoid this: use a comma separator (V9H4+MC,Paris) or provide city/country in the form fields.

resolvePlusCode — failure cases

Input Nominatim mock Expected
('NOTACODE', 'Paris', 'France') Returns Paris coords { code: null, note: null } — no extractable code
('V9H4+MC', 'Paris', 'France') Returns [] { code: null, note: null } — no geocoding result
('V9H4+MC', 'Paris', 'France') Throws { code: null, note: null } — fetch error caught
('', '', '') Returns Paris coords { code: null, note: null } — empty input