alebatistella/duskapiconf
alebatistella/duskapiconf is a Laravel package that helps configure Laravel Dusk for API testing. It streamlines Dusk environment and test-runner setup, reducing manual boilerplate so you can run API-focused Dusk tests more easily with less configuration friction.
This package solves one narrow but real problem: Dusk tests drive a separate PHP process (the app server) from the one running your test suite, so Config::set() / putenv() inside a Dusk test does not affect the application the browser is talking to. duskapiconf exposes a small HTTP endpoint plus a Dusk-side helper so a test can push config values into the running app before it exercises the UI.
Minimal setup:
composer require alebatistella/duskapiconf --dev
php artisan vendor:publish --provider="Alebatistella\DuskApiConf\DuskApiConfServiceProvider"
Verify the exact provider FQCN / publish tag against the README — the package is small and the tag name is the first thing to confirm..env.dusk.local (or whatever env file php artisan dusk boots with), not in .env:
DUSK_API_CONF_ENABLED=true
DUSK_API_CONF_TOKEN=some-long-random-string
tests/Browser/*Test.php classes extend/use, so individual tests just call something like $this->setApiConfig(['services.stripe.enabled' => false]) in setUp()..env.dusk variants and two app servers, flip services.stripe.enabled from inside the test, then let the browser flow assert the "disabled" branch.Where to look first, in order: the README's endpoint contract (path, HTTP method, payload shape, auth header), config/duskapiconf.php after publishing, then src/ — it's a handful of files, so read the service provider and the controller before trusting the docs. Also check the package's own tests/ for the canonical call from a Dusk test.
Snapshot → mutate → assert → restore. The app server keeps serving requests across your whole Dusk run, so treat config as shared mutable state. In the test base class:
protected function setUp(): void
{
parent::setUp();
$this->original = $this->getApiConfig([...keys you'll touch...]);
}
protected function tearDown(): void
{
$this->setApiConfig($this->original); // or a reset call if the package offers one
parent::tearDown();
}
Resetting in tearDown (not just setUp) is what keeps tests independent when one fails mid-flight.
Wrap the calls in your own trait. Don't sprinkle raw HTTP calls through test classes. A thin InteractsWithApiConf trait with setApiConfig(array $values), getApiConfig(array $keys), and resetApiConfig() gives you one place to change when the package's contract moves — and one place to add logging when a config push silently no-ops.
Call it over plain HTTP when the helper doesn't fit. If a scenario needs config changed mid-test (after the browser has already loaded a page), you can hit the endpoint from inside the page with $browser->script() + fetch(), or from the test process with Http::withToken(...)->post(...). Make sure the endpoint is reachable from the browser's origin (CSRF/session middleware are the usual blockers) — an API-style route outside the web middleware group avoids that class of problem.
Persist through a store the app re-reads, not through in-memory state. PHP-FPM/artisan serve re-bootstraps the framework per request, so a config change only "sticks" if the package writes it somewhere (cache, file under storage/, etc.) that a boot-time hook merges into config(). Know which store you're using: it determines whether the change survives php artisan config:clear, whether it's shared across parallel Dusk processes, and whether you need to reset it in CI between jobs.
Guard the route, twice. Environment flag and a token header. The service provider registers the route automatically in the packages' typical pattern, so a misconfigured prod deploy exposes an arbitrary-config-write endpoint. Add an assertion in a non-Dusk test that the route is absent/403s when APP_ENV=production.
CI wiring. GitHub Actions / GitLab CI need the app server reachable at the base URL Dusk uses. If you run php artisan serve in the pipeline, the endpoint comes free; with Sail/Docker, confirm the port mapping and that the token env var is present inside the container, not just the runner. Run php artisan config:clear before the Dusk job so a cached config from an earlier step doesn't shadow the values the package merges in.
Good candidates to drive this way: feature flags, payment/queue/mail driver selection, throttle limits, external API base URLs, pagination sizes — anything where the alternative is duplicating an env file or restarting the server mid-suite.
php artisan config:cache is the classic failure. Cached config is a plain array baked at boot; packages that merge values at boot may be ignored entirely. Clear it in the Dusk environment and don't cache there.env() in your config files won't change. Config entries that read env('X') at boot are frozen once cached; only direct config() overrides written by the package take effect. Prefer config keys whose values are literals or derived from other config.--stop-on-failure run plus a single-test run to isolate suspected leakage.dusk --parallel or split suites across CI shards, two tests can overwrite each other's config. Either serialize the config-mutating tests or scope the store per process if the package supports it.storage/logs/laravel.log and whatever file/cache key the package writes.Route::has(...) returning true in a non-testing environment is a smell. Inspect php artisan route:list in each environment once.POST route plus a file-backed config merge is a realistic afternoon, not a rewrite.vendor/ is avoidable here.Http::fake() or a Laravel fake will do. This is for browser tests where the app under test must behave differently — not for unit/feature tests, where Config::set() works normally.How can I help you explore Laravel packages today?