diff --git a/bin/pest b/bin/pest index f00e8f02..bae7b4eb 100755 --- a/bin/pest +++ b/bin/pest @@ -5,6 +5,7 @@ use Pest\ConfigLoader; use Pest\Kernel; use Pest\Support\Container; use Pest\TestCaseFilters\GitDirtyTestCaseFilter; +use Pest\TestCaseMethodFilters\TodoTestCaseFilter; use Pest\TestSuite; use Symfony\Component\Console\Input\ArgvInput; use Symfony\Component\Console\Input\InputInterface; @@ -17,6 +18,7 @@ use Symfony\Component\Console\Output\OutputInterface; $args = $_SERVER['argv']; $dirty = false; + $todo = false; foreach ($args as $key => $value) { if (str_contains($value, '--compact')) { @@ -38,6 +40,11 @@ use Symfony\Component\Console\Output\OutputInterface; unset($args[$key]); } + if (str_contains($value, '--todo')) { + $todo = true; + unset($args[$key]); + } + if (str_contains($value, '--teamcity')) { unset($args[$key]); $args[] = '--no-output'; @@ -69,7 +76,11 @@ use Symfony\Component\Console\Output\OutputInterface; ); if ($dirty) { - $testSuite->tests->filter(new GitDirtyTestCaseFilter($rootPath)); + $testSuite->tests->addTestCaseFilter(new GitDirtyTestCaseFilter($rootPath)); + } + + if ($todo) { + $testSuite->tests->addTestCaseMethodFilter(new TodoTestCaseFilter()); } $isDecorated = $argv->getParameterOption('--colors', 'always') !== 'never'; diff --git a/src/Contracts/TestCaseMethodFilter.php b/src/Contracts/TestCaseMethodFilter.php new file mode 100644 index 00000000..04f2f36f --- /dev/null +++ b/src/Contracts/TestCaseMethodFilter.php @@ -0,0 +1,15 @@ +skip('__TODO__'); + return $test->todo(); } } diff --git a/src/Logging/TeamCity/TeamCityLogger.php b/src/Logging/TeamCity/TeamCityLogger.php index 3ab17550..747d4c4e 100644 --- a/src/Logging/TeamCity/TeamCityLogger.php +++ b/src/Logging/TeamCity/TeamCityLogger.php @@ -208,7 +208,6 @@ final class TeamCityLogger $telemetry->memoryUsageSinceStart(), $telemetry->durationSincePrevious(), $telemetry->memoryUsageSincePrevious(), - $telemetry->emitter(), ); } diff --git a/src/PendingCalls/TestCall.php b/src/PendingCalls/TestCall.php index 3cd8cee6..72dfb1b2 100644 --- a/src/PendingCalls/TestCall.php +++ b/src/PendingCalls/TestCall.php @@ -177,6 +177,8 @@ final class TestCall { $this->skip('__TODO__'); + $this->testCaseMethod->todo = true; + return $this; } diff --git a/src/Repositories/TestRepository.php b/src/Repositories/TestRepository.php index 4cb98940..e20b67ab 100644 --- a/src/Repositories/TestRepository.php +++ b/src/Repositories/TestRepository.php @@ -6,6 +6,7 @@ namespace Pest\Repositories; use Closure; use Pest\Contracts\TestCaseFilter; +use Pest\Contracts\TestCaseMethodFilter; use Pest\Exceptions\TestCaseAlreadyInUse; use Pest\Exceptions\TestCaseClassOrTraitNotFound; use Pest\Factories\TestCaseFactory; @@ -31,7 +32,12 @@ final class TestRepository /** * @var array */ - private array $filters = []; + private array $testCaseFilters = []; + + /** + * @var array + */ + private array $testCaseMethodFilters = []; /** * Counts the number of test cases. @@ -93,9 +99,17 @@ final class TestRepository /** * Filters the test cases using the given filter. */ - public function filter(TestCaseFilter $filter): void + public function addTestCaseFilter(TestCaseFilter $filter): void { - $this->filters[] = $filter; + $this->testCaseFilters[] = $filter; + } + + /** + * Filters the test cases using the given filter. + */ + public function addTestCaseMethodFilter(TestCaseMethodFilter $filter): void + { + $this->testCaseMethodFilters[] = $filter; } /** @@ -111,6 +125,12 @@ final class TestRepository */ public function set(TestCaseMethodFactory $method): void { + foreach ($this->testCaseMethodFilters as $filter) { + if (! $filter->accept($method)) { + return; + } + } + if (! array_key_exists($method->filename, $this->testCases)) { $this->testCases[$method->filename] = new TestCaseFactory($method->filename); } @@ -128,7 +148,7 @@ final class TestRepository } $accepted = array_reduce( - $this->filters, + $this->testCaseFilters, fn (bool $carry, TestCaseFilter $filter): bool => $carry && $filter->accept($filename), true, ); diff --git a/src/TestCaseMethodFilters/TodoTestCaseFilter.php b/src/TestCaseMethodFilters/TodoTestCaseFilter.php new file mode 100644 index 00000000..401666dc --- /dev/null +++ b/src/TestCaseMethodFilters/TodoTestCaseFilter.php @@ -0,0 +1,16 @@ +todo; + } +} diff --git a/tests/.snapshots/Failure.php.inc b/tests/.snapshots/Failure.php.inc index e44b5067..5a422a49 100644 --- a/tests/.snapshots/Failure.php.inc +++ b/tests/.snapshots/Failure.php.inc @@ -1,6 +1,6 @@ ##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:312|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:101|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:312|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[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'] @@ -9,7 +9,7 @@ ##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:101|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: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[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'] diff --git a/tests/.snapshots/success.txt b/tests/.snapshots/success.txt index 7d26d0b0..e80dff6b 100644 --- a/tests/.snapshots/success.txt +++ b/tests/.snapshots/success.txt @@ -896,7 +896,10 @@ - visual snapshot of team city with ('Failure.php') - visual snapshot of team city with ('SuccessOnly.php') + PASS Tests\Visual\Todo + ✓ todo + PASS Tests\Visual\Version ✓ visual snapshot of help command output - Tests: 4 incomplete, 4 todos, 18 skipped, 624 passed (1511 assertions) \ No newline at end of file + Tests: 4 incomplete, 4 todos, 18 skipped, 625 passed (1512 assertions) \ No newline at end of file diff --git a/tests/.snapshots/todo.txt b/tests/.snapshots/todo.txt new file mode 100644 index 00000000..af7d2a8c --- /dev/null +++ b/tests/.snapshots/todo.txt @@ -0,0 +1,12 @@ + PASS Tests\Features\DatasetsTests + ↓ forbids to define tests in Datasets dirs and Datasets.php files + + PASS Tests\Features\Todo + ↓ something todo later + ↓ something todo later chained + ↓ something todo later chained and with function body + + PASS Tests\CustomTestCase\ExecutedTest + ✓ that gets executed + + Tests: 4 todos, 1 passed (1 assertions) diff --git a/tests/Visual/Todo.php b/tests/Visual/Todo.php new file mode 100644 index 00000000..ac4f3ba5 --- /dev/null +++ b/tests/Visual/Todo.php @@ -0,0 +1,27 @@ + 'DefaultPrinter', 'COLLISION_IGNORE_DURATION' => 'true'], + ); + + $process->run(); + + return $decorated ? $process->getOutput() : preg_replace('#\\x1b[[][^A-Za-z]*[A-Za-z]#', '', $process->getOutput()); +}; + +$snapshot = function ($name) { + $testsPath = dirname(__DIR__); + + return file_get_contents(implode(DIRECTORY_SEPARATOR, [ + $testsPath, + '.snapshots', + "$name.txt", + ])); +}; + +test('todo', function () use ($run, $snapshot) { + expect($run('--todo'))->toContain($snapshot('todo')); +})->skip(PHP_OS_FAMILY === 'Windows');