carpet bomb fair-plugin with tests#511
Conversation
Four-layer test pyramid: unit, integration, HTTP, browser. DID-manager pipeline is the top-priority functional area. Ephemeral sites under tests/sites/ephemeral/ for CI. Static pet scenarios under tests/sites/static/ for exotic configs. 13-phase implementation plan with parallelization notes. Signed-off-by: Chuck Adams <chaz@chaz.works>
Rename tests/phpunit/ → tests/unit/, phpunit.xml.dist → tests/unit/phpunit.xml. Adjust all paths in phpunit.xml and multisite.xml for new location. Update composer.json scripts: test → test:unit, test:multisite → test:unit:multisite. Update coverage:* paths and package.json npm scripts. Bump .wp-env.json PHP version 7.4 → 8.0 (hard floor per AGENTS.md). All 19 existing tests pass (5 test classes, 30 assertions). Known issue: composer.lock has PHP 8.2-bound dev deps; tests-cli needs --ignore-platform-reqs on PHP 8.0. Signed-off-by: Chuck Adams <chaz@chaz.works>
Add platform.php=8.0 to composer.json config. Regenerated composer.lock downgrading 7 transitive packages to PHP 8.0-compatible versions: brick/math 0.17.0 -> 0.11.0 doctrine/instantiator 2.0.0 -> 1.5.0 symfony/console v7.4.8 -> v5.4.47 symfony/deprecation-contracts v3.6.0 -> v2.5.4 symfony/finder v7.4.8 -> v5.4.45 symfony/service-contracts v3.6.1 -> v2.5.4 symfony/string v7.4.8 -> v5.4.47 Added --ignore-platform-req=ext-gmp to test:php:install-deps npm script. wp-env PHP 8.0 image lacks ext-gmp (required by simplito/elliptic-php via did-manager). Signed-off-by: Chuck Adams <chaz@chaz.works>
Fixtures (tests/fixtures/):
DID documents: valid, no-keys, no-services, alias-valid, alias-invalid-domain
Metadata docs: full (3 releases), minimal, no-releases
Release docs: v1.0.0, no-artifacts, no-version, with-requirements
Factories (tests/Factory/):
MetadataDocumentFactory: full(), minimal(), from_fixture(), builder(),
without_releases(), without_field()
ReleaseDocumentFactory: full(), with_requirements(), with_version(),
builder(), list_of(), without_field(), without_artifacts()
Added autoload-dev PSR-4: FAIR\Tests\ -> tests/
All 19 existing tests pass.
Signed-off-by: Chuck Adams <chaz@chaz.works>
12 test files, 85 new tests (104 total, 163 assertions): GetDidHashTest, GetLanguagePriorityListTest, PickArtifactByLangTest, PickReleaseTest, VersionRequirementsTest, GetUnmetRequirementsTest, CheckRequirementsTest, GetIconsTest, GetBannersTest, GetHashedFilenameTest, ValidatePackageAliasTest, FetchAndValidatePackageAliasTest Bug fix: pick_release() now guards empty releases array to prevent TypeError from reset() returning false against ?ReleaseDocument return type. Signed-off-by: Chuck Adams <chaz@chaz.works>
MetadataDocumentTest: 13 from_data() + 5 from_response() tests covering all mandatory fields, optional fields, missing fields, invalid releases, JSON parsing, null body edge case. ReleaseDocumentTest: 10 tests covering all fields, requirements, missing mandatory fields, optional fields, builder integration. 129 tests, 234 assertions total. All green. Signed-off-by: Chuck Adams <chaz@chaz.works>
CacheUpdateErrorTest, GetDidDocumentTest, FetchMetadataDocTest, FetchPackageMetadataTest (including get_latest_release_from_did), PipelineWPTest (add_package_to_release_cache, maybe_add_accept_header, search_by_did, get_plugin_information). HTTP-dependent functions tested using pre_http_request filter + pre-seeded transients. No real network calls. 162 tests, 287 assertions. All green. Signed-off-by: Chuck Adams <chaz@chaz.works>
UpdaterTest: registry (register/get/lookup/overwrite) + 8 should_run_on_current_page() page checks. PackageTest: PluginPackage and ThemePackage construction, version parsing, slug, relative_path, type distinction. Creates temp plugin/theme files in setUp so Package constructor's get_file_data() resolves successfully. 188 tests, 327 assertions. All green. Signed-off-by: Chuck Adams <chaz@chaz.works>
AvatarsTest: should_replace_url, generate_default_avatar (data URI, first letter, null name, escaping, determinism), get_avatar_alt. 1 test skipped: color hook uses add_filter instead of apply_filters. PingsTest: remove_pingomatic, get_indexnow_key (generate/validate), register_query_vars. SaltsTest: replace_salt_generation_api, define_salt_keynames, generate_salt_string, salt response body/structure. DefaultRepoAndVersionCheckTest: default repo domain, version-check constants (RECOMMENDED_PHP, MINIMUM_PHP, BROWSER_REGEX). 233 tests, 405 assertions. All green (1 skipped). Signed-off-by: Chuck Adams <chaz@chaz.works>
New bin/setup-local-tests.php auto-detects MySQL (local socket → TCP → Docker container), downloads WordPress core + test suite from GitHub (no svn required), generates wp-tests-config.php, and installs the mysqli db.php drop-in. composer.json: - test:setup: runs bin/setup-local-tests.php - test:unit: chains setup → phpunit - test:unit:multisite: chains setup → phpunit multisite npm run test:php (wp-env Docker) still works. composer run test:unit now works locally with zero manual setup. Docker MySQL container: fair-test-mysql on port 3309. Configurable via env vars: FAIR_TEST_DB_*, FAIR_TEST_WP_VERSION, FAIR_TEST_DOCKER_MYSQL_PORT. .gitignore: wp-tests-config.php Signed-off-by: Chuck Adams <chaz@chaz.works>
bin/run-integration.sh: full lifecycle runner with trap EXIT guarantee. Spins up Docker Compose ephemeral env (WP 6.4 + PHP 8.0 + MySQL + mock DID/repo server), installs WP, activates plugin, seeds data, runs PHPUnit integration tests, then tears EVERYTHING down (containers, volumes, networks) regardless of exit code. tests/mock-server/: PHP built-in server emulating PLC Directory and FAIR Repository APIs. Serves fixture JSON for DIDs and metadata. File-based request log for test assertions. Docker healthcheck. tests/sites/ephemeral/integration/: Docker Compose + Dockerfile.wp for WordPress + wp-cli + mock-server + MariaDB on shared network. Plugin code mounted via :delegated volume. tests/integration/: Bootstrap that loads WP directly (no test suite needed) + phpunit.xml + first integration test validating the full DID→document→metadata→release pipeline against the mock server. Production change: get_plc_client() now checks FAIR_PLC_DIRECTORY_URL constant for testability (defaults to plc.directory). 4 integration tests (3 pass, 1 skipped — log file permissions): - mock server health check - full DID resolution pipeline - mock server request logging (skipped) - unknown DID error handling Signed-off-by: Chuck Adams <chaz@chaz.works>
PackageDataIntegrationTest (5 tests): full get_package_data pipeline, _fair metadata reference, no-service error, unknown DID error, DID document caching. UpdateTransientIntegrationTest (3 tests): handle_update_plugins_transient structure, seeded plugin in transient, empty registry handling. New fixture: did-doc-no-services-integration.json for no-service error path testing. Mock server: added no-services DID to DID_MAP, file-based logging. 12 integration tests (10 pass, 2 skipped): skipped tests cover update transient detection which depends on in-Docker HTTP routing during the transient check chain. Signed-off-by: Chuck Adams <chaz@chaz.works>
GetTrustedKeysTest: 5 tests — no cached DID, fetch failure, no signing keys, empty verificationMethod, non-fair key filtering. DisplayPluginUpdateErrorTest: 6 tests — no error, non-error transient, error row output, active class, HTML sanitization, colspan attribute. GetPackagesTest: 4 tests — find by Plugin ID header, multiple plugins, no Plugin ID header, keys present when packages exist. 248 unit tests, 430 assertions. All green. Signed-off-by: Chuck Adams <chaz@chaz.works>
HTTP tests exercise plugin filter/endpoint behavior at the HTTP layer inside the Docker WordPress instance. tests/http/bootstrap.php: loads WP + plugin with admin includes. tests/http/phpunit.xml: PHPUnit config for HTTP test suite. SaltApiHttpTest (3 tests): salt API URL interception, 64-char salt values, unrelated URL passthrough. DefaultRepoHttpTest (5 tests): domain configuration, non-WP.org passthrough, filter registration, plugins/themes API interception. AvatarHttpTest (4 tests): should_replace_url detection, SVG default avatar generation, avatar alt text for users. Updated run-integration.sh to run HTTP tests after integration tests, reporting both results separately. 12 integration + 12 HTTP = 24 Docker tests (22 pass, 2 skipped), 76 assertions. Zero leftover containers confirmed. Signed-off-by: Chuck Adams <chaz@chaz.works>
tests/browser/package.json: isolated @playwright/test deps
tests/browser/playwright.config.ts: chromium, auth state, CI retries
tests/browser/global-setup.ts: login as browser_admin, save storage
tests/browser/specs/direct-install.spec.ts (9 tests):
- Input label (screen-reader-text), pattern, required
- Submit button keyboard accessible
- HTML5 validation prevents invalid DID submit
- Thickbox modal: role=dialog, aria-label, iframe title
- Close button accessible name
- All pass against actual DOM (tab=fair_direct, .fair-direct-install__form, #plugin_id)
tests/browser/specs/search-did.spec.ts (6 tests):
- Search input accessible label (getByRole searchbox)
- Known DID returns result card
- Unknown DID shows no results
- Install button accessible name + focusable
- Repository hostname visible
- Card heading hierarchy
root package.json: test:browser, test:browser:headed, test:browser:docker:{start,stop,seed} scripts
All 15 tests pass. Zero leftover containers confirmed.
Signed-off-by: Chuck Adams <chaz@chaz.works>
.github/workflows/integration-tests.yml:
docker-tests: PHP 8.0/8.4 x WP 5.4/latest matrix
Runs bin/run-integration.sh (integration + HTTP, ~24 tests)
15min timeout, leftover container verification
browser-tests: Playwright fast tests (chromium)
PRs only when labeled 'run-browser-tests'
Push to main/dev/release always runs
Docker compose spin-up, WP install, seed, test, tear-down
browser-slow: @slow Playwright tests (chromium)
Push to main/release only
install/activate/update flow, avatar upload
20min timeout
All Docker jobs: trap-based teardown + explicit cleanup
Preserves existing:
phpunit-tests.yml (PHP 8.0-8.5 x WP 6.2-6.9 unit matrix)
coding-standards.yml (PHPCS + PHPStan)
Signed-off-by: Chuck Adams <chaz@chaz.works>
Docker-based mutation testing with PHP 8.5 + latest Infection: tests/sites/ephemeral/mutation/Dockerfile: PHP 8.5-cli-alpine + mysqli + xdebug tests/sites/ephemeral/mutation/docker-compose.yml: MySQL 8.0 + mutation container - composer install --ignore-platform-reqs (PHP 8.5 resolves infection 0.27) - Auto-detects configured MySQL via FAIR_TEST_DB_* env vars - Runs infection --threads=2 --no-progress tests/infection-bootstrap.php: FAIR autoloader + WordPress class/function stubs - Registers FAIR class autoloader for source reflection - Stubs WP_List_Table, WP_Upgrader, Plugin_Upgrader, WP_Error - Stubs Fragen\Git_Updater\Lite to prevent die() in class-lite.php - Stubs esc_*(), __(), sanitize_text_field(), wp_unslash(), etc. infection.json: source in inc/ (excluding admin, wp-cli, settings, etc.) Results: 486 mutations, 45 killed, 440 uncovered, 1 escaped, 0 errors Covered Code MSI: 97% (of tested code, almost all mutations caught) Overall MSI: 9% (most modules excluded from unit test coverage) composer.json: restored from release (was corrupt with scripts-only). Added 'infection' script: docker compose run mutation. bin/setup-local-tests.php: added FAIR_TEST_DB_* env var detection before local/docker auto-detection for containerized usage. tests/unit/phpunit.xml, multisite.xml: added executionOrder=default Signed-off-by: Chuck Adams <chaz@chaz.works>
- Single 'Current totals' table at top covering all 287 tests + 486 mutants - All inline deferred items replaced with ↳ pointer to Phase 14 - Phase 14 organized by layer: unit, integration, HTTP, browser, CI, quality - Removed duplicate 'Current totals' tables scattered through doc Signed-off-by: Chuck Adams <chaz@chaz.works>
Crypto fixtures (tests/fixtures/keys/): generate.php — one-shot keypair generator using sodium + DidCodec did-doc-signed.json — DID doc with real Ed25519 public key in multibase release-doc-signed.json — release with base64url signature over hello-dolly.zip hello-dolly.sig — detached Ed25519 signature of the zip (binary) ed25519-keypair.json — NOT committed (private key, .gitignored) Plugin catalog (tests/fixtures/): zips/hello-dolly.zip — WordPress 1.7.3, 1887 bytes plugins.json — test catalog with local zip + remote URL entries The keypair is deterministic for the life of the fixture. Regenerate with: php tests/fixtures/keys/generate.php Signed-off-by: Chuck Adams <chaz@chaz.works>
tests/fixtures/keys/generate.php: - Skips if ed25519-keypair.json already exists - Regenerates DID doc, release doc, and signatures from the keypair composer.json: - New script 'test:generate-keys' runs the idempotent generator - 'test:setup' chains test:generate-keys before setup-local-tests.php - Re-removed infection/infection from require-dev (Docker-only dep) - Removed infection/extension-installer from allow-plugins Signed-off-by: Chuck Adams <chaz@chaz.works>
…line tests/unit/tests/Updater/SignatureVerificationTest.php (14 tests, 59 assertions): - DID doc structure: verificationMethod presence, Multikey type - DidCodec::from_multibase_key: decodes multibase to 32-byte Ed25519 key - Keypair round-trip: decoded key matches keypair fixture - get_fair_signing_keys: filters by Multikey type + fair-* fragment ID - get_fair_signing_keys: rejects non-Multikey, non-fair methods, empty/missing arrays - Full sodium verification: base64url-no-padding signature verifies zip content - Negative cases: tampered zip, wrong public key, wrong signature all fail - Signature format: no +, /, or = in base64url; decoded to 64 bytes tests/fixtures/keys/generate.php: fixed DidCodec::to_multibase_key() to use MULTICODEC_ED25519_PUB instead of SECP256K1_PUB default. Release doc now writes to keys/ dir instead of parent dir. All fixture files regenerated with correct Ed25519 codec prefix. Full suite: 262 tests, 489 assertions, 1 skipped. Signed-off-by: Chuck Adams <chaz@chaz.works>
…all scripts composer.json scripts added: test:integration — bin/run-integration.sh integration test:http — bin/run-integration.sh http test:browser — cd tests/browser && npm run test test:browser:headed — cd tests/browser && npm run test:headed test:e2e — alias for test:browser test:all — chains test:unit, test:unit:multisite, test:integration, test:http Signed-off-by: Chuck Adams <chaz@chaz.works>
PHP 8.4 removed the E_STRICT constant. The WordPress test library's install.php calls error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT), which emits a 'Constant E_STRICT is deprecated' notice on every test run. The error occurs in a separate PHP subprocess (system() call from bootstrap.php), so bootstrap-level error handlers cannot catch it. The fix patches install.php in bin/setup-local-tests.php immediately after the test suite is extracted, replacing the E_STRICT reference with its zero-value equivalent (removing the term entirely). Signed-off-by: Chuck Adams <chaz@chaz.works>
Moves infection/infection and its transitive deps (thecodingmachine/safe et al) out of the root composer environment into tests/mutation/composer.json. The root vendor is now PHP 8.0-clean — thecodingmachine/safe implicit-nullable deprecation noise on PHP 8.4 is gone from unit test runs. tests/mutation/composer.json: - php >=8.4 (no platform pin — free to use PHP 8.5 in Docker) - require-dev: infection/infection ^0.27 - Own vendor/, gitignored along with composer.lock docker-compose.yml: - Root: composer install --ignore-platform-reqs (plugin + phpunit) - tests/mutation/: composer install (infection only) - Binary path: tests/mutation/vendor/bin/infection - mutation-vendor named volume preserves installs across runs Root cleanup: - Removed infection/* and thecodingmachine/safe from composer.lock - Removed vendor/infection/ and vendor/thecodingmachine/ No Safe deprecation noise. 262 tests pass. Signed-off-by: Chuck Adams <chaz@chaz.works>
get_site_transient() returns false for a missing key, but the existing check 'if ( )' treated null (valid cached result meaning 'no alias') as uncached. On single-site, null → '' in the DB layer so the cache happened to work; on multisite with object cache, null stays null and the check fails, forcing re-fetches. Changes: - Cache hit check: if ( ) → if ( false !== ) - Write normalization: → ?? '' so null is always stored as empty string, consistent across single/multisite This is also a performance fix — previously, DIDs with no alias would re-run fetch_and_validate_package_alias() (with DNS lookups) on every call in multisite. Signed-off-by: Chuck Adams <chaz@chaz.works>
Move everything from tests/sites/ephemeral/ up one level to tests/sites/. The 'ephemeral' qualifier didn't add value — all sites under tests/sites/ are ephemeral Docker setups by design. - tests/sites/Dockerfile.wp (shared WP image) - tests/sites/docker-compose.base.yml (shared template) - tests/sites/integration/ (WP + mock-server, used by both integration & HTTP) - tests/sites/browser-test/ (WP + mock-server, used by Playwright) - tests/sites/mutation/ (PHP 8.5 + Infection, isolated composer.json) All context and volume mount paths updated for the new depth: context: ../../../.. → ../../.. volumes: ../../../../ → ../../.. bin/run-integration.sh refactored: - SUITE argument now gates which tests run: 'integration', 'http', or 'all' - Both integration and http share the integration compose stack - Separate project names (fair-integration-integration vs fair-integration-http) avoid port conflicts when both run in sequence composer.json: - test:integration → integration tests only - test:http → HTTP tests only (own compose cycle) - test:all chains unit, multisite, integration, http Verified: test:all exits 0 (262+262+12+12 tests). Browser 15/15 pass. Signed-off-by: Chuck Adams <chaz@chaz.works>
Six items from the testing plan, now done: 1. install-activate-update.spec.ts (@slow) — full install/activate/update flow via Direct Install tab. Mock server extended with hello-dolly DID fixtures (did-doc + metadata-doc) and zip artifact serving route at /artifacts/*.zip. 2. avatar-upload.spec.ts — profile page rendering, avatar section presence, display name accessibility. Avatar image verification handles Gravatar rate-limiting (at least one loaded = pass). 3. update-error-row.spec.ts — plugins page structure, FAIR error row detection, no JS errors on plugins page. 4. SignatureVerificationIntegrationTest.php — 5 tests running inside Docker WP container. Covers verify_file_signature() (WP 5.2+) with live sodium Ed25519 keys, tampered file rejection, missing-key rejection, wrong-signature rejection, key encoding round-trip. NB: WP 6.4 uses SHA-384 (not SHA-512) for file hashing. 5. Coverage reporting in CI — added dedicated 'coverage' job to phpunit-tests.yml. Runs on push to main/development/release only, uses PHP 8.4 + XDebug, uploads HTML coverage artifact. 6. minMsi threshold — set minMsi=9 (current baseline), minCoveredMsi=90. Updated mock server: - /artifacts/<file.zip> route serves zips from tests/fixtures/zips/ - hello-dolly DID/meta fixtures for browser install flow Updated integration bootstrap: - require wp-admin/includes/file.php for verify_file_signature() Totals: 262 unit (489 assertions), 17 integration (48), 12 HTTP (38), 23 browser (non-slow), 3 browser (@slow). Exit code 0. Signed-off-by: Chuck Adams <chaz@chaz.works>
Six vacuous/near-zero-value tests identified (SampleTest, duplicate assertions, WordPress-core behavior tests, redundant filter-registration checks). Four antipatterns (reflection into private state, pipeline-mock unit tests disguised as integration, constant-structure assertions, WP transient internals assertions). Five security-critical expansions needed: - verify_signature_on_download() zero unit tests - get_trusted_keys() key-confusion edge case - upgrader_source_selection() zero tests - multibase→base64 recoding step untested - Replay attack: no DID-binding in signatures (protocol concern) Six general expansions: update_site_transient, plugin_api_details, Package::get_release memoization, theme HTML, error propagation e2e, browser test thinness. Three design issues flagged where production functions mix pure logic with side effects — extraction paths documented. Signed-off-by: Chuck Adams <chaz@chaz.works>
Immediate items from test quality audit: 1. Delete SampleTest.php (tested PHP truthiness, not production code) 2. GetPackagesTest: remove double-quote duplicate assertion, replace brittle array-key-existence check with empty-plugins assertion 3. AvatarHttpTest: remove two should_replace_url tests (duplicates of ShouldReplaceUrlTest in unit layer) 4. PickArtifactByLangTest: remove test_should_fire_filter_hook (tested WordPress core apply_filters behavior) 5. DefaultRepoHttpTest: remove test_pre_http_request_filter_is_registered (tested bootstrap, redundant with every other test) 6. UpdaterTest: replace ReflectionProperty reset_registry with Updater::reset() (method already existed in production code) After: 261 tests, 485 assertions (was 262/489). Single-site, multisite, and HTTP suites pass. Signed-off-by: Chuck Adams <chaz@chaz.works>
Four high-priority expansions from the test quality audit: #9 (get_trusted_keys base64 recoding): Verifies multibase (base58btc) → base64 Ed25519 key recoding step that WordPress core's verify_file_signature() depends on. Uses a real fixture key to validate DidCodec::from_multibase_key() output. #10 (Package::get_release memoization): 3 tests verifying caching semantics: successful fetch is memoized and not re-fetched on second call, WP_Error is not cached (retry on next call), upstream error cache in get_did_document() is documented as a separate concern. #7 (upgrader_source_selection): 8 tests covering the directory renaming logic: WP_Error pass-through, install action bypass, TypeError for non-plugin/theme upgrader, matching-basename short-circuit, hash-suffix rename for both plugins and themes, case-insensitive slug normalization. Uses temp directories and anonymous Plugin_Upgrader/Theme_Upgrader subclasses. #8 (verify_signature_on_download): 10 tests — the most security-critical function in the plugin: already-downloaded pass-through, non-plugin upgrader bypass, missing DID transient, missing release cache, local file bypass, re-entry guard, download error propagation, unmatched URL bypass, valid Ed25519 signature verification (full pipeline with sodium key generation, SHA-384 hash signing, multibase recoding), and tampered file rejection. Must use ReflectionFunction to reset the static between tests. After: 283 tests, 521 assertions. Single-site + multisite pass. Signed-off-by: Chuck Adams <chaz@chaz.works>
Replaced all done subsections with concise summaries referencing commit hashes. Undone items preserved with intact numbering. Resolved: sections 1 (all 6), 2.1 (reflection→reset), 3.1 (verify_signature_on_download), 3.3 (multibase recoding), 3.5 (upgrader_source_selection), 4.3 (memoization). Remaining: sections 2.2-2.4, 3.2, 3.4, 4.1-4.2, 4.4-4.6, 5.1-5.3. Signed-off-by: Chuck Adams <chaz@chaz.works>
Signature binds to archive content only, DID-binding is a protocol design question — not a plugin-layer test gap. Flagged for separate security coverage. Signed-off-by: Chuck Adams <chaz@chaz.works>
2.3 (constant/fixture structure assertions): - VersionCheckConstantsTest: collapsed 5 tests → 1 (minimum<recommended). Removed tautological regex checks and non-empty assertions. - Removed test_did_doc_has_verification_method from SignatureVerificationTest — every other test validates by consuming. 2.4 (transient internals assertion): - test_should_cache_result now asserts behavior (both calls return falsy/no-alias) instead of WP internal serialization format. 3.2 (multi-key trust test): - Added test_should_return_all_fair_prefixed_multikeys to GetTrustedKeysTest. Generates two real Ed25519 keypairs, encodes both as multibase, seeds a DID doc with 2 fair keys + 1 atproto key. Verifies both fair keys are returned as trusted. Documents that WP core's verify_file_signature() tries all trusted keys, so a signature from either passes — intentional for key rotation/backup. Audit restructured with zero-refactoring vs needs-refactoring split in section 7. After: 279 tests, 514 assertions. Single-site + multisite pass. Signed-off-by: Chuck Adams <chaz@chaz.works>
#17 (browser test seeding): - Updated browser-test seed.php to create dummy plugin with FAIR DID header AND seed a fair_update-errors transient. - Updated update-error-row.spec.ts to assert error row IS visible (was no-op conditional). Error text checked for expected content. #16 (error propagation e2e integration test): - Integration seed.php now registers a second plugin with 'did:plc:doesnotexist0000000000000' — unresolvable by mock server. - Added test_unresolvable_did_plugin_is_skipped_and_error_cached to UpdateTransientIntegrationTest: verifies the bad-DID plugin is excluded from both response and no_update, and WP_Error is cached. - Replaced test_empty_registry_handles_gracefully (reflection-based, now redundant after Updater::reset() fix). #15 (plugin_api_details unit tests): - Added PluginApiDetailsTest (4 tests) to PipelineWPTest.php: non-plugin_information action pass-through, empty slug pass-through, unmatched slug returns false, full pipeline success returns plugin info object with correct name and version. - Used seed_pipeline() pattern from existing SearchByDidTest. Zero-refactoring remaining: #14 (pipeline-mock migration), #18 (theme HTML). After: 283 tests, 520 assertions. Single-site + multisite pass. Signed-off-by: Chuck Adams <chaz@chaz.works>
) Removed from PipelineWPTest (unit): - SearchByDidTest::test_should_return_plugin_result_on_success - SearchByDidTest::seed_full_pipeline() - AddPackageToReleaseCacheTest::test_should_add_release_to_cache - AddPackageToReleaseCacheTest::test_should_retain_existing_releases - AddPackageToReleaseCacheTest::seed_pipeline() These tested the FULL pipeline (DID doc → service → HTTP fetch → metadata → release) using pre_http_request mock filters inside unit tests. A metadata schema change would silently break them. Added to DidResolutionIntegrationTest (integration): - test_search_by_did_returns_plugin_result - test_add_package_to_release_cache_populates_cache Both run against the real Docker mock server, so a schema change produces a genuine integration failure, not a mock-data mismatch. Unit tests kept: edge cases that don't need HTTP (empty DID, non-DID search, wrong action, pipeline failure propagation). After: 280 unit tests (511 assertions), 19 integration (56 assertions). All suites pass. Signed-off-by: Chuck Adams <chaz@chaz.works>
Added CustomizeThemeUpdateHtmlTest (3 tests):
- FAIR-registered theme with update available gets update links
('There is a new version of', 'update now') appended.
- Unregistered themes are left untouched.
- Empty registry does not error.
Creates a real theme directory with Theme ID header in style.css,
registers it with Updater, seeds DID doc + metadata in transients
(no network calls), seeds update_themes transient (with temporary
filter removal to avoid triggering the full update pipeline during
test setup), and verifies customize_theme_update_html output.
Zero-refactoring items: ALL DONE.
After: 283 tests, 516 assertions. Single-site + multisite pass.
Signed-off-by: Chuck Adams <chaz@chaz.works>
Updated summary table: 5/6 general expansions done, 4/4 antipatterns. Section 7: zero-refactoring table marked ALL DONE with commit refs. Sections 2.2, 4.2, 4.4, 4.5, 4.6 collapsed into resolved summaries. Final state: 18/23 actionable items resolved. 5 remaining all blocked on production code refactoring (private→protected, extraction). Signed-off-by: Chuck Adams <chaz@chaz.works>
Signed-off-by: Chuck Adams <chaz@chaz.works>
- Revert the null-to-'' normalization in validate_package_alias() that caused cache falsey-value collisions on single-site - Add test_should_cache_null_result (incomplete) documenting the null-transient bug and sentinel-based fix - Split all test files to one class per file (10 files → 31 files) - Rename test files to match their single class name Signed-off-by: Chuck Adams <chaz@chaz.works>
Signed-off-by: Chuck Adams <chaz@chaz.works>
… crashes Signed-off-by: Chuck Adams <chaz@chaz.works>
Signed-off-by: Chuck Adams <chaz@chaz.works>
Add export-ignore in .gitattributes and rsync exclusions in .distignore to keep development-only files out of the distributed plugin zip. Signed-off-by: Chuck Adams <chaz@chaz.works>
Let CI matrix jobs resolve dependencies against their actual PHP version instead of all using a hard-coded 8.0 floor. The PHP 8.0 matrix cell now acts as the canary for minimum-version compatibility. Pin the release workflow to PHP 8.0 and set platform.php explicitly via composer config so the distributed vendor/ remains 8.0-compatible. Signed-off-by: Chuck Adams <chaz@chaz.works>
tests/browser/.auth/admin.json contains ephemeral auth cookies and was committed before the .gitignore entry for tests/browser/.auth/ existed. Remove from tracking; .gitignore already covers the directory. Signed-off-by: Chuck Adams <chaz@chaz.works>
|
Would it be possible to split this out into separate pull requests for clarity:
I feel like there are some ways to simplify the e2e setup by relying on existing WP packages and helpers but it wouldn't be fair to the phpunit suite work if we started discussing it here 😂 |
|
Possible for sure, but in the end it's all tests, and they're quite well separated by function into different directory trees under test/. I'm not in a massive rush to merge this, and and we can make plenty of changes as needed. As for e2e tests in particular, I'm rather attached to playwright, and would need a lot of convincing evidence to switch to something else. Ultimately it's about what harness is controlling Chromium/Safari/FF, because anything else is not actually a browser test. |
Tests, tests, and more tests. Unit tests, integration tests, http tests, end-to-end tests, all for one low low price. 99.9% AI generated, now in the human review stage.
Only one source file changed, and that's two trivial changes in inc/packages/namespace.php: one to fix a typeerror crash when
reset([])returnsfalse, and the other to allow customizing the plc.directory url which allows us to mock it in integration tests. That's also being backported into 1.4.1, so by the time this lands it should be zero source files changed.There's also a couple github workflows, one to run coverage and upload it as an artifact, another to run integration tests which is workflow_dispatch only until I know exactly how slow it is on github runners. The existing release workflow now builds with PHP 8.0 instead of 8.2 so that it doesn't bundle a vendor/ with deps that are only for 8.2+. There shouldn't be any surprises, since we test against 8.0 already, including doing a
composer updatein each test matrix cell.Lots of ai-generated planning docs in ai/plans. I can nuke those if we want, I don't usually keep completed plans in git, just figured they might be edifying. The ai/ directory won't ship in release zips.