Skip to content

Add comprehensive regression-test battery across PHPUnit, Jest, and E2E#450

Merged
cbravobernal merged 7 commits into
trunkfrom
tests/full-coverage-battery
Jun 12, 2026
Merged

Add comprehensive regression-test battery across PHPUnit, Jest, and E2E#450
cbravobernal merged 7 commits into
trunkfrom
tests/full-coverage-battery

Conversation

@cbravobernal

Copy link
Copy Markdown
Contributor

This PR adds a comprehensive regression-test battery across the three suites, targeting the areas that previously had no coverage at all — the code paths most at risk during backports and feature work.

What's added

PHPUnit: 2261 → 2788 tests (+527 tests, +2074 assertions)

All integration-style against in-process WordPress (WorDBless), minimal mocking:

  • Public template API (tests/php/includes/api/, 107 tests): get_field/the_field/get_field_object(s)/update_field/delete_field across post, options, user contexts; the full row API (have_rows/the_row/add_row/update_row/delete_row/sub-field variants) including nested repeaters, flexible content layouts, and loop-state handling; acf_get_valid_post_id and term helpers.
  • Upgrades & revisions (test-upgrades.php, test-revisions.php, 42 tests): 5.0.0 field-group migration, 5.5.0 termmeta migration, upgrade boundaries, revision save/restore round-trips via real wp_restore_post_revision().
  • Local JSON / local fields / local meta (55 tests): real .json file save/load/delete sync, malformed-file handling, local field registration/dedup/removal, acf_setup_meta/acf_reset_meta.
  • Meta storage backends + ACF_Data (tests/php/includes/meta/, test-class-acf-data.php, 50 tests): Post/User/Term/Comment/Option backends through both class API and typed-ID routing, slashing/serialization edge cases, every public ACF_Data method.
  • Validation + options pages (59 tests): acf_validate_save_post with simulated form $_POST, filter contracts, nested repeater/group validation; legacy acf_options_page class API and UI↔code interplay.
  • Abilities (tests/php/includes/abilities/, 58 tests): registration surface (48 abilities), CRUD callbacks for field groups/post types/UI options pages, plus schema-robustness repros (see "Findings" below).
  • Blocks PHP (tests/php/includes/blocks/, 63 tests): acf_register_block_type validation, block.json registration, real do_blocks() renders, bindings get_value resolution, auto-inline-editing DOM rewriting.
  • AJAX handlers, Site Health, misc (93 tests): check-screen/query-users/user-setting/local-json-diff handler responses, Site Health data, user/post functions, legacy locations, taxonomy walker.

Jest: 772 → 946 tests (+174, 31 → 36 suites)

Hook/EventManager system, core acf utilities, serialization (incl. flexible-content normalization), the legacy compatibility layer (loaded with production sloppy-mode semantics), and unsaved-changes warning — real DOMPurify/localStorage, only jQuery stubbed.

E2E (Playwright): +4 tests, 2 flaky specs fixed, new isolation utility

  • New specs: UI options page lifecycle, field group duplication (verifies new unique field keys), user profile fields (profile.php + user-edit.php).
  • tests/e2e/plugins/scf-test-utilities.php: REST purge endpoint for SCF internal posts, fixing order-dependent failures (a stray malformed field bricks scf/list-fields for the whole suite).
  • field-type-url: explicit saveDraft() before preview to avoid racing the metabox save.

Findings documented by tests (not fixed here — tests assert current behavior with NOTE comments)

The strongest one: scf/list-fields fails its own output schema on any site with code-registered fields (local fields have ID = 0, violating the schema's minimum: 1), and a single unknown-type field likewise invalidates the entire listing (test-scf-list-fields-schema-robustness.php). Others: Meta/Option.php unserialize/slashing inconsistencies, acf_rendered_block() preview leaking acf_setup_meta() state, local-meta shadowing unlisted meta names, Site Health 'PHP' !== 'php' count bug, acf_get_users() undefined-key warning. Issues to follow.

Verification

  • composer test:php: OK (2788 tests, 6371 assertions)
  • composer test:phpstan: clean
  • npm run test:unit: 36 suites / 946 tests passed
  • Full E2E suite: all specs passing (see PR checks)
  • phpcs clean on all new PHP files; wp-scripts lint-js clean on all new JS/TS files

Closes

Use of AI Tools

This PR was authored by Claude Code (Claude Fable 5) under human direction: the test plan, area prioritization, conventions, and review of all findings were human-supervised; the test code was AI-generated and verified by running the full suites (PHPUnit, PHPStan, Jest, Playwright) to green. Behavioral findings were documented rather than "fixed" to keep this PR purely additive.

PHPUnit 2261 -> 2788 tests (+527, +2074 assertions) covering previously
untested flows: public template API (get_field/update_field/have_rows row
API), upgrade migrations, revision save/restore, local JSON/fields/meta,
Meta storage backends, ACF_Data, validation, options pages, abilities
(incl. schema-robustness repros), blocks PHP (registration/render/
bindings), AJAX handlers, Site Health, and misc functions.

Jest 772 -> 946 tests (+174) for the hooks system, core utilities,
serialization, the legacy compatibility layer, and unload warnings.

E2E: +4 tests (options page UI lifecycle, field group duplication, user
profile fields), a REST purge utility plugin for suite isolation, and
fixes for two order/timing-dependent specs (abilities-fields, url
preview race).

Known-behavior findings are documented in-test with NOTE comments and
left unfixed to keep this change purely additive.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

Core Committers: Use this line as a base for the props when committing in SVN:

Props cbravobernal.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

PHP 7.4 raises E_NOTICE for undefined array keys (PHP 8 raises
E_WARNING) and the notice is not converted to a Throwable, so the
try/catch capture never fired. Capture via an explicit error handler
covering both error types instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
cbravobernal and others added 5 commits June 12, 2026 11:00
Review feedback: tests that assert possible-bug behavior as green
expectations now reference the GitHub issues tracking each finding
(#453-#461), so future fixes read as intentional, not regressions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…est.step structure

- scf-test-get-field-user.php reads ?scf_test_user_id (absint-validated),
  falling back to the queried author, removing the user_1 assumption;
  user-profile-fields.spec.ts derives the real admin ID via /users/me.
- Purge endpoint renamed to /purge-internal-posts to match what it
  deletes; single shared purgeScfInternalPosts() helper in
  field-helpers.js replaces four duplicated copies.
- Large lifecycle tests restructured with test.step() (duplication,
  options page, post-type integration flow) with small local helpers
  for repeated workflows; assertions unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Seeded, CI-reproducible fuzz/property tests (SCF_FUZZ_ITERATIONS to crank
locally; failing seed + input embedded in assertion messages):

- PHP (tests/php/includes/fuzz/): post-id decoding, value round-trips,
  validation, the JSON schema validator, local JSON file ingestion,
  block.json registration, and escaping/sanitization helpers — including
  a security property that acf_maybe_unserialize() never instantiates
  real objects (verified: object-injection payloads decode only to
  __PHP_Incomplete_Class placeholders).
- JS (tests/js/fuzz/): acf.serialize, flexible-content normalization,
  and escaping utilities under a seeded PRNG.

Adds 27 PHPUnit + 5 Jest tests (~3s). Crashes surfaced on hostile input
are documented in-test with NOTE comments (generators constrained) and
reported for follow-up issues; no source was modified.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A NUL byte in the schema name makes it an invalid filesystem path, so
load_schema()'s file_exists() raised a TypeError on PHP 7.4 (PHP 8
returns false), failing the property on that runtime. NUL in a schema
identifier is not a realistic input; the property exercises the
validator's unknown-schema handling, so strip NUL like the data-key
generator already does.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@cbravobernal cbravobernal added this to the 6.9.0 milestone Jun 12, 2026
@cbravobernal cbravobernal merged commit 8151b31 into trunk Jun 12, 2026
20 checks passed
@cbravobernal cbravobernal deleted the tests/full-coverage-battery branch June 12, 2026 11:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant