Add integration tests for the base website and ticket purchase flow - #50
Open
daedeloth wants to merge 12 commits into
Open
Add integration tests for the base website and ticket purchase flow#50daedeloth wants to merge 12 commits into
daedeloth wants to merge 12 commits into
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013HqprN6hPwwHLXeCRbGdgo
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013HqprN6hPwwHLXeCRbGdgo
Adds phpunit.integration.xml, bin/integration-tests.sh, and tests/Integration/IntegrationTestCase.php so integration tests run inside the docker-compose webserver container against a dedicated catlab_events_test database, never the dev database. HarnessTest verifies the DB connection name and that /status responds. Bumped mockery/mockery from 0.9.* to ^1.6 (composer.json/composer.lock): Laravel's RefreshDatabase trait mocks console output via Mockery on every artisan() call, and Mockery 0.9.11 (2015) generates invalid "?mixed" parameter syntax under PHP 8.5, causing a fatal error before migrate:fresh even runs. Nothing in the repo uses the Mockery API directly (tests use PHPUnit's createMock), so the bump is safe. Host Unit suite (7 tests) still passes after the bump. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013HqprN6hPwwHLXeCRbGdgo
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013HqprN6hPwwHLXeCRbGdgo
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013HqprN6hPwwHLXeCRbGdgo
Order::synchronize() unconditionally cancelled any order lacking a catlab_order_id. Free-ticket orders never receive a catlab_order_id (no payment API call is made for them), so simply loading or reloading the thanks page silently flipped every accepted free order to CANCELLED. Restrict the cancel-on-missing-id branch to orders still PENDING; accepted orders are left untouched. Covered by the new FreeTicketPurchaseTest integration test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013HqprN6hPwwHLXeCRbGdgo
Introduces FakeCatLabApiClient, FakeCatLabApiClientFactory and FakeEuklesClient, bound in IntegrationTestCase::setUp() so tests never hit the real CatLab Accounts or Eukles services. FreeTicketPurchaseTest exercises a full free-ticket registration end to end, including visiting the thanks page, and asserts the order stays ACCEPTED and exactly one confirmation email is requested. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013HqprN6hPwwHLXeCRbGdgo
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013HqprN6hPwwHLXeCRbGdgo
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013HqprN6hPwwHLXeCRbGdgo
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013HqprN6hPwwHLXeCRbGdgo
- Use explicit nullable types (?User) for CatLabApiClientFactory::forUser() and its test fake, since implicit nullable is deprecated on PHP 8.4+ and production runs 8.5. - Pin external-service env vars in phpunit.integration.xml so the container no longer inherits the developer's .env: fixed Eukles key/secret make EuklesEventSubscriber register deterministically against the fake client, and UiTDatabank credentials are blanked. Add an assertion in FreeTicketPurchaseTest that order confirmation is now reliably tracked via the faked Eukles client. - Add a PaidTicketPurchaseTest covering the payment-sync callback when the buyer's session/auth has been dropped, since real PSP callbacks arrive without one. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013HqprN6hPwwHLXeCRbGdgo
The default 3312 mapping collides with other local docker projects; the integration tests themselves use the internal network and are unaffected, but docker compose up refuses to start the container. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013HqprN6hPwwHLXeCRbGdgo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
HTTP-level integration tests proving the public site renders and the full ticket purchase flow works — free and paid — against a real MySQL 8 database with every external service faked. Runs inside the docker-compose
webservercontainer (production PHP) against a dedicatedcatlab_events_testdatabase, so dev data is never touched and no local PHP/DB setup is needed:Stacked on #49 (needs the PHP 8.5 image) — merge that first, then retarget/merge this.
What's covered (10 tests)
ACCEPTED, thanks page renders, confirmation email requested, no payment API involved, Eukles tracking fired (all via fakes).orders/{id}/syncflips the order toACCEPTED— exercised both authenticated and as a guest, locking in the unauthenticated-callback contract real PSP calls depend on.migrate:freshon a clean MySQL 8 every run — proves the migration chain end-to-end.Production changes (2, both deliberate)
CatLabApiClientFactoryseam — the three directnew ApiClient(...)sites (EventController, Order, SendEmail) now resolve a factory from the container so tests can bind a fake. Behavior identical in production.Order::synchronize()cancelled any order lacking acatlab_order_id; free orders never get one, and the thanks page callssynchronize(). It now only cancels orders stillPENDING. Side benefit: the unauthenticatedGET orders/{id}/synccan no longer flip an accepted or refunded order toCANCELLED(which re-fired cancellation email + UitPAS cancel).Also:
mockery/mockerydev-dependency bumped 0.9 → ^1.6 (0.9 fatals under PHP 8.5 inside Laravel'sRefreshDatabase; nothing in the repo uses the Mockery API directly).Deviations from the spec (documented)
events.startDate/endDatemoved to theevent_datestable (2021),description/event_typeare NOT NULL,requires_teamdefaults true — the fixtures trait adapts, with comments./processdirectly rather than walking select → confirm first;confirmRegisterand thePreparingOrderevent are not yet exercised.Known follow-ups (pre-existing, out of scope)
Order::synchronize()compares$this->status, which is not a column (always null) — the "don't go cancelled → pending" guard is dead code.Order::getEuklesAttributes()does$data['price']on a nullgetOrderData()result for orders without acatlab_order_id.Organisation::getRepresentedOrganisation()'s function-static cache makes some smoke-test outcomes order-dependent within one phpunit process.Verification
bin/integration-tests.sh: OK (10 tests, 36 assertions)vendor/bin/phpunit --testsuite Unit: OK (9 tests) — still DB-free🤖 Generated with Claude Code
https://claude.ai/code/session_013HqprN6hPwwHLXeCRbGdgo