luttje / livewire-gloom
Laravel Dusk helpers for working with Livewire
Fund package maintenance!
luttje
Requires (Dev)
- php: ^8.1
- colinodell/indentation: ^1.0
- illuminate/contracts: ^10.0
- larastan/larastan: ^2.0.1
- laravel/dusk: ^7.0.0
- laravel/pint: ^1.0
- livewire/livewire: ^3.0.3
- luttje/php-example-tester: ^0.2.0
- nunomaduro/collision: ^7.9
- orchestra/testbench: >=8.18.0 <8.19.0
- orchestra/testbench-dusk: ^8.18
- phpstan/extension-installer: ^1.1
- phpstan/phpstan-deprecation-rules: ^1.0
- phpstan/phpstan-phpunit: ^1.0
- phpunit/phpunit: ^10.5
- spatie/laravel-package-tools: ^1.15.0
README
Add functions to Laravel Dusk for working with Livewire.
Warning
This package is still in development. It is not yet ready for production use and the API may change at any time.
Provided macros
The examples below test the NameComponent
Livewire component.
waitUntilLivewireCommitSucceeds
It can be tricky to know if Livewire finished a request cycle. You can work
with $browser->pause(...)
but that's not very reliable.
The waitUntilLivewireCommitSucceeds
method waits until Livewire finished a
request cycle for the specified method (and optionally parameters).
$browser->type('@name-input', 'John Doe') ->click('@split-button-debounced') ->waitUntilLivewireCommitSucceeds('splitNameParts', ['John Doe']) ->assertSeeIn('@first-name', 'John');
The above call won't match the request if the call has no parameters, or has different parameters. If you don't care about the parameters, you can omit them.
$browser->type('@name-input', 'John Doe') ->click('@split-button-debounced') ->waitUntilLivewireCommitSucceeds('splitNameParts') ->assertSeeIn('@first-name', 'John');
waitUntilLivewireCommitFails
The inverse of waitUntilLivewireCommitSucceeds
.
$browser->type('@name-input', 'John Doe') ->click('@button-to-404-debounced') ->waitUntilLivewireCommitFails('throws404') ->assertSeeIn('@first-name', 'empty');
clickAndWaitUntilLivewireCommitSucceeds
This sets up waitUntilLivewireCommitSucceeds
to listen for a Livewire request
cycle and clicks the element.
$parameters = ['John Doe']; // Optional, leave this out if you don't have parameters or wish to match any parameters $browser->type('@name-input', 'John Doe') ->clickAndWaitUntilLivewireCommitSucceeds('@split-button-debounced', 'splitNameParts', $parameters) ->assertSeeIn('@first-name', 'John');
waitUntilLivewireUpdateSucceeds
It can be tricky to know if Livewire finished a request cycle surrounding the
updating of a property. You can work with $browser->pause(...)
but that's not
very reliable.
The waitUntilLivewireUpdateSucceeds
method waits until Livewire finished a
request cycle for the specified property keys.
$browser->type('@age-input', '42') ->click('@split-button-debounced') ->waitUntilLivewireUpdateSucceeds(['age']) ->assertSeeIn('@age', '42');
Or for multiple properties:
$browser->type('@age-input', '42') ->type('@job-input', 'Plumber') ->click('@split-button-debounced') ->waitUntilLivewireUpdateSucceeds(['age', 'job']) ->assertSeeIn('@age', '42') ->assertSeeIn('@job', 'Plumber');
With this last example the browser will wait until an update cycle is finished
in which both the age
and job
livewire properties are updated.
If those properties are deferred (by default) then Livewire will wait
a request is made.
In the example above they are deferred until clicking @split-button-debounced
.
Regex matching
You can use Regex matching in waitUntilLivewireUpdateSucceeds
, just start the
property key with a /
and end it with /
:
$browser->type('@hobby-name-2', 'Gaming Professionally') ->click('@split-button-debounced') ->waitUntilLivewireUpdateSucceeds(['/hobbies\.[^\.]+\.name/']) ->assertValue('@hobby-name-2', 'Gaming Professionally');
waitUntilLivewireUpdateFails
The inverse of waitUntilLivewireUpdateSucceeds
.
$browser->type('@age-input', '42') ->click('@button-to-404-debounced') ->waitUntilLivewireUpdateFails(['age']) ->assertSeeIn('@age', '-1');
clickAndWaitUntilLivewireUpdateSucceeds
This sets up waitUntilLivewireUpdateSucceeds
to listen for a Livewire request
cycle and clicks the element.
$browser->type('@age-input', '42') ->clickAndWaitUntilLivewireUpdateSucceeds('@split-button-debounced', ['age']) ->assertSeeIn('@age', '42');
The action
parameter
Sometimes a sequence of actions may trigger too fast for you to listen for a Livewire commit or update:
// ! This test fails sometimes when the button is kinda slow. In that case the waitUntilLivewireCommitSucceeds is in time (but that's not reliable). $browser->type('@name-input', 'John Doe') ->click('@split-button') // *🚀 hyperfast split-button somehow already completed a full commit here* ->waitUntilLivewireCommitSucceeds('splitNameParts', ['John Doe']) // test fails here due to timeout ->assertSeeIn('@first-name', 'John');
Because the waitUntilLivewireCommitSucceeds
sets up the listener, it will
miss the commit that happened before it was set up. The test will then fail
with a timeout exception.
In such a situation you will want to be sure that before an action is started, we setup the listener. That way we don't miss the commit. To reiterate we want to:
- Set up the listener for the Livewire commit
- Click the button which triggers the Livewire commit
- Wait for the listener to be triggered by the Livewire commit (succeeding or failing)
- Assert now that we know the Livewire commit is finished
You can ensure of the above sequence by providing a closure, which we call an action. It will be executed after the listener is set up. The following functions support this:
waitUntilLivewireCommitSucceeds
waitUntilLivewireCommitFails
waitUntilLivewireUpdateSucceeds
waitUntilLivewireUpdateFails
Here is an example how you can use this action
parameter with
waitUntilLivewireCommitSucceeds
:
$browser->type('@name-input', 'John Doe') ->waitUntilLivewireCommitSucceeds( 'splitNameParts', ['John Doe'], action: function () use ($browser) { $browser->click('@split-button'); } ) ->assertSeeIn('@first-name', 'John');
Internally the clickAndWaitUntilLivewireCommitSucceeds
and
clickAndWaitUntilLivewireUpdateSucceeds
functions use the action
parameter
to call click
on the Browser. So the above example can be simplified by using
either of those functions.
Note
All of the above examples are taken from the tests. If you want to see more code surrounding the examples, check out those tests.
To generate the examples, run composer compile-readme
. This is done
through luttje/php-example-tester.
Installation
You can install the package via composer:
composer require luttje/livewire-gloom
Usage
Create a new Dusk test case and use the macros described above:
class ExampleTest extends BrowserTestCase { public function testExample(): void { $this->browse(function (Browser $browser) { $browser->visit('/example') ->type('@name-input', 'John Doe') ->clickAndWaitUntilLivewireCommitSucceeds('@split-button', 'splitNameParts', ['John Doe']) ->assertSeeIn('@first-name', 'John'); }); } }
Testing
Make sure you have installed the Dusk Chrome driver by running:
./vendor/bin/dusk-updater detect --auto-update
Then run the tests with:
composer test
License
The MIT License (MIT). Please see License File for more information.
e (MIT). Please see License File for more information.