diff --git a/composer.json b/composer.json index a8436b33..3c674c61 100644 --- a/composer.json +++ b/composer.json @@ -72,7 +72,7 @@ "test:refacto": "rector --dry-run", "test:lint": "pint --test", "test:type:check": "phpstan analyse --ansi --memory-limit=-1 --debug", - "test:type:coverage": "php bin/pest --type-coverage --min=100", + "test:type:coverage": "php -d memory_limit=-1 bin/pest --type-coverage --min=100", "test:unit": "php bin/pest --colors=always --exclude-group=integration --compact", "test:inline": "php bin/pest --colors=always --configuration=phpunit.inline.xml", "test:parallel": "php bin/pest --colors=always --exclude-group=integration --parallel --processes=3", diff --git a/src/Concerns/Testable.php b/src/Concerns/Testable.php index 74c499b0..27e3a268 100644 --- a/src/Concerns/Testable.php +++ b/src/Concerns/Testable.php @@ -291,11 +291,13 @@ trait Testable $afterEach = ChainableClosure::bound($this->__afterEach, $afterEach); } - $this->__callClosure($afterEach, $arguments); + try { + $this->__callClosure($afterEach, func_get_args()); + } finally { + parent::tearDown(); - parent::tearDown(); - - TestSuite::getInstance()->test = null; + TestSuite::getInstance()->test = null; + } } /** diff --git a/src/Exceptions/TestClosureMustNotBeStatic.php b/src/Exceptions/TestClosureMustNotBeStatic.php new file mode 100644 index 00000000..b1f91e95 --- /dev/null +++ b/src/Exceptions/TestClosureMustNotBeStatic.php @@ -0,0 +1,31 @@ +description, + $method->filename + ) + ); + } +} diff --git a/src/Expectation.php b/src/Expectation.php index ec1cc7df..41adc06b 100644 --- a/src/Expectation.php +++ b/src/Expectation.php @@ -509,7 +509,7 @@ final class Expectation { return Targeted::make( $this, - fn (ObjectDescription $object): bool => str_contains((string) file_get_contents($object->path), 'declare(strict_types=1);'), + fn (ObjectDescription $object): bool => (bool) preg_match('/^<\?php\s+declare\(.*?strict_types\s?=\s?1.*?\);/', (string) file_get_contents($object->path)), 'to use strict types', FileLineFinder::where(fn (string $line): bool => str_contains($line, 'original, - fn (ObjectDescription $object): bool => ! str_contains((string) file_get_contents($object->path), 'declare(strict_types=1);'), + fn (ObjectDescription $object): bool => ! (bool) preg_match('/^<\?php\s+declare\(.*?strict_types\s?=\s?1.*?\);/', (string) file_get_contents($object->path)), 'not to use strict types', FileLineFinder::where(fn (string $line): bool => str_contains($line, 'filename, $method->description); } + if ( + $method->closure instanceof \Closure && + (new \ReflectionFunction($method->closure))->isStatic() + ) { + + throw new TestClosureMustNotBeStatic($method); + } + if (! $method->receivesArguments()) { if (! $method->closure instanceof \Closure) { throw ShouldNotHappen::fromMessage('The test closure may not be empty.'); diff --git a/src/Result.php b/src/Result.php index 9b3a83e5..98e9e8b6 100644 --- a/src/Result.php +++ b/src/Result.php @@ -40,9 +40,20 @@ final class Result */ public static function exitCode(Configuration $configuration, TestResult $result): int { - if ($result->wasSuccessfulIgnoringPhpunitWarnings() - && ! $result->hasTestTriggeredPhpunitWarningEvents()) { - return self::SUCCESS_EXIT; + if ($result->wasSuccessfulIgnoringPhpunitWarnings()) { + if ($configuration->failOnWarning()) { + $warnings = $result->numberOfTestsWithTestTriggeredPhpunitWarningEvents() + + count($result->warnings()) + + count($result->phpWarnings()); + + if ($warnings > 0) { + return self::FAILURE_EXIT; + } + } + + if (! $result->hasTestTriggeredPhpunitWarningEvents()) { + return self::SUCCESS_EXIT; + } } if ($configuration->failOnEmptyTestSuite() && ResultReflection::numberOfTests($result) === 0) { @@ -54,14 +65,6 @@ final class Result $returnCode = self::FAILURE_EXIT; } - $warnings = $result->numberOfTestsWithTestTriggeredPhpunitWarningEvents() - + count($result->warnings()) - + count($result->phpWarnings()); - - if ($configuration->failOnWarning() && $warnings > 0) { - $returnCode = self::FAILURE_EXIT; - } - if ($configuration->failOnIncomplete() && $result->hasTestMarkedIncompleteEvents()) { $returnCode = self::FAILURE_EXIT; } diff --git a/tests/.snapshots/success.txt b/tests/.snapshots/success.txt index 71b5ef5a..e69de29b 100644 --- a/tests/.snapshots/success.txt +++ b/tests/.snapshots/success.txt @@ -1,1569 +0,0 @@ - - PASS Tests\Arch - ✓ arch "php" preset - ✓ arch "strict" preset - ✓ arch "security" preset - ✓ globals - ✓ dependencies - ✓ contracts - - PASS Tests\Environments\Windows - ✓ global functions are loaded - - WARN Tests\Features\After - ✓ it can run after test - ✓ it can run after test twice - - it does not run when skipped - - something → it does not run when skipped - ✓ something → it can run after test - ✓ something 2 → it can run after test - ✓ high order test - - high order test with skip - ✓ post 'foo' → defer Closure Object () → expect Closure Object () → toBe 1 - - PASS Tests\Features\AfterAll - ✓ deletes file after all - - PASS Tests\Features\AfterEach - ✓ it does not get executed before the test - ✓ it gets executed after the test - - PASS Tests\Features\Assignee - ✓ it may be associated with an assignee [@nunomaduro, @taylorotwell] - ✓ nested → it may be associated with an assignee [@nunomaduro, @jamesbrooks, @joedixon, @taylorotwell] - // an note between an the assignee - - PASS Tests\Features\BeforeAll - ✓ it gets executed before tests - ✓ it do not get executed before each test - - PASS Tests\Features\BeforeEach - ✓ it gets executed before each test - ✓ it gets executed before each test once again - - PASS Tests\Features\BeforeEachProxiesToTestCallWithExpectations - ✓ runs 1 - ✓ runs 2 - ✓ runs 3 - - WARN Tests\Features\BeforeEachProxiesToTestCallWithSkip - - does not run 1 - - does not run 2 - - does not run 3 - - TODO Tests\Features\BeforeEachProxiesToTestCallWithTodo - 4 todos - ↓ is marked as todo 1 - ↓ is marked as todo 2 - ↓ is marked as todo 3 - ↓ shouldBeMarkedAsTodo - - WARN Tests\Features\Coverage - ✓ it has plugin - - it adds coverage if --coverage exist → Coverage is not available - ✓ it adds coverage if --min exist - ✓ it generates coverage based on file input - - PASS Tests\Features\Covers - ✓ it uses the correct PHPUnit attribute for class - ✓ it uses the correct PHPUnit attribute for function - ✓ it guesses if the given argument is a class or function - ✓ it uses the correct PHPUnit attribute for trait - ✓ it uses the correct PHPUnit attribute for covers nothing - ✓ it throws exception if no class nor method has been found - - PASS Tests\Features\DatasetsTests - 1 todo - ✓ it throws exception if dataset does not exist - ✓ it throws exception if dataset already exist - ✓ it sets closures - ✓ it sets arrays - ✓ it gets bound to test case object with ('a') - ✓ it gets bound to test case object with ('b') - ✓ it truncates the description with ('FoooFoooFoooFoooFoooFoooFoooF…ooFooo') - ✓ lazy datasets with (1) - ✓ lazy datasets with (2) - ✓ lazy datasets did the job right - ✓ interpolated (1) lazy datasets - ✓ interpolated (2) lazy datasets - ✓ eager datasets with (1) - ✓ eager datasets with (2) - ✓ eager datasets did the job right - ✓ lazy registered datasets with (1) - ✓ lazy registered datasets with (2) - ✓ lazy registered datasets did the job right - ✓ eager registered datasets with (1) - ✓ eager registered datasets with (2) - ✓ eager registered datasets did the job right - ✓ eager wrapped registered datasets with (1) - ✓ eager wrapped registered datasets with (2) - ✓ eager registered wrapped datasets did the job right - ✓ named datasets with dataset "one" - ✓ named datasets with dataset "two" - ✓ interpolated "one" named datasets - ✓ interpolated "two" named datasets - ✓ named datasets did the job right - ✓ lazy named datasets with (Bar) - ✓ it creates unique test case names with ('Name 1', Pest\Plugin, true) #1 - ✓ it creates unique test case names with ('Name 1', Pest\Plugin, true) #2 - ✓ it creates unique test case names with ('Name 1', Pest\Plugin, false) - ✓ it creates unique test case names with ('Name 2', Pest\Plugin, false) - ✓ it creates unique test case names with ('Name 2', Pest\Plugin, true) - ✓ it creates unique test case names with ('Name 1', Pest\Plugin, true) #3 - ✓ it creates unique test case names - count - ✓ lazy multiple datasets with (1) / (3) - ✓ lazy multiple datasets with (1) / (4) - ✓ lazy multiple datasets with (2) / (3) - ✓ lazy multiple datasets with (2) / (4) - ✓ lazy multiple datasets did the job right - ✓ eager multiple datasets with (1) / (3) - ✓ eager multiple datasets with (1) / (4) - ✓ eager multiple datasets with (2) / (3) - ✓ eager multiple datasets with (2) / (4) - ✓ eager multiple datasets did the job right - ✓ lazy registered multiple datasets with (1) / (1) - ✓ lazy registered multiple datasets with (1) / (2) - ✓ lazy registered multiple datasets with (2) / (1) - ✓ lazy registered multiple datasets with (2) / (2) - ✓ lazy registered multiple datasets did the job right - ✓ eager registered multiple datasets with (1) / (1) - ✓ eager registered multiple datasets with (1) / (2) - ✓ eager registered multiple datasets with (2) / (1) - ✓ eager registered multiple datasets with (2) / (2) - ✓ eager registered multiple datasets did the job right - ✓ eager wrapped registered multiple datasets with (1) / (1) - ✓ eager wrapped registered multiple datasets with (1) / (2) - ✓ eager wrapped registered multiple datasets with (2) / (1) - ✓ eager wrapped registered multiple datasets with (2) / (2) - ✓ eager wrapped registered multiple datasets did the job right - ✓ named multiple datasets with dataset "one" / dataset "three" - ✓ named multiple datasets with dataset "one" / dataset "four" - ✓ named multiple datasets with dataset "two" / dataset "three" - ✓ named multiple datasets with dataset "two" / dataset "four" - ✓ named multiple datasets did the job right - ✓ more than two datasets with (1) / (3) / (5) - ✓ more than two datasets with (1) / (3) / (6) - ✓ more than two datasets with (1) / (4) / (5) - ✓ more than two datasets with (1) / (4) / (6) - ✓ more than two datasets with (2) / (3) / (5) - ✓ more than two datasets with (2) / (3) / (6) - ✓ more than two datasets with (2) / (4) / (5) - ✓ more than two datasets with (2) / (4) / (6) - ✓ more than two datasets did the job right - ✓ eager registered wrapped datasets with Generator functions with (1) - ✓ eager registered wrapped datasets with Generator functions with (2) - ✓ eager registered wrapped datasets with Generator functions with (3) - ✓ eager registered wrapped datasets with Generator functions with (4) - ✓ eager registered wrapped datasets with Generator functions did the job right - ✓ eager registered wrapped datasets with Generator functions display description with dataset "taylor" - ✓ eager registered wrapped datasets with Generator functions display description with dataset "james" - ✓ it can resolve a dataset after the test case is available with (Closure Object ()) #1 - ✓ it can resolve a dataset after the test case is available with (Closure Object ()) #2 - ✓ it can resolve a dataset after the test case is available with multiple datasets with (Closure Object ()) / (Closure Object ()) #1 - ✓ it can resolve a dataset after the test case is available with multiple datasets with (Closure Object ()) / (Closure Object ()) #2 - ✓ it can resolve a dataset after the test case is available with multiple datasets with (Closure Object ()) / (Closure Object ()) #3 - ✓ it can resolve a dataset after the test case is available with multiple datasets with (Closure Object ()) / (Closure Object ()) #4 - ✓ it can resolve a dataset after the test case is available with shared yield sets with (Closure Object ()) #1 - ✓ it can resolve a dataset after the test case is available with shared yield sets with (Closure Object ()) #2 - ✓ it can resolve a dataset after the test case is available with shared array sets with (Closure Object ()) #1 - ✓ it can resolve a dataset after the test case is available with shared array sets with (Closure Object ()) #2 - ✓ it resolves a potential bound dataset logically with ('foo', Closure Object ()) - ✓ it resolves a potential bound dataset logically even when the closure comes first with (Closure Object (), 'bar') - ✓ it will not resolve a closure if it is type hinted as a closure with (Closure Object ()) #1 - ✓ it will not resolve a closure if it is type hinted as a closure with (Closure Object ()) #2 - ✓ it will not resolve a closure if it is type hinted as a callable with (Closure Object ()) #1 - ✓ it will not resolve a closure if it is type hinted as a callable with (Closure Object ()) #2 - ✓ it can correctly resolve a bound dataset that returns an array with (Closure Object ()) - ✓ it can correctly resolve a bound dataset that returns an array but wants to be spread with (Closure Object ()) - ↓ forbids to define tests in Datasets dirs and Datasets.php files - ✓ it may be used with high order with dataset "formal" - ✓ it may be used with high order with dataset "informal" - ✓ it may be used with high order even when bound with dataset "formal" - ✓ it may be used with high order even when bound with dataset "informal" - - PASS Tests\Features\Depends - ✓ first - ✓ second - ✓ depends - ✓ depends with ...params - ✓ depends with defined arguments - ✓ depends run test only once - ✓ it asserts true is true - ✓ depends works with the correct test name - - PASS Tests\Features\DependsInheritance - ✓ it is a test - ✓ it uses correct parent class - - DEPR Tests\Features\Deprecated - ! deprecated → str_contains(): Passing null to parameter #1 ($haystack) of type string is deprecated // tests/Features/Deprecated.php:4 - ! user deprecated → Since foo 1.0: This is a deprecation description // tests/Features/Deprecated.php:10 - - PASS Tests\Features\Describe - 5 todos - ✓ before each - ✓ hooks → value - ✓ hooks in different orders → value - ↓ todo - ✓ previous describable before each does not get applied here - ↓ todo on hook → should not fail - ↓ todo on hook → should run - ↓ todo on describe → should not fail - ↓ todo on describe → should run - ✓ should run - ✓ with with (1) - ✓ with on hook → value with (2) - ✓ with on describe → value with (3) - ✓ depends on describe → foo - ✓ depends on describe → bar - ✓ depends on describe using with → foo with (3) - ✓ depends on describe using with → bar with (3) - - PASS Tests\Features\DescriptionLess - ✓ get 'foo' - ✓ get 'foo' → get 'bar' → expect true → toBeTrue - ✓ get 'foo' → expect true → toBeTrue - ✓ a "describe" group of tests → get 'foo' - ✓ a "describe" group of tests → get 'foo' → get 'bar' → expect true → toBeTrue - ✓ a "describe" group of tests → get 'foo' → expect true → toBeTrue - - PASS Tests\Features\Done - ✓ it may have an associated assignee [@nunomaduro] - ✓ it may have an associated issue #1 - ✓ it may have an associated PR #1 - ✓ it may have an associated note - // a note - - PASS Tests\Features\Exceptions - ✓ it gives access the the underlying expectException - ✓ it catch exceptions - ✓ it catch exceptions and messages - ✓ it catch exceptions, messages and code - ✓ it can just define the message - ✓ it can just define the code - ✓ it not catch exceptions if given condition is false - ✓ it catch exceptions if given condition is true - ✓ it catch exceptions and messages if given condition is true - ✓ it catch exceptions, messages and code if given condition is true - ✓ it can just define the message if given condition is true - ✓ it can just define the code if given condition is true - ✓ it can just define the message if given condition is 1 - ✓ it can just define the code if given condition is 1 - ✓ it not catch exceptions if given condition is true - ✓ it catch exceptions if given condition is false - ✓ it catch exceptions and messages if given condition is false - ✓ it catch exceptions, messages and code if given condition is false - ✓ it can just define the message if given condition is false - ✓ it can just define the code if given condition is false - ✓ it can just define the message if given condition is 0 - ✓ it can just define the code if given condition is 0 - - PASS Tests\Features\Expect\HigherOrder\methods - ✓ it can access methods - ✓ it can access multiple methods - ✓ it works with not - ✓ it can accept arguments - ✓ it works with each - ✓ it works inside of each - ✓ it works with sequence - ✓ it can compose complex expectations - ✓ it can handle nested method calls - ✓ it works with higher order tests - ✓ it can use the scoped method to lock into the given level for expectations - ✓ it works consistently with the json expectation method - - PASS Tests\Features\Expect\HigherOrder\methodsAndProperties - ✓ it can access methods and properties - ✓ it can handle nested methods and properties - ✓ it works with higher order tests - ✓ it can start a new higher order expectation using the and syntax - ✓ it can start a new higher order expectation using the and syntax in higher order tests - ✓ it can start a new higher order expectation using the and syntax without nesting expectations - - PASS Tests\Features\Expect\HigherOrder\properties - ✓ it allows properties to be accessed from the value - ✓ it can access multiple properties from the value - ✓ it works with not - ✓ it works with each - ✓ it works inside of each - ✓ it works with sequence - ✓ it can compose complex expectations - ✓ it works with objects - ✓ it works with nested properties - ✓ it works with higher order tests - - PASS Tests\Features\Expect\each - ✓ an exception is thrown if the the type is not iterable - ✓ it expects on each item - ✓ it chains expectations on each item - ✓ opposite expectations on each item - ✓ chained opposite and non-opposite expectations - ✓ it can add expectations via "and" - ✓ it accepts callables - ✓ it passes the key of the current item to callables - - PASS Tests\Features\Expect\extend - ✓ it macros true is true - ✓ it macros false is not true - ✓ it macros true is true with argument - ✓ it macros false is not true with argument - - PASS Tests\Features\Expect\json - ✓ it properly parses json string - ✓ fails with broken json string - - PASS Tests\Features\Expect\matchExpectation - ✓ it pass - ✓ it failures - ✓ it runs with truthy - ✓ it runs with falsy - ✓ it runs with truthy closure condition - ✓ it runs with falsy closure condition - ✓ it can be passed non-callable values - ✓ it fails with unhandled match - ✓ it can be used in higher order tests - - PASS Tests\Features\Expect\not - ✓ not property calls - - PASS Tests\Features\Expect\pipes - ✓ pipe is applied and can stop pipeline - ✓ pipe is run and can let the pipeline keep going - ✓ pipe works with negated expectation - ✓ interceptor is applied - ✓ interceptor stops the pipeline - ✓ interceptor is called only when filter is met - ✓ interceptor can be filtered with a closure - ✓ interceptor can be filter the expected parameter as well - ✓ interceptor works with negated expectation - ✓ intercept can add new parameters to the expectation - - PASS Tests\Features\Expect\ray - ✓ ray calls do not fail when ray is not installed - - PASS Tests\Features\Expect\sequence - ✓ an exception is thrown if the the type is not iterable - ✓ an exception is thrown if there are no expectations - ✓ allows for sequences of checks to be run on iterable data - ✓ loops back to the start if it runs out of sequence items - ✓ fails if the number of iterable items is less than the number of expectations - ✓ it works with associative arrays - ✓ it can be passed non-callable values - ✓ it can be passed a mixture of value types - ✓ it works with traversables - - PASS Tests\Features\Expect\toBe - ✓ strict comparisons - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeAlpha - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeAlphaNumeric - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeArray - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeBetween - ✓ passes with int - ✓ passes with float - ✓ passes with float and int - ✓ passes with DateTime - ✓ failure with int - ✓ failure with float - ✓ failure with float and int - ✓ failure with DateTime - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeBool - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeCallable - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeCamelCase - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeDigits - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeDirectory - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeEmpty - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeFalse - ✓ strict comparisons - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeFalsy - ✓ passes as falsy with (false) - ✓ passes as falsy with ('') - ✓ passes as falsy with (null) - ✓ passes as falsy with (0) - ✓ passes as falsy with ('0') - ✓ passes as not falsy with (true) - ✓ passes as not falsy with (1) #1 - ✓ passes as not falsy with ('false') - ✓ passes as not falsy with (1) #2 - ✓ passes as not falsy with (-1) - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeFile - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeFloat - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeGreaterThan - ✓ passes - ✓ passes with DateTime and DateTimeImmutable - ✓ passes with strings - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeGreaterThanOrEqual - ✓ passes - ✓ passes with DateTime and DateTimeImmutable - ✓ passes with strings - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeIn - ✓ passes - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeInfinite - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeInstanceOf - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeInt - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeIntBackedEnum - ✓ enum is backed by int - ✓ enum is not backed by int - - PASS Tests\Features\Expect\toBeInvokable - ✓ class is invokable - ✓ opposite class is invokable - ✓ class is invokable via a parent class - ✓ class is invokable via a trait - ✓ failure when the class is not invokable - ✓ class is not invokable - - PASS Tests\Features\Expect\toBeIterable - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeJson - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeKebabCase - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeLessThan - ✓ passes - ✓ passes with DateTime and DateTimeImmutable - ✓ passes with strings - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeLessThanOrEqual - ✓ passes - ✓ passes with DateTime and DateTimeImmutable - ✓ passes with strings - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeList - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeLowercase - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeNAN - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeNull - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeNumeric - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeObject - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeReadableDirectory - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeReadableFile - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeResource - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeScalar - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeSnakeCase - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeString - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeStringBackedEnum - ✓ enum is backed by string - ✓ enum is not backed by string - - PASS Tests\Features\Expect\toBeStudlyCase - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeTrue - ✓ strict comparisons - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeTruthy - ✓ passes as truthy with (true) - ✓ passes as truthy with (1) #1 - ✓ passes as truthy with ('false') - ✓ passes as truthy with (1) #2 - ✓ passes as truthy with (-1) - ✓ passes as not truthy with (false) - ✓ passes as not truthy with ('') - ✓ passes as not truthy with (null) - ✓ passes as not truthy with (0) - ✓ passes as not truthy with ('0') - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeUppercase - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeUrl - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ failures with default message - ✓ not failures - - PASS Tests\Features\Expect\toBeUuid - ✓ failures with wrong type - ✓ pass - ✓ failures - ✓ failures with message - ✓ not failures - - PASS Tests\Features\Expect\toBeWritableDirectory - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toBeWritableFile - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toContain - ✓ passes strings - ✓ passes strings with multiple needles - ✓ passes arrays - ✓ passes arrays with multiple needles - ✓ passes with array needles - ✓ failures - ✓ failures with multiple needles (all failing) - ✓ failures with multiple needles (some failing) - ✓ not failures - ✓ not failures with multiple needles (all failing) - ✓ not failures with multiple needles (some failing) - - PASS Tests\Features\Expect\toContainEqual - ✓ passes arrays - ✓ passes arrays with multiple needles - ✓ failures - ✓ failures with multiple needles (all failing) - ✓ failures with multiple needles (some failing) - ✓ not failures - ✓ not failures with multiple needles (all failing) - ✓ not failures with multiple needles (some failing) - - PASS Tests\Features\Expect\toContainOnlyInstancesOf - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toEndWith - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toEqual - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toEqualCanonicalizing - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toEqualWithDelta - ✓ pass - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toHaveAttribute - ✓ class has attribute - ✓ opposite class has attribute - ✓ class not has attribute - - PASS Tests\Features\Expect\toHaveCamelCaseKeys - ✓ pass - ✓ failures - ✓ failures with message - ✓ not failures - - PASS Tests\Features\Expect\toHaveConstructor - ✓ class has constructor - ✓ class has no constructor - - PASS Tests\Features\Expect\toHaveCount - ✓ pass - ✓ failures with invalid type - ✓ failures - ✓ failures with message - ✓ not failures - - PASS Tests\Features\Expect\toHaveDestructor - ✓ class has destructor - ✓ class has no destructor - - PASS Tests\Features\Expect\toHaveFileSystemPermissions - ✓ pass - ✓ failures - ✓ not failures - - PASS Tests\Features\Expect\toHaveKebabCaseKeys - ✓ pass - ✓ failures - ✓ failures with message - ✓ not failures - - PASS Tests\Features\Expect\toHaveKey - ✓ pass - ✓ pass with nested key - ✓ pass with plain key with dots - ✓ pass with value check - ✓ pass with value check and nested key - ✓ pass with value check and plain key with dots - ✓ failures - ✓ failures with custom message - ✓ failures with custom message and Any matcher - ✓ failures with nested key - ✓ failures with nested key and custom message - ✓ failures with nested key and custom message with Any matcher - ✓ failures with plain key with dots - ✓ fails with wrong value - ✓ fails with wrong value and nested key - ✓ fails with wrong value and plain key with dots - ✓ not failures - ✓ not failures with nested key - ✓ not failures with plain key with dots - ✓ not failures with correct value - ✓ not failures with correct value and with nested key - ✓ not failures with correct value and with plain key with dots - - PASS Tests\Features\Expect\toHaveKeys - ✓ pass - ✓ pass with multi-dimensional arrays - ✓ failures - ✓ failures with custom message - ✓ failures with multi-dimensional arrays - ✓ failures with multi-dimensional arrays and custom message - ✓ not failures - ✓ not failures with multi-dimensional arrays - - PASS Tests\Features\Expect\toHaveLength - ✓ it passes with ('Fortaleza') - ✓ it passes with ('Sollefteå') - ✓ it passes with ('Ιεράπετρα') - ✓ it passes with (stdClass) - ✓ it passes with array - ✓ it passes with *not* - ✓ it properly fails with *not* - ✓ it fails - ✓ it fails with message - - PASS Tests\Features\Expect\toHaveLineCountLessThan - ✓ it passes - ✓ it fails - - PASS Tests\Features\Expect\toHaveMethod - ✓ class has method - ✓ opposite class has method - ✓ class has method via a parent class - ✓ class has method via a trait - ✓ failure when the class has no method - ✓ class has no method - - PASS Tests\Features\Expect\toHaveMethods - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toHaveMethodsDocumented - ✓ it passes - ✓ it fails 1 - ✓ it fails 2 - - PASS Tests\Features\Expect\toHavePrefix - ✓ missing prefix - ✓ has prefix - ✓ opposite missing prefix - ✓ opposite has prefix - - PASS Tests\Features\Expect\toHavePrivateMethodsBesides - ✓ pass - ✓ failures - - PASS Tests\Features\Expect\toHaveProperties - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toHavePropertiesDocumented - ✓ it passes - ✓ it fails 1 - ✓ it fails 2 - - PASS Tests\Features\Expect\toHaveProperty - ✓ pass - ✓ failures - ✓ failures with message - ✓ failures with message and Any matcher - ✓ not failures - - PASS Tests\Features\Expect\toHaveProtectedMethodsBesides - ✓ pass - ✓ failures - - PASS Tests\Features\Expect\toHavePublicMethodsBesides - ✓ pass - ✓ failures - - PASS Tests\Features\Expect\toHaveSameSize - ✓ failures with wrong type - ✓ pass - ✓ failures - ✓ failures with message - ✓ not failures - - PASS Tests\Features\Expect\toHaveSnakeCaseKeys - ✓ pass - ✓ failures - ✓ failures with message - ✓ not failures - - PASS Tests\Features\Expect\toHaveStudlyCaseKeys - ✓ pass - ✓ failures - ✓ failures with message - ✓ not failures - - PASS Tests\Features\Expect\toHaveSuffix - ✓ missing suffix - ✓ has suffix - ✓ opposite missing suffix - ✓ opposite has suffix - - PASS Tests\Features\Expect\toMatch - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toMatchArray - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toMatchConstraint - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toMatchObject - ✓ pass - ✓ pass with class - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toMatchSnapshot - ✓ pass - ✓ pass using pipes - ✓ pass with __toString - ✓ pass with toString - ✓ pass with dataset with ('my-datas-set-value') - ✓ within describe → pass with dataset with ('my-datas-set-value') - ✓ pass with toArray - ✓ pass with array - ✓ pass with toSnapshot - ✓ failures - ✓ failures with custom message - ✓ not failures - ✓ multiple snapshot expectations - ✓ multiple snapshot expectations with datasets with (1) - ✓ multiple snapshot expectations with datasets with ('foo') - ✓ multiple snapshot expectations with datasets with ('bar') - ✓ multiple snapshot expectations with datasets with ('baz') - ✓ describable → multiple snapshot expectations with describe - ✓ multiple snapshot expectations with repeat @ repetition 1 of 10 - ✓ multiple snapshot expectations with repeat @ repetition 2 of 10 - ✓ multiple snapshot expectations with repeat @ repetition 3 of 10 - ✓ multiple snapshot expectations with repeat @ repetition 4 of 10 - ✓ multiple snapshot expectations with repeat @ repetition 5 of 10 - ✓ multiple snapshot expectations with repeat @ repetition 6 of 10 - ✓ multiple snapshot expectations with repeat @ repetition 7 of 10 - ✓ multiple snapshot expectations with repeat @ repetition 8 of 10 - ✓ multiple snapshot expectations with repeat @ repetition 9 of 10 - ✓ multiple snapshot expectations with repeat @ repetition 10 of 10 - - PASS Tests\Features\Expect\toStartWith - ✓ pass - ✓ failures - ✓ failures with custom message - ✓ not failures - - PASS Tests\Features\Expect\toThrow - ✓ passes - ✓ failures 1 - ✓ failures 2 - ✓ failures 3 - ✓ failures 4 - ✓ failures 5 - ✓ failures 6 - ✓ failures 7 - ✓ failures 8 - ✓ failures with custom message - ✓ not failures - ✓ closure missing parameter - ✓ closure missing type-hint - ✓ it can handle a non-defined exception - ✓ it can handle a class not found Error - - PASS Tests\Features\Expect\toUseTrait - ✓ pass - ✓ failures - ✓ not failures - - PASS Tests\Features\Expect\unless - ✓ it pass - ✓ it failures - ✓ it runs with truthy - ✓ it skips with falsy - ✓ it runs with truthy closure condition - ✓ it skips with falsy closure condition - ✓ it can be used in higher order tests - - PASS Tests\Features\Expect\when - ✓ it pass - ✓ it failures - ✓ it runs with truthy - ✓ it skips with falsy - ✓ it runs with truthy closure condition - ✓ it skips with falsy closure condition - ✓ it can be used in higher order tests - - PASS Tests\Features\Fail - ✓ it may fail - ✓ it may fail with the given message - - PASS Tests\Features\Fails - ✓ it may fail - ✓ it may fail with the given message - - WARN Tests\Features\Helpers - ✓ it can set/get properties on $this - ! it gets null if property do not exist → Undefined property Tests\Features\Helpers::$wqdwqdqw - ✓ it allows to call underlying protected/private methods - ✓ it throws error if method do not exist - ✓ it can forward unexpected calls to any global function - ✓ it can use helpers from helpers file - ✓ it can use helpers from helpers directory - - PASS Tests\Features\HigherOrderTests - ✓ it proxies calls to object - ✓ it is capable doing multiple assertions - ✓ it resolves expect callables correctly - ✓ does not treat method names as callables - ✓ it can defer a method until after test setup - ✓ it can tap a method until after test setup - ✓ it can pass datasets into the expect callables with (1, 2, 3) - ✓ it can pass datasets into the defer callable with (1, 2, 3) - ✓ it can pass datasets into the tap callable with (1, 2, 3) - ✓ it can pass shared datasets into callables with (1) - ✓ it can pass shared datasets into callables with (2) - - WARN Tests\Features\Incompleted - … incompleted - … it is incompleted - … it is incompleted even with method calls like skip - … it is incompleted even with method calls like group - ✓ it is not incompleted because of expect - ✓ it is not incompleted because of assert - ✓ it is not incompleted because of test with assertions - … a "describe" group of tests → it is incompleted - - PASS Tests\Features\Issue - ✓ it may be associated with an issue #1, #2 - ✓ nested → it may be associated with an issue #1, #4, #5, #6, #3 - // an note between an the issue - - PASS Tests\Features\It - ✓ it is a test - ✓ it is a higher order message test - ✓ a "describe" group of tests → it is a test - ✓ a "describe" group of tests → it is a higher order message test - - PASS Tests\Features\Note - ✓ it may have a static note - // This is before each static note - // This is a note - // This is before each runtime note - ✓ it may have a runtime note - // This is before each static note - // This is before each runtime note - // This is a runtime note - ✓ it may have static note and runtime note - // This is before each static note - // This is a static note - // This is before each runtime note - // This is a runtime note - ✓ nested → it may have static note and runtime note - // This is before each static note - // This is describe static note - // This is a static note within describe - // This is before each runtime note - // This is a runtime note within describe - ✓ multiple notes - // This is before each static note - // This is before each runtime note - // This is a runtime note - // This is another runtime note - - NOTI Tests\Features\Notices - ! notice → This is a notice description // tests/Features/Notices.php:4 - ! a "describe" group of tests → notice → This is a notice description // tests/Features/Notices.php:11 - - PASS Tests\Features\Pr - ✓ it may be associated with an pr #1, #2 - ✓ nested → it may be associated with an pr #1, #4, #5, #6, #3 - // an note between an the pr - - PASS Tests\Features\Repeat - ✓ once - ✓ multiple times @ repetition 1 of 5 - ✓ multiple times @ repetition 2 of 5 - ✓ multiple times @ repetition 3 of 5 - ✓ multiple times @ repetition 4 of 5 - ✓ multiple times @ repetition 5 of 5 - ✓ multiple times with single dataset dataset "a" @ repetition 1 of 6 - ✓ multiple times with single dataset dataset "b" @ repetition 1 of 6 - ✓ multiple times with single dataset dataset "c" @ repetition 1 of 6 - ✓ multiple times with single dataset dataset "a" @ repetition 2 of 6 - ✓ multiple times with single dataset dataset "b" @ repetition 2 of 6 - ✓ multiple times with single dataset dataset "c" @ repetition 2 of 6 - ✓ multiple times with single dataset dataset "a" @ repetition 3 of 6 - ✓ multiple times with single dataset dataset "b" @ repetition 3 of 6 - ✓ multiple times with single dataset dataset "c" @ repetition 3 of 6 - ✓ multiple times with single dataset dataset "a" @ repetition 4 of 6 - ✓ multiple times with single dataset dataset "b" @ repetition 4 of 6 - ✓ multiple times with single dataset dataset "c" @ repetition 4 of 6 - ✓ multiple times with single dataset dataset "a" @ repetition 5 of 6 - ✓ multiple times with single dataset dataset "b" @ repetition 5 of 6 - ✓ multiple times with single dataset dataset "c" @ repetition 5 of 6 - ✓ multiple times with single dataset dataset "a" @ repetition 6 of 6 - ✓ multiple times with single dataset dataset "b" @ repetition 6 of 6 - ✓ multiple times with single dataset dataset "c" @ repetition 6 of 6 - ✓ multiple times with multiple dataset dataset "a" / (4) @ repetition 1 of 7 - ✓ multiple times with multiple dataset dataset "a" / (5) @ repetition 1 of 7 - ✓ multiple times with multiple dataset dataset "a" / (6) @ repetition 1 of 7 - ✓ multiple times with multiple dataset dataset "b" / (4) @ repetition 1 of 7 - ✓ multiple times with multiple dataset dataset "b" / (5) @ repetition 1 of 7 - ✓ multiple times with multiple dataset dataset "b" / (6) @ repetition 1 of 7 - ✓ multiple times with multiple dataset dataset "c" / (4) @ repetition 1 of 7 - ✓ multiple times with multiple dataset dataset "c" / (5) @ repetition 1 of 7 - ✓ multiple times with multiple dataset dataset "c" / (6) @ repetition 1 of 7 - ✓ multiple times with multiple dataset dataset "a" / (4) @ repetition 2 of 7 - ✓ multiple times with multiple dataset dataset "a" / (5) @ repetition 2 of 7 - ✓ multiple times with multiple dataset dataset "a" / (6) @ repetition 2 of 7 - ✓ multiple times with multiple dataset dataset "b" / (4) @ repetition 2 of 7 - ✓ multiple times with multiple dataset dataset "b" / (5) @ repetition 2 of 7 - ✓ multiple times with multiple dataset dataset "b" / (6) @ repetition 2 of 7 - ✓ multiple times with multiple dataset dataset "c" / (4) @ repetition 2 of 7 - ✓ multiple times with multiple dataset dataset "c" / (5) @ repetition 2 of 7 - ✓ multiple times with multiple dataset dataset "c" / (6) @ repetition 2 of 7 - ✓ multiple times with multiple dataset dataset "a" / (4) @ repetition 3 of 7 - ✓ multiple times with multiple dataset dataset "a" / (5) @ repetition 3 of 7 - ✓ multiple times with multiple dataset dataset "a" / (6) @ repetition 3 of 7 - ✓ multiple times with multiple dataset dataset "b" / (4) @ repetition 3 of 7 - ✓ multiple times with multiple dataset dataset "b" / (5) @ repetition 3 of 7 - ✓ multiple times with multiple dataset dataset "b" / (6) @ repetition 3 of 7 - ✓ multiple times with multiple dataset dataset "c" / (4) @ repetition 3 of 7 - ✓ multiple times with multiple dataset dataset "c" / (5) @ repetition 3 of 7 - ✓ multiple times with multiple dataset dataset "c" / (6) @ repetition 3 of 7 - ✓ multiple times with multiple dataset dataset "a" / (4) @ repetition 4 of 7 - ✓ multiple times with multiple dataset dataset "a" / (5) @ repetition 4 of 7 - ✓ multiple times with multiple dataset dataset "a" / (6) @ repetition 4 of 7 - ✓ multiple times with multiple dataset dataset "b" / (4) @ repetition 4 of 7 - ✓ multiple times with multiple dataset dataset "b" / (5) @ repetition 4 of 7 - ✓ multiple times with multiple dataset dataset "b" / (6) @ repetition 4 of 7 - ✓ multiple times with multiple dataset dataset "c" / (4) @ repetition 4 of 7 - ✓ multiple times with multiple dataset dataset "c" / (5) @ repetition 4 of 7 - ✓ multiple times with multiple dataset dataset "c" / (6) @ repetition 4 of 7 - ✓ multiple times with multiple dataset dataset "a" / (4) @ repetition 5 of 7 - ✓ multiple times with multiple dataset dataset "a" / (5) @ repetition 5 of 7 - ✓ multiple times with multiple dataset dataset "a" / (6) @ repetition 5 of 7 - ✓ multiple times with multiple dataset dataset "b" / (4) @ repetition 5 of 7 - ✓ multiple times with multiple dataset dataset "b" / (5) @ repetition 5 of 7 - ✓ multiple times with multiple dataset dataset "b" / (6) @ repetition 5 of 7 - ✓ multiple times with multiple dataset dataset "c" / (4) @ repetition 5 of 7 - ✓ multiple times with multiple dataset dataset "c" / (5) @ repetition 5 of 7 - ✓ multiple times with multiple dataset dataset "c" / (6) @ repetition 5 of 7 - ✓ multiple times with multiple dataset dataset "a" / (4) @ repetition 6 of 7 - ✓ multiple times with multiple dataset dataset "a" / (5) @ repetition 6 of 7 - ✓ multiple times with multiple dataset dataset "a" / (6) @ repetition 6 of 7 - ✓ multiple times with multiple dataset dataset "b" / (4) @ repetition 6 of 7 - ✓ multiple times with multiple dataset dataset "b" / (5) @ repetition 6 of 7 - ✓ multiple times with multiple dataset dataset "b" / (6) @ repetition 6 of 7 - ✓ multiple times with multiple dataset dataset "c" / (4) @ repetition 6 of 7 - ✓ multiple times with multiple dataset dataset "c" / (5) @ repetition 6 of 7 - ✓ multiple times with multiple dataset dataset "c" / (6) @ repetition 6 of 7 - ✓ multiple times with multiple dataset dataset "a" / (4) @ repetition 7 of 7 - ✓ multiple times with multiple dataset dataset "a" / (5) @ repetition 7 of 7 - ✓ multiple times with multiple dataset dataset "a" / (6) @ repetition 7 of 7 - ✓ multiple times with multiple dataset dataset "b" / (4) @ repetition 7 of 7 - ✓ multiple times with multiple dataset dataset "b" / (5) @ repetition 7 of 7 - ✓ multiple times with multiple dataset dataset "b" / (6) @ repetition 7 of 7 - ✓ multiple times with multiple dataset dataset "c" / (4) @ repetition 7 of 7 - ✓ multiple times with multiple dataset dataset "c" / (5) @ repetition 7 of 7 - ✓ multiple times with multiple dataset dataset "c" / (6) @ repetition 7 of 7 - ✓ multiple times with iterator @ repetition 1 of 2 - ✓ multiple times with iterator @ repetition 2 of 2 - ✓ multiple times with repeat iterator with single dataset ('a') @ repetition 1 of 2 - ✓ multiple times with repeat iterator with single dataset ('b') @ repetition 1 of 2 - ✓ multiple times with repeat iterator with single dataset ('c') @ repetition 1 of 2 - ✓ multiple times with repeat iterator with single dataset ('a') @ repetition 2 of 2 - ✓ multiple times with repeat iterator with single dataset ('b') @ repetition 2 of 2 - ✓ multiple times with repeat iterator with single dataset ('c') @ repetition 2 of 2 - ✓ multiple times with repeat iterator with multiple dataset ('a') / ('d') @ repetition 1 of 2 - ✓ multiple times with repeat iterator with multiple dataset ('a') / ('e') @ repetition 1 of 2 - ✓ multiple times with repeat iterator with multiple dataset ('a') / ('f') @ repetition 1 of 2 - ✓ multiple times with repeat iterator with multiple dataset ('b') / ('d') @ repetition 1 of 2 - ✓ multiple times with repeat iterator with multiple dataset ('b') / ('e') @ repetition 1 of 2 - ✓ multiple times with repeat iterator with multiple dataset ('b') / ('f') @ repetition 1 of 2 - ✓ multiple times with repeat iterator with multiple dataset ('c') / ('d') @ repetition 1 of 2 - ✓ multiple times with repeat iterator with multiple dataset ('c') / ('e') @ repetition 1 of 2 - ✓ multiple times with repeat iterator with multiple dataset ('c') / ('f') @ repetition 1 of 2 - ✓ multiple times with repeat iterator with multiple dataset ('a') / ('d') @ repetition 2 of 2 - ✓ multiple times with repeat iterator with multiple dataset ('a') / ('e') @ repetition 2 of 2 - ✓ multiple times with repeat iterator with multiple dataset ('a') / ('f') @ repetition 2 of 2 - ✓ multiple times with repeat iterator with multiple dataset ('b') / ('d') @ repetition 2 of 2 - ✓ multiple times with repeat iterator with multiple dataset ('b') / ('e') @ repetition 2 of 2 - ✓ multiple times with repeat iterator with multiple dataset ('b') / ('f') @ repetition 2 of 2 - ✓ multiple times with repeat iterator with multiple dataset ('c') / ('d') @ repetition 2 of 2 - ✓ multiple times with repeat iterator with multiple dataset ('c') / ('e') @ repetition 2 of 2 - ✓ multiple times with repeat iterator with multiple dataset ('c') / ('f') @ repetition 2 of 2 - - PASS Tests\Features\ScopedDatasets\Directory\NestedDirectory1\TestFileInNestedDirectoryWithDatasetsFile - ✓ uses dataset with (1) - ✓ uses dataset with (2) - ✓ uses dataset with (3) - ✓ uses dataset with (4) - ✓ uses dataset with (5) - ✓ uses dataset with ('ScopedDatasets/NestedDirector…ts.php') - ✓ the right dataset is taken - - PASS Tests\Features\ScopedDatasets\Directory\NestedDirectory2\TestFileInNestedDirectory - ✓ uses dataset with (1) - ✓ uses dataset with (2) - ✓ uses dataset with (3) - ✓ uses dataset with (4) - ✓ uses dataset with (5) - ✓ uses dataset with ('ScopedDatasets/Datasets/Scoped.php') - ✓ the right dataset is taken - - PASS Tests\Features\ScopedDatasets\Directory\TestFileWithLocallyDefinedDataset - ✓ uses dataset with (1) - ✓ uses dataset with (2) - ✓ uses dataset with (3) - ✓ uses dataset with (4) - ✓ uses dataset with (5) - ✓ uses dataset with ('ScopedDatasets/ScopedDatasets.php') - ✓ the right dataset is taken - - PASS Tests\Features\ScopedDatasets\Directory\TestFileWithScopedDataset - ✓ uses dataset with (1) - ✓ uses dataset with (2) - ✓ uses dataset with (3) - ✓ uses dataset with (4) - ✓ uses dataset with (5) - ✓ uses dataset with ('ScopedDatasets/Datasets/Scoped.php') - ✓ the right dataset is taken - - PASS Tests\Features\ScopedDatasets\TestFileOutOfScope - ✓ uses dataset with (1) - ✓ uses dataset with (2) - ✓ the right dataset is taken - ✓ it can see datasets defined in Pest.php file with ('A') - ✓ it can see datasets defined in Pest.php file with ('B') - ✓ Pest.php dataset is taken - - WARN Tests\Features\Skip - ✓ it do not skips - - it skips with truthy → 1 - - it skips with truthy condition by default - - it skips with message → skipped because bar - - it skips with truthy closure condition - ✓ it do not skips with falsy closure condition - - it skips with condition and message → skipped because foo - - it skips when skip after assertion - - it can use something in the test case as a condition → This test was skipped - - it can user higher order callables and skip - - WARN Tests\Features\SkipOnPhp - ✓ it can run on php version - ✓ it can run on specific php version - - it can skip on php versions depending on constraint → This test is skipped on PHP [>=7.4.0]. - - PASS Tests\Features\Test - ✓ a test - ✓ higher order message test - - PASS Tests\Features\ThrowsNoExceptions - ✓ it allows access to the underlying expectNotToPerformAssertions method - ✓ it allows performing no expectations without being risky - ✓ a "describe" group of tests → it allows performing no expectations without being risky - - PASS Tests\Features\Ticket - ✓ it may be associated with an ticket #1, #2 - ✓ nested → it may be associated with an ticket #1, #4, #5, #6, #3 - // an note between an the ticket - - PASS Tests\Features\Todo - 7 todos - ↓ something todo later - ↓ something todo later chained - ↓ something todo later chained and with function body - ✓ it does something within a file with a todo - ↓ it may have an associated assignee [@nunomaduro] - ↓ it may have an associated issue #1 - ↓ it may have an associated PR #1 - ↓ it may have an associated note - // a note - - WARN Tests\Features\Warnings - ! warning → Undefined property: P\Tests\Features\Warnings::$fooqwdfwqdfqw - ! user warning → This is a warning description - ! a "describe" group of tests → user warning → This is a warning description - - WARN Tests\Fixtures\CollisionTest - - error - - success - - PASS Tests\Fixtures\DirectoryWithTests\ExampleTest - ✓ it example 1 - - PASS Tests\Fixtures\ExampleTest - ✓ it example 2 - - WARN Tests\Fixtures\UnexpectedOutput - - output - - PASS Tests\Helpers\TestInHelpers - ✓ it executes tests in the Helpers directory - - PASS Tests\Hooks\AfterEachTest - ✓ global afterEach execution order - - PASS Tests\Hooks\BeforeEachTest - ✓ global beforeEach execution order - - PASS Tests\Overrides\VersionsTest - ✓ versions with dataset "Runner/Filter/NameFilterIterator.php" - ✓ versions with dataset "Runner/ResultCache/DefaultResultCache.php" - ✓ versions with dataset "Runner/TestSuiteLoader.php" - ✓ versions with dataset "TextUI/Command/Commands/WarmCodeCoverageCacheCommand.php" - ✓ versions with dataset "TextUI/Output/Default/ProgressPrinter/Subscriber/TestSkippedSubscriber.php" - ✓ versions with dataset "TextUI/TestSuiteFilterProcessor.php" - ✓ versions with dataset "Event/Value/ThrowableBuilder.php" - ✓ versions with dataset "Logging/JUnit/JunitXmlLogger.php" - - PASS Tests\PHPUnit\CustomAffixes\InvalidTestName - ✓ it runs file names like @#$%^&()-_=+.php - - PASS Tests\PHPUnit\CustomAffixes\ATestWithSpaces - ✓ it runs file names like A Test With Spaces.php - - PASS Tests\PHPUnit\CustomAffixes\AdditionalFileExtension - ✓ it runs file names like AdditionalFileExtension.spec.php - - PASS Tests\PHPUnit\CustomAffixes\FolderWithAn\ExampleTest - ✓ custom traits can be used - ✓ trait applied in this file - - PASS Tests\PHPUnit\CustomAffixes\ManyExtensions - ✓ it runs file names like ManyExtensions.class.test.php - - PASS Tests\PHPUnit\CustomAffixes\TestCaseWithQuotes - ✓ it runs file names like Test 'Case' With Quotes.php - - PASS Tests\PHPUnit\CustomAffixes\kebabcasespec - ✓ it runs file names like kebab-case-spec.php - - PASS Tests\PHPUnit\CustomAffixes\snakecasespec - ✓ it runs file names like snake_case_spec.php - - PASS Tests\CustomTestCase\ChildTest - ✓ override method - - PASS Tests\CustomTestCase\ExecutedTest - ✓ that gets executed - - PASS Tests\CustomTestCase\ParentTest - ✓ override method - - PASS Tests\PHPUnit\CustomTestCase\UsesPerDirectory - ✓ closure was bound to CustomTestCase - - PASS Tests\PHPUnit\CustomTestCaseInSubFolders\SubFolder\SubFolder\UsesPerSubDirectory - ✓ closure was bound to CustomTestCase - - PASS Tests\PHPUnit\CustomTestCaseInSubFolders\SubFolder2\UsesPerFile - ✓ custom traits can be used - ✓ trait applied in this file - - PASS Tests\PHPUnit\GlobPatternTests\SubFolder\InnerFolder\UsesPerDirectoryAsPattern - ✓ closure was bound to CustomTestCase - - PASS Tests\PHPUnit\GlobPatternTests\SubFolder2\UsesPerFileAsPattern - ✓ closure was bound to CustomTestCase - - PASS Tests\Playground - ✓ basic - - PASS Tests\Plugins\Traits - ✓ it allows global uses - ✓ it allows multiple global uses registered in the same path - - PASS Tests\Unit\Configuration\In - ✓ it proxies to uses call - - PASS Tests\Unit\Configuration\Theme - ✓ it creates a theme instance - - PASS Tests\Unit\Console\Help - ✓ it outputs the help information when --help is used - - PASS Tests\Unit\DatasetsTests - ✓ it show only the names of named datasets in their description - ✓ it show the actual dataset of non-named datasets in their description - ✓ it show only the names of multiple named datasets in their description - ✓ it show the actual dataset of multiple non-named datasets in their description - ✓ it show the correct description for mixed named and not-named datasets - ✓ it shows the correct description for long texts with newlines - ✓ it shows the correct description for arrays with many elements - ✓ it shows the correct description of datasets with html - - PASS Tests\Unit\Expectations\OppositeExpectation - ✓ it throw expectation failed exception with string argument - ✓ it throw expectation failed exception with array argument - - PASS Tests\Unit\Overrides\ThrowableBuilder - ✓ collision editor can be added to the stack trace - - PASS Tests\Unit\Plugins\Concerns\HandleArguments - ✓ method hasArgument with ('--long-argument', true) - ✓ method hasArgument with ('-a', true) - ✓ method hasArgument with ('--with-equal-sign', true) - ✓ method hasArgument with ('someValue', true) - ✓ method hasArgument with ('--a', false) - ✓ method hasArgument with ('--undefined-argument', false) - - PASS Tests\Unit\Plugins\Environment - ✓ environment is set to CI when --ci option is used - ✓ environment is set to Local when --ci option is not used - - PASS Tests\Unit\Plugins\Retry - ✓ it orders by defects and stop on defects if when --retry is used - - PASS Tests\Unit\Support\Backtrace - ✓ it gets file name from called file - - PASS Tests\Unit\Support\Container - ✓ it exists - ✓ it gets an instance - ✓ autowire - ✓ it creates an instance and resolves parameters - ✓ it creates an instance and resolves also sub parameters - ✓ it can resolve builtin value types - ✓ it cannot resolve a parameter without type - - PASS Tests\Unit\Support\DatasetInfo - ✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Datase…rs.php', true) - ✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Datasets.php', false) - ✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Featur…rs.php', true) - ✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Featur…rs.php', false) - ✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Featur…ts.php', false) - ✓ it can check if dataset is defined inside a Datasets.php file with ('/var/www/project/tests/Datase…rs.php', false) - ✓ it can check if dataset is defined inside a Datasets.php file with ('/var/www/project/tests/Datasets.php', true) - ✓ it can check if dataset is defined inside a Datasets.php file with ('/var/www/project/tests/Featur…rs.php', false) #1 - ✓ it can check if dataset is defined inside a Datasets.php file with ('/var/www/project/tests/Featur…rs.php', false) #2 - ✓ it can check if dataset is defined inside a Datasets.php file with ('/var/www/project/tests/Featur…ts.php', true) - ✓ it computes the dataset scope with ('/var/www/project/tests/Datase…rs.php', '/var/www/project/tests') - ✓ it computes the dataset scope with ('/var/www/project/tests/Datasets.php', '/var/www/project/tests') - ✓ it computes the dataset scope with ('/var/www/project/tests/Featur…rs.php', '/var/www/project/tests/Features') - ✓ it computes the dataset scope with ('/var/www/project/tests/Featur…rs.php', '/var/www/project/tests/Featur…rs.php') #1 - ✓ it computes the dataset scope with ('/var/www/project/tests/Featur…ts.php', '/var/www/project/tests/Features') - ✓ it computes the dataset scope with ('/var/www/project/tests/Featur…rs.php', '/var/www/project/tests/Featur…ollers') - ✓ it computes the dataset scope with ('/var/www/project/tests/Featur…rs.php', '/var/www/project/tests/Featur…rs.php') #2 - ✓ it computes the dataset scope with ('/var/www/project/tests/Featur…ts.php', '/var/www/project/tests/Featur…ollers') - - PASS Tests\Unit\Support\ExceptionTrace - ✓ it ensures the given closures reports the correct class name - ✓ it ensures the given closures reports the correct class name and suggests the [pest()] function - - PASS Tests\Unit\Support\HigherOrderMessage - ✓ undefined method exceptions - - PASS Tests\Unit\Support\Reflection - ✓ it gets file name from closure - ✓ it gets property values - ✓ it gets properties from classes - ✓ it gets methods from classes - - PASS Tests\Unit\Support\Str - ✓ it evaluates the code with ('version()', '__pest_evaluable_version__') - ✓ it evaluates the code with ('version__ ', '__pest_evaluable_version_____') - ✓ it evaluates the code with ('version\', '__pest_evaluable_version_') - - PASS Tests\Unit\TestName - ✓ it may start with P with ('P\Tests\BarTest', 'Tests\BarTest') - ✓ it may start with P with ('P\Packages\Foo', 'Packages\Foo') - ✓ it may start with P with ('P\PPPackages\Foo', 'PPPackages\Foo') - ✓ it may start with P with ('PPPackages\Foo', 'PPPackages\Foo') #1 - ✓ it may start with P with ('PPPackages\Foo', 'PPPackages\Foo') #2 - ✓ test description - ✓ test_description - ✓ ふ+が+ - ✓ ほげ - ✓ 卜竹弓一十山 - ✓ アゴデヸ - ✓ !p8VrB - ✓ &xe6VeKWF#n4 - ✓ %%HurHUnw7zM! - ✓ rundeliekend - ✓ g%%c!Jt9$fy#Kf - ✓ NRs*Gz2@hmB$W$BPD%%b2U%3P%z%apnwSX - ✓ ÀĤ{¼÷ - ✓ ìèéàòç - ✓ زهراء المعادي - ✓ الجبيهه - ✓ الظهران - ✓ Каролин - ✓ অ্যান্টার্কটিকা - ✓ Frýdek-Místek" - ✓ Allingåbro& - ✓ Κεντροαφρικανική Δημοκρατία - ✓ آذربایجان غربی - ✓ זימבבואה - ✓ Belišće - ✓ Գվատեմալա - ✓ パプアニューギニア - ✓ 富山県 - ✓ Қарағанды - ✓ Қостанай - ✓ 안양시 동안구 - ✓ Itālija - ✓ Honningsvåg - ✓ Águeda - ✓ Râșcani - ✓ Năsăud - ✓ Орехово-Зуево - ✓ Čereňany - ✓ Moravče - ✓ Šentjernej - ✓ Врање - ✓ Крушевац - ✓ Åkersberga - ✓ บอสเนียและเฮอร์เซโกวีนา - ✓ Birleşik Arap Emirlikleri - ✓ Німеччина - ✓ Nam Định - ✓ 呼和浩特 - ✓ test /** with comment */ should do - - PASS Tests\Unit\TestSuite - ✓ it does not allow to add the same test description twice - ✓ it alerts users about tests with arguments but no input - ✓ it can return an array of all test suite filenames - - PASS Tests\Visual\BeforeEachTestName - ✓ description - ✓ latest description - - PASS Tests\Visual\Collision - ✓ collision with (['']) - - PASS Tests\Visual\Help - ✓ visual snapshot of help command output - - WARN Tests\Visual\JUnit - ✓ junit output - - junit with parallel → Not working yet - - PASS Tests\Visual\Parallel - ✓ parallel - ✓ a parallel test can extend another test with same name - - PASS Tests\Visual\SingleTestOrDirectory - ✓ allows to run a single test - ✓ allows to run a directory - ✓ it disable decorating printer when colors is set to never - - WARN Tests\Visual\Success - - visual snapshot of test suite on success - - WARN Tests\Visual\TeamCity - - visual snapshot of team city with ('Failure.php') - - visual snapshot of team city with ('SuccessOnly.php') - - PASS Tests\Visual\Todo - ✓ todos - ✓ todos in parallel - ✓ todo - ✓ todo in parallel - - WARN Tests\Visual\Version - - visual snapshot of help command output - - Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 17 todos, 24 skipped, 1088 passed (2648 assertions) \ No newline at end of file diff --git a/tests/Unit/TestSuite.php b/tests/Unit/TestSuite.php index c718ad0d..7f2077dd 100644 --- a/tests/Unit/TestSuite.php +++ b/tests/Unit/TestSuite.php @@ -2,6 +2,7 @@ use Pest\Exceptions\DatasetMissing; use Pest\Exceptions\TestAlreadyExist; +use Pest\Exceptions\TestClosureMustNotBeStatic; use Pest\Factories\TestCaseMethodFactory; use Pest\TestSuite; @@ -17,6 +18,16 @@ it('does not allow to add the same test description twice', function () { sprintf('A test with the description `%s` already exists in the filename `%s`.', 'bar', 'foo'), ); +it('does not allow static closures', function () { + $testSuite = new TestSuite(getcwd(), 'tests'); + $method = new TestCaseMethodFactory('foo', 'bar', static function () {}); + + $testSuite->tests->set($method); +})->throws( + TestClosureMustNotBeStatic::class, + 'Test closure must not be static. Please remove the `static` keyword from the `bar` method in `foo`.', +); + it('alerts users about tests with arguments but no input', function () { $testSuite = new TestSuite(getcwd(), 'tests'); diff --git a/tests/Visual/Parallel.php b/tests/Visual/Parallel.php index aad9adcf..03fd5937 100644 --- a/tests/Visual/Parallel.php +++ b/tests/Visual/Parallel.php @@ -16,7 +16,7 @@ $run = function () { test('parallel', function () use ($run) { expect($run('--exclude-group=integration')) - ->toContain('Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 17 todos, 19 skipped, 1074 passed (2616 assertions)') + ->toContain('Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 17 todos, 19 skipped, 1075 passed (2617 assertions)') ->toContain('Parallel: 3 processes'); })->skipOnWindows();