feat: support for deprecated, notices, and warnings

This commit is contained in:
Nuno Maduro
2023-03-02 20:37:18 +00:00
parent 3f6b2e856e
commit 1e61034e86
11 changed files with 124 additions and 38 deletions

View File

@ -61,9 +61,11 @@ final class TestSkippedSubscriber extends Subscriber implements SkippedSubscribe
*/ */
public function notify(Skipped $event): void public function notify(Skipped $event): void
{ {
str_contains($event->message(), '__TODO__') if (str_contains($event->message(), '__TODO__')) {
? $this->printTodoItem() $this->printTodoItem();
: $this->printer()->testSkipped(); }
$this->printer()->testSkipped();
} }
/** /**

View File

@ -12,12 +12,6 @@
stopOnError="false" stopOnError="false"
stopOnFailure="false" stopOnFailure="false"
backupStaticProperties="false" backupStaticProperties="false"
displayDetailsOnIncompleteTests="true"
displayDetailsOnSkippedTests="true"
displayDetailsOnTestsThatTriggerDeprecations="true"
displayDetailsOnTestsThatTriggerErrors="true"
displayDetailsOnTestsThatTriggerNotices="true"
displayDetailsOnTestsThatTriggerWarnings="true"
> >
<testsuites> <testsuites>
<testsuite name="default"> <testsuite name="default">

View File

@ -12,6 +12,7 @@ use function fread;
use function fseek; use function fseek;
use function ftell; use function ftell;
use function fwrite; use function fwrite;
use NunoMaduro\Collision\Adapters\Phpunit\State;
use ParaTest\Options; use ParaTest\Options;
use Pest\Plugins\Parallel\Support\CompactPrinter; use Pest\Plugins\Parallel\Support\CompactPrinter;
use Pest\Support\StateGenerator; use Pest\Support\StateGenerator;
@ -27,11 +28,21 @@ use Symfony\Component\Console\Output\OutputInterface;
/** @internal */ /** @internal */
final class ResultPrinter final class ResultPrinter
{ {
/**
* If the test should be marked as todo.
*/
public bool $lastWasTodo = false;
/** /**
* The "native" printer. * The "native" printer.
*/ */
public readonly Printer $printer; public readonly Printer $printer;
/**
* The state.
*/
public int $passedTests = 0;
/** /**
* The "compact" printer. * The "compact" printer.
*/ */
@ -140,7 +151,7 @@ final class ResultPrinter
return; return;
} }
$state = (new StateGenerator())->fromPhpUnitTestResult($testResult); $state = (new StateGenerator())->fromPhpUnitTestResult($this->passedTests, $testResult);
$this->compactPrinter->errors($state); $this->compactPrinter->errors($state);
$this->compactPrinter->recap($state, $testResult, $duration, $this->options); $this->compactPrinter->recap($state, $testResult, $duration, $this->options);
@ -148,6 +159,20 @@ final class ResultPrinter
private function printFeedbackItem(string $item): void private function printFeedbackItem(string $item): void
{ {
if ($this->lastWasTodo) {
$this->lastWasTodo = false;
return;
}
if ($item === 'T') {
$this->lastWasTodo = true;
}
if ($item === '.') {
$this->passedTests++;
}
$this->compactPrinter->descriptionItem($item); $this->compactPrinter->descriptionItem($item);
} }

View File

@ -36,8 +36,8 @@ final class CompactPrinter
'.' => ['gray', '.'], '.' => ['gray', '.'],
'S' => ['yellow', 's'], 'S' => ['yellow', 's'],
'T' => ['cyan', 't'], 'T' => ['cyan', 't'],
'I' => ['yellow', 'i'], 'I' => ['yellow', '!'],
'N' => ['yellow', 'i'], 'N' => ['yellow', '!'],
'D' => ['yellow', '!'], 'D' => ['yellow', '!'],
'R' => ['yellow', '!'], 'R' => ['yellow', '!'],
'W' => ['yellow', '!'], 'W' => ['yellow', '!'],
@ -106,7 +106,9 @@ final class CompactPrinter
*/ */
public function errors(State $state): void public function errors(State $state): void
{ {
$this->style->writeErrorsSummary($state, false); $this->output->writeln('');
$this->style->writeErrorsSummary($state);
} }
/** /**

View File

@ -6,15 +6,12 @@ namespace Pest\Support;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use ReflectionClass; use ReflectionClass;
use Throwable;
/** /**
* @internal * @internal
*/ */
final class HigherOrderTapProxy final class HigherOrderTapProxy
{ {
private const UNDEFINED_PROPERTY = 'Undefined property: P\\'; // @phpstan-ignore-line
/** /**
* Create a new tap proxy instance. * Create a new tap proxy instance.
*/ */
@ -40,16 +37,18 @@ final class HigherOrderTapProxy
public function __get(string $property) public function __get(string $property)
{ {
if (property_exists($this->target, $property)) { if (property_exists($this->target, $property)) {
return $this->target->{$property}; return $this->target->{$property}; // @phpstan-ignore-line
} }
$className = (new ReflectionClass($this->target))->getName(); $className = (new ReflectionClass($this->target))->getName();
if (str_starts_with($className, "P\\")) { if (str_starts_with($className, 'P\\')) {
$className = substr($className, 2); $className = substr($className, 2);
} }
trigger_error(sprintf('Undefined property %s::$%s', $className, $property), E_USER_WARNING); trigger_error(sprintf('Undefined property %s::$%s', $className, $property), E_USER_WARNING);
return null;
} }
/** /**

View File

@ -11,6 +11,7 @@ use PHPUnit\Event\Code\TestMethod;
use PHPUnit\Event\Code\Throwable; use PHPUnit\Event\Code\Throwable;
use PHPUnit\Event\Test\Errored; use PHPUnit\Event\Test\Errored;
use PHPUnit\Event\TestData\TestDataCollection; use PHPUnit\Event\TestData\TestDataCollection;
use PHPUnit\Framework\Exception;
use PHPUnit\Framework\IncompleteTestError; use PHPUnit\Framework\IncompleteTestError;
use PHPUnit\Framework\SkippedWithMessageException; use PHPUnit\Framework\SkippedWithMessageException;
use PHPUnit\Metadata\MetadataCollection; use PHPUnit\Metadata\MetadataCollection;
@ -18,7 +19,7 @@ use PHPUnit\TestRunner\TestResult\TestResult as PHPUnitTestResult;
final class StateGenerator final class StateGenerator
{ {
public function fromPhpUnitTestResult(PHPUnitTestResult $testResult): State public function fromPhpUnitTestResult(int $passedTests, PHPUnitTestResult $testResult): State
{ {
$state = new State(); $state = new State();
@ -74,16 +75,69 @@ final class StateGenerator
)); ));
} }
$numberOfPassedTests = $testResult->numberOfTestsRun() foreach ($testResult->testTriggeredDeprecationEvents() as $testResultEvent) {
- $testResult->numberOfTestErroredEvents() $testResultEvent = $testResultEvent[0];
- $testResult->numberOfTestFailedEvents()
- $testResult->numberOfTestSkippedEvents()
- $testResult->numberOfTestsWithTestConsideredRiskyEvents()
- $testResult->numberOfTestMarkedIncompleteEvents();
for ($i = 0; $i < $numberOfPassedTests; $i++) {
$state->add(TestResult::fromTestCase( $state->add(TestResult::fromTestCase(
$testResultEvent->test(),
TestResult::DEPRECATED,
Throwable::from(new Exception($testResultEvent->message()))
));
}
foreach ($testResult->testTriggeredPhpDeprecationEvents() as $testResultEvent) {
$testResultEvent = $testResultEvent[0];
$state->add(TestResult::fromTestCase(
$testResultEvent->test(),
TestResult::DEPRECATED,
Throwable::from(new Exception($testResultEvent->message()))
));
}
foreach ($testResult->testTriggeredNoticeEvents() as $testResultEvent) {
$testResultEvent = $testResultEvent[0];
$state->add(TestResult::fromTestCase(
$testResultEvent->test(),
TestResult::NOTICE,
Throwable::from(new Exception($testResultEvent->message()))
));
}
foreach ($testResult->testTriggeredPhpNoticeEvents() as $testResultEvent) {
$testResultEvent = $testResultEvent[0];
$state->add(TestResult::fromTestCase(
$testResultEvent->test(),
TestResult::NOTICE,
Throwable::from(new Exception($testResultEvent->message()))
));
}
foreach ($testResult->testTriggeredWarningEvents() as $testResultEvent) {
$testResultEvent = $testResultEvent[0];
$state->add(TestResult::fromTestCase(
$testResultEvent->test(),
TestResult::WARN,
Throwable::from(new Exception($testResultEvent->message()))
));
}
foreach ($testResult->testTriggeredPhpWarningEvents() as $testResultEvent) {
$testResultEvent = $testResultEvent[0];
$state->add(TestResult::fromTestCase(
$testResultEvent->test(),
TestResult::WARN,
Throwable::from(new Exception($testResultEvent->message()))
));
}
// for each test that passed, we need to add it to the state
for ($i = 0; $i < $passedTests; $i++) {
$state->add(TestResult::fromTestCase(
new TestMethod( new TestMethod(
/** @phpstan-ignore-next-line */ /** @phpstan-ignore-next-line */
"$i", "$i",

View File

@ -18,7 +18,3 @@
##teamcity[testIgnored name='build this one.' message='This test was ignored.' details='' 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[testFinished name='build this one.' duration='100000' flowId='1234']
##teamcity[testSuiteFinished name='Tests/tests/Failure' flowId='1234'] ##teamcity[testSuiteFinished name='Tests/tests/Failure' flowId='1234']
Tests: 2 failed, 1 risky, 2 todos, 1 skipped (2 assertions)
Duration: 1.00s

View File

@ -4,7 +4,3 @@
##teamcity[testStarted name='can also pass' locationHint='pest_qn://tests/.tests/SuccessOnly.php::can also pass' flowId='1234'] ##teamcity[testStarted name='can also pass' locationHint='pest_qn://tests/.tests/SuccessOnly.php::can also pass' flowId='1234']
##teamcity[testFinished name='can also pass' duration='100000' flowId='1234'] ##teamcity[testFinished name='can also pass' duration='100000' flowId='1234']
##teamcity[testSuiteFinished name='Tests/tests/SuccessOnly' flowId='1234'] ##teamcity[testSuiteFinished name='Tests/tests/SuccessOnly' flowId='1234']
Tests: 2 passed (2 assertions)
Duration: 1.00s

View File

@ -139,6 +139,10 @@
✓ it is a test ✓ it is a test
✓ it uses correct parent class ✓ it uses correct parent class
DEPR Tests\Features\Deprecated
! deprecated → str_contains(): Passing null to parameter #2 ($needle) of type string is deprecated
! user deprecated → Since foo 1.0: This is a deprecation description
PASS Tests\Features\Exceptions PASS Tests\Features\Exceptions
✓ it gives access the the underlying expectException ✓ it gives access the the underlying expectException
✓ it catch exceptions ✓ it catch exceptions
@ -646,9 +650,9 @@
✓ it skips with falsy closure condition ✓ it skips with falsy closure condition
✓ it can be used in higher order tests ✓ it can be used in higher order tests
PASS Tests\Features\Helpers WARN Tests\Features\Helpers
✓ it can set/get properties on $this ✓ it can set/get properties on $this
it throws error if property do not exist ! it gets null if property do not exist → Undefined property Tests\Features\Helpers::$wqdwqdqw
✓ it allows to call underlying protected/private methods ✓ it allows to call underlying protected/private methods
✓ it throws error if method do not exist ✓ it throws error if method do not exist
✓ it can forward unexpected calls to any global function ✓ it can forward unexpected calls to any global function
@ -678,6 +682,9 @@
✓ it is a test ✓ it is a test
✓ it is a higher order message test ✓ it is a higher order message test
NOTI Tests\Features\Notices
! notice → This is a notice description
PASS Tests\Features\PendingHigherOrderTests PASS Tests\Features\PendingHigherOrderTests
✓ get 'foo' ✓ get 'foo'
✓ get 'foo' → get 'bar' → expect true → toBeTrue ✓ get 'foo' → get 'bar' → expect true → toBeTrue
@ -750,6 +757,10 @@
↓ something todo later chained and with function body ↓ something todo later chained and with function body
✓ it does something within a file with a todo ✓ it does something within a file with a todo
WARN Tests\Features\Warnings
! warning → Undefined property: P\Tests\Features\Warnings::$fooqwdfwqdfqw
! user warning → This is a warning description
PASS Tests\Fixtures\DirectoryWithTests\ExampleTest PASS Tests\Fixtures\DirectoryWithTests\ExampleTest
✓ it example 1 ✓ it example 1
@ -917,4 +928,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, 634 passed (1560 assertions) Tests: 2 deprecated, 3 warnings, 4 incomplete, 1 notice, 4 todos, 18 skipped, 633 passed (1564 assertions)

View File

@ -0,0 +1,7 @@
<?php
test('notice', function () {
trigger_error('This is a notice description', E_USER_NOTICE);
expect(true)->toBeTrue();
});

View File

@ -15,6 +15,6 @@ $run = function () {
}; };
test('parallel', function () use ($run) { test('parallel', function () use ($run) {
expect($run())->toContain('Tests: 4 incomplete, 4 todos, 15 skipped, 627 passed (1551 assertions)') expect($run())->toContain('Tests: 2 deprecated, 3 warnings, 4 incomplete, 1 notice, 4 todos, 15 skipped, 626 passed (1555 assertions)')
->toContain('Parallel: 3 processes'); ->toContain('Parallel: 3 processes');
}); });