mirror of
https://github.com/pestphp/pest.git
synced 2026-03-06 07:47:22 +01:00
feat: support for deprecated, notices, and warnings
This commit is contained in:
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -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">
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
@ -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']
|
||||||
|
|
||||||
[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
|
|
||||||
|
|
||||||
|
|||||||
@ -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']
|
||||||
|
|
||||||
[90mTests:[39m [32;1m2 passed[39;22m[90m (2 assertions)[39m
|
|
||||||
[90mDuration:[39m [39m1.00s[39m
|
|
||||||
|
|
||||||
|
|||||||
@ -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)
|
||||||
7
tests/Features/Notices.php
Normal file
7
tests/Features/Notices.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
test('notice', function () {
|
||||||
|
trigger_error('This is a notice description', E_USER_NOTICE);
|
||||||
|
|
||||||
|
expect(true)->toBeTrue();
|
||||||
|
});
|
||||||
@ -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');
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user