mirror of
https://github.com/pestphp/pest.git
synced 2026-03-06 07:47:22 +01:00
refacto: --retry option
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -8,7 +8,6 @@ coverage.xml
|
|||||||
/.php-cs-fixer.php
|
/.php-cs-fixer.php
|
||||||
.php-cs-fixer.cache
|
.php-cs-fixer.cache
|
||||||
.temp/coverage.php
|
.temp/coverage.php
|
||||||
.temp/retry.json
|
|
||||||
*.swp
|
*.swp
|
||||||
*.swo
|
*.swo
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|||||||
1
.temp/retry.json
Normal file
1
.temp/retry.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
["P\\Tests\\Temporary\\A::it_can_run_a_test_5#(3)","P\\Tests\\Temporary\\A::it_can_run_a_test_5#(4)"]
|
||||||
1
.temp/test-results
Normal file
1
.temp/test-results
Normal file
File diff suppressed because one or more lines are too long
@ -81,6 +81,7 @@
|
|||||||
"extra": {
|
"extra": {
|
||||||
"pest": {
|
"pest": {
|
||||||
"plugins": [
|
"plugins": [
|
||||||
|
"Pest\\Plugins\\Cache",
|
||||||
"Pest\\Plugins\\Coverage",
|
"Pest\\Plugins\\Coverage",
|
||||||
"Pest\\Plugins\\Init",
|
"Pest\\Plugins\\Init",
|
||||||
"Pest\\Plugins\\Environment",
|
"Pest\\Plugins\\Environment",
|
||||||
|
|||||||
@ -5,14 +5,12 @@
|
|||||||
beStrictAboutTestsThatDoNotTestAnything="true"
|
beStrictAboutTestsThatDoNotTestAnything="true"
|
||||||
beStrictAboutOutputDuringTests="true"
|
beStrictAboutOutputDuringTests="true"
|
||||||
bootstrap="vendor/autoload.php"
|
bootstrap="vendor/autoload.php"
|
||||||
cacheResult="false"
|
|
||||||
colors="true"
|
colors="true"
|
||||||
failOnRisky="true"
|
failOnRisky="true"
|
||||||
failOnWarning="true"
|
failOnWarning="true"
|
||||||
processIsolation="false"
|
processIsolation="false"
|
||||||
stopOnError="false"
|
stopOnError="false"
|
||||||
stopOnFailure="false"
|
stopOnFailure="false"
|
||||||
cacheDirectory=".phpunit.cache"
|
|
||||||
backupStaticProperties="false"
|
backupStaticProperties="false"
|
||||||
displayDetailsOnIncompleteTests="true"
|
displayDetailsOnIncompleteTests="true"
|
||||||
displayDetailsOnSkippedTests="true"
|
displayDetailsOnSkippedTests="true"
|
||||||
|
|||||||
@ -22,10 +22,7 @@ final class BootSubscribers implements Bootstrapper
|
|||||||
*/
|
*/
|
||||||
private const SUBSCRIBERS = [
|
private const SUBSCRIBERS = [
|
||||||
Subscribers\EnsureConfigurationIsValid::class,
|
Subscribers\EnsureConfigurationIsValid::class,
|
||||||
Subscribers\EnsureConfigurationDefaults::class,
|
Subscribers\EnsureConfigurationIsAvailable::class,
|
||||||
Subscribers\EnsureRetryRepositoryExists::class,
|
|
||||||
Subscribers\EnsureErroredTestsAreRetryable::class,
|
|
||||||
Subscribers\EnsureFailedTestsAreRetryable::class,
|
|
||||||
Subscribers\EnsureTeamCityEnabled::class,
|
Subscribers\EnsureTeamCityEnabled::class,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,6 @@ use Closure;
|
|||||||
use Pest\Contracts\AddsAnnotations;
|
use Pest\Contracts\AddsAnnotations;
|
||||||
use Pest\Exceptions\ShouldNotHappen;
|
use Pest\Exceptions\ShouldNotHappen;
|
||||||
use Pest\Factories\Concerns\HigherOrderable;
|
use Pest\Factories\Concerns\HigherOrderable;
|
||||||
use Pest\Plugins\Retry;
|
|
||||||
use Pest\Repositories\DatasetsRepository;
|
use Pest\Repositories\DatasetsRepository;
|
||||||
use Pest\Support\Str;
|
use Pest\Support\Str;
|
||||||
use Pest\TestSuite;
|
use Pest\TestSuite;
|
||||||
@ -129,12 +128,6 @@ final class TestCaseMethodFactory
|
|||||||
|
|
||||||
$methodName = Str::evaluable($this->description);
|
$methodName = Str::evaluable($this->description);
|
||||||
|
|
||||||
$retryRepository = TestSuite::getInstance()->retryRepository;
|
|
||||||
|
|
||||||
if (Retry::$retrying && ! $retryRepository->isEmpty() && ! $retryRepository->exists(sprintf('%s::%s', $classFQN, $methodName))) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$datasetsCode = '';
|
$datasetsCode = '';
|
||||||
$annotations = ['@test'];
|
$annotations = ['@test'];
|
||||||
$attributes = [];
|
$attributes = [];
|
||||||
|
|||||||
37
src/Plugins/Cache.php
Normal file
37
src/Plugins/Cache.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Pest\Plugins;
|
||||||
|
|
||||||
|
use Pest\Contracts\Plugins\HandlesArguments;
|
||||||
|
use Pest\Plugins\Concerns\HandleArguments;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
final class Cache implements HandlesArguments
|
||||||
|
{
|
||||||
|
use HandleArguments;
|
||||||
|
|
||||||
|
private const TEMPORARY_FOLDER = __DIR__
|
||||||
|
.DIRECTORY_SEPARATOR
|
||||||
|
.'..'
|
||||||
|
.DIRECTORY_SEPARATOR
|
||||||
|
.'..'
|
||||||
|
.DIRECTORY_SEPARATOR
|
||||||
|
.'.temp';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function handleArguments(array $arguments): array
|
||||||
|
{
|
||||||
|
$arguments = $this->pushArgument(
|
||||||
|
sprintf('--cache-directory=%s', realpath(self::TEMPORARY_FOLDER)),
|
||||||
|
$arguments
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->pushArgument('--cache-result', $arguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -13,18 +13,18 @@ final class Retry implements HandlesArguments
|
|||||||
{
|
{
|
||||||
use Concerns\HandleArguments;
|
use Concerns\HandleArguments;
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether it should show retry or not.
|
|
||||||
*/
|
|
||||||
public static bool $retrying = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
public function handleArguments(array $arguments): array
|
public function handleArguments(array $arguments): array
|
||||||
{
|
{
|
||||||
self::$retrying = $this->hasArgument('--retry', $arguments);
|
if ($this->hasArgument('--retry', $arguments)) {
|
||||||
|
$arguments = $this->popArgument('--retry', $arguments);
|
||||||
|
|
||||||
return $this->popArgument('--retry', $arguments);
|
$arguments = $this->pushArgument('--order-by=defects', $arguments);
|
||||||
|
$arguments = $this->pushArgument(' --stop-on-defect', $arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $arguments;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,91 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Pest\Repositories;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
final class RetryRepository
|
|
||||||
{
|
|
||||||
private const TEMPORARY_FOLDER = __DIR__
|
|
||||||
.DIRECTORY_SEPARATOR
|
|
||||||
.'..'
|
|
||||||
.DIRECTORY_SEPARATOR
|
|
||||||
.'..'
|
|
||||||
.DIRECTORY_SEPARATOR
|
|
||||||
.'.temp';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new Temp Repository instance.
|
|
||||||
*/
|
|
||||||
public function __construct(private readonly string $filename)
|
|
||||||
{
|
|
||||||
// ..
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a new element.
|
|
||||||
*/
|
|
||||||
public function add(string $element): void
|
|
||||||
{
|
|
||||||
$this->save([...$this->all(), ...[$element]]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears the existing file, if any, and re-creates it.
|
|
||||||
*/
|
|
||||||
public function boot(): void
|
|
||||||
{
|
|
||||||
@unlink(self::TEMPORARY_FOLDER.'/'.$this->filename.'.json'); // @phpstan-ignore-line
|
|
||||||
|
|
||||||
$this->save([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if there is any element.
|
|
||||||
*/
|
|
||||||
public function isEmpty(): bool
|
|
||||||
{
|
|
||||||
return $this->all() === [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the given element exists.
|
|
||||||
*/
|
|
||||||
public function exists(string $element): bool
|
|
||||||
{
|
|
||||||
return in_array($element, $this->all(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets all elements.
|
|
||||||
*
|
|
||||||
* @return array<int, string>
|
|
||||||
*/
|
|
||||||
private function all(): array
|
|
||||||
{
|
|
||||||
$path = self::TEMPORARY_FOLDER.'/'.$this->filename.'.json';
|
|
||||||
|
|
||||||
$contents = file_exists($path) ? file_get_contents($path) : '{}';
|
|
||||||
|
|
||||||
assert(is_string($contents));
|
|
||||||
|
|
||||||
$all = json_decode($contents, true, 512, JSON_THROW_ON_ERROR);
|
|
||||||
|
|
||||||
return is_array($all) ? $all : [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save the given elements.
|
|
||||||
*
|
|
||||||
* @param array<int, string> $elements
|
|
||||||
*/
|
|
||||||
private function save(array $elements): void
|
|
||||||
{
|
|
||||||
$contents = json_encode($elements, JSON_THROW_ON_ERROR);
|
|
||||||
|
|
||||||
file_put_contents(self::TEMPORARY_FOLDER.'/'.$this->filename.'.json', $contents);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -4,19 +4,21 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Pest\Subscribers;
|
namespace Pest\Subscribers;
|
||||||
|
|
||||||
|
use Pest\Support\Container;
|
||||||
use PHPUnit\Event\TestRunner\Configured;
|
use PHPUnit\Event\TestRunner\Configured;
|
||||||
use PHPUnit\Event\TestRunner\ConfiguredSubscriber;
|
use PHPUnit\Event\TestRunner\ConfiguredSubscriber;
|
||||||
|
use PHPUnit\TextUI\Configuration\Configuration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
final class EnsureConfigurationDefaults implements ConfiguredSubscriber
|
final class EnsureConfigurationIsAvailable implements ConfiguredSubscriber
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Runs the subscriber.
|
* Runs the subscriber.
|
||||||
*/
|
*/
|
||||||
public function notify(Configured $event): void
|
public function notify(Configured $event): void
|
||||||
{
|
{
|
||||||
// TODO...
|
Container::getInstance()->add(Configuration::class, $event->configuration());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,23 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Pest\Subscribers;
|
|
||||||
|
|
||||||
use Pest\TestSuite;
|
|
||||||
use PHPUnit\Event\Test\Errored;
|
|
||||||
use PHPUnit\Event\Test\ErroredSubscriber;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
final class EnsureErroredTestsAreRetryable implements ErroredSubscriber
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Runs the subscriber.
|
|
||||||
*/
|
|
||||||
public function notify(Errored $event): void
|
|
||||||
{
|
|
||||||
TestSuite::getInstance()->retryRepository->add($event->test()->id());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Pest\Subscribers;
|
|
||||||
|
|
||||||
use Pest\TestSuite;
|
|
||||||
use PHPUnit\Event\Test\Failed;
|
|
||||||
use PHPUnit\Event\Test\FailedSubscriber;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
final class EnsureFailedTestsAreRetryable implements FailedSubscriber
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Runs the subscriber.
|
|
||||||
*/
|
|
||||||
public function notify(Failed $event): void
|
|
||||||
{
|
|
||||||
TestSuite::getInstance()->retryRepository->add($event->test()->id());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Pest\Subscribers;
|
|
||||||
|
|
||||||
use Pest\TestSuite;
|
|
||||||
use PHPUnit\Event\TestRunner\Started;
|
|
||||||
use PHPUnit\Event\TestRunner\StartedSubscriber;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
final class EnsureRetryRepositoryExists implements StartedSubscriber
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Runs the subscriber.
|
|
||||||
*/
|
|
||||||
public function notify(Started $event): void
|
|
||||||
{
|
|
||||||
TestSuite::getInstance()->retryRepository->boot();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -9,7 +9,6 @@ use Pest\Repositories\AfterAllRepository;
|
|||||||
use Pest\Repositories\AfterEachRepository;
|
use Pest\Repositories\AfterEachRepository;
|
||||||
use Pest\Repositories\BeforeAllRepository;
|
use Pest\Repositories\BeforeAllRepository;
|
||||||
use Pest\Repositories\BeforeEachRepository;
|
use Pest\Repositories\BeforeEachRepository;
|
||||||
use Pest\Repositories\RetryRepository;
|
|
||||||
use Pest\Repositories\TestRepository;
|
use Pest\Repositories\TestRepository;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
@ -48,11 +47,6 @@ final class TestSuite
|
|||||||
*/
|
*/
|
||||||
public AfterAllRepository $afterAll;
|
public AfterAllRepository $afterAll;
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds the retry repository.
|
|
||||||
*/
|
|
||||||
public RetryRepository $retryRepository;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds the root path.
|
* Holds the root path.
|
||||||
*/
|
*/
|
||||||
@ -75,7 +69,6 @@ final class TestSuite
|
|||||||
$this->tests = new TestRepository();
|
$this->tests = new TestRepository();
|
||||||
$this->afterEach = new AfterEachRepository();
|
$this->afterEach = new AfterEachRepository();
|
||||||
$this->afterAll = new AfterAllRepository();
|
$this->afterAll = new AfterAllRepository();
|
||||||
$this->retryRepository = new RetryRepository('retry');
|
|
||||||
|
|
||||||
$this->rootPath = (string) realpath($rootPath);
|
$this->rootPath = (string) realpath($rootPath);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
##teamcity[testSuiteStarted name='Tests/tests/Failure' locationHint='file://tests/.tests/Failure.php' flowId='1234']
|
##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[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:106|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[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[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[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[testIgnored name='it can be ignored because of no assertions' message='This test did not perform any assertions' details='' flowId='1234']
|
||||||
@ -9,7 +9,7 @@
|
|||||||
##teamcity[testIgnored name='it can be ignored because it is skipped' message='This test was ignored.' details='' 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[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[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:106|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[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[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[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[testIgnored name='it is not done yet' message='This test was ignored.' details='' flowId='1234']
|
||||||
|
|||||||
@ -843,7 +843,7 @@
|
|||||||
✓ environment is set to Local when --ci option is not used
|
✓ environment is set to Local when --ci option is not used
|
||||||
|
|
||||||
PASS Tests\Unit\Plugins\Retry
|
PASS Tests\Unit\Plugins\Retry
|
||||||
✓ it retries if --retry argument is used
|
✓ it orders by defects and stop on defects if when --retry is used
|
||||||
|
|
||||||
PASS Tests\Unit\Support\Backtrace
|
PASS Tests\Unit\Support\Backtrace
|
||||||
✓ it gets file name from called file
|
✓ it gets file name from called file
|
||||||
|
|||||||
@ -2,14 +2,13 @@
|
|||||||
|
|
||||||
use Pest\Plugins\Retry;
|
use Pest\Plugins\Retry;
|
||||||
|
|
||||||
beforeEach(fn () => Retry::$retrying = false);
|
it('orders by defects and stop on defects if when --retry is used ', function () {
|
||||||
|
|
||||||
afterEach(fn () => Retry::$retrying = false);
|
|
||||||
|
|
||||||
it('retries if --retry argument is used', function () {
|
|
||||||
$retry = new Retry();
|
$retry = new Retry();
|
||||||
|
|
||||||
$retry->handleArguments(['--retry']);
|
$arguments = $retry->handleArguments(['--retry']);
|
||||||
|
|
||||||
expect(Retry::$retrying)->toBeTrue();
|
expect($arguments)->toBe([
|
||||||
|
'--order-by=defects',
|
||||||
|
' --stop-on-defect',
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user