Replace Dusk with Pest 4 browser testing (Playwright) #54
Labels
No labels
app
backlog
bug
ci-cd
contribution welcome
duplicate
enhancement
good first issue
help wanted
question
testing
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Blocks
#55 Add browser test for registration}
lvl0/dishplanner
#56 Add browser test for logout}
lvl0/dishplanner
#57 Add browser tests for editing and deleting users}
lvl0/dishplanner
#58 Add browser test for skipping a meal and marking eating out}
lvl0/dishplanner
#59 Add browser test for the dashboard}
lvl0/dishplanner
Reference: lvl0/dishplanner#54
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Why
Laravel's own documentation now steers new browser testing away from Dusk:
Dusk is not deprecated and stays supported, but the direction has moved.
Three reasons this matters here specifically:
DuskTestCasecurrently carriesTIMEOUT_SHORT = 2,TIMEOUT_MEDIUM = 3,PAUSE_SHORT = 500,PAUSE_MEDIUM = 1000. Playwright auto-waits on every interaction, which removes most of that class of flakiness. This app is Blade + Livewire + Alpine, so nearly every assertion follows awire:round-trip — precisely where fixed pauses are fragile.pest --headedopens a real browser window so a fix can be watched end-to-end, andpest --debugpauses on failure with the browser open. This is wanted for verifying bug fixes rather than trusting a green assertion.--paralleland--shard.Migration size
11 browser tests across four areas:
tests/Browser/Auth/tests/Browser/Dishes/tests/Browser/Schedule/tests/Browser/Users/tests/Browser/RedirectTest.phpNone use
RefreshDatabase. This is a real port, not a trivial one — but still small enough to be worth doing before browser coverage grows further.Scope
Install
Pest is a wrapper around PHPUnit, not a replacement — existing PHPUnit test cases are reused as-is, so the existing PHPUnit suite keeps working. Installation does involve
composer remove phpunit/phpunit(Pest pulls its own PHPUnit 12), so the dependency swap needs care.Port all 11 tests in
tests/Browser/to Pest browser syntax, including theLoginHelpers.phpshared helper.Remove Dusk once the ports pass:
laravel/duskfrom composer,tests/DuskTestCase.php,phpunit.dusk.xml,.env.dusk.local, and theseleniumservice from the compose file. Also clean up thetests/Browser/console,screenshots, andsourceartifact directories Dusk generates.CI —
.forgejo/workflows/ci.ymlbuilds a PHP-only image with no Node. Playwright needs Node plus browser binaries, so the CI image or workflow needs extending. Scope this before starting; it may be the largest part of the work.shell.nix— add a helper for headed runs.Verify
phpunit.xmlsurvivesphpunit.xmlwas just hardened in #53 with<server>+force="true"on every value, which is what stops tests from wiping the dev database. Confirm those still apply under Pest, and that a run withAPP_ENV=localin the environment still resolves to sqlite:memory:.Note that Dusk's
.env.dusk.localuses real MySQL (dishplanner_test), so it was never covered by #53's fix — removing Dusk also removes that exposure.Known limitations, accepted
Pest's plugin is a thin wrapper over Playwright and does not expose everything raw Playwright does:
page.route()). Not needed here — server-rendered Livewire (Blade + 4 Livewire components + Alpine, no React/Vue), andHttp::fake()covers third-party calls at the PHP layer.What it does cover: click, type, select, check, radio, file upload, keyboard with modifiers, hover, drag, iframes, resize; Chrome/Firefox/Safari; mobile viewports and device presets; dark mode; geolocation; accessibility scanning; console-error assertions; ARIA assertions.
Out of scope
pest-plugin-driftcan do it later if wanted; nothing forces it.Acceptance
pest-plugin-browserand Playwright installedpest --headedopens a visible browser locallyphpunit.dusk.xml,.env.dusk.local, and Dusk artifact dirs removedAPP_ENV=localset still uses sqlite:memory:and leaves thedishplannerdatabase untouched