mirror of
https://github.com/pestphp/pest.git
synced 2026-03-06 07:47:22 +01:00
chore: different refactors
This commit is contained in:
17
bin/pest
17
bin/pest
@ -17,6 +17,7 @@ use Symfony\Component\Console\Output\OutputInterface;
|
|||||||
$_SERVER['COLLISION_PRINTER'] = 'DefaultPrinter';
|
$_SERVER['COLLISION_PRINTER'] = 'DefaultPrinter';
|
||||||
|
|
||||||
$args = $_SERVER['argv'];
|
$args = $_SERVER['argv'];
|
||||||
|
|
||||||
$dirty = false;
|
$dirty = false;
|
||||||
$todo = false;
|
$todo = false;
|
||||||
|
|
||||||
@ -68,11 +69,11 @@ use Symfony\Component\Console\Output\OutputInterface;
|
|||||||
|
|
||||||
// Get $rootPath based on $autoloadPath
|
// Get $rootPath based on $autoloadPath
|
||||||
$rootPath = dirname($autoloadPath, 2);
|
$rootPath = dirname($autoloadPath, 2);
|
||||||
$argv = new ArgvInput();
|
$input = new ArgvInput();
|
||||||
|
|
||||||
$testSuite = TestSuite::getInstance(
|
$testSuite = TestSuite::getInstance(
|
||||||
$rootPath,
|
$rootPath,
|
||||||
$argv->getParameterOption('--test-directory', (new ConfigLoader($rootPath))->getTestsDirectory()),
|
$input->getParameterOption('--test-directory', (new ConfigLoader($rootPath))->getTestsDirectory()),
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($dirty) {
|
if ($dirty) {
|
||||||
@ -83,19 +84,13 @@ use Symfony\Component\Console\Output\OutputInterface;
|
|||||||
$testSuite->tests->addTestCaseMethodFilter(new TodoTestCaseFilter());
|
$testSuite->tests->addTestCaseMethodFilter(new TodoTestCaseFilter());
|
||||||
}
|
}
|
||||||
|
|
||||||
$isDecorated = $argv->getParameterOption('--colors', 'always') !== 'never';
|
$isDecorated = $input->getParameterOption('--colors', 'always') !== 'never';
|
||||||
|
|
||||||
$output = new ConsoleOutput(ConsoleOutput::VERBOSITY_NORMAL, $isDecorated);
|
$output = new ConsoleOutput(ConsoleOutput::VERBOSITY_NORMAL, $isDecorated);
|
||||||
|
|
||||||
$container = Container::getInstance();
|
$kernel = Kernel::boot($testSuite, $input, $output);
|
||||||
$container->add(TestSuite::class, $testSuite);
|
|
||||||
$container->add(OutputInterface::class, $output);
|
|
||||||
$container->add(InputInterface::class, $argv);
|
|
||||||
$container->add(Container::class, $container);
|
|
||||||
|
|
||||||
$kernel = Kernel::boot();
|
$result = $kernel->handle($args);
|
||||||
|
|
||||||
$result = $kernel->handle($output, $args);
|
|
||||||
|
|
||||||
$kernel->shutdown();
|
$kernel->shutdown();
|
||||||
|
|
||||||
|
|||||||
@ -7,37 +7,31 @@ use ParaTest\WrapperRunner\WrapperWorker;
|
|||||||
use Pest\ConfigLoader;
|
use Pest\ConfigLoader;
|
||||||
use Pest\Kernel;
|
use Pest\Kernel;
|
||||||
use Pest\Plugins\Actions\CallsHandleArguments;
|
use Pest\Plugins\Actions\CallsHandleArguments;
|
||||||
use Pest\Support\Container;
|
|
||||||
use Pest\TestCaseMethodFilters\TodoTestCaseFilter;
|
use Pest\TestCaseMethodFilters\TodoTestCaseFilter;
|
||||||
use Pest\TestSuite;
|
use Pest\TestSuite;
|
||||||
use Symfony\Component\Console\Input\ArgvInput;
|
use Symfony\Component\Console\Input\ArgvInput;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
$bootPest = (static function (): void {
|
$bootPest = (static function (): void {
|
||||||
$argv = new ArgvInput();
|
$workerArgv = new ArgvInput();
|
||||||
$parentProcessArgv = new ArgvInput(json_decode($_SERVER['PEST_PARALLEL_ARGV']));
|
$masterArgv = new ArgvInput(json_decode($_SERVER['PEST_PARALLEL_ARGV']));
|
||||||
|
|
||||||
$rootPath = dirname(PHPUNIT_COMPOSER_INSTALL, 2);
|
$rootPath = dirname(PHPUNIT_COMPOSER_INSTALL, 2);
|
||||||
$testSuite = TestSuite::getInstance(
|
$testSuite = TestSuite::getInstance($rootPath, $workerArgv->getParameterOption(
|
||||||
$rootPath,
|
'--test-directory',
|
||||||
$argv->getParameterOption('--test-directory', (new ConfigLoader($rootPath))->getTestsDirectory()),
|
(new ConfigLoader($rootPath))->getTestsDirectory()
|
||||||
);
|
));
|
||||||
|
|
||||||
if ($parentProcessArgv->hasParameterOption('--todo')) {
|
if ($masterArgv->hasParameterOption('--todo')) {
|
||||||
$testSuite->tests->addTestCaseMethodFilter(new TodoTestCaseFilter());
|
$testSuite->tests->addTestCaseMethodFilter(new TodoTestCaseFilter());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$input = new ArgvInput();
|
||||||
|
|
||||||
$output = new ConsoleOutput(OutputInterface::VERBOSITY_NORMAL, true);
|
$output = new ConsoleOutput(OutputInterface::VERBOSITY_NORMAL, true);
|
||||||
|
|
||||||
$container = Container::getInstance();
|
Kernel::boot($testSuite, $input, $output);
|
||||||
$container->add(TestSuite::class, $testSuite);
|
|
||||||
$container->add(OutputInterface::class, $output);
|
|
||||||
$container->add(InputInterface::class, $argv);
|
|
||||||
$container->add(Container::class, $container);
|
|
||||||
|
|
||||||
Kernel::boot();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
(static function () use ($bootPest): void {
|
(static function () use ($bootPest): void {
|
||||||
@ -104,10 +98,10 @@ $bootPest = (static function (): void {
|
|||||||
$testPath = fgets(STDIN);
|
$testPath = fgets(STDIN);
|
||||||
if ($testPath === false || $testPath === WrapperWorker::COMMAND_EXIT) {
|
if ($testPath === false || $testPath === WrapperWorker::COMMAND_EXIT) {
|
||||||
$application->end();
|
$application->end();
|
||||||
|
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// It must be a 1 byte string to ensure filesize() is equal to the number of tests executed
|
|
||||||
$exitCode = $application->runTest(trim($testPath));
|
$exitCode = $application->runTest(trim($testPath));
|
||||||
|
|
||||||
fwrite($statusFile, (string) $exitCode);
|
fwrite($statusFile, (string) $exitCode);
|
||||||
@ -46,7 +46,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"brianium/paratest": "^7.0.4",
|
"brianium/paratest": "^7.0.5",
|
||||||
"pestphp/pest-dev-tools": "^2.4.0",
|
"pestphp/pest-dev-tools": "^2.4.0",
|
||||||
"pestphp/pest-plugin-arch": "^2.0.0",
|
"pestphp/pest-plugin-arch": "^2.0.0",
|
||||||
"symfony/process": "^6.2.5"
|
"symfony/process": "^6.2.5"
|
||||||
|
|||||||
@ -12,9 +12,10 @@ parameters:
|
|||||||
reportUnmatchedIgnoredErrors: true
|
reportUnmatchedIgnoredErrors: true
|
||||||
|
|
||||||
ignoreErrors:
|
ignoreErrors:
|
||||||
|
- "#Language construct isset\\(\\) should not be used.#"
|
||||||
|
- "#is not allowed to extend#"
|
||||||
- "#with a nullable type declaration#"
|
- "#with a nullable type declaration#"
|
||||||
- "#type mixed is not subtype of native#"
|
- "#type mixed is not subtype of native#"
|
||||||
- "#is not allowed to extend#"
|
|
||||||
- "# with null as default value#"
|
- "# with null as default value#"
|
||||||
- "#has parameter \\$closure with default value.#"
|
- "#has parameter \\$closure with default value.#"
|
||||||
- "#has parameter \\$description with default value.#"
|
- "#has parameter \\$description with default value.#"
|
||||||
|
|||||||
@ -11,7 +11,7 @@ use Pest\Plugins\Actions\CallsBoot;
|
|||||||
use Pest\Plugins\Actions\CallsShutdown;
|
use Pest\Plugins\Actions\CallsShutdown;
|
||||||
use Pest\Support\Container;
|
use Pest\Support\Container;
|
||||||
use PHPUnit\TextUI\Application;
|
use PHPUnit\TextUI\Application;
|
||||||
use PHPUnit\TextUI\Exception;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -36,7 +36,8 @@ final class Kernel
|
|||||||
* Creates a new Kernel instance.
|
* Creates a new Kernel instance.
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly Application $application
|
private readonly Application $application,
|
||||||
|
private readonly OutputInterface $output,
|
||||||
) {
|
) {
|
||||||
register_shutdown_function(function (): void {
|
register_shutdown_function(function (): void {
|
||||||
if (error_get_last() !== null) {
|
if (error_get_last() !== null) {
|
||||||
@ -50,8 +51,16 @@ final class Kernel
|
|||||||
/**
|
/**
|
||||||
* Boots the Kernel.
|
* Boots the Kernel.
|
||||||
*/
|
*/
|
||||||
public static function boot(): self
|
public static function boot(TestSuite $testSuite, InputInterface $input, OutputInterface $output): self
|
||||||
{
|
{
|
||||||
|
$container = Container::getInstance();
|
||||||
|
|
||||||
|
$container
|
||||||
|
->add(TestSuite::class, $testSuite)
|
||||||
|
->add(InputInterface::class, $input)
|
||||||
|
->add(OutputInterface::class, $output)
|
||||||
|
->add(Container::class, $container);
|
||||||
|
|
||||||
foreach (self::BOOTSTRAPPERS as $bootstrapper) {
|
foreach (self::BOOTSTRAPPERS as $bootstrapper) {
|
||||||
$bootstrapper = Container::getInstance()->get($bootstrapper);
|
$bootstrapper = Container::getInstance()->get($bootstrapper);
|
||||||
assert($bootstrapper instanceof Bootstrapper);
|
assert($bootstrapper instanceof Bootstrapper);
|
||||||
@ -61,24 +70,25 @@ final class Kernel
|
|||||||
|
|
||||||
(new CallsBoot())->__invoke();
|
(new CallsBoot())->__invoke();
|
||||||
|
|
||||||
return new self(new Application());
|
return new self(
|
||||||
|
new Application(),
|
||||||
|
$output,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the given argv.
|
* Runs the application, and returns the exit code.
|
||||||
*
|
*
|
||||||
* @param array<int, string> $argv
|
* @param array<int, string> $args
|
||||||
*
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
*/
|
||||||
public function handle(OutputInterface $output, array $argv): int
|
public function handle(array $args): int
|
||||||
{
|
{
|
||||||
$argv = (new Plugins\Actions\CallsHandleArguments())->__invoke($argv);
|
$args = (new Plugins\Actions\CallsHandleArguments())->__invoke($args);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->application->run($argv);
|
$this->application->run($args);
|
||||||
} catch (NoTestsFound) {
|
} catch (NoTestsFound) {
|
||||||
$output->writeln([
|
$this->output->writeln([
|
||||||
'',
|
'',
|
||||||
' <fg=white;options=bold;bg=blue> INFO </> No tests found.',
|
' <fg=white;options=bold;bg=blue> INFO </> No tests found.',
|
||||||
'',
|
'',
|
||||||
|
|||||||
@ -4,11 +4,12 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Pest\Plugins;
|
namespace Pest\Plugins;
|
||||||
|
|
||||||
|
use JsonException;
|
||||||
use ParaTest\ParaTestCommand;
|
use ParaTest\ParaTestCommand;
|
||||||
use Pest\Contracts\Plugins\HandlesArguments;
|
use Pest\Contracts\Plugins\HandlesArguments;
|
||||||
use Pest\Plugins\Actions\CallsAddsOutput;
|
use Pest\Plugins\Actions\CallsAddsOutput;
|
||||||
use Pest\Plugins\Concerns\HandleArguments;
|
use Pest\Plugins\Concerns\HandleArguments;
|
||||||
use Pest\Plugins\Parallel\Contracts\HandlesSubprocessArguments;
|
use Pest\Plugins\Parallel\Contracts\HandlersWorkerArguments;
|
||||||
use Pest\Plugins\Parallel\Paratest\CleanConsoleOutput;
|
use Pest\Plugins\Parallel\Paratest\CleanConsoleOutput;
|
||||||
use Pest\Support\Arr;
|
use Pest\Support\Arr;
|
||||||
use Pest\Support\Container;
|
use Pest\Support\Container;
|
||||||
@ -31,7 +32,11 @@ final class Parallel implements HandlesArguments
|
|||||||
|
|
||||||
public static function isInParallelProcess(): bool
|
public static function isInParallelProcess(): bool
|
||||||
{
|
{
|
||||||
return (int) Arr::get($_SERVER, 'PARATEST') === 1;
|
$argvValue = Arr::get($_SERVER, 'PARATEST');
|
||||||
|
|
||||||
|
assert(is_string($argvValue) || is_int($argvValue) || is_null($argvValue));
|
||||||
|
|
||||||
|
return ((int) $argvValue) === 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleArguments(array $arguments): array
|
public function handleArguments(array $arguments): array
|
||||||
@ -41,12 +46,15 @@ final class Parallel implements HandlesArguments
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (self::isInParallelProcess()) {
|
if (self::isInParallelProcess()) {
|
||||||
return $this->runSubprocessHandlers($arguments);
|
return $this->runWorkersHandlers($arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $arguments;
|
return $arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<int, string> $arguments
|
||||||
|
*/
|
||||||
private function argumentsContainParallelFlags(array $arguments): bool
|
private function argumentsContainParallelFlags(array $arguments): bool
|
||||||
{
|
{
|
||||||
if ($this->hasArgument('--parallel', $arguments)) {
|
if ($this->hasArgument('--parallel', $arguments)) {
|
||||||
@ -56,6 +64,11 @@ final class Parallel implements HandlesArguments
|
|||||||
return $this->hasArgument('-p', $arguments);
|
return $this->hasArgument('-p', $arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<int, string> $arguments
|
||||||
|
*
|
||||||
|
* @throws JsonException
|
||||||
|
*/
|
||||||
private function runTestSuiteInParallel(array $arguments): int
|
private function runTestSuiteInParallel(array $arguments): int
|
||||||
{
|
{
|
||||||
if (! class_exists(ParaTestCommand::class)) {
|
if (! class_exists(ParaTestCommand::class)) {
|
||||||
@ -64,16 +77,16 @@ final class Parallel implements HandlesArguments
|
|||||||
return Command::FAILURE;
|
return Command::FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
$_ENV['PEST_PARALLEL_ARGV'] = json_encode($_SERVER['argv']);
|
$_ENV['PEST_PARALLEL_ARGV'] = json_encode($_SERVER['argv'], JSON_THROW_ON_ERROR);
|
||||||
|
|
||||||
$handlers = array_filter(
|
$handlers = array_filter(
|
||||||
array_map(fn ($handler) => Container::getInstance()->get($handler), self::HANDLERS),
|
array_map(fn ($handler): object|string => Container::getInstance()->get($handler), self::HANDLERS),
|
||||||
fn ($handler) => $handler instanceof HandlesArguments,
|
fn ($handler): bool => $handler instanceof HandlesArguments,
|
||||||
);
|
);
|
||||||
|
|
||||||
$filteredArguments = array_reduce(
|
$filteredArguments = array_reduce(
|
||||||
$handlers,
|
$handlers,
|
||||||
fn ($arguments, HandlesArguments $handler) => $handler->handleArguments($arguments),
|
fn ($arguments, HandlesArguments $handler): array => $handler->handleArguments($arguments),
|
||||||
$arguments
|
$arguments
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -82,23 +95,30 @@ final class Parallel implements HandlesArguments
|
|||||||
return (new CallsAddsOutput())($exitCode);
|
return (new CallsAddsOutput())($exitCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function runSubprocessHandlers(array $arguments): array
|
/**
|
||||||
|
* @param array<int, string> $arguments
|
||||||
|
* @return array<int, string>
|
||||||
|
*/
|
||||||
|
private function runWorkersHandlers(array $arguments): array
|
||||||
{
|
{
|
||||||
$handlers = array_filter(
|
$handlers = array_filter(
|
||||||
array_map(fn ($handler) => Container::getInstance()->get($handler), self::HANDLERS),
|
array_map(fn ($handler): object|string => Container::getInstance()->get($handler), self::HANDLERS),
|
||||||
fn ($handler) => $handler instanceof HandlesSubprocessArguments,
|
fn ($handler): bool => $handler instanceof HandlersWorkerArguments,
|
||||||
);
|
);
|
||||||
|
|
||||||
return array_reduce(
|
return array_reduce(
|
||||||
$handlers,
|
$handlers,
|
||||||
fn ($arguments, HandlesSubprocessArguments $handler) => $handler->handleSubprocessArguments($arguments),
|
fn ($arguments, HandlersWorkerArguments $handler): array => $handler->handleWorkerArguments($arguments),
|
||||||
$arguments
|
$arguments
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function askUserToInstallParatest(): void
|
private function askUserToInstallParatest(): void
|
||||||
{
|
{
|
||||||
Container::getInstance()->get(OutputInterface::class)->writeln([
|
/** @var OutputInterface $output */
|
||||||
|
$output = Container::getInstance()->get(OutputInterface::class);
|
||||||
|
|
||||||
|
$output->writeln([
|
||||||
'<fg=red>Pest Parallel requires ParaTest to run.</>',
|
'<fg=red>Pest Parallel requires ParaTest to run.</>',
|
||||||
'Please run <fg=yellow>composer require --dev brianium/paratest</>.',
|
'Please run <fg=yellow>composer require --dev brianium/paratest</>.',
|
||||||
]);
|
]);
|
||||||
@ -106,7 +126,10 @@ final class Parallel implements HandlesArguments
|
|||||||
|
|
||||||
private function paratestCommand(): Application
|
private function paratestCommand(): Application
|
||||||
{
|
{
|
||||||
$command = ParaTestCommand::applicationFactory(TestSuite::getInstance()->rootPath);
|
/** @var non-empty-string $rootPath */
|
||||||
|
$rootPath = TestSuite::getInstance()->rootPath;
|
||||||
|
|
||||||
|
$command = ParaTestCommand::applicationFactory($rootPath);
|
||||||
$command->setAutoExit(false);
|
$command->setAutoExit(false);
|
||||||
$command->setName('Pest');
|
$command->setName('Pest');
|
||||||
$command->setVersion(version());
|
$command->setVersion(version());
|
||||||
|
|||||||
14
src/Plugins/Parallel/Contracts/HandlersWorkerArguments.php
Normal file
14
src/Plugins/Parallel/Contracts/HandlersWorkerArguments.php
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Pest\Plugins\Parallel\Contracts;
|
||||||
|
|
||||||
|
interface HandlersWorkerArguments
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param array<int, string> $arguments
|
||||||
|
* @return array<int, string>
|
||||||
|
*/
|
||||||
|
public function handleWorkerArguments(array $arguments): array;
|
||||||
|
}
|
||||||
@ -1,10 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Pest\Plugins\Parallel\Contracts;
|
|
||||||
|
|
||||||
interface HandlesSubprocessArguments
|
|
||||||
{
|
|
||||||
public function handleSubprocessArguments(array $arguments): array;
|
|
||||||
}
|
|
||||||
@ -11,8 +11,6 @@ use ParaTest\RunnerInterface;
|
|||||||
use Pest\Contracts\Plugins\HandlesArguments;
|
use Pest\Contracts\Plugins\HandlesArguments;
|
||||||
use Pest\Plugins\Concerns\HandleArguments;
|
use Pest\Plugins\Concerns\HandleArguments;
|
||||||
use Pest\Plugins\Parallel\Paratest\WrapperRunner;
|
use Pest\Plugins\Parallel\Paratest\WrapperRunner;
|
||||||
use Symfony\Component\Console\Command\Command;
|
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -22,13 +20,6 @@ final class Laravel implements HandlesArguments
|
|||||||
{
|
{
|
||||||
use HandleArguments;
|
use HandleArguments;
|
||||||
|
|
||||||
public function __construct(
|
|
||||||
private readonly OutputInterface $output,
|
|
||||||
private readonly InputInterface $input,
|
|
||||||
)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handleArguments(array $arguments): array
|
public function handleArguments(array $arguments): array
|
||||||
{
|
{
|
||||||
if (! self::isALaravelApplication()) {
|
if (! self::isALaravelApplication()) {
|
||||||
@ -44,18 +35,18 @@ final class Laravel implements HandlesArguments
|
|||||||
|
|
||||||
private function setLaravelParallelRunner(): void
|
private function setLaravelParallelRunner(): void
|
||||||
{
|
{
|
||||||
if (! method_exists(ParallelRunner::class, 'resolveRunnerUsing')) {
|
ParallelRunner::resolveRunnerUsing( // @phpstan-ignore-line
|
||||||
$this->output->writeln(' <fg=red>Using parallel with Pest requires Laravel v8.55.0 or higher.</>');
|
fn (Options $options, OutputInterface $output): RunnerInterface => new WrapperRunner($options, $output)
|
||||||
exit(Command::FAILURE);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
ParallelRunner::resolveRunnerUsing(fn (Options $options, OutputInterface $output): RunnerInterface => new WrapperRunner($options, $output));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function isALaravelApplication(): bool
|
private static function isALaravelApplication(): bool
|
||||||
{
|
{
|
||||||
return InstalledVersions::isInstalled('laravel/framework', false)
|
if (! InstalledVersions::isInstalled('laravel/framework', false)) {
|
||||||
&& ! class_exists(\Orchestra\Testbench\TestCase::class);
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ! class_exists(\Orchestra\Testbench\TestCase::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -75,6 +66,7 @@ final class Laravel implements HandlesArguments
|
|||||||
}
|
}
|
||||||
|
|
||||||
$arguments = $this->popArgument('--recreate-databases', $arguments);
|
$arguments = $this->popArgument('--recreate-databases', $arguments);
|
||||||
|
|
||||||
return $this->popArgument('--drop-databases', $arguments);
|
return $this->popArgument('--drop-databases', $arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +77,7 @@ final class Laravel implements HandlesArguments
|
|||||||
private function useLaravelRunner(array $arguments): array
|
private function useLaravelRunner(array $arguments): array
|
||||||
{
|
{
|
||||||
foreach ($arguments as $value) {
|
foreach ($arguments as $value) {
|
||||||
if (str_starts_with((string)$value, '--runner')) {
|
if (str_starts_with($value, '--runner')) {
|
||||||
$arguments = $this->popArgument($value, $arguments);
|
$arguments = $this->popArgument($value, $arguments);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,15 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace Pest\Plugins\Parallel\Handlers;
|
namespace Pest\Plugins\Parallel\Handlers;
|
||||||
|
|
||||||
use Pest\Contracts\Plugins\HandlesArguments;
|
use Pest\Contracts\Plugins\HandlesArguments;
|
||||||
use Pest\Plugins\Concerns\HandleArguments;
|
use Pest\Plugins\Concerns\HandleArguments;
|
||||||
use Pest\Plugins\Parallel\Contracts\HandlesSubprocessArguments;
|
use Pest\Plugins\Parallel\Contracts\HandlersWorkerArguments;
|
||||||
use Pest\Plugins\Retry;
|
use Pest\Plugins\Retry;
|
||||||
|
|
||||||
final class Pest implements HandlesArguments, HandlesSubprocessArguments
|
final class Pest implements HandlesArguments, HandlersWorkerArguments
|
||||||
{
|
{
|
||||||
use HandleArguments;
|
use HandleArguments;
|
||||||
|
|
||||||
@ -20,7 +22,7 @@ final class Pest implements HandlesArguments, HandlesSubprocessArguments
|
|||||||
return $arguments;
|
return $arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleSubprocessArguments(array $arguments): array
|
public function handleWorkerArguments(array $arguments): array
|
||||||
{
|
{
|
||||||
$_SERVER['PEST_PARALLEL'] = '1';
|
$_SERVER['PEST_PARALLEL'] = '1';
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,15 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace Pest\Plugins\Parallel\Paratest;
|
namespace Pest\Plugins\Parallel\Paratest;
|
||||||
|
|
||||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||||
|
|
||||||
class CleanConsoleOutput extends ConsoleOutput
|
final class CleanConsoleOutput extends ConsoleOutput
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
protected function doWrite(string $message, bool $newline): void
|
protected function doWrite(string $message, bool $newline): void
|
||||||
{
|
{
|
||||||
|
|||||||
@ -37,7 +37,9 @@ use function unlink;
|
|||||||
use function unserialize;
|
use function unserialize;
|
||||||
use function usleep;
|
use function usleep;
|
||||||
|
|
||||||
/** @internal */
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
final class WrapperRunner implements RunnerInterface
|
final class WrapperRunner implements RunnerInterface
|
||||||
{
|
{
|
||||||
private const CYCLE_SLEEP = 10000;
|
private const CYCLE_SLEEP = 10000;
|
||||||
@ -46,36 +48,36 @@ final class WrapperRunner implements RunnerInterface
|
|||||||
|
|
||||||
private readonly Timer $timer;
|
private readonly Timer $timer;
|
||||||
|
|
||||||
/** @var non-empty-string[] */
|
/** @var array<int, string> */
|
||||||
private array $pending = [];
|
private array $pending = [];
|
||||||
|
|
||||||
private int $exitcode = -1;
|
private int $exitCode = -1;
|
||||||
|
|
||||||
/** @var array<positive-int,WrapperWorker> */
|
/** @var array<int,WrapperWorker> */
|
||||||
private array $workers = [];
|
private array $workers = [];
|
||||||
|
|
||||||
/** @var array<int,int> */
|
/** @var array<int,int> */
|
||||||
private array $batches = [];
|
private array $batches = [];
|
||||||
|
|
||||||
/** @var list<SplFileInfo> */
|
/** @var array<int, SplFileInfo> */
|
||||||
private array $testresultFiles = [];
|
private array $testresultFiles = [];
|
||||||
|
|
||||||
/** @var list<SplFileInfo> */
|
/** @var array<int, SplFileInfo> */
|
||||||
private array $coverageFiles = [];
|
private array $coverageFiles = [];
|
||||||
|
|
||||||
/** @var list<SplFileInfo> */
|
/** @var array<int, SplFileInfo> */
|
||||||
private array $junitFiles = [];
|
private array $junitFiles = [];
|
||||||
|
|
||||||
/** @var list<SplFileInfo> */
|
/** @var array<int, SplFileInfo> */
|
||||||
private array $teamcityFiles = [];
|
private array $teamcityFiles = [];
|
||||||
|
|
||||||
/** @var list<SplFileInfo> */
|
/** @var array<int, SplFileInfo> */
|
||||||
private array $testdoxFiles = [];
|
private array $testdoxFiles = [];
|
||||||
|
|
||||||
/** @var non-empty-string[] */
|
/** @var array<int, string> */
|
||||||
private readonly array $parameters;
|
private readonly array $parameters;
|
||||||
|
|
||||||
private CodeCoverageFilterRegistry $codeCoverageFilterRegistry;
|
private readonly CodeCoverageFilterRegistry $codeCoverageFilterRegistry;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly Options $options,
|
private readonly Options $options,
|
||||||
@ -84,11 +86,11 @@ final class WrapperRunner implements RunnerInterface
|
|||||||
$this->printer = new ResultPrinter($output, $options);
|
$this->printer = new ResultPrinter($output, $options);
|
||||||
$this->timer = new Timer();
|
$this->timer = new Timer();
|
||||||
|
|
||||||
$wrapper = realpath(
|
$worker = realpath(
|
||||||
dirname(__DIR__, 4).DIRECTORY_SEPARATOR.'bin'.DIRECTORY_SEPARATOR.'pest-wrapper.php',
|
dirname(__DIR__, 4).DIRECTORY_SEPARATOR.'bin'.DIRECTORY_SEPARATOR.'worker.php',
|
||||||
);
|
);
|
||||||
|
|
||||||
assert($wrapper !== false);
|
assert($worker !== false);
|
||||||
$phpFinder = new PhpExecutableFinder();
|
$phpFinder = new PhpExecutableFinder();
|
||||||
$phpBin = $phpFinder->find(false);
|
$phpBin = $phpFinder->find(false);
|
||||||
assert($phpBin !== false);
|
assert($phpBin !== false);
|
||||||
@ -99,7 +101,7 @@ final class WrapperRunner implements RunnerInterface
|
|||||||
$parameters = array_merge($parameters, $options->passthruPhp);
|
$parameters = array_merge($parameters, $options->passthruPhp);
|
||||||
}
|
}
|
||||||
|
|
||||||
$parameters[] = $wrapper;
|
$parameters[] = $worker;
|
||||||
|
|
||||||
$this->parameters = $parameters;
|
$this->parameters = $parameters;
|
||||||
$this->codeCoverageFilterRegistry = new CodeCoverageFilterRegistry();
|
$this->codeCoverageFilterRegistry = new CodeCoverageFilterRegistry();
|
||||||
@ -113,6 +115,7 @@ final class WrapperRunner implements RunnerInterface
|
|||||||
|
|
||||||
TestResultFacade::init();
|
TestResultFacade::init();
|
||||||
EventFacade::seal();
|
EventFacade::seal();
|
||||||
|
|
||||||
$suiteLoader = new SuiteLoader($this->options, $this->output, $this->codeCoverageFilterRegistry);
|
$suiteLoader = new SuiteLoader($this->options, $this->output, $this->codeCoverageFilterRegistry);
|
||||||
$this->pending = $this->getTestFiles($suiteLoader);
|
$this->pending = $this->getTestFiles($suiteLoader);
|
||||||
|
|
||||||
@ -159,7 +162,7 @@ final class WrapperRunner implements RunnerInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
$this->exitcode > 0
|
$this->exitCode > 0
|
||||||
&& $this->options->configuration->stopOnFailure()
|
&& $this->options->configuration->stopOnFailure()
|
||||||
) {
|
) {
|
||||||
$this->pending = [];
|
$this->pending = [];
|
||||||
@ -177,7 +180,7 @@ final class WrapperRunner implements RunnerInterface
|
|||||||
|
|
||||||
private function flushWorker(WrapperWorker $worker): void
|
private function flushWorker(WrapperWorker $worker): void
|
||||||
{
|
{
|
||||||
$this->exitcode = max($this->exitcode, $worker->getExitCode());
|
$this->exitCode = max($this->exitCode, $worker->getExitCode());
|
||||||
$this->printer->printFeedback(
|
$this->printer->printFeedback(
|
||||||
$worker->progressFile,
|
$worker->progressFile,
|
||||||
$this->teamcityFiles,
|
$this->teamcityFiles,
|
||||||
@ -191,7 +194,7 @@ final class WrapperRunner implements RunnerInterface
|
|||||||
while ($this->workers !== []) {
|
while ($this->workers !== []) {
|
||||||
foreach ($this->workers as $index => $worker) {
|
foreach ($this->workers as $index => $worker) {
|
||||||
if ($worker->isRunning()) {
|
if ($worker->isRunning()) {
|
||||||
if (! isset($stopped[$index]) && $worker->isFree()) {
|
if (! array_key_exists($index, $stopped) && $worker->isFree()) {
|
||||||
$worker->stop();
|
$worker->stop();
|
||||||
$stopped[$index] = true;
|
$stopped[$index] = true;
|
||||||
}
|
}
|
||||||
@ -213,16 +216,22 @@ final class WrapperRunner implements RunnerInterface
|
|||||||
|
|
||||||
private function startWorker(int $token): WrapperWorker
|
private function startWorker(int $token): WrapperWorker
|
||||||
{
|
{
|
||||||
|
/** @var array<non-empty-string> $parameters */
|
||||||
|
$parameters = $this->parameters;
|
||||||
|
|
||||||
$worker = new WrapperWorker(
|
$worker = new WrapperWorker(
|
||||||
$this->output,
|
$this->output,
|
||||||
$this->options,
|
$this->options,
|
||||||
$this->parameters,
|
$parameters,
|
||||||
$token,
|
$token,
|
||||||
);
|
);
|
||||||
|
|
||||||
$worker->start();
|
$worker->start();
|
||||||
|
|
||||||
$this->batches[$token] = 0;
|
$this->batches[$token] = 0;
|
||||||
|
|
||||||
$this->testresultFiles[] = $worker->testresultFile;
|
$this->testresultFiles[] = $worker->testresultFile;
|
||||||
|
|
||||||
if (isset($worker->junitFile)) {
|
if (isset($worker->junitFile)) {
|
||||||
$this->junitFiles[] = $worker->junitFile;
|
$this->junitFiles[] = $worker->junitFile;
|
||||||
}
|
}
|
||||||
@ -349,7 +358,7 @@ final class WrapperRunner implements RunnerInterface
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param list<SplFileInfo> $files */
|
/** @param array<int, SplFileInfo> $files */
|
||||||
private function clearFiles(array $files): void
|
private function clearFiles(array $files): void
|
||||||
{
|
{
|
||||||
foreach ($files as $file) {
|
foreach ($files as $file) {
|
||||||
@ -362,23 +371,29 @@ final class WrapperRunner implements RunnerInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We are doing this because the SuiteLoader returns filenames incorrectly
|
* Returns the test files to be executed.
|
||||||
* for Pest tests. Ideally we should find a cleaner solution.
|
*
|
||||||
|
* @return array<int, string>
|
||||||
*/
|
*/
|
||||||
private function getTestFiles(SuiteLoader $suiteLoader): array
|
private function getTestFiles(SuiteLoader $suiteLoader): array
|
||||||
{
|
{
|
||||||
$this->debug(sprintf('Found %d test file%s', count($suiteLoader->files), count($suiteLoader->files) === 1 ? '' : 's'));
|
$this->debug(sprintf('Found %d test file%s', count($suiteLoader->files), count($suiteLoader->files) === 1 ? '' : 's'));
|
||||||
|
|
||||||
$phpunitTests = array_filter(
|
/** @var array<string, string> $files */
|
||||||
$suiteLoader->files,
|
$files = $suiteLoader->files;
|
||||||
|
|
||||||
|
return [
|
||||||
|
...array_values(array_filter(
|
||||||
|
$files,
|
||||||
fn (string $filename): bool => ! str_ends_with($filename, "eval()'d code")
|
fn (string $filename): bool => ! str_ends_with($filename, "eval()'d code")
|
||||||
);
|
)),
|
||||||
|
...TestSuite::getInstance()->tests->getFilenames(),
|
||||||
$pestTests = TestSuite::getInstance()->tests->getFilenames();
|
];
|
||||||
|
|
||||||
return [...$phpunitTests, ...$pestTests];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints a debug message.
|
||||||
|
*/
|
||||||
private function debug(string $message): void
|
private function debug(string $message): void
|
||||||
{
|
{
|
||||||
if ($this->options->verbose) {
|
if ($this->options->verbose) {
|
||||||
|
|||||||
@ -54,13 +54,13 @@ final class TestRepository
|
|||||||
*/
|
*/
|
||||||
public function getFilenames(): array
|
public function getFilenames(): array
|
||||||
{
|
{
|
||||||
$testCases = array_filter($this->testCases, static fn(TestCaseFactory $testCase): bool => $testCase->methodsUsingOnly() !== []);
|
$testCases = array_filter($this->testCases, static fn (TestCaseFactory $testCase): bool => $testCase->methodsUsingOnly() !== []);
|
||||||
|
|
||||||
if ($testCases === []) {
|
if ($testCases === []) {
|
||||||
$testCases = $this->testCases;
|
$testCases = $this->testCases;
|
||||||
}
|
}
|
||||||
|
|
||||||
return array_values(array_map(static fn(TestCaseFactory $factory): string => $factory->filename, $testCases));
|
return array_values(array_map(static fn (TestCaseFactory $factory): string => $factory->filename, $testCases));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -126,18 +126,18 @@ final class TestRepository
|
|||||||
public function set(TestCaseMethodFactory $method): void
|
public function set(TestCaseMethodFactory $method): void
|
||||||
{
|
{
|
||||||
foreach ($this->testCaseFilters as $filter) {
|
foreach ($this->testCaseFilters as $filter) {
|
||||||
if (!$filter->accept($method->filename)) {
|
if (! $filter->accept($method->filename)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->testCaseMethodFilters as $filter) {
|
foreach ($this->testCaseMethodFilters as $filter) {
|
||||||
if (!$filter->accept($method)) {
|
if (! $filter->accept($method)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!array_key_exists($method->filename, $this->testCases)) {
|
if (! array_key_exists($method->filename, $this->testCases)) {
|
||||||
$this->testCases[$method->filename] = new TestCaseFactory($method->filename);
|
$this->testCases[$method->filename] = new TestCaseFactory($method->filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,12 +149,12 @@ final class TestRepository
|
|||||||
*/
|
*/
|
||||||
public function makeIfNeeded(string $filename): void
|
public function makeIfNeeded(string $filename): void
|
||||||
{
|
{
|
||||||
if (!array_key_exists($filename, $this->testCases)) {
|
if (! array_key_exists($filename, $this->testCases)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->testCaseFilters as $filter) {
|
foreach ($this->testCaseFilters as $filter) {
|
||||||
if (!$filter->accept($filename)) {
|
if (! $filter->accept($filename)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -167,12 +167,12 @@ final class TestRepository
|
|||||||
*/
|
*/
|
||||||
private function make(TestCaseFactory $testCase): void
|
private function make(TestCaseFactory $testCase): void
|
||||||
{
|
{
|
||||||
$startsWith = static fn(string $target, string $directory): bool => Str::startsWith($target, $directory . DIRECTORY_SEPARATOR);
|
$startsWith = static fn (string $target, string $directory): bool => Str::startsWith($target, $directory.DIRECTORY_SEPARATOR);
|
||||||
|
|
||||||
foreach ($this->uses as $path => $uses) {
|
foreach ($this->uses as $path => $uses) {
|
||||||
[$classOrTraits, $groups, $hooks] = $uses;
|
[$classOrTraits, $groups, $hooks] = $uses;
|
||||||
|
|
||||||
if ((!is_dir($path) && $testCase->filename === $path) || (is_dir($path) && $startsWith($testCase->filename, $path))) {
|
if ((! is_dir($path) && $testCase->filename === $path) || (is_dir($path) && $startsWith($testCase->filename, $path))) {
|
||||||
foreach ($classOrTraits as $class) {
|
foreach ($classOrTraits as $class) {
|
||||||
/** @var string $class */
|
/** @var string $class */
|
||||||
if (class_exists($class)) {
|
if (class_exists($class)) {
|
||||||
|
|||||||
@ -21,8 +21,8 @@ final class EnsureTeamCityEnabled implements ConfiguredSubscriber
|
|||||||
* Creates a new Configured Subscriber instance.
|
* Creates a new Configured Subscriber instance.
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly OutputInterface $output,
|
|
||||||
private readonly InputInterface $input,
|
private readonly InputInterface $input,
|
||||||
|
private readonly OutputInterface $output,
|
||||||
private readonly TestSuite $testSuite,
|
private readonly TestSuite $testSuite,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,10 +47,14 @@ final class Container
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the given instance to the container.
|
* Adds the given instance to the container.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function add(string $id, object|string $instance): void
|
public function add(string $id, object|string $instance): self
|
||||||
{
|
{
|
||||||
$this->instances[$id] = $instance;
|
$this->instances[$id] = $instance;
|
||||||
|
|
||||||
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -23,12 +23,15 @@ final class StateGenerator
|
|||||||
$state = new State();
|
$state = new State();
|
||||||
|
|
||||||
foreach ($testResult->testErroredEvents() as $testResultEvent) {
|
foreach ($testResult->testErroredEvents() as $testResultEvent) {
|
||||||
assert($testResultEvent instanceof Errored);
|
if ($testResultEvent instanceof Errored) {
|
||||||
$state->add(\NunoMaduro\Collision\Adapters\Phpunit\TestResult::fromTestCase(
|
$state->add(TestResult::fromTestCase(
|
||||||
$testResultEvent->test(),
|
$testResultEvent->test(),
|
||||||
TestResult::FAIL,
|
TestResult::FAIL,
|
||||||
$testResultEvent->throwable()
|
$testResultEvent->throwable()
|
||||||
));
|
));
|
||||||
|
} else {
|
||||||
|
$state->add(TestResult::fromBeforeFirstTestMethodErrored($testResultEvent));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($testResult->testFailedEvents() as $testResultEvent) {
|
foreach ($testResult->testFailedEvents() as $testResultEvent) {
|
||||||
|
|||||||
@ -1,24 +0,0 @@
|
|||||||
##teamcity[testSuiteStarted name='Tests/tests/Failure' locationHint='file://tests/.tests/Failure.php' flowId='1234']
|
|
||||||
##teamcity[testStarted name='it can fail with comparison' locationHint='pest_qn://tests/.tests/Failure.php::it can fail with comparison' flowId='1234']
|
|
||||||
##teamcity[testFailed name='it can fail with comparison' message='Failed asserting that true matches expected false.' details='at src/Mixins/Expectation.php:342|nat src/Support/ExpectationPipeline.php:75|nat src/Support/ExpectationPipeline.php:79|nat src/Expectation.php:300|nat tests/.tests/Failure.php:6|nat src/Factories/TestCaseMethodFactory.php:105|nat src/Concerns/Testable.php:262|nat src/Support/ExceptionTrace.php:28|nat src/Concerns/Testable.php:262|nat src/Concerns/Testable.php:217|nat src/Kernel.php:79' type='comparisonFailure' actual='true' expected='false' flowId='1234']
|
|
||||||
##teamcity[testFinished name='it can fail with comparison' duration='100000' flowId='1234']
|
|
||||||
##teamcity[testStarted name='it can be ignored because of no assertions' locationHint='pest_qn://tests/.tests/Failure.php::it can be ignored because of no assertions' flowId='1234']
|
|
||||||
##teamcity[testIgnored name='it can be ignored because of no assertions' message='This test did not perform any assertions' details='' flowId='1234']
|
|
||||||
##teamcity[testFinished name='it can be ignored because of no assertions' duration='100000' flowId='1234']
|
|
||||||
##teamcity[testStarted name='it can be ignored because it is skipped' locationHint='pest_qn://tests/.tests/Failure.php::it can be ignored because it is skipped' flowId='1234']
|
|
||||||
##teamcity[testIgnored name='it can be ignored because it is skipped' message='This test was ignored.' details='' flowId='1234']
|
|
||||||
##teamcity[testFinished name='it can be ignored because it is skipped' duration='100000' flowId='1234']
|
|
||||||
##teamcity[testStarted name='it can fail' locationHint='pest_qn://tests/.tests/Failure.php::it can fail' flowId='1234']
|
|
||||||
##teamcity[testFailed name='it can fail' message='oh noo' details='at tests/.tests/Failure.php:18|nat src/Factories/TestCaseMethodFactory.php:105|nat src/Concerns/Testable.php:262|nat src/Support/ExceptionTrace.php:28|nat src/Concerns/Testable.php:262|nat src/Concerns/Testable.php:217|nat src/Kernel.php:79' flowId='1234']
|
|
||||||
##teamcity[testFinished name='it can fail' duration='100000' flowId='1234']
|
|
||||||
##teamcity[testStarted name='it is not done yet' locationHint='pest_qn://tests/.tests/Failure.php::it is not done yet' flowId='1234']
|
|
||||||
##teamcity[testIgnored name='it is not done yet' message='This test was ignored.' details='' flowId='1234']
|
|
||||||
##teamcity[testFinished name='it is not done yet' duration='100000' flowId='1234']
|
|
||||||
##teamcity[testStarted name='build this one.' locationHint='pest_qn://tests/.tests/Failure.php::build this one.' flowId='1234']
|
|
||||||
##teamcity[testIgnored name='build this one.' message='This test was ignored.' details='' flowId='1234']
|
|
||||||
##teamcity[testFinished name='build this one.' duration='100000' flowId='1234']
|
|
||||||
##teamcity[testSuiteFinished name='Tests/tests/Failure' flowId='1234']
|
|
||||||
|
|
||||||
[90mTests:[39m [31;1m2 failed[39;22m[90m,[39m[39m [39m[33;1m1 risky[39;22m[90m,[39m[39m [39m[36;1m2 todos[39;22m[90m,[39m[39m [39m[33;1m1 skipped[39;22m[90m (2 assertions)[39m
|
|
||||||
[90mDuration:[39m [39m1.00s[39m
|
|
||||||
|
|
||||||
|
|||||||
@ -896,6 +896,9 @@
|
|||||||
PASS Tests\Visual\Help
|
PASS Tests\Visual\Help
|
||||||
✓ visual snapshot of help command output
|
✓ visual snapshot of help command output
|
||||||
|
|
||||||
|
PASS Tests\Visual\Parallel
|
||||||
|
✓ parallel
|
||||||
|
|
||||||
PASS Tests\Visual\SingleTestOrDirectory
|
PASS Tests\Visual\SingleTestOrDirectory
|
||||||
✓ allows to run a single test
|
✓ allows to run a single test
|
||||||
✓ allows to run a directory
|
✓ allows to run a directory
|
||||||
@ -914,4 +917,4 @@
|
|||||||
PASS Tests\Visual\Version
|
PASS Tests\Visual\Version
|
||||||
✓ visual snapshot of help command output
|
✓ visual snapshot of help command output
|
||||||
|
|
||||||
Tests: 4 incomplete, 4 todos, 18 skipped, 633 passed (1552 assertions)
|
Tests: 4 incomplete, 4 todos, 18 skipped, 634 passed (1554 assertions)
|
||||||
18
tests/Visual/Parallel.php
Normal file
18
tests/Visual/Parallel.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Symfony\Component\Process\Process;
|
||||||
|
|
||||||
|
$run = function () {
|
||||||
|
$process = new Process(['php', 'bin/pest', '--parallel', '--processes=3', '--exclude-group=integration'], dirname(__DIR__, 2),
|
||||||
|
['COLLISION_PRINTER' => 'DefaultPrinter', 'COLLISION_IGNORE_DURATION' => 'true'],
|
||||||
|
);
|
||||||
|
|
||||||
|
$process->run();
|
||||||
|
|
||||||
|
return preg_replace('#\\x1b[[][^A-Za-z]*[A-Za-z]#', '', $process->getOutput());
|
||||||
|
};
|
||||||
|
|
||||||
|
test('parallel', function () use ($run) {
|
||||||
|
expect($run())->toContain('Running 650 tests using 3 processes')
|
||||||
|
->toContain('Tests: 4 incomplete, 4 todos, 15 skipped, 627 passed (1546 assertions)');
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user