refacto: --retry option

This commit is contained in:
Nuno Maduro
2023-02-11 16:48:06 +00:00
parent a8f0b96338
commit d69f61c8d3
18 changed files with 61 additions and 200 deletions

1
.gitignore vendored
View File

@ -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
View 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

File diff suppressed because one or more lines are too long

View File

@ -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",

View File

@ -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"

View File

@ -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,
]; ];

View File

@ -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
View 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);
}
}

View File

@ -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;
} }
} }

View File

@ -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);
}
}

View File

@ -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());
} }
} }

View File

@ -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());
}
}

View File

@ -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());
}
}

View File

@ -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();
}
}

View File

@ -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);
} }

View File

@ -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']

View File

@ -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

View 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',
]);
}); });