Skip to content

Commit 6457645

Browse files
committed
Update TestCase.php
Initial commit Add integration test for parallel worker sessions Rewrite integration test to use real parallel processes Add Dusk fixture suite and run it under paratest in integration tests Replace fixture tests with real Dusk browser tests against a local server Split fixture suite into LoginTest, DashboardTest and NavigationTest Fix missing --browse and --without-tty options in DuskParallelCommand
0 parents  commit 6457645

19 files changed

+690
-0
lines changed

.github/workflows/ci.yml

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
name: Tests
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
unit:
11+
runs-on: ubuntu-latest
12+
13+
strategy:
14+
fail-fast: false
15+
matrix:
16+
php: ['8.1', '8.2', '8.3', '8.4']
17+
18+
name: Unit (PHP ${{ matrix.php }})
19+
20+
steps:
21+
- name: Checkout
22+
uses: actions/checkout@v4
23+
24+
- name: Setup PHP
25+
uses: shivammathur/setup-php@v2
26+
with:
27+
php-version: ${{ matrix.php }}
28+
extensions: zip, json
29+
coverage: none
30+
31+
- name: Install dependencies
32+
run: composer install --prefer-dist --no-interaction --no-progress
33+
34+
- name: Run unit tests
35+
run: vendor/bin/phpunit --testsuite=Unit
36+
37+
integration:
38+
runs-on: ubuntu-latest
39+
40+
name: Integration (PHP 8.3)
41+
42+
steps:
43+
- name: Checkout
44+
uses: actions/checkout@v4
45+
46+
- name: Setup PHP
47+
uses: shivammathur/setup-php@v2
48+
with:
49+
php-version: '8.3'
50+
extensions: zip, json
51+
coverage: none
52+
53+
- name: Install dependencies
54+
run: composer install --prefer-dist --no-interaction --no-progress
55+
56+
- name: Start test services
57+
run: |
58+
php -S localhost:8000 -t tests/Integration/Fixtures/public &
59+
chromedriver --port=9515 &
60+
chromedriver --port=9516 &
61+
sleep 2
62+
63+
- name: Run integration tests
64+
run: vendor/bin/phpunit --testsuite=Integration

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/.idea
2+
/vendor
3+
.phpunit.result.cache
4+
*.lock

composer.json

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
{
2+
"name": "jackbayliss/laravel-dusk-parallel",
3+
"description": "Parallel test execution for Laravel Dusk.",
4+
"keywords": [
5+
"laravel",
6+
"dusk",
7+
"testing",
8+
"parallel"
9+
],
10+
"license": "MIT",
11+
"authors": [
12+
{
13+
"name": "Jack Bayliss",
14+
"email": "jjbdev@proton.me"
15+
}
16+
],
17+
"require": {
18+
"php": "^8.1",
19+
"laravel/dusk": "^8.0|^9.0"
20+
},
21+
"require-dev": {
22+
"brianium/paratest": "^7.0|^8.0",
23+
"orchestra/testbench": "^8.0|^9.0|^10.0",
24+
"phpunit/phpunit": "^10.5|^11.0"
25+
},
26+
"suggest": {
27+
"brianium/paratest": "Required for PHPUnit parallel execution. Not needed when using Pest --parallel."
28+
},
29+
"autoload": {
30+
"psr-4": {
31+
"JackBayliss\\DuskParallel\\": "src/"
32+
}
33+
},
34+
"autoload-dev": {
35+
"psr-4": {
36+
"JackBayliss\\DuskParallel\\Tests\\": "tests/"
37+
}
38+
},
39+
"extra": {
40+
"laravel": {
41+
"providers": [
42+
"JackBayliss\\DuskParallel\\DuskParallelServiceProvider"
43+
]
44+
}
45+
},
46+
"scripts": {
47+
"test": "vendor/bin/phpunit"
48+
},
49+
"config": {
50+
"sort-packages": true
51+
},
52+
"minimum-stability": "dev",
53+
"prefer-stable": true
54+
}

phpunit.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
4+
bootstrap="vendor/autoload.php"
5+
colors="true"
6+
>
7+
<testsuites>
8+
<testsuite name="Unit">
9+
<directory>tests/Unit</directory>
10+
</testsuite>
11+
<testsuite name="Integration">
12+
<directory>tests/Integration</directory>
13+
</testsuite>
14+
</testsuites>
15+
</phpunit>
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
namespace JackBayliss\DuskParallel\Console;
4+
5+
use Laravel\Dusk\Console\DuskCommand;
6+
use Symfony\Component\Console\Attribute\AsCommand;
7+
8+
#[AsCommand(name: 'dusk:parallel')]
9+
class DuskParallelCommand extends DuskCommand
10+
{
11+
protected $signature = 'dusk:parallel
12+
{--processes=2 : Number of parallel processes to use}
13+
{--browse : Open a browser instead of using headless mode}
14+
{--without-tty : Disable output to TTY}';
15+
16+
protected $description = 'Run the Dusk tests in parallel';
17+
18+
protected function binary()
19+
{
20+
$paratestPath = base_path('vendor/bin/paratest');
21+
22+
if (! file_exists($paratestPath)) {
23+
$this->error('paratest not found. Install it with: composer require --dev brianium/paratest');
24+
25+
exit(1);
26+
}
27+
28+
return [PHP_BINARY, $paratestPath];
29+
}
30+
31+
protected function phpunitArguments($options)
32+
{
33+
$options = array_values(array_filter($options, function ($option) {
34+
return ! str_starts_with($option, '--processes=')
35+
&& ! str_starts_with($option, '--runner=');
36+
}));
37+
38+
$args = parent::phpunitArguments($options);
39+
40+
$args[] = '--processes';
41+
$args[] = $this->option('processes');
42+
43+
$args[] = '--runner';
44+
$args[] = 'WrapperRunner';
45+
46+
return $args;
47+
}
48+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace JackBayliss\DuskParallel;
4+
5+
use Illuminate\Support\ServiceProvider;
6+
use JackBayliss\DuskParallel\Console\DuskParallelCommand;
7+
8+
class DuskParallelServiceProvider extends ServiceProvider
9+
{
10+
/**
11+
* Register the service provider.
12+
*
13+
* @return void
14+
*/
15+
public function register(): void
16+
{
17+
if ($this->app->runningInConsole()) {
18+
$this->commands([
19+
DuskParallelCommand::class,
20+
]);
21+
}
22+
}
23+
}

src/ParallelDriver.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
namespace JackBayliss\DuskParallel;
4+
5+
class ParallelDriver
6+
{
7+
public static function runningInParallel(): bool
8+
{
9+
return isset($_ENV['TEST_TOKEN']);
10+
}
11+
12+
public static function parallelDriverPort(): int
13+
{
14+
return 9515 + (int) $_ENV['TEST_TOKEN'];
15+
}
16+
17+
public static function hasExplicitPort(array $arguments): bool
18+
{
19+
foreach ($arguments as $argument) {
20+
if (str_starts_with($argument, '--port=')) {
21+
return true;
22+
}
23+
}
24+
25+
return false;
26+
}
27+
28+
public static function hasExplicitDriverUrl(): bool
29+
{
30+
return isset($_ENV['DUSK_DRIVER_URL']) || env('DUSK_DRIVER_URL') !== null;
31+
}
32+
33+
public static function resolveDriverArguments(array $arguments = []): array
34+
{
35+
if (static::runningInParallel() && ! static::hasExplicitDriverUrl() && ! static::hasExplicitPort($arguments)) {
36+
$arguments[] = '--port='.static::parallelDriverPort();
37+
}
38+
39+
return $arguments;
40+
}
41+
42+
public static function resolveDriverUrl(): string
43+
{
44+
$url = $_ENV['DUSK_DRIVER_URL'] ?? env('DUSK_DRIVER_URL');
45+
46+
if (! $url && static::runningInParallel()) {
47+
$url = 'http://localhost:'.static::parallelDriverPort();
48+
}
49+
50+
return $url ?? 'http://localhost:9515';
51+
}
52+
}

src/TestCase.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace JackBayliss\DuskParallel;
4+
5+
use Facebook\WebDriver\Remote\DesiredCapabilities;
6+
use Facebook\WebDriver\Remote\RemoteWebDriver;
7+
use Laravel\Dusk\TestCase as DuskTestCase;
8+
9+
abstract class TestCase extends DuskTestCase
10+
{
11+
public static function startChromeDriver(array $arguments = []): void
12+
{
13+
parent::startChromeDriver(ParallelDriver::resolveDriverArguments($arguments));
14+
}
15+
16+
protected function driver(): RemoteWebDriver
17+
{
18+
return RemoteWebDriver::create(
19+
ParallelDriver::resolveDriverUrl(),
20+
DesiredCapabilities::chrome()
21+
);
22+
}
23+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace JackBayliss\DuskParallel\Tests\Integration\Fixtures;
4+
5+
use Laravel\Dusk\Browser;
6+
7+
class DashboardTest extends DuskTestCase
8+
{
9+
public function test_dashboard_page_loads(): void
10+
{
11+
$this->browse(function (Browser $browser) {
12+
$browser->visit('/dashboard.html')
13+
->assertTitle('Dashboard - Test App')
14+
->assertSee('You are logged in.');
15+
});
16+
}
17+
18+
public function test_dashboard_has_home_link(): void
19+
{
20+
$this->browse(function (Browser $browser) {
21+
$browser->visit('/dashboard.html')
22+
->assertSeeLink('Home');
23+
});
24+
}
25+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace JackBayliss\DuskParallel\Tests\Integration\Fixtures;
4+
5+
use JackBayliss\DuskParallel\TestCase;
6+
use Orchestra\Testbench\Concerns\CreatesApplication;
7+
8+
abstract class DuskTestCase extends TestCase
9+
{
10+
use CreatesApplication;
11+
12+
protected function baseUrl(): string
13+
{
14+
return 'http://localhost:8000';
15+
}
16+
}

0 commit comments

Comments
 (0)