php-xapi/json-test-fixtures
A collection of JSON test fixtures for the php-xapi ecosystem, offering ready-made xAPI statement samples and related JSON documents to simplify writing and running unit tests in your PHP projects.
Architecture fit. This is a Laravel/PHP package whose test surface exposes "attachment fixtures" — reusable representations of an attachment's JSON metadata plus, optionally, its raw bytes. v2.0.0 reshapes each fixture from a flat/scalar value into a two-key object: metadata (JSON-encoded attachment descriptor) and content (optional raw attachment payload). For a TPM this is a test-contract change, not a runtime behaviour change, but it sits directly on the seam between our application code and our CI suite. The object form is architecturally cleaner — it lets a single fixture express both halves of a multipart-ish attachment (descriptor + bytes) — and matches how Laravel's HTTP fake/test helpers usually separate payload from body. Fit is good for teams already using fixtures in feature tests; it is neutral for teams that only consume the package's runtime API.
Integration feasibility. Low-to-moderate effort. Because v2.0.0 is a major bump, adoption is opt-in via an explicit constraint change; nothing forces our hand today. The work is concentrated in test code: any place that treats a fixture as a string, array-with-different-keys, or passes it straight into a request body must be updated to read ->metadata / ['metadata'] and, where raw upload fidelity matters, ->content. Fixtures are usually referenced through a small number of helper methods, so the blast radius is typically narrow but highly visible (many failing tests at once if helpers aren't centralised).
Technical risk. The core risk is a silent mismatch between metadata (JSON-encoded string) and content (raw bytes): teams that previously relied on a single blended value may now accidentally send metadata where bytes are expected, or double-encode. A second risk is the "up to two keys" wording — content is optional, so fixtures without raw content must not be assumed to carry it; null/absent handling needs explicit assertions. Third, JSON encoding of metadata means string comparisons in existing assertions will drift (escaped characters, ordering) and snapshot-style tests will churn. Fourth, this is a test-fixture-only change, so production correctness is not directly at risk, but our regression net is — a botched migration could weaken upload-path coverage without anything failing.
Key questions. (1) Is the fixture shape change purely additive (old scalar form deprecated but accepted) or hard-breaking with no shim? (2) Is there a documented upgrade guide or Rector/rector-style automated transformation? (3) Which fixtures include content and which omit it — is that documented per fixture, or must we inspect at runtime? (4) Does metadata remain a JSON string, or is a decoded-array accessor also provided? (5) Do the package's own assertion helpers (assertAttachment, HTTP fakes) accept the new object directly, so we can avoid bespoke plumbing? (6) Is v1.x still receiving security/compat patches, and for how long?
Stack fit. Standard Composer dependency in a Laravel app: constrain in composer.json (^2.0), install, and let the package's service provider and test helpers register as before. No infrastructure, queue, or storage-layer changes are implied by the notes; this is confined to the testing layer. Teams on Pest or PHPUnit are equally affected — the change is in fixture shape, not test framework integration.
Migration path. Recommended sequence: (a) pin a branch and run the full suite against v2.0.0 in a scratch branch to enumerate failures; (b) centralise fixture access behind one or two project-local helpers (e.g. attachmentMetadata($fixture), attachmentBody($fixture)) that normalise v1 and v2 shapes, so the rest of the suite is decoupled from the package's representation; (c) update direct fixture consumers to the helper; (d) refresh snapshots and any hard-coded expected JSON; (e) merge, then delete the compatibility shim in a follow-up. If the package provides no shim for the scalar form, step (b) is the only realistic way to keep v1 and v2 branches testable in parallel.
Compatibility. Requires PHP and Laravel versions supported by the v2 line — confirm against our oldest supported app (Laravel LTS in use, PHP floor). No database migration or config publish expected. Watch for interactions with other upload/media packages (e.g. Spatie Media Library-style integrations) if they also ship fixtures; two packages' fixture shapes can collide in shared test helpers. Because metadata is JSON-encoded, any assertion helper that compares decoded arrays must be adjusted, not just fixture accessors.
Sequencing. Land the helper abstraction and a v2 smoke test first (low risk, no production exposure). Migrate the highest-value suites — attachment upload, validation, and retrieval — before peripheral tests. Keep the dependency bump as its own PR, separate from the mechanical fixture migration, so a revert is cheap. Defer the bump until after any in-flight release branch is cut, since a large test diff during a release freeze adds noisiness to review.
Maintenance. Steady-state cost is low — one pinned dependency and a thin project-local helper. The recurring cost is chasing fixture-shape changes on future majors; the helper abstraction is what converts a suite-wide break into a one-file change next time. Document the metadata vs content distinction in the team's testing conventions, since it is exactly the kind of detail that gets misremembered.
Support. Internal only: no vendor SLA implied. Escalation path is the package's issue tracker plus our own helper layer. Identify one owner (typically the backend engineer owning uploads) and record the pinned version and upgrade notes in the repo. Because this is a testing utility, an upstream defect manifests as flaky or failing tests rather than a customer-facing incident — tolerable, but it can block merges.
Scaling. Negligible runtime scaling implications. Test-suite wall-clock may shift slightly if fixtures now carry raw bytes inline — large content payloads in fixtures increase memory and disk churn in CI. Recommend keeping fixture binaries small and loading large ones on demand, and confirm CI artifact/snapshot storage isn't bloated by full raw content being echoed into failure output.
Failure modes. (1) Fixtures lacking content treated as present → malformed upload requests in tests that pass for the wrong reason. (2) Metadata sent where raw bytes are expected, or double-encoded JSON → assertions on encoded strings silently diverge. (3) Helpers not centralised → the next major repeats the full-suite churn. (4) Mixed v1/v2 fixtures across shared helpers in a monorepo → divergent, hard-to-reproduce failures. (5) Snapshot churn accepted uncritically → weakened assertions that stop catching real regressions. Mitigation for all five: a single normalisation helper, explicit assertions that absent content is absent, and a review rule that snapshot updates are justified line by line.
Ramp-up. Under a day for an engineer familiar with the suite; roughly a day and a half if the team is new to the package. Onboarding note for new engineers: explain that a fixture is a two-part object (encoded descriptor + optional raw bytes), show one worked example of each form, and point at the project helper as the sanctioned access path.
How can I help you explore Laravel packages today?