Skip to content

Commit

Permalink
polishes/deps
Browse files Browse the repository at this point in the history
  • Loading branch information
surgiie committed Feb 16, 2024
1 parent 58e5e45 commit 0a0f357
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 51 deletions.
44 changes: 12 additions & 32 deletions app/Commands/VisitCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

namespace App\Commands;

use Laravel\Dusk\Browser;
use Illuminate\Support\Str;
use App\Support\BaseCommand;
use Laravel\Dusk\Browser;
use LaravelZero\Framework\Commands\Command;

class VisitCommand extends BaseCommand
{
Expand All @@ -15,32 +16,13 @@ class VisitCommand extends BaseCommand
*/
protected $signature = 'visit {url : The url to visit.}';

/**
* Allow the command to accept arbitrary options.
*
* @var bool
*/
protected bool $arbitraryOptions = true;

/**
* The description of the command.
*
* @var string
*/
protected $description = 'Visit site and perform actions/make assertions.';

/**
* The validation rules for the input/options.
*/
public function rules(): array
{
return [
'url'=>[
'required',
'url',
],
];
}
/**
* Parse function arguments from an option value.
*
Expand Down Expand Up @@ -92,24 +74,22 @@ protected function configureScreenshot(array $arguments)
*/
public function handle()
{
if(! Str::isUrl($this->argument('url'))){
$this->components->error("The url argument is invalid, must be full url including protocol.");
return 1;
}


$this->browse(function ($browser){
// see https://github.com/laravel/dusk/issues/781
invade($browser)->browser->resolver->prefix = 'html';

$browser = $browser->visit($this->data->get("url"));

global $argv;

foreach($argv as $option){
if(!str_starts_with($option, "--")){
continue;
}

$value = strpos($option, "=") != false ? Str::after($option, "=") : "";
$browser = $browser->visit($this->argument("url"));

$option = Str::before(str_replace("--", "", $option), "=");
foreach($this->arbitraryOptions as $name=>$option){
$value = is_string($option) ? $option : "";

$method = Str::camel($option);
$method = Str::camel($name);
$arguments = $this->parseActionArguments($value);

// allow screenshots to be saved to a custom path
Expand Down
61 changes: 45 additions & 16 deletions app/Support/BaseCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,57 @@

namespace App\Support;

use Laravel\Prompts\Spinner;
use Surgiie\Console\Command;
use App\Exceptions\Commands\ExitException;
use Illuminate\Console\Contracts\NewLineAware;
use Illuminate\Console\View\Components\Factory as ConsoleViewFactory;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\View;
use LaravelZero\Framework\Commands\Command;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

use function Termwind\render;
use function Termwind\renderUsing;

abstract class BaseCommand extends Command
{
/**
* Run a task using the given title and callback.
* @param string $title
* @param \Closure|callable|null $task
* @return bool|null
* The options that are not defined on the command.
*/
protected Collection $arbitraryOptions;

/**
* Constuct a new Command instance.
*/
public function __construct()
{
parent::__construct();

$this->arbitraryOptions = collect();

// Ignore validation errors for arbitrary options support.
$this->ignoreValidationErrors();
}

/**
* Initialize the command input/ouput objects.
*/
public function task(string $title = '', $task = null): bool
protected function initialize(InputInterface $input, OutputInterface $output): void
{
$result = (new Spinner($title))->spin(
$task,
$title,
);
// parse arbitrary options for variable data.
$tokens = $input instanceof ArrayInput ? invade($input)->parameters : invade($input)->tokens;
$parser = new CommandOptionsParser($tokens);

$this->output->writeln(
" $title: ".($result !== false ? '<info>Successful</info>' : '<fg=red>Failed</fg=red>')
);
$definition = $this->getDefinition();

return $result !== false;
foreach ($parser->parse() as $name => $data) {
if (! $definition->hasOption($name)) {
$this->arbitraryOptions->put($name, $data['value']);
$this->addOption($name, mode: $data['mode']);
}
}
//rebind input definition
$input->bind($definition);
}
}
}
112 changes: 112 additions & 0 deletions app/Support/CommandOptionsParser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<?php

namespace App\Support;

use Illuminate\Support\Arr;
use InvalidArgumentException;
use Symfony\Component\Console\Input\InputOption;

class CommandOptionsParser
{
/**
* The options being parsed.
*/
protected array $options = [];

/**
* Construct new CommandOptionsParser instance.
*/
public function __construct(array $options)
{
$this->setOptions($options);
}

/**
* Set the options to parse.
*/
public function setOptions(array $options): static
{
$this->options = array_filter($options);

return $this;
}

/**
* Tests use ArrayInput objects, so we need to handle the tokens differently.
*
* @return void
*/
protected function parseTokensForTests()
{
$options = [];
foreach ($this->options as $token => $v) {
if (str_starts_with($token, '--')) {
if ($v == false) {
continue;
}
if (is_array($v)) {
foreach ($v as $item) {
$options[] = "$token=$item";

}
} else {
$token = $token.($v ? "=$v" : '');
$options[] = $token;
}
}
}

return $options;
}

/**
* Parse the set options.
*/
public function parse(): array
{
$options = [];
$iterable = $this->options;

if (app()->runningUnitTests()) {
$iterable = $this->parseTokensForTests();
}

foreach ($iterable as $token) {

preg_match('/--([^=]+)(=)?(.*)/', $token, $match);

if (! $match) {
continue;
}

$name = $match[1];
$equals = $match[2] ?? false;
$value = $match[3] ?? false;

$optionExists = array_key_exists($name, $options);

if ($optionExists && ($value || $equals)) {
$options[$name] = [
'mode' => InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
'value' => $options[$name]['value'] ?? [],
];
$options[$name]['value'] = Arr::wrap($options[$name]['value']);
$options[$name]['value'][] = $value;
} elseif ($value) {
$options[$name] = [
'mode' => InputOption::VALUE_REQUIRED,
'value' => $value,
];
} elseif (! $optionExists) {
$options[$name] = [
'mode' => ($value == '' && $equals) ? InputOption::VALUE_OPTIONAL : InputOption::VALUE_NONE,
'value' => ($value == '' && $equals) ? '' : true,
];
} else {
throw new InvalidArgumentException("The '$name' option has already been provided.");
}
}

return $options;
}
}
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
"intonate/tinker-zero": "^1.2",
"laravel-zero/framework": "^10.0",
"nunomaduro/laravel-console-dusk": "^1.11",
"surgiie/console": "^4.0.0",
"pestphp/pest": "^1.21.3",
"spatie/invade": "^2.0",
"symfony/yaml": "^6.2"
},
"require-dev": {
Expand Down
2 changes: 1 addition & 1 deletion config/app.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
| number MAJOR.MINOR.PATCH when an update happens: https://semver.org.
|
*/
'version' => require base_path('version.php'),
'version' => app('git.version'),

/*
|--------------------------------------------------------------------------
Expand Down
1 change: 0 additions & 1 deletion version.php

This file was deleted.

0 comments on commit 0a0f357

Please sign in to comment.