Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Tddd Laravel Package

pragmarx/tddd

TDDD (Test Driven Development Dashboard) gives Laravel developers a live web dashboard for their test suite: run your tests and watch pass/fail results, timings and failure details update in real time, keeping the red-green-refactor loop fast and visible without digging through terminal output.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal steps

  1. Install it as a dev-only dependency in the Laravel app you want to watch:
    composer require pragmarx/tddd --dev
    
  2. Publish the package config (check php artisan vendor:publish output for the exact tag/provider — it varies between releases):
    php artisan vendor:publish --tag=tddd
    
  3. Open config/tddd.php and point at least one project at a test directory. The config is an array of "projects"; each entry needs a name, a filesystem path to watch, and the command used to run its tests (typically vendor/bin/phpunit, vendor/bin/pest, or php artisan test).
  4. Start the watcher + dashboard:
    php artisan tddd
    
    The command prints the dashboard URL (usually http://localhost on a dedicated port). Open it, save any file under the watched path, and watch the run appear.

Where to look first

  • config/tddd.php — the entire behaviour of the package (projects, watch globs, test commands, server/websocket settings) is driven from here. Read the published file end-to-end before touching anything else.
  • php artisan list — confirm the actual command names in your installed version; the package exposes a watcher command plus (in some versions) helpers to run a single project's tests.
  • vendor/pragmarx/tddd/src — when a run doesn't show up, this is where the watcher and the output parser live. It is a small codebase and readable.

First use case

The highest-value first setup is a single Laravel project watching only tests/ and app/, running PHPUnit/Pest on every save, and leaving the dashboard open on a second monitor. That turns "edit → alt-tab → run tests → read terminal" into "edit → glance at dashboard" and is the entire pitch of the package.

Implementation Patterns

Declare projects, not directories. The projects array is the unit of configuration, and each project carries its own path and test command. Model it the way you actually work:

'projects' => [
    [
        'name'    => 'App — unit',
        'path'    => base_path(),
        'tests'   => base_path('tests/Unit'),
        'command' => 'vendor/bin/phpunit --testsuite=Unit',
    ],
    [
        'name'    => 'App — feature',
        'path'    => base_path(),
        'tests'   => base_path('tests/Feature'),
        'command' => 'vendor/bin/phpunit --testsuite=Feature',
    ],
],

Split fast from slow. Unit tests (milliseconds) and Dusk/browser/integration tests (tens of seconds) should be separate projects so a unit save doesn't kick off a browser run. Many teams simply never wire Dusk into the watcher and run it manually — that's a legitimate pattern, not a workaround.

Constrain the watch paths aggressively. Watch app/, tests/, routes/, config/, database/ — never the repo root. Every watched save triggers a full test command; the difference between a 30-file watch and a 30,000-file watch is the difference between a usable dashboard and a fan spinning up.

Use it alongside, not instead of, artisan serve. Typical local stack: php artisan serve in one terminal, npm run watch in another, php artisan tddd in a third, dashboard in a browser tab. The package does not serve your app; it only serves its own dashboard and runs test commands as child processes.

Wrap your runner if the parser doesn't understand it. The dashboard parses test output to extract pass/fail counts and failing test names. If you use Pest, ParaTest, or a custom runner whose output format differs from PHPUnit's classic output, either pin the command to PHPUnit-compatible output (--testdox or similar) or write a thin wrapper script and point command at the wrapper.

Custom command per project is the extension point. Any executable works as a command as long as it writes results to stdout/stderr. That means you can watch a Composer package's suite, a second Laravel app in a monorepo, or a JS project's npm test from the same dashboard.

Realtime vs polling. If the websocket/broadcast piece is configured, results push to the browser instantly; without it the dashboard polls. On a laptop, polling is fine and removes a moving part. Only wire up the realtime transport if you're running the dashboard on a shared dev box for a team.

Shared dev host pattern. Run tddd on a build machine, expose the dashboard port on the LAN, and each developer gets a live view of the branch under test. This is the "self-hosted dashboard" use case the package was designed for — but it only makes sense once you've validated it works for a single developer locally.

Gotchas and Tips

It is a dev dependency and should stay one. Everything is behind require-dev, and there is no reason for the dashboard, routes, or watcher to be registered in production. If you see stray routes or config in a deployed app, check composer.json and APP_ENV guards.

Package age is the biggest risk. This is a 2018-era package and its dependency constraints reflect that. Before adopting, run composer why-not pragmarx/tddd against your Laravel/PHP version. On Laravel 10/11 and PHP 8.2+ you may need to fork it, relax constraints, or accept that it won't install. Budget time for this — a clean composer require on a modern app is not a given.

php artisan config:cache will bite you. If anyone on the team has cached config, edits to config/tddd.php silently do nothing. php artisan config:clear when the dashboard ignores your changes. In CI/CD, make sure the cache step doesn't cache a stale tddd config into an image.

Watch for save-triggered loops. Editors that write temp files, run formatters on save, or write to a watched directory can trigger two, three, or more runs per keystroke. Watch the watcher output; if you see cascades, add the formatter's temp paths to the exclude list and consider your editor's atomic-save setting. Tests that themselves write into watched directories (snapshot updates, log files in app/) will also loop — exclude them.

Always exclude vendor/, node_modules/, storage/, .git/, and bootstrap/cache/. A missing exclude here is the number one cause of "the dashboard is stuck / the watcher is pegging a core."

Test isolation is on you. The watcher runs your test command repeatedly against your working environment. If the command hits the dev database, you'll see flapping failures and possibly data loss. Force an isolated test DB in the command itself (--env=testing or an inline DB_DATABASE=:memory:), don't rely on the developer's .env.

Port and process conflicts. The dashboard binds a port; the websocket listener binds another. Two developers on one box, or a leftover watcher process, means EADDRINUSE. php artisan tddd is a foreground process — kill it explicitly, and check for orphaned test processes after a crash.

Long-running memory growth. The watcher and any embedded websocket server will accumulate memory across hundreds of runs. If the dashboard stops updating after a few hours, restart the command. Don't run it as a daemon expecting it to survive a day of edits.

Dusk and browser tests need their own infrastructure. The watcher will happily run your Dusk command, but it does not start ChromeDriver, and a failed Chromedriver handshake looks identical to a test failure in the dashboard. Start the driver yourself or leave Dusk out of the watcher.

Debugging checklist when a run doesn't appear:

  1. Run the exact command string manually from the project's path in a shell — if it fails there, it fails in the watcher.
  2. Confirm the file you saved is under a watched glob (watchers are usually exact-directory, not recursive-by-default — check the config's glob syntax).
  3. php artisan config:clear, then restart tddd.
  4. Tail the command's terminal output; parser errors surface there before they surface in the browser.
  5. Check storage/logs/laravel.log — the package proxies through Laravel's logger for its own failures.

Have a fallback in your pocket. If the package doesn't install cleanly on your stack, the same workflow is achievable with spatie/phpunit-watcher or Pest's built-in --watch, at the cost of the dashboard UI. Validate the package on a scratch branch before pitching it to a team as the standard workflow.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource