├── .github ├── FUNDING.yml └── workflows │ └── static.yml ├── src ├── Contracts │ ├── ManagerContract.php │ ├── Drivers │ │ └── DriverContract.php │ ├── ConsoleBrowserContract.php │ └── ConsoleBrowserFactoryContract.php ├── ConsoleBrowserFactory.php ├── Drivers │ └── Chrome.php ├── Manager.php ├── LaravelConsoleDuskServiceProvider.php └── ConsoleBrowser.php ├── LICENSE.md ├── config └── laravel-console-dusk.php ├── composer.json └── README.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [nunomaduro] 4 | custom: https://www.paypal.com/paypalme/enunomaduro 5 | -------------------------------------------------------------------------------- /src/Contracts/ManagerContract.php: -------------------------------------------------------------------------------- 1 | driver = $driver; 23 | 24 | return new ConsoleBrowser($command, new Browser($this->createWebDriver())); 25 | } 26 | 27 | protected function driver() 28 | { 29 | return $this->driver->getDriver(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Nuno Maduro 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /config/laravel-console-dusk.php: -------------------------------------------------------------------------------- 1 | [ 13 | 'screenshots' => storage_path('laravel-console-dusk/screenshots'), 14 | 'log' => storage_path('laravel-console-dusk/log'), 15 | 'source' => storage_path('laravel-console-dusk/source'), 16 | ], 17 | 18 | /* 19 | | -------------------------------------------------------------------------- 20 | | Headless Mode 21 | | -------------------------------------------------------------------------- 22 | | 23 | | When false it will show a Chrome window while running. Within production 24 | | it will be forced to run in headless mode. 25 | */ 26 | 'headless' => true, 27 | 28 | /* 29 | | -------------------------------------------------------------------------- 30 | | Driver Configuration 31 | | -------------------------------------------------------------------------- 32 | | 33 | | Here you may pass options to the browser driver being automated. 34 | | 35 | | A list of available Chromium command line switches is available at 36 | | https://peter.sh/experiments/chromium-command-line-switches/ 37 | */ 38 | 'driver' => [ 39 | 'chrome' => [ 40 | 'options' => [ 41 | '--disable-gpu', 42 | ], 43 | ], 44 | ], 45 | ]; 46 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nunomaduro/laravel-console-dusk", 3 | "description": "Laravel Console Dusk allows the usage of Laravel Dusk in Laravel/Laravel Zero artisan commands.", 4 | "keywords": ["console", "command-line", "php", "cli", "laravel-zero", "laravel", "Laravel Dusk", "artisan", "symfony"], 5 | "license": "MIT", 6 | "support": { 7 | "issues": "https://github.com/nunomaduro/laravel-console-dusk/issues", 8 | "source": "https://github.com/nunomaduro/laravel-console-dusk" 9 | }, 10 | "authors": [ 11 | { 12 | "name": "Nuno Maduro", 13 | "email": "enunomaduro@gmail.com" 14 | } 15 | ], 16 | "require": { 17 | "php": "^8.2", 18 | "laravel/dusk": "^8.2", 19 | "illuminate/console": "^11.4|^12.0", 20 | "illuminate/support": "^11.4|^12.0", 21 | "nunomaduro/laravel-console-task": "^1.9" 22 | }, 23 | "require-dev": { 24 | "laravel/pint": "^1.21" 25 | }, 26 | "autoload": { 27 | "psr-4": { 28 | "NunoMaduro\\LaravelConsoleDusk\\": "src/" 29 | } 30 | }, 31 | "config": { 32 | "preferred-install": "dist", 33 | "sort-packages": true 34 | }, 35 | "scripts": { 36 | "lint": "pint --ansi", 37 | "test:lint": "pint --test --ansi", 38 | "test": [ 39 | "@test:lint" 40 | ] 41 | }, 42 | "extra": { 43 | "laravel": { 44 | "providers": [ 45 | "NunoMaduro\\LaravelConsoleDusk\\LaravelConsoleDuskServiceProvider" 46 | ] 47 | } 48 | }, 49 | "suggest": { 50 | "phpunit/phpunit": "Required to perform browser test assertions." 51 | }, 52 | "minimum-stability": "dev", 53 | "prefer-stable": true 54 | } 55 | -------------------------------------------------------------------------------- /src/Drivers/Chrome.php: -------------------------------------------------------------------------------- 1 | addArguments( 36 | array_filter(array_merge( 37 | config('laravel-console-dusk.driver.chrome.options', []), 38 | [$this->runHeadless()] 39 | )) 40 | ); 41 | 42 | return RemoteWebDriver::create( 43 | $_ENV['DUSK_DRIVER_URL'] ?? 'http://localhost:9515', 44 | DesiredCapabilities::chrome() 45 | ->setCapability( 46 | ChromeOptions::CAPABILITY, 47 | $options 48 | ) 49 | ); 50 | } 51 | 52 | /** 53 | * Running around headless, or not.. 54 | */ 55 | protected function runHeadless(): ?string 56 | { 57 | return ! config('laravel-console-dusk.headless', true) && ! app()->isProduction() ? null : '--headless'; 58 | } 59 | 60 | public function __destruct() 61 | { 62 | $this->close(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Manager.php: -------------------------------------------------------------------------------- 1 | driver = $driver ?: new Chrome; 26 | $this->browserFactory = $browserFactory ?: new ConsoleBrowserFactory; 27 | } 28 | 29 | public function browse(Command $command, Closure $callback): void 30 | { 31 | $this->driver->open(); 32 | 33 | $browsers = $this->createBrowsers($command, $callback); 34 | 35 | try { 36 | $callback(...$browsers->all()); 37 | } catch (\Throwable $e) { 38 | } 39 | 40 | $browsers->each->quit(); 41 | 42 | $this->driver->close(); 43 | 44 | if (! empty($e)) { 45 | throw $e; 46 | } 47 | } 48 | 49 | /** @return Collection */ 50 | protected function createBrowsers(Command $command, Closure $callback): Collection 51 | { 52 | $browsers = collect(); 53 | 54 | $browsersNeededFor = (new ReflectionFunction($callback))->getNumberOfParameters(); 55 | 56 | for ($i = 0; $i < $browsersNeededFor; $i++) { 57 | $browsers->push($this->browserFactory->make($command, $this->driver)); 58 | } 59 | 60 | return $browsers; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/LaravelConsoleDuskServiceProvider.php: -------------------------------------------------------------------------------- 1 | app->runningInConsole()) { 20 | $this->publishes([ 21 | __DIR__.'/../config/laravel-console-dusk.php' => config_path('laravel-console-dusk.php'), 22 | ], 'config'); 23 | 24 | $manager = resolve(ManagerContract::class); 25 | 26 | Browser::$baseUrl = config('app.url'); 27 | Browser::$storeScreenshotsAt = $this->getPath(config('laravel-console-dusk.paths.screenshots')); 28 | Browser::$storeConsoleLogAt = $this->getPath(config('laravel-console-dusk.paths.log')); 29 | Browser::$storeSourceAt = $this->getPath(config('laravel-console-dusk.paths.source')); 30 | 31 | Command::macro('browse', function ($callback) use ($manager) { 32 | $manager->browse($this, $callback); 33 | }); 34 | } 35 | } 36 | 37 | public function register(): void 38 | { 39 | $this->mergeConfigFrom(__DIR__.'/../config/laravel-console-dusk.php', 'laravel-console-dusk'); 40 | 41 | $this->app->bind(ManagerContract::class, function ($app) { 42 | return new Manager; 43 | }); 44 | 45 | $this->commands([ 46 | ChromeDriverCommand::class, 47 | ]); 48 | } 49 | 50 | public function provides(): array 51 | { 52 | return [ManagerContract::class]; 53 | } 54 | 55 | protected function getPath(string $path): string 56 | { 57 | return tap($path, function ($path) { 58 | if (! File::exists($path)) { 59 | File::makeDirectory($path, 0755, true); 60 | } 61 | }); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/ConsoleBrowser.php: -------------------------------------------------------------------------------- 1 | command = $command; 23 | $this->browser = $browser; 24 | } 25 | 26 | public function getOriginalBrowser(): Browser 27 | { 28 | return $this->browser; 29 | } 30 | 31 | public function inSecret(): ConsoleBrowserContract 32 | { 33 | $this->inSecret = true; 34 | 35 | return $this; 36 | } 37 | 38 | public function __call(string $name, array $arguments) 39 | { 40 | $description = $this->getHumanReadableMethodDescription($name, $arguments); 41 | 42 | $exception = null; 43 | $result = null; 44 | 45 | $this->command->task($description, function () use ($name, $arguments, &$exception, &$result) { 46 | try { 47 | $result = call_user_func_array([$this->browser, $name], $arguments); 48 | } catch (\Throwable $e) { 49 | $exception = $e; 50 | 51 | return false; 52 | } 53 | }); 54 | 55 | if ($exception !== null) { 56 | throw $exception; 57 | } 58 | 59 | return $result instanceof Browser ? $this : $result; 60 | } 61 | 62 | protected function getHumanReadableMethodDescription(string $methodName, array $arguments): string 63 | { 64 | $description = Str::ucfirst(Str::lower(Str::snake($methodName, ' '))); 65 | 66 | if (! $this->inSecret) { 67 | foreach ($arguments as $argument) { 68 | if (\is_string($argument) || (\is_object($argument) && \is_callable([$argument, '__toString']))) { 69 | $description .= " $argument"; 70 | } 71 | } 72 | } else { 73 | $description .= ' ...'; 74 | $this->inSecret = false; 75 | } 76 | 77 | return $description; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 |

6 | Static Analysis 7 | Latest Stable Version 8 | License 9 |

10 | 11 | ## About Laravel Console Dusk 12 | 13 | Laravel Console Dusk was created by, and is maintained by [Nuno Maduro](https://github.com/nunomaduro), and allows the usage of [Laravel Dusk](https://github.com/laravel/dusk) in Laravel/Laravel Zero artisan commands. 14 | 15 | ## Installation 16 | 17 | > **Requires [PHP 8.2+](https://php.net/releases)** 18 | 19 | Require Laravel Console Dusk using [Composer](https://getcomposer.org): 20 | 21 | ```bash 22 | composer require nunomaduro/laravel-console-dusk 23 | ``` 24 | 25 | The package provide a config file that allows you to configure some options. 26 | ```php 27 | return [ 28 | /* 29 | |-------------------------------------------------------------------------- 30 | | Laravel Console Dusk Paths 31 | |-------------------------------------------------------------------------- 32 | | 33 | | Here you may configure the name of screenshots and logs directory as you wish. 34 | */ 35 | 'paths' => [ 36 | 'screenshots' => storage_path('laravel-console-dusk/screenshots'), 37 | 'log' => storage_path('laravel-console-dusk/log'), 38 | ], 39 | 40 | /* 41 | | -------------------------------------------------------------------------- 42 | | Headless Mode 43 | | -------------------------------------------------------------------------- 44 | | 45 | | When false it will show a Chrome window while running. Within production 46 | | it will be forced to run in headless mode. 47 | */ 48 | 'headless' => true, 49 | 50 | /* 51 | | -------------------------------------------------------------------------- 52 | | Driver Configuration 53 | | -------------------------------------------------------------------------- 54 | | 55 | | Here you may pass options to the browser driver being automated. 56 | | 57 | | A list of available Chromium command line switches is available at 58 | | https://peter.sh/experiments/chromium-command-line-switches/ 59 | */ 60 | 'driver' => [ 61 | 'chrome' => [ 62 | 'options' => [ 63 | '--disable-gpu', 64 | ], 65 | ], 66 | ], 67 | ]; 68 | ``` 69 | 70 | You can publish the config file using the following artisan command: 71 | ```bash 72 | php artisan vendor:publish --provider="NunoMaduro\LaravelConsoleDusk\LaravelConsoleDuskServiceProvider" --tag="config" 73 | ``` 74 | 75 | 76 | ## Usage 77 | 78 | ```php 79 | class VisitLaravelZeroCommand extends Command 80 | { 81 | /** 82 | * Execute the console command. 83 | * 84 | * @return void 85 | */ 86 | public function handle() 87 | { 88 | $this->browse(function ($browser) { 89 | $browser->visit('http://laravel-zero.com') 90 | ->assertSee('100% Open Source'); 91 | }); 92 | } 93 | } 94 | ``` 95 | 96 | Check how use [Laravel Dusk here](https://github.com/laravel/dusk). 97 | 98 | ## Contributing 99 | 100 | Thank you for considering to contribute to Laravel Console Dusk. All the contribution guidelines are mentioned [here](CONTRIBUTING.md). 101 | 102 | You can have a look at the [CHANGELOG](CHANGELOG.md) for constant updates & detailed information about the changes. You can also follow the twitter account for latest announcements or just come say hi!: [@enunomaduro](https://twitter.com/enunomaduro) 103 | 104 | ## Support the development 105 | **Do you like this project? Support it by donating** 106 | 107 | - PayPal: [Donate](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=66BYDWAT92N6L) 108 | - Patreon: [Donate](https://www.patreon.com/nunomaduro) 109 | 110 | ## License 111 | 112 | Laravel Console Dusk is an open-sourced software licensed under the [MIT license](LICENSE.md). 113 | --------------------------------------------------------------------------------