Skip to content

test(tooling): harden loyalty e2e — unique-phone isolation + PHPStan level 5 on tools - #59

Merged
Drago37 merged 2 commits into
developfrom
feature/loyalty-e2e-isolation
Sep 23, 2026
Merged

Drago37 merged 2 commits into
developfrom
feature/loyalty-e2e-isolation

Conversation

@Drago37

@Drago37 Drago37 commented Sep 23, 2026 •

Copy link
Copy Markdown
Owner

Two follow-ups surfaced by the 1.4.0 production e2e sweep, both in test tooling (tools/, never deployed). Kept in one PR because they touch the same e2e cores.

#58 — Isolate loyalty e2e with a unique phone per run

The loyalty e2e reused fixed test phones (0600000000/0600000001). Loyalty aggregates by identity (email OR phone), and autoLink() ties a fixed phone to the first run's email for good — so on a persistent DB (prod, local dev), a run interrupted before cleanup leaves residual ledger data that later runs re-aggregate, inflating baselines (the 1.4.0 sweep had to purge it by hand).

  • Every run draws a unique test phone, so one run's identity can never link to another's.
  • The three prod-runnable cores (e2e-loyalty-prod, e2e-offered-pot, e2e-exclusion) also clear the identity-link rows for the test contact in teardown (the finally only deleted ledger rows).

#57 — Analyse tools/ with PHPStan (level 5)

The prod-only e2e cores were never run locally nor in CI, so a drifting signature rotted silently — the loyalty prod core had called GetCustomerLoyaltyHandler with an obsolete Clock argument since 1.3.0, only surfacing as an empty prod response during the sweep.

  • New phpstan-tools.neon.dist analyses tools/ at level 5 (argument-type checking → catches exactly that class of rot) instead of the theme's level max, which would drown the procedural glue under mixed noise. src/ + inc/ stay at level max.
  • Committed WP-CLI stub (the stub package isn't installable in this environment); wordpress/woocommerce stubs and inc/ scanned for symbols.
  • 44 findings handled: real fixes (add_order_note int, set_total string, narrow WC_Order_Item before get_total, drop redundant nullsafe) + a small documented ignoreErrors block for genuine PHPStan blind spots (the deploy-time REPLACE_WITH_TOKEN guard, $GLOBALS mail arrays populated by hooks, a reference-captured property) — never the rot class.
  • composer stan now runs both configs; CI enforces it.

Verified: the 14 touched local e2e targets all pass, and composer stan is green on both configs.

Fixes #58
Fixes #57

🤖 Generated with Claude Code

The loyalty e2e reused fixed test phones (0600000000/0600000001). Loyalty
aggregates by identity (email OR phone) and autoLink() ties a fixed phone to the
first run's email for good, so on a persistent DB (prod, local dev) a run
interrupted before its cleanup leaves residual ledger data that later runs
re-aggregate — inflating baselines (the 1.4.0 prod sweep had to purge it by hand).

Each run now draws a unique test phone, so a run's identity can never link to
another run's. The three prod-runnable cores (loyalty-prod, offered-pot,
exclusion) additionally clear the identity-link rows for the test contact in
their teardown (the finally only deleted ledger rows before), so the links table
no longer accumulates. Verified: e2e-offered-pot-local passes 24/24 twice in a
row on a persistent DB, and the full local loyalty suite stays green.
@Drago37 Drago37 added the enhancement New feature or request label Sep 23, 2026
@Drago37 Drago37 self-assigned this Sep 23, 2026
The prod-only e2e cores (tools/*-prod.php) were never run locally nor in CI, so a
drifting constructor/method signature rotted silently — the loyalty prod core had
called GetCustomerLoyaltyHandler with an obsolete Clock argument since 1.3.0, only
surfacing as an empty prod response during the 1.4.0 e2e sweep.

tools/ is procedural WordPress/WP-CLI glue (global $wpdb, WC getters returning
mixed): holding it at the theme's level max would drown the signal under hundreds
of mixed warnings. A dedicated phpstan-tools.neon.dist analyses it at level 5 — the
level that checks argument types, so it catches exactly that class of rot — without
the mixed noise. src/ and inc/ stay at level max.

- Add a small committed WP_CLI stub (php-stubs/wp-cli-stubs is not installable here)
  and scan wordpress/woocommerce stubs; scan inc/ for its luziapi_* helpers.
- Fix the real findings: add_order_note expects int (0/1, not bool), set_total
  expects string, narrow WC_Order_Item to WC_Order_Item_Product before get_total,
  drop redundant nullsafe accesses PHPStan proved non-null.
- A small, documented ignoreErrors block covers genuine PHPStan blind spots on test
  glue (the deploy-time REPLACE_WITH_TOKEN guard, $GLOBALS mail/attachment arrays
  populated by hooks, a reference-captured property) — never the rot class.
- composer stan now runs both configs; CI (composer stan) enforces it.

Fixes #57
@Drago37 Drago37 changed the title test(loyalty): isolate loyalty e2e with a unique phone per run test(tooling): harden loyalty e2e — unique-phone isolation + PHPStan level 5 on tools Sep 23, 2026
@Drago37
Drago37 marked this pull request as ready for review September 23, 2026 13:39
@Drago37
Drago37 merged commit a789cc7 into develop Sep 23, 2026
6 checks passed
@Drago37
Drago37 deleted the feature/loyalty-e2e-isolation branch September 23, 2026 13:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant