codewithdennis/filament-tests
Filament Tests lets you run and review your PHPUnit or Pest test suite directly from a Filament panel. Trigger tests, inspect pass/fail results and output, and monitor your Laravel app’s health without leaving the admin dashboard.
Resolve the product question before you install anything. The repo's description says it generates PEST tests for Filament resources; its documentation section describes a test-runner page inside the Filament admin panel (run Pest/PHPUnit, view pass/fail, configure test paths and commands). These are different products. Before writing code, open the repo and identify which artifact actually exists:
composer.json — package name, type (library vs filament-plugin), and require/require-dev constraints. This tells you the supported Filament/PEST majors.src/ — look for a generator/command class (something that writes files under tests/) versus a Filament Page/Plugin class (something that renders inside the panel).config/ — published config keys. If it's a runner, expect command allowlists and path settings. If it's a generator, expect output paths and stub paths.Minimal install (dev-only, on a throwaway branch):
composer require --dev codewithdennis/filament-tests --with-all-dependencies
Then immediately check the lockfile diff. A dev dependency can still pull transitives, and you want to confirm it resolves cleanly against your existing Filament, Livewire, and PEST constraints — not introduce a second copy of anything.
If it's a generator: pick the simplest resource you have — a plain CRUD resource with a form schema and a table, no relation managers, no custom Livewire components, no actions. Generate its test, open the emitted file, and read every assertion before running it. Then run just that file:
./vendor/bin/pest tests/Feature/Filament/YourResourceTest.php
If it's a runner page: register the plugin in a local-only panel provider (or gate the page behind Gate::define / app()->isLocal()), then hit the page and confirm it can see and invoke your test command. Do not put this on a panel that's reachable from production.
First use case worth measuring: the pass rate of unmodified generated output on three representative resources — one simple CRUD resource, one with a relation manager, one with actions plus a custom form component. That number, not the README, is the real evaluation.
Harvest the output, not the dependency. This is the dominant pattern for an archived, zero-dependent, MIT-licensed package. On a branch:
require-dev, pinned to an exact tag.composer remove --dev codewithdennis/filament-tests and re-run the suite.Whatever survives that sequence is the deliverable. It stands on its own, has no upstream coupling, and the exit cost is a composer entry you've already deleted.
Generate in reviewed batches, keyed by resource family. Don't run the generator across the whole app/Filament/Resources tree in one commit. Group resources into batches (simple CRUD → resources with relation managers → resources with actions/custom components), generate, review, repair, and commit per batch. That gives you a per-family brittleness signal you can act on before you're 40 files deep into tests nobody will maintain.
Keep generated files identifiable. Whatever naming convention the generator uses, preserve it so that regeneration is a readable diff rather than an arbitrary overwrite. Even in the harvest model, you may regenerate again before a Filament upgrade (from a fork), and knowing which files are machine-authored is what makes that safe.
Treat generated tests as a floor, then hand-extend where the generator can't know. Generated assertions typically cover render/validation basics. For each resource, append the assertions only you can write:
Use it as executable specification for onboarding. Once harvested, the test files double as a readable statement of what each resource is supposed to do — useful when handing the admin panel to a new engineer, and useful as the diff surface when someone refactors a resource.
Wire it into CI as a required check. Generated tests that aren't enforced are decorative. If the output is worth keeping, it goes in the same job as the rest of the Pest suite, with the same RefreshDatabase, factory, and seeded-permission setup. Filament resource tests are stateful and will surface environment assumptions immediately — better in CI than in a developer's local run three weeks later.
Trigger it on a risky change, not as a coverage initiative. The highest-value moment is right before a Filament v3→v4 upgrade, a Laravel major bump, or a refactor of resource classes. Run the generator (or your fork) against the resource inventory, harvest, then make the risky change with a net in place. That sequencing gives you a legitimate reason to fund the work; "raise admin coverage" generally doesn't.
Fork into packages/ or tools/ only when regeneration is recurring. If you have many resources in flight and ongoing admin growth, one engineer owning a small internal generator that you can patch against future Filament versions is cheaper than re-running the harvest dance every quarter. Otherwise, harvest and move on.
If the artifact turns out to be the dashboard runner rather than a generator, the day-to-day pattern is different: register it on a local/staging panel only, configure the test paths and commands to a narrow allowlist (your Pest invocation, nothing that takes arbitrary shell input), and use it as a convenience for triggering runs while iterating — never as a CI substitute, and never on a panel an end user can reach.
Archived is a hard constraint, not a warning label. No CVE response, no compatibility work, no upstream triage. Pin an exact version in require-dev, never promote it to require, and plan for the package to disappear from your stack at the end of the spike. If your org has a dependency-approval or SBOM process, expect this to be blocked as a standing dependency — which is exactly what the harvest pattern avoids.
The description/documentation mismatch will bite you. Whichever product the repo actually contains, its documentation section describes the other one. Assume nothing from the prose; read composer.json, the service provider, and the source. If you're evaluating this for a decision, a short spike that confirms which artifact exists is cheaper than a plan built on the wrong one.
Generated tests do not upgrade themselves. The output is static source pinned to a specific Filament testing API (Livewire component assertions, table/form/action helpers) and a specific Pest major. Both have moved across majors — Filament's testing surface changed v2→v3→v4, Pest's syntax moved with its majors. Once generated, these files are hand-maintained artifacts that drift with every framework bump. Budget the maintenance: they are first-class code under normal review, with a named owner.
Coverage assumptions are the silent failure mode. Generated assertions reflect what the generator author decided was worth asserting — usually render and validation. Treating the output as a safety net without reading it produces false confidence, particularly around actions, bulk actions, relation managers, authorization matrices, and tenant-scoped panels. Read every generated file once; the ones that only assert assertSuccessful() after a GET are documenting that the page renders, not that the resource works.
Customization is where the generated tests break. Wizards, custom Livewire components, nested relation managers, and heavy action closures are the predictable brittleness points. If the generator introspects resources via reflection rather than conventions, it's also fragile to Filament internals — a Filament minor can change a property name and silently produce tests that assert nothing meaningful. Run the generated file in isolation and diff it against what you'd have hand-written; the gap is your brittleness map.
Environment assumptions surface fast, and they're yours to fix. These tests need the same RefreshDatabase/DatabaseTransactions strategy, factories, seeded roles, and panel-provider registration as the rest of the suite. If a generated test fails on a fresh checkout, the fix is almost always in TestCase/Pest.php setup (panel provider registered in tests, guard configured, roles seeded), not in the generated file. Fix it once in the base case, not per test.
Seeded data and permissions are a common cause of false reds. A test asserting a resource index page will fail if the acting user lacks the policy permission the panel enforces. Assert the authorization matrix explicitly rather than assuming a super-admin actor; otherwise a policy change turns your whole generated suite red for a reason nobody remembers.
Regeneration is destructive unless your fork supports it. If you hand-edited generated tests — and you will, to add action and policy coverage — re-running the generator will overwrite those edits. In the harvest model this is fine (you removed the package). If you fork the generator, make regeneration additive (skip existing files, or output to .generated suffixed files you can diff) before you rely on it a second time.
Extension points to check before you write anything custom: whether the config is publishable (php artisan vendor:publish), whether stub templates are overridable, and whether the generator is a class you can subclass or a final artisan command. If the config is publishable, publish it into version control so your settings don't depend on package defaults you can't see.
If it's the dashboard runner: gate the page behind app()->isLocal() or an explicit gate, keep it off any production panel, and constrain the configured commands to a fixed invocation. A UI that shells out from inside an admin panel is a sharp tool — the value is iteration convenience, and the risk is anything that accepts arbitrary input.
How can I help you explore Laravel packages today?