Add WordPress integration test suite and CI - #2
Merged
Conversation
The plugin had no automated tests. Almost every interesting branch in it touches WordPress state — transients, options, template_redirect query conditionals, REST requests, cron — so the suite is integration tests against a real WordPress rather than mock-heavy unit tests. The CiteCue delivery API is faked at the wp_remote_get layer, which is the one place every outbound call passes through, so no test touches the network. WordPress core and its test library come from Composer, so setup is `composer install` plus an empty database. Testability change: Citecue_Proxy and Citecue_Llms_Txt each now split into a decide() that returns what should happen and the existing serve() that emits headers and exits. All the branching moved into decide(), which is behaviour-preserving — serve() previously ended the request, so nothing downstream could be asserted against it. Covers: crawler UA matching and registry refresh, request eligibility (feeds, previews, logged-in users, AJAX/cron, WooCommerce store pages), every delivery API outcome including stale-serve and cache eviction, the circuit breaker and the outbound lookup budget, llms.txt, ingest HMAC auth (replay, clock skew, rate limiting), ingest post/page behaviour (status cap, local-edit protection, trashed pushes), settings sanitation and the activation/cron/uninstall lifecycle. 211 tests. Product pushes need a real WooCommerce and run in a dedicated CI job; store-page exclusion rules run against a minimal stand-in, since whether WooCommerce exists is a process-wide fact rather than a per-test one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MbkhCSV8HnNwmTce9qoNpV
/llms.txt had neither of the two protections the crawler path has, and it is the one endpoint served to every visitor rather than only to bots: - A 404 (llms.txt switched off for the project in CiteCue) evicted the cached copy but recorded nothing, so every subsequent hit on the URL made a fresh outbound call. It is now negative-cached for 60s, matching the page path. - The per-minute lookup budget only covered the crawler path, so llms.txt traffic was uncapped and could also be used to sidestep the ceiling on the other path. The budget moved to Citecue_Cache — alongside the circuit breaker, the other transient-backed throttle — and both paths now share it. Same filter name, same default, so no behaviour change for existing installs beyond the wider coverage. On an exhausted budget llms.txt degrades like the crawler path: a cached body is still served, otherwise the request falls through to WordPress. README gains a Performance section and an outage section covering what a human visitor pays (nothing), what a crawler pays, and the recommendation to run a persistent object cache so cached bodies stay out of wp_options. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MbkhCSV8HnNwmTce9qoNpV
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.
What
Adds automated tests to a plugin that had none, plus CI, and fixes two
outbound-call gaps found while writing them.
217 tests, WordPress integration rather than mock-heavy units — almost
every branch in this plugin touches WordPress state (transients, options,
template_redirectconditionals, REST, cron). The CiteCue delivery API isfaked at the
wp_remote_getlayer, the single choke point every outboundcall passes through, so no test touches the network. WordPress core and its
test library come from Composer: setup is
composer installplus an emptydatabase.
Coverage
and registry refresh (version floor, bundled-token floor, junk payloads)
AJAX/cron, and the WooCommerce store pages
and the "404 evicts a previously cached body" rule
and that unsigned junk cannot exhaust the budget
conflicts, sanitisation
Production changes
Testability.
Citecue_ProxyandCitecue_Llms_Txteach split into adecide()returning what should happen and the existingserve()that emitsheaders and calls
exit. Behaviour-preserving — all branching moved intodecide(), which is what the tests drive.Two fixes on the llms.txt path, the one endpoint served to every visitor
rather than only to bots:
recorded nothing, so every subsequent hit made a fresh outbound call. Now
negative-cached for 60s, matching the page path.
uncapped — and usable to sidestep the ceiling on the other path. The budget
moved to
Citecue_Cachealongside the circuit breaker, and both paths nowshare it. Same filter name and default, so no change for existing installs
beyond the wider coverage.
CI
Static checks (
php -l, WPCS, PHPCompatibility) plus the suite on PHP7.4/8.2/8.4 against current WordPress, PHP 7.4/8.3 against WordPress 5.9/6.5,
and a separate job against a real WooCommerce.
WordPress 5.9 rather than the plugin's declared 5.8 floor: WordPress's own
test library only gained PHPUnit 9 support in 5.9, and 5.8 hard-fails with
"compatible with PHPUnit up to 7.x". 5.8 support rests on the
PHPCompatibility checks and manual verification.
Not covered
class-citecue-admin.php(564 lines) — nonce checks and the test-connectionhandler need the same
decide()/emit split, since they arewp_dieandredirect-and-exit throughout.
tests/cases/test-ingest-products.phpis written but was never executed:it needs a real WooCommerce, and wordpress.org was unreachable from the
environment it was written in. The
test-woocommerceCI job is its firstreal run — expect to iterate there.
🤖 Generated with Claude Code