misaf/vendra-testing
Testing toolkit for Vendra-powered Laravel applications. It supplies helper traits, model factories, and custom assertions for feature and unit tests, so you can cover marketplace and e-commerce flows with less boilerplate and more readable suites.
Install as a dev dependency only.
composer require --dev misaf/vendra-testing
This is a test-support package. It has no production runtime, no migrations to publish, and no data path. If you find it in your non-dev require block, that is a smell — it should only ever resolve through require-dev.
Where to look first. Two files explain almost everything you need:
src/Helpers.php — files-autoloaded (not class-based), so the functions are callable directly in any test file without a use of a class. This is where createTestTenant(), makeCurrentTestTenant(), createTestUser(), and setUpFilamentAdminTestContext() live.src/Expectations.php — the Pest expectation extensions (expect()->to...) for prices, totals, and order states.Then glance at TableSorting (drives toSortByEverySortableColumn()) and TranslationParity (locale-parity assertions for translatable fields). Both are generic utilities, not domain-specific — you will reuse them across every module.
Your first test. The canonical first use case is "a tenant with a user and a cart has the right total":
it('totals a cart for a tenant', function () {
makeCurrentTestTenant();
$user = createTestUser();
// build product + cart through your own factories or Vendra helpers
// ...
expect($cart->total())->toBePrice(1999);
});
If that runs, the bootstrap works and you can start asserting order state transitions and product availability. If it does not, the failure is almost always tenancy (see Gotchas).
Run the package's own suite from the host app, not from a random directory:
php artisan test --compact --testsuite=vendra-testing
composer stan
vendor/bin/pint --dirty --format agent
Tenant lifecycle is explicit, not implicit. The helpers mirror the TenantResolver / TenantAwareness contracts from misaf/vendra-support:
$tenant = createTestTenant(); // persisted, not yet current
makeCurrentTestTenant(); // create + make current in one call
switchToTestTenant($other); // move an existing tenant into context
currentTestTenant(); // read it back
forgetCurrentTestTenant(); // tear down between assertions
Use forgetCurrentTestTenant() in an afterEach() if you are switching tenants inside a single test file — leaking tenant context between tests is the single most common source of confusing failures in a multi-tenant e-commerce suite.
Feature flags need determinism, so use the dedicated helper. makeCurrentTestTenantWithFeatures() exists specifically because Pennant state leaks between tests when set imperatively. Reach for it instead of chaining makeCurrentTestTenant() + Feature::activate().
Filament admin tests have a one-call setup. setUpFilamentAdminTestContext() wires the shared admin panel, an authenticated admin, a tenant, a resource, and feature state in one go. This collapses what is normally 20+ lines of beforeEach() into a single call, and it is the pattern to standardise on for any resource-page test.
Compose custom expectations rather than inline math. Assertions read better and fail louder when the value is wrong:
expect($order->total)->toBePrice(4999);
expect($line->unit_price)->toBePrice(1999);
For sortable tables, delegate rather than hardcode columns:
expect($table)->toSortByEverySortableColumn();
toSortByEverySortableColumn() is a thin delegation to TableSorting — it verifies every sortable column ascending, and optionally descending, without you naming a single column. That means adding a sortable column to a resource automatically extends coverage.
Translation parity is a lint, not a test. Use TranslationParity to assert locale key sets match across languages. Keep assertions locale-order independent — never assert against a hardcoded array literal of keys, or your test breaks every time someone adds a translation.
Pest and PHPUnit both work, but prefer Pest. The expectation extensions are Pest-native, so PHPUnit users get the helpers and test case but lose the fluent assertions. If your codebase is mixed, port the e-commerce feature tests to Pest first.
Respect the module boundary. Module test suites should import Misaf\VendraTesting and never Misaf\VendraTenant. This is enforced by the root PackageManifestConsistencyTest, so violating it fails CI rather than silently coupling your module to a concrete tenant provider. If you genuinely need tenant internals, that is a signal you belong in vendra-tenant's own tests.
Tenancy-disabled helpers silently return null. Every tenant helper no-ops when tenancy is off — returns null rather than throwing. That is deliberate (it lets non-tenant modules share helpers), but it means a typo'd or misconfigured tenancy setup produces a null downstream rather than a clear failure. If createTestUser() returns null or your tenant is unexpectedly null, check tenancy config before you check the helper.
You must not import Misaf\VendraTenant. The package's own arch test asserts arch()->expect('Misaf\VendraTesting')->not->toUse('Misaf\VendraTenant'), and the root PackageManifestConsistencyTest extends that rule to consuming module suites. misaf/vendra-support is the one sanctioned dependency. This is not stylistic — it is what keeps the utilities usable by modules that do not ship a tenant provider at all.
Provider absence is a hard failure, not a fallback. makeCurrentTestTenantWithFeatures() and setUpFilamentAdminTestContext() are provider-neutral but will fail clearly when the required providers (Pennant, Filament) are missing. Read that error as "you have not installed what this helper needs", not as a package bug.
Helper signatures are public contract. Treat the function names and argument shapes in src/Helpers.php as an API. When evolving them, deprecate rather than break — downstream module suites call these directly and a signature change ripples across every package in the graph without any version boundary protecting you.
Version bumps are code-review events, not automated updates. Recent releases carry no changelog text beyond a compare link, so a ^1.12 bump is un-auditable from the artifact alone. Before floating the constraint:
composer.json between tags — PHP floor, illuminate/* range, and PHPUnit/Pest major compatibility. Test-support packages most commonly break here.Expectations and the fixture shapes in the helpers.The dangerous failure direction is silent assertion relaxation — tests that pass when they should fail. A test-support bump that turns red CI is cheap; one that turns green tests that no longer test anything is not.
Watch CI wall-clock, not just correctness. Helpers that add per-test bootstrapping (tenant creation, Filament panel setup, feature state) compound across parallel shards. Measure suite duration before and after a bump rather than assuming neutrality.
Keep a pin-or-fork escape hatch. Support signal is weak by design for a single-maintainer split package. The exit cost is low because swapping it out only affects tests — but only if you have not let the helpers leak into production code paths. Keep it dev-only and the escape stays cheap.
The $translatable rule applies to your fixtures too. Every field a model declares in $translatable must be a JSON column, and its factory and test data must be translation-shaped. A field not in $translatable must not receive translation-shaped arrays. Mismatches here surface as baffling TranslationParity failures rather than as schema errors, so check the model's array before you debug the expectation.
Use the package's own suite as your smoke test after any change. php artisan test --compact --testsuite=vendra-testing must run from the host app — running it from inside the package directory bypasses the app bootstrap these helpers depend on, and the failures you get there are meaningless.
How can I help you explore Laravel packages today?