Add FunctionalJavascript coverage for the place map and calendar JavaScript

What this adds

Ten browser tests for the place picker, in one class. Tests only: no production file is touched. The picker is the headline way to buy a seat and none of it is reachable from PHP, so until now the whole interaction layer was unguarded.

Scope is the place map, as the issue proposes; the calendar follows in its own MR.

The two bugs the issue was filed over

Both are guarded, and reading the code corrected my understanding of the first one:

  • #3611882 was pointer capture on the viewport swallowing the place button's click, so a plain click booked nothing. (The comment at venue-map.js:1250-1252 records why the pointer listeners moved to the window.) So the guard is two-sided: testSeatIsBookedOnClick proves a plain click still books, and testDraggingTheMapBooksNothing proves a pan does not.
  • #3611904 was the panel controls disappearing once the selection list grew. testSelectionControlsSurviveLongList takes six seats and asserts Remove all, the total and the last row's tariff control are visible, not merely present. The elements existed throughout, which is exactly why no PHP test could have caught it.

The rest

testSeatIsReleasedOnSecondClick (and that focus returns to the seat, so the keyboard does not lose its place), testSeatIsReleasedFromThePicksList, testPoolUnitsAreTakenAndReturned (the counter and "N left" both move, and the minus button is disabled at zero), testRemoveAllClearsSeatsAndPools (the only operation that touches both at once, so the highest value per round trip), testTotalSumsSeatsAndPoolUnits, testChangingTariffUpdatesTotal, and testSeatTakenAfterLoadFlipsToTaken — that last one holds the seat from PHP after the page is drawn, so the 409 path runs for real with no stubbing.

Two things worth a reviewer's attention

Every live-region assertion has to poll. announce() (venue-map.js:572-577) blanks the region and refills it 30ms later on purpose, so a screen reader re-announces a repeated message. Reading it straight after an action finds the blank. Two tests failed on this first time and four others were passing by luck; all six now go through one assertAnnounced() helper. Please do not "simplify" them back to elementTextContains.

The drag test fakes the gesture rather than performing it. WebDriver's drag moves between element centres and does not reliably produce the click that the guard protects, so the test dispatches pointerdown / pointermove past the 4px threshold / pointerup and then clicks. It also books a different seat afterwards and waits for that, because otherwise "nothing happened" would assert true before a booking could have landed anyway.

Fixture

One private hall(), following house style (yoyaku has no shared test trait and every existing fixture is a private method): a background SVG whose sprite is a real shape, so seats cannot draw invisibly and let an assertion pass against an empty hall; six drawn seats in a row; a pooled area declaring capacity ten and naming no shape on the plan, because an untouched area that has a shape is sold from the plan and keeps its panel block hidden; and two priced tariffs on one grade so a pick has something to switch to.

The payment stack (yoyaku_order, kessai, yoyaku_payment) is installed for one reason: a tariff's price comes from the payment policy resolver, and with no price the total never renders, so the assertion that seats and pooled units are summed would have nothing to read.

Runs

Ten tests, 87 assertions, two clean consecutive runs at 181s and 240s before pushing, because a browser test that passes once is not yet known to be stable. The whole FunctionalJavascript directory is 12 tests, 100 assertions, 230s alongside the two from [#3614076].

No production changes, so there is nothing for eslint or phpstan that was not already there, no new translatable strings, and nothing to document: fr.po and docs/ are deliberately untouched.

Follow-up filed

op: category failing is handled by nothing: the endpoint answers 409 {ok: false, error: 'Not held.'} and the select's handler checks r.ok and then does nothing, so the dropdown keeps showing a tariff the server refused. testChangingTariffUpdatesTotal covers the happy path only and says so.

Not in scope

The check-in scanner. It drives a camera through getUserMedia, which needs fake-media Chrome flags and a fabricated QR frame; a flaky test that later gets disabled is worse than none, so it belongs in its own issue with its own setup.

Merge request reports

Loading
Loading