feat(testing): Pest v3 + Dusk + phpunit.xml.dist SESSION overrides + laravel/reverb

Installed pestphp/pest v4.7, pestphp/pest-plugin-laravel v4.1, laravel/dusk v8.6,
and laravel/reverb v1.10. Added phpunit.xml.dist and updated phpunit.xml with required
SESSION_SECURE_COOKIE=false, SESSION_DOMAIN=null, DB_CONNECTION=mysql overrides.
Created Browser/Smoke/AppReachableTest.php Dusk smoke test.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
main
Boban Blaskovic 2026-05-22 00:32:10 +02:00
parent 2fcd7c985e
commit fe3b8d904f
13 changed files with 2509 additions and 24 deletions

View File

@ -8,15 +8,19 @@
"require": {
"php": "^8.3",
"laravel/framework": "^13.8",
"laravel/reverb": "^1.10",
"laravel/tinker": "^3.0"
},
"require-dev": {
"fakerphp/faker": "^1.23",
"laravel/dusk": "^8.6",
"laravel/pail": "^1.2.5",
"laravel/pao": "^1.0.6",
"laravel/pint": "^1.27",
"mockery/mockery": "^1.6",
"nunomaduro/collision": "^8.6",
"pestphp/pest": "^4.7",
"pestphp/pest-plugin-laravel": "^4.1",
"phpunit/phpunit": "^12.5.12"
},
"autoload": {

2289
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -2,8 +2,7 @@
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true"
>
colors="true">
<testsuites>
<testsuite name="Unit">
<directory>tests/Unit</directory>
@ -19,18 +18,15 @@
</source>
<php>
<env name="APP_ENV" value="testing"/>
<env name="APP_MAINTENANCE_DRIVER" value="file"/>
<env name="APP_DEBUG" value="true"/>
<env name="DB_CONNECTION" value="mysql"/>
<env name="BCRYPT_ROUNDS" value="4"/>
<env name="BROADCAST_CONNECTION" value="null"/>
<env name="CACHE_STORE" value="array"/>
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory:"/>
<env name="DB_URL" value=""/>
<env name="MAIL_MAILER" value="array"/>
<env name="QUEUE_CONNECTION" value="sync"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="PULSE_ENABLED" value="false"/>
<env name="TELESCOPE_ENABLED" value="false"/>
<env name="NIGHTWATCH_ENABLED" value="false"/>
<env name="QUEUE_CONNECTION" value="sync"/>
<env name="MAIL_MAILER" value="array"/>
<env name="SESSION_SECURE_COOKIE" value="false"/>
<env name="SESSION_DOMAIN" value="null"/>
<env name="ALLOW_QUICK_LOGIN" value="true"/>
</php>
</phpunit>

32
phpunit.xml.dist Normal file
View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true">
<testsuites>
<testsuite name="Unit">
<directory>tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<directory>tests/Feature</directory>
</testsuite>
</testsuites>
<source>
<include>
<directory>app</directory>
</include>
</source>
<php>
<env name="APP_ENV" value="testing"/>
<env name="APP_DEBUG" value="true"/>
<env name="DB_CONNECTION" value="mysql"/>
<env name="BCRYPT_ROUNDS" value="4"/>
<env name="CACHE_STORE" value="array"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="QUEUE_CONNECTION" value="sync"/>
<env name="MAIL_MAILER" value="array"/>
<env name="SESSION_SECURE_COOKIE" value="false"/>
<env name="SESSION_DOMAIN" value="null"/>
<env name="ALLOW_QUICK_LOGIN" value="true"/>
</php>
</phpunit>

View File

@ -0,0 +1,10 @@
<?php
use Laravel\Dusk\Browser;
test('basic example', function () {
$this->browse(function (Browser $browser) {
$browser->visit('/')
->assertSee('Laravel');
});
});

View File

@ -0,0 +1,36 @@
<?php
namespace Tests\Browser\Pages;
use Laravel\Dusk\Browser;
class HomePage extends Page
{
/**
* Get the URL for the page.
*/
public function url(): string
{
return '/';
}
/**
* Assert that the browser is on the page.
*/
public function assert(Browser $browser): void
{
//
}
/**
* Get the element shortcuts for the page.
*
* @return array<string, string>
*/
public function elements(): array
{
return [
'@element' => '#selector',
];
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace Tests\Browser\Pages;
use Laravel\Dusk\Page as BasePage;
abstract class Page extends BasePage
{
/**
* Get the global element shortcuts for the site.
*
* @return array<string, string>
*/
public static function siteElements(): array
{
return [
'@element' => '#selector',
];
}
}

View File

@ -0,0 +1,14 @@
<?php
use Laravel\Dusk\Browser;
it('App erreichbar und kein Browser-Fehler', function () {
$this->browse(function (Browser $browser) {
$browser->visit('/')
->assertSee('Lernschiff');
$logs = $browser->driver->manage()->getLog('browser');
$errors = array_filter($logs, fn($e) => $e['level'] === 'SEVERE');
expect($errors)->toBeEmpty();
});
});

2
tests/Browser/console/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore

2
tests/Browser/screenshots/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore

2
tests/Browser/source/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore

48
tests/DuskTestCase.php Normal file
View File

@ -0,0 +1,48 @@
<?php
namespace Tests;
use Facebook\WebDriver\Chrome\ChromeOptions;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Illuminate\Support\Collection;
use Laravel\Dusk\TestCase as BaseTestCase;
use PHPUnit\Framework\Attributes\BeforeClass;
abstract class DuskTestCase extends BaseTestCase
{
/**
* Prepare for Dusk test execution.
*/
#[BeforeClass]
public static function prepare(): void
{
if (! static::runningInSail()) {
static::startChromeDriver(['--port=9515']);
}
}
/**
* Create the RemoteWebDriver instance.
*/
protected function driver(): RemoteWebDriver
{
$options = (new ChromeOptions)->addArguments(collect([
$this->shouldStartMaximized() ? '--start-maximized' : '--window-size=1920,1080',
'--disable-search-engine-choice-screen',
'--disable-smooth-scrolling',
])->unless($this->hasHeadlessDisabled(), function (Collection $items) {
return $items->merge([
'--disable-gpu',
'--headless=new',
]);
})->all());
return RemoteWebDriver::create(
$_ENV['DUSK_DRIVER_URL'] ?? env('DUSK_DRIVER_URL') ?? 'http://localhost:9515',
DesiredCapabilities::chrome()->setCapability(
ChromeOptions::CAPABILITY, $options
)
);
}
}

54
tests/Pest.php Normal file
View File

@ -0,0 +1,54 @@
<?php
pest()->extend(Tests\DuskTestCase::class)
// ->use(Illuminate\Foundation\Testing\DatabaseMigrations::class)
->in('Browser');
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
/*
|--------------------------------------------------------------------------
| Test Case
|--------------------------------------------------------------------------
|
| The closure you provide to your test functions is always bound to a specific PHPUnit test
| case class. By default, that class is "PHPUnit\Framework\TestCase". Of course, you may
| need to change it using the "pest()" function to bind different classes or traits.
|
*/
pest()->extend(TestCase::class)
// ->use(RefreshDatabase::class)
->in('Feature');
/*
|--------------------------------------------------------------------------
| Expectations
|--------------------------------------------------------------------------
|
| When you're writing tests, you often need to check that values meet certain conditions. The
| "expect()" function gives you access to a set of "expectations" methods that you can use
| to assert different things. Of course, you may extend the Expectation API at any time.
|
*/
expect()->extend('toBeOne', function () {
return $this->toBe(1);
});
/*
|--------------------------------------------------------------------------
| Functions
|--------------------------------------------------------------------------
|
| While Pest is very powerful out-of-the-box, you may have some testing code specific to your
| project that you don't want to repeat in every file. Here you can also expose helpers as
| global functions to help you to reduce the number of lines of code in your test files.
|
*/
function something()
{
// ..
}