mirror of
https://github.com/pestphp/pest.git
synced 2026-03-06 07:47:22 +01:00
Uses Collision ^7.0
This commit is contained in:
3
TODO.md
3
TODO.md
@ -2,3 +2,6 @@
|
||||
2. Support for `default` printer.
|
||||
3. Support for `TeamCity` printer.
|
||||
4. Support for `JUnit` log.
|
||||
5. Plugins
|
||||
6. Parallel
|
||||
7. Collision's todo...
|
||||
|
||||
3
bin/pest
3
bin/pest
@ -11,6 +11,9 @@ use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
(static function () {
|
||||
// Ensures Collision's Printer is registered.
|
||||
$_SERVER['COLLISION_PRINTER'] = 'DefaultPrinter';
|
||||
|
||||
// Used when Pest is required using composer.
|
||||
$vendorPath = dirname(__DIR__, 4) . '/vendor/autoload.php';
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
],
|
||||
"require": {
|
||||
"php": "^8.1.0",
|
||||
"nunomaduro/collision": "^6.3",
|
||||
"nunomaduro/collision": "dev-next",
|
||||
"pestphp/pest-plugin": "^1.0.0",
|
||||
"phpunit/phpunit": "10.0.x-dev"
|
||||
},
|
||||
@ -86,6 +86,7 @@
|
||||
"Pest\\Plugins\\Init",
|
||||
"Pest\\Plugins\\Environment",
|
||||
"Pest\\Plugins\\Memory",
|
||||
"Pest\\Plugins\\Printer",
|
||||
"Pest\\Plugins\\Retry",
|
||||
"Pest\\Plugins\\Version"
|
||||
]
|
||||
|
||||
@ -44,14 +44,13 @@ use function basename;
|
||||
use function class_exists;
|
||||
use function get_declared_classes;
|
||||
|
||||
use Pest\Contracts\HasPrintableTestCaseName;
|
||||
use Pest\TestCases\IgnorableTestCase;
|
||||
use Pest\TestSuite;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
|
||||
use function stripos;
|
||||
use function strlen;
|
||||
use function substr;
|
||||
|
||||
/**
|
||||
@ -83,7 +82,6 @@ final class TestSuiteLoader
|
||||
{
|
||||
$suiteClassName = $this->classNameFromFileName($suiteClassFile);
|
||||
|
||||
if (!class_exists($suiteClassName, false)) {
|
||||
(static function () use ($suiteClassFile) {
|
||||
include_once $suiteClassFile;
|
||||
|
||||
@ -105,14 +103,22 @@ final class TestSuiteLoader
|
||||
if (empty(self::$loadedClasses)) {
|
||||
return $this->exceptionFor($suiteClassName, $suiteClassFile);
|
||||
}
|
||||
}
|
||||
|
||||
if (!class_exists($suiteClassName, false)) {
|
||||
// this block will handle namespaced classes
|
||||
$offset = 0 - strlen($suiteClassName);
|
||||
$testCaseFound = false;
|
||||
|
||||
foreach (self::$loadedClasses as $loadedClass) {
|
||||
if (stripos(substr($loadedClass, $offset - 1), '\\' . $suiteClassName) === 0) {
|
||||
if (is_subclass_of($loadedClass, HasPrintableTestCaseName::class)) {
|
||||
$suiteClassName = $loadedClass;
|
||||
|
||||
$testCaseFound = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$testCaseFound) {
|
||||
foreach (self::$loadedClasses as $loadedClass) {
|
||||
if (is_subclass_of($loadedClass, TestCase::class)) {
|
||||
$suiteClassName = $loadedClass;
|
||||
|
||||
break;
|
||||
|
||||
17
phpunit.xml
17
phpunit.xml
@ -1,8 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.0/phpunit.xsd"
|
||||
backupGlobals="false"
|
||||
beStrictAboutTestsThatDoNotTestAnything="true"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
bootstrap="vendor/autoload.php"
|
||||
cacheResult="false"
|
||||
colors="true"
|
||||
failOnRisky="true"
|
||||
failOnWarning="true"
|
||||
processIsolation="false"
|
||||
stopOnError="false"
|
||||
stopOnFailure="false"
|
||||
cacheDirectory=".phpunit.cache"
|
||||
backupStaticProperties="false"
|
||||
displayDetailsOnIncompleteTests="true"
|
||||
displayDetailsOnSkippedTests="true"
|
||||
displayDetailsOnTestsThatTriggerDeprecations="true"
|
||||
displayDetailsOnTestsThatTriggerErrors="true"
|
||||
displayDetailsOnTestsThatTriggerNotices="true"
|
||||
displayDetailsOnTestsThatTriggerWarnings="true"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="default">
|
||||
|
||||
@ -9,13 +9,21 @@ use Pest\Support\ChainableClosure;
|
||||
use Pest\Support\ExceptionTrace;
|
||||
use Pest\Support\Reflection;
|
||||
use Pest\TestSuite;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @mixin TestCase
|
||||
*/
|
||||
trait Testable
|
||||
{
|
||||
/**
|
||||
* Test method description.
|
||||
*/
|
||||
private static string $__description;
|
||||
|
||||
/**
|
||||
* The Test Case "test" closure.
|
||||
*/
|
||||
@ -118,14 +126,6 @@ trait Testable
|
||||
: $hook;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Test Case filename.
|
||||
*/
|
||||
public static function __getFilename(): string
|
||||
{
|
||||
return self::$__filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called before the first test of this Test Case is run.
|
||||
*/
|
||||
@ -211,6 +211,13 @@ trait Testable
|
||||
*/
|
||||
private function __resolveTestArguments(array $arguments): array
|
||||
{
|
||||
$method = TestSuite::getInstance()->tests->get(self::$__filename)->getMethod($this->name());
|
||||
if ($this->dataName()) {
|
||||
self::$__description = $method->description . ' with ' . $this->dataName();
|
||||
} else {
|
||||
self::$__description = $method->description;
|
||||
}
|
||||
|
||||
if (count($arguments) !== 1) {
|
||||
return $arguments;
|
||||
}
|
||||
@ -246,8 +253,16 @@ trait Testable
|
||||
/**
|
||||
* Gets the Test Case name that should be used by printers.
|
||||
*/
|
||||
public function getPrintableTestCaseName(): string
|
||||
public static function getPrintableTestCaseName(): string
|
||||
{
|
||||
return ltrim(self::class, 'P\\');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Test Case name that should be used by printers.
|
||||
*/
|
||||
public static function getPrintableTestCaseMethodName(): string
|
||||
{
|
||||
return self::$__description;
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,9 +12,9 @@ interface HandlesArguments
|
||||
/**
|
||||
* Adds arguments before of the Test Suite execution.
|
||||
*
|
||||
* @param array<int, string> $argv
|
||||
* @param array<int, string> $arguments
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function handleArguments(array $argv): array;
|
||||
public function handleArguments(array $arguments): array;
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ final class ShouldNotHappen extends RuntimeException
|
||||
{
|
||||
$message = $exception->getMessage();
|
||||
|
||||
parent::__construct(sprintf(<<<EOF
|
||||
parent::__construct(sprintf(<<<'EOF'
|
||||
|
||||
This should not happen - please create an new issue here: https://github.com/pestphp/pest.
|
||||
|
||||
|
||||
@ -186,6 +186,7 @@ final class Expectation
|
||||
foreach ($values as $key => $item) {
|
||||
if ($callbacks[$key] instanceof Closure) {
|
||||
call_user_func($callbacks[$key], new self($item), new self($keys[$key]));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -220,6 +221,7 @@ final class Expectation
|
||||
|
||||
if (is_callable($callback)) {
|
||||
$callback(new self($this->value));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@ -121,7 +121,17 @@ final class TestCaseFactory
|
||||
$filename = str_replace('\\\\', '\\', addslashes((string) realpath($filename)));
|
||||
$rootPath = TestSuite::getInstance()->rootPath;
|
||||
$relativePath = str_replace($rootPath . DIRECTORY_SEPARATOR, '', $filename);
|
||||
$relativePath = dirname(ucfirst($relativePath)) . DIRECTORY_SEPARATOR . basename($relativePath, '.php');
|
||||
|
||||
$basename = basename($relativePath, '.php');
|
||||
|
||||
$dotPos = strpos($basename, '.');
|
||||
|
||||
if ($dotPos !== false) {
|
||||
$basename = substr($basename, 0, $dotPos);
|
||||
}
|
||||
|
||||
$relativePath = dirname(ucfirst($relativePath)) . DIRECTORY_SEPARATOR . $basename;
|
||||
|
||||
$relativePath = str_replace(DIRECTORY_SEPARATOR, '\\', $relativePath);
|
||||
|
||||
// Strip out any %-encoded octets.
|
||||
@ -132,6 +142,7 @@ final class TestCaseFactory
|
||||
$relativePath = (string) preg_replace('/[^A-Za-z0-9\\\\]/', '', $relativePath);
|
||||
|
||||
$classFQN = 'P\\' . $relativePath;
|
||||
|
||||
if (class_exists($classFQN)) {
|
||||
return;
|
||||
}
|
||||
@ -174,17 +185,16 @@ final class TestCaseFactory
|
||||
));
|
||||
|
||||
$classAttributesCode = implode('', array_map(
|
||||
static fn (string $attribute) => sprintf("\n %s", $attribute),
|
||||
static fn (string $attribute) => sprintf("\n%s", $attribute),
|
||||
array_unique($classAttributes),
|
||||
));
|
||||
|
||||
try {
|
||||
eval("
|
||||
$classCode = <<<PHP
|
||||
namespace $namespace;
|
||||
|
||||
use Pest\Repositories\DatasetsRepository as __PestDatasets;
|
||||
use Pest\TestSuite as __PestTestSuite;
|
||||
|
||||
$classAttributesCode
|
||||
#[\AllowDynamicProperties]
|
||||
final class $className extends $baseClass implements $hasPrintableTestCaseClassFQN {
|
||||
@ -194,7 +204,9 @@ final class TestCaseFactory
|
||||
|
||||
$methodsCode
|
||||
}
|
||||
");
|
||||
PHP;
|
||||
|
||||
eval($classCode);
|
||||
} catch (ParseError $caught) {
|
||||
throw new RuntimeException(sprintf('Unable to create test case for test file at %s', $filename), 1, $caught);
|
||||
}
|
||||
|
||||
@ -91,7 +91,6 @@ final class TestCaseMethodFactory
|
||||
|
||||
return function () use ($testCase, $method, $closure): mixed { // @phpstan-ignore-line
|
||||
/* @var TestCase $this */
|
||||
|
||||
$testCase->proxies->proxy($this);
|
||||
$method->proxies->proxy($this);
|
||||
|
||||
@ -155,21 +154,22 @@ final class TestCaseMethodFactory
|
||||
static fn ($attribute) => sprintf("\n %s", $attribute), $attributes,
|
||||
));
|
||||
|
||||
return <<<EOF
|
||||
return <<<PHP
|
||||
|
||||
/**$annotations
|
||||
*/
|
||||
$attributes
|
||||
public function $methodName()
|
||||
{
|
||||
\$test = \Pest\TestSuite::getInstance()->tests->get(self::\$__filename)->getMethod(\$this->name())->getClosure(\$this);
|
||||
|
||||
return \$this->__runTest(
|
||||
\$this->__test,
|
||||
\$test,
|
||||
...func_get_args(),
|
||||
);
|
||||
}
|
||||
|
||||
$datasetsCode
|
||||
EOF;
|
||||
PHP;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -19,6 +19,20 @@ trait HandleArguments
|
||||
return in_array($argument, $arguments, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given argument and value to the list of arguments.
|
||||
*
|
||||
* @param array<int, string> $arguments
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function pushArgument(string $argument, array $arguments): array
|
||||
{
|
||||
$arguments[] = $argument;
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops the given argument from the arguments.
|
||||
*
|
||||
|
||||
27
src/Plugins/Printer.php
Normal file
27
src/Plugins/Printer.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Pest\Plugins;
|
||||
|
||||
use Pest\Contracts\Plugins\HandlesArguments;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class Printer implements HandlesArguments
|
||||
{
|
||||
use Concerns\HandleArguments;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function handleArguments(array $arguments): array
|
||||
{
|
||||
if (! array_key_exists('COLLISION_PRINTER', $_SERVER)) {
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
return $this->pushArgument('--no-output', $arguments);
|
||||
}
|
||||
}
|
||||
@ -57,6 +57,11 @@ final class DatasetsRepository
|
||||
self::$withs[$filename . '>>>' . $description] = $with;
|
||||
}
|
||||
|
||||
public static function has(string $filename, string $description): bool
|
||||
{
|
||||
return array_key_exists($filename . '>>>' . $description, self::$withs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Closure|iterable<int|string, mixed>|never
|
||||
*
|
||||
@ -107,7 +112,7 @@ final class DatasetsRepository
|
||||
$values = array_merge($values, $datasetCombinationElement['values']);
|
||||
}
|
||||
|
||||
$datasetDescriptions[] = $description . ' with ' . implode(' / ', $partialDescriptions);
|
||||
$datasetDescriptions[] = implode(' / ', $partialDescriptions);
|
||||
$datasetValues[] = $values;
|
||||
}
|
||||
|
||||
|
||||
@ -56,7 +56,7 @@ final class ExceptionTrace
|
||||
|
||||
$cleanedTrace = [];
|
||||
foreach ($trace as $item) {
|
||||
if (key_exists('file', $item) && mb_strpos($item['file'], 'vendor/pestphp/pest/') > 0) {
|
||||
if (array_key_exists('file', $item) && mb_strpos($item['file'], 'vendor/pestphp/pest/') > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@ -13,6 +13,7 @@ abstract class Printer implements \PHPUnit\Util\Printer
|
||||
private $stream;
|
||||
|
||||
private bool $isPhpStream;
|
||||
|
||||
private bool $isOpen;
|
||||
|
||||
private function __construct(string $out)
|
||||
|
||||
@ -12,11 +12,4 @@ use PHPUnit\Framework\TestCase;
|
||||
*/
|
||||
class IgnorableTestCase extends TestCase
|
||||
{
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function fake(): void
|
||||
{
|
||||
self::markTestIncomplete();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,4 @@
|
||||
|
||||
PASS Tests\CustomTestCase\ExecutedTest
|
||||
✓ that gets executed
|
||||
|
||||
PASS Tests\Features\AfterAll
|
||||
✓ deletes file after all
|
||||
|
||||
@ -23,6 +20,15 @@
|
||||
✓ 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 removes duplicated attributes
|
||||
✓ it guesses if the given argument is a class or function
|
||||
✓ it appends CoversNothing to method attributes
|
||||
✓ it does not append CoversNothing to other methods
|
||||
✓ it throws exception if no class nor method has been found
|
||||
|
||||
PASS Tests\Features\Datasets
|
||||
✓ it throws exception if dataset does not exist
|
||||
✓ it throws exception if dataset already exist
|
||||
@ -111,16 +117,35 @@
|
||||
✓ 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 (...))
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
PASS Tests\Features\Expect\HigherOrder\methods
|
||||
✓ it can access methods
|
||||
@ -133,6 +158,8 @@
|
||||
✓ 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
|
||||
@ -140,6 +167,7 @@
|
||||
✓ 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
|
||||
@ -161,6 +189,7 @@
|
||||
✓ 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
|
||||
@ -186,15 +215,16 @@
|
||||
PASS Tests\Features\Expect\not
|
||||
✓ not property calls
|
||||
|
||||
PASS Tests\Features\Expect\pipe
|
||||
PASS Tests\Features\Expect\pipes
|
||||
✓ pipe is applied and can stop pipeline
|
||||
✓ interceptor works with negated expectation
|
||||
✓ pipe works with negated expectation
|
||||
✓ pipe is run and can let the pipeline keep going
|
||||
✓ intercept is applied
|
||||
✓ intercept stops the pipeline
|
||||
✓ interception is called only when filter is met
|
||||
✓ intercept can be filtered with a closure
|
||||
✓ 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
|
||||
@ -405,6 +435,11 @@
|
||||
✓ not failures with multiple needles (all failing)
|
||||
✓ not failures with multiple needles (some failing)
|
||||
|
||||
PASS Tests\Features\Expect\toContainOnlyInstancesOf
|
||||
✓ pass
|
||||
✓ failures
|
||||
✓ not failures
|
||||
|
||||
PASS Tests\Features\Expect\toEndWith
|
||||
✓ pass
|
||||
✓ failures
|
||||
@ -452,8 +487,11 @@
|
||||
|
||||
PASS Tests\Features\Expect\toHaveKeys
|
||||
✓ pass
|
||||
✓ pass with multi-dimensional arrays
|
||||
✓ failures
|
||||
✓ failures with multi-dimensional arrays
|
||||
✓ not failures
|
||||
✓ not failures with multi-dimensional arrays
|
||||
|
||||
PASS Tests\Features\Expect\toHaveLength
|
||||
✓ it passes with ('Fortaleza')
|
||||
@ -496,6 +534,7 @@
|
||||
|
||||
PASS Tests\Features\Expect\toMatchObject
|
||||
✓ pass
|
||||
✓ pass with class
|
||||
✓ failures
|
||||
✓ not failures
|
||||
|
||||
@ -516,6 +555,8 @@
|
||||
✓ 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\unless
|
||||
✓ it pass
|
||||
@ -548,9 +589,9 @@
|
||||
✓ it is capable doing multiple assertions
|
||||
✓ it resolves expect callables correctly
|
||||
✓ does not treat method names as callables
|
||||
✓ it can tap into the test
|
||||
✓ it can defer a method until after test setup
|
||||
✓ it can pass datasets into the expect callables with (1, 2, 3)
|
||||
✓ it can pass datasets into the tap callable with (1, 2, 3)
|
||||
✓ it can pass datasets into the defer callable with (1, 2, 3)
|
||||
✓ it can pass shared datasets into callables with (1)
|
||||
✓ it can pass shared datasets into callables with (2)
|
||||
|
||||
@ -578,7 +619,7 @@
|
||||
|
||||
WARN Tests\Features\Skip
|
||||
✓ it do not skips
|
||||
- it skips with truthy
|
||||
- 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
|
||||
@ -592,6 +633,10 @@
|
||||
✓ 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
|
||||
|
||||
PASS Tests\Fixtures\DirectoryWithTests\ExampleTest
|
||||
✓ it example 1
|
||||
|
||||
@ -618,14 +663,14 @@
|
||||
PASS Tests\PHPUnit\CustomAffixes\ATestWithSpaces
|
||||
✓ it runs file names like `A Test With Spaces.php`
|
||||
|
||||
PASS Tests\PHPUnit\CustomAffixes\AdditionalFileExtensionspec
|
||||
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\ManyExtensionsclasstest
|
||||
PASS Tests\PHPUnit\CustomAffixes\ManyExtensions
|
||||
✓ it runs file names like `ManyExtensions.class.test.php`
|
||||
|
||||
PASS Tests\PHPUnit\CustomAffixes\TestCaseWithQuotes
|
||||
@ -654,18 +699,14 @@
|
||||
✓ it allows global uses
|
||||
✓ it allows multiple global uses registered in the same path
|
||||
|
||||
PASS Tests\Unit\Actions\AddsDefaults
|
||||
✓ it sets defaults
|
||||
✓ it does not override options
|
||||
|
||||
PASS Tests\Unit\Actions\AddsTests
|
||||
✓ default php unit tests
|
||||
✓ it removes warnings
|
||||
|
||||
PASS Tests\Unit\Actions\ValidatesConfiguration
|
||||
✓ it throws exception when configuration not found
|
||||
✓ it throws exception when `process isolation` is true
|
||||
✓ it do not throws exception when `process isolation` is false
|
||||
WARN Tests\Unit\ConfigLoader
|
||||
✓ it fallbacks to default path if no phpunit file is found
|
||||
- it fallbacks to default path if phpunit is not a valid XML
|
||||
- it fallbacks to default path if failing to read phpunit content
|
||||
- it fallbacks to default path if there is no test suites directory
|
||||
- it fallbacks to default path if test suite directory has no value
|
||||
- it fallbacks to default path if test suite directory does not exist
|
||||
- it returns the parent folder of first test suite directory
|
||||
|
||||
PASS Tests\Unit\Console\Help
|
||||
✓ it outputs the help information when --help is used
|
||||
@ -681,6 +722,9 @@
|
||||
✓ 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 retries if --retry argument is used
|
||||
|
||||
PASS Tests\Unit\Plugins\Version
|
||||
✓ it outputs the version when --version is used
|
||||
✓ it do not outputs version when --version is not used
|
||||
@ -708,37 +752,66 @@
|
||||
✓ it can filter the test suite filenames to those with the only method
|
||||
✓ it does not filter the test suite filenames to those with the only method when working in CI pipeline
|
||||
|
||||
PASS Tests\Visual\Help
|
||||
✓ visual snapshot of help command output
|
||||
WARN Tests\Visual\Help
|
||||
- visual snapshot of help command output → Not supported yet.
|
||||
|
||||
PASS Tests\Visual\JUnit
|
||||
✓ it is can successfully call all public methods
|
||||
WARN Tests\Visual\JUnit
|
||||
- it is can successfully call all public methods → Not supported yet.
|
||||
|
||||
PASS Tests\Visual\SingleTestOrDirectory
|
||||
FAIL Tests\Visual\SingleTestOrDirectory
|
||||
✓ allows to run a single test
|
||||
✓ allows to run a directory
|
||||
✓ it has ascii chars
|
||||
⨯ it has ascii chars
|
||||
✓ it disable decorating printer when colors is set to never
|
||||
|
||||
WARN Tests\Visual\Success
|
||||
- visual snapshot of test suite on success
|
||||
|
||||
PASS Tests\Visual\TeamCity
|
||||
✓ it is can successfully call all public methods
|
||||
WARN Tests\Visual\TeamCity
|
||||
- it is can successfully call all public methods → Not supported yet.
|
||||
|
||||
PASS Tests\Features\Depends
|
||||
✓ first
|
||||
✓ second
|
||||
✓ it asserts true is true
|
||||
✓ depends
|
||||
✓ depends with ...params
|
||||
✓ depends with defined arguments
|
||||
✓ depends run test only once
|
||||
✓ depends works with the correct test name
|
||||
PHPUnit\Framework\ExpectationFailedException
|
||||
|
||||
PASS Tests\Features\DependsInheritance
|
||||
✓ it is a test
|
||||
✓ it uses correct parent class
|
||||
Failed asserting that '\n
|
||||
PASS Tests\Fixtures\DirectoryWithTests\ExampleTest\n
|
||||
✓ it example 1\n
|
||||
\n
|
||||
Tests: 1 passed\n
|
||||
Time: 0.00s\n
|
||||
\n
|
||||
' contains "
|
||||
PASS Tests\Fixtures\DirectoryWithTests\ExampleTest
|
||||
✓ it example 1
|
||||
|
||||
Tests: 4 incompleted, 9 skipped, 487 passed
|
||||
Tests: 1 passed
|
||||
".
|
||||
|
||||
/Users/nunomaduro/Work/Code/pest/src/Mixins/Expectation.php:181
|
||||
/Users/nunomaduro/Work/Code/pest/src/Support/ExpectationPipeline.php:80
|
||||
/Users/nunomaduro/Work/Code/pest/src/Support/ExpectationPipeline.php:84
|
||||
/Users/nunomaduro/Work/Code/pest/src/Expectation.php:297
|
||||
/Users/nunomaduro/Work/Code/pest/tests/Visual/SingleTestOrDirectory.php:32
|
||||
/Users/nunomaduro/Work/Code/pest/src/Factories/TestCaseMethodFactory.php:101
|
||||
/Users/nunomaduro/Work/Code/pest/src/Concerns/Testable.php:251
|
||||
/Users/nunomaduro/Work/Code/pest/src/Support/ExceptionTrace.php:29
|
||||
/Users/nunomaduro/Work/Code/pest/src/Concerns/Testable.php:251
|
||||
/Users/nunomaduro/Work/Code/pest/src/Concerns/Testable.php:205
|
||||
/Users/nunomaduro/Work/Code/pest/src/Kernel.php:57
|
||||
|
||||
at src/Mixins/Expectation.php:181
|
||||
177▕ {
|
||||
178▕ foreach ($needles as $needle) {
|
||||
179▕ if (is_string($this->value)) {
|
||||
180▕ // @phpstan-ignore-next-line
|
||||
➜ 181▕ Assert::assertStringContainsString((string) $needle, $this->value);
|
||||
182▕ } else {
|
||||
183▕ if (!is_iterable($this->value)) {
|
||||
184▕ InvalidExpectationValue::expected('iterable');
|
||||
185▕ }
|
||||
|
||||
1 src/Mixins/Expectation.php:181
|
||||
2 src/Support/ExpectationPipeline.php:80
|
||||
|
||||
|
||||
Tests: 1 failed, 4 incompleted, 18 skipped, 514 passed, 8 pending
|
||||
|
||||
@ -1,11 +1,19 @@
|
||||
<?php
|
||||
|
||||
dataset('bound.closure', function () {
|
||||
yield function () { return 1; };
|
||||
yield function () { return 2; };
|
||||
yield function () {
|
||||
return 1;
|
||||
};
|
||||
yield function () {
|
||||
return 2;
|
||||
};
|
||||
});
|
||||
|
||||
dataset('bound.array', [
|
||||
function () { return 1; },
|
||||
function () { return 2; },
|
||||
function () {
|
||||
return 1;
|
||||
},
|
||||
function () {
|
||||
return 2;
|
||||
},
|
||||
]);
|
||||
|
||||
@ -9,7 +9,6 @@ it('has plugin')->assertTrue(class_exists(CoveragePlugin::class));
|
||||
|
||||
it('adds coverage if --coverage exist', function () {
|
||||
$plugin = new CoveragePlugin(new ConsoleOutput());
|
||||
$testSuite = TestSuite::getInstance();
|
||||
|
||||
expect($plugin->coverage)->toBeFalse();
|
||||
$arguments = $plugin->handleArguments([]);
|
||||
|
||||
@ -28,23 +28,23 @@ it('sets closures', function () {
|
||||
yield [1];
|
||||
});
|
||||
|
||||
expect(DatasetsRepository::resolve('foo', ['foo']))->toBe(['foo with (1)' => [1]]);
|
||||
expect(DatasetsRepository::resolve('foo', ['foo']))->toBe(['(1)' => [1]]);
|
||||
});
|
||||
|
||||
it('sets arrays', function () {
|
||||
DatasetsRepository::set('bar', [[2]]);
|
||||
|
||||
expect(DatasetsRepository::resolve('bar', ['bar']))->toBe(['bar with (2)' => [2]]);
|
||||
expect(DatasetsRepository::resolve('bar', ['bar']))->toBe(['(2)' => [2]]);
|
||||
});
|
||||
|
||||
it('gets bound to test case object', function () {
|
||||
it('gets bound to test case object', function ($value) {
|
||||
$this->assertTrue(true);
|
||||
})->with([['a'], ['b']]);
|
||||
|
||||
test('it truncates the description', function () {
|
||||
expect(true)->toBe(true);
|
||||
// it gets tested by the integration test
|
||||
})->with([str_repeat('Fooo', 10000000)]);
|
||||
})->with([str_repeat('Fooo', 10)]);
|
||||
|
||||
$state = new stdClass();
|
||||
$state->text = '';
|
||||
@ -233,8 +233,12 @@ test('more than two datasets did the job right', function () use ($state) {
|
||||
it('can resolve a dataset after the test case is available', function ($result) {
|
||||
expect($result)->toBe('bar');
|
||||
})->with([
|
||||
function () { return $this->foo; },
|
||||
[function () { return $this->foo; }],
|
||||
function () {
|
||||
return $this->foo;
|
||||
},
|
||||
[function () {
|
||||
return $this->foo;
|
||||
}],
|
||||
]);
|
||||
|
||||
it('can resolve a dataset after the test case is available with shared yield sets', function ($result) {
|
||||
@ -249,38 +253,54 @@ it('resolves a potential bound dataset logically', function ($foo, $bar) {
|
||||
expect($foo)->toBe('foo');
|
||||
expect($bar())->toBe('bar');
|
||||
})->with([
|
||||
['foo', function () { return 'bar'; }], // This should be passed as a closure because we've passed multiple arguments
|
||||
['foo', function () {
|
||||
return 'bar';
|
||||
}], // This should be passed as a closure because we've passed multiple arguments
|
||||
]);
|
||||
|
||||
it('resolves a potential bound dataset logically even when the closure comes first', function ($foo, $bar) {
|
||||
expect($foo())->toBe('foo');
|
||||
expect($bar)->toBe('bar');
|
||||
})->with([
|
||||
[function () { return 'foo'; }, 'bar'], // This should be passed as a closure because we've passed multiple arguments
|
||||
[function () {
|
||||
return 'foo';
|
||||
}, 'bar'], // This should be passed as a closure because we've passed multiple arguments
|
||||
]);
|
||||
|
||||
it('will not resolve a closure if it is type hinted as a closure', function (Closure $data) {
|
||||
expect($data())->toBeString();
|
||||
})->with([
|
||||
function () { return 'foo'; },
|
||||
function () { return 'bar'; },
|
||||
function () {
|
||||
return 'foo';
|
||||
},
|
||||
function () {
|
||||
return 'bar';
|
||||
},
|
||||
]);
|
||||
|
||||
it('will not resolve a closure if it is type hinted as a callable', function (callable $data) {
|
||||
expect($data())->toBeString();
|
||||
})->with([
|
||||
function () { return 'foo'; },
|
||||
function () { return 'bar'; },
|
||||
function () {
|
||||
return 'foo';
|
||||
},
|
||||
function () {
|
||||
return 'bar';
|
||||
},
|
||||
]);
|
||||
|
||||
it('can correctly resolve a bound dataset that returns an array', function (array $data) {
|
||||
expect($data)->toBe(['foo', 'bar', 'baz']);
|
||||
})->with([
|
||||
function () { return ['foo', 'bar', 'baz']; },
|
||||
function () {
|
||||
return ['foo', 'bar', 'baz'];
|
||||
},
|
||||
]);
|
||||
|
||||
it('can correctly resolve a bound dataset that returns an array but wants to be spread', function (string $foo, string $bar, string $baz) {
|
||||
expect([$foo, $bar, $baz])->toBe(['foo', 'bar', 'baz']);
|
||||
})->with([
|
||||
function () { return ['foo', 'bar', 'baz']; },
|
||||
function () {
|
||||
return ['foo', 'bar', 'baz'];
|
||||
},
|
||||
]);
|
||||
|
||||
@ -32,7 +32,9 @@ it('not catch exceptions if given condition is false', function () {
|
||||
|
||||
it('catch exceptions if given condition is true', function () {
|
||||
throw new Exception('Something bad happened');
|
||||
})->throwsIf(function () { return true; }, Exception::class);
|
||||
})->throwsIf(function () {
|
||||
return true;
|
||||
}, Exception::class);
|
||||
|
||||
it('catch exceptions and messages if given condition is true', function () {
|
||||
throw new Exception('Something bad happened');
|
||||
|
||||
@ -40,8 +40,12 @@ it('works inside of each', function () {
|
||||
it('works with sequence', function () {
|
||||
expect(new HasMethods())
|
||||
->books()->sequence(
|
||||
function ($book) { $book->title->toEqual('Foo')->cost->toEqual(20); },
|
||||
function ($book) { $book->title->toEqual('Bar')->cost->toEqual(30); },
|
||||
function ($book) {
|
||||
$book->title->toEqual('Foo')->cost->toEqual(20);
|
||||
},
|
||||
function ($book) {
|
||||
$book->title->toEqual('Bar')->cost->toEqual(30);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@ -54,8 +58,12 @@ it('can compose complex expectations', function () {
|
||||
->attributes()->toBeArray()
|
||||
->books()->toBeArray->each->not->toBeEmpty
|
||||
->books()->sequence(
|
||||
function ($book) { $book->title->toEqual('Foo')->cost->toEqual(20); },
|
||||
function ($book) { $book->title->toEqual('Bar')->cost->toEqual(30); },
|
||||
function ($book) {
|
||||
$book->title->toEqual('Foo')->cost->toEqual(20);
|
||||
},
|
||||
function ($book) {
|
||||
$book->title->toEqual('Bar')->cost->toEqual(30);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@ -9,8 +9,12 @@ it('can access methods and properties', function () {
|
||||
})->books()->toBeArray()
|
||||
->posts->toBeArray->each->not->toBeEmpty
|
||||
->books()->sequence(
|
||||
function ($book) { $book->title->toEqual('Foo')->cost->toEqual(20); },
|
||||
function ($book) { $book->title->toEqual('Bar')->cost->toEqual(30); },
|
||||
function ($book) {
|
||||
$book->title->toEqual('Foo')->cost->toEqual(20);
|
||||
},
|
||||
function ($book) {
|
||||
$book->title->toEqual('Bar')->cost->toEqual(30);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@ -53,7 +57,9 @@ it('can start a new higher order expectation using the and syntax without nestin
|
||||
->toBeInstanceOf(HasMethodsAndProperties::class)
|
||||
->meta
|
||||
->sequence(
|
||||
function ($value, $key) { $value->toBeArray()->and($key)->toBe('foo'); },
|
||||
function ($value, $key) {
|
||||
$value->toBeArray()->and($key)->toBe('foo');
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@ -35,8 +35,12 @@ it('works inside of each', function () {
|
||||
it('works with sequence', function () {
|
||||
expect(['books' => [['title' => 'Foo', 'cost' => 20], ['title' => 'Bar', 'cost' => 30]]])
|
||||
->books->sequence(
|
||||
function ($book) { $book->title->toEqual('Foo')->cost->toEqual(20); },
|
||||
function ($book) { $book->title->toEqual('Bar')->cost->toEqual(30); },
|
||||
function ($book) {
|
||||
$book->title->toEqual('Foo')->cost->toEqual(20);
|
||||
},
|
||||
function ($book) {
|
||||
$book->title->toEqual('Bar')->cost->toEqual(30);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@ -51,10 +55,16 @@ it('can compose complex expectations', function () {
|
||||
it('works with objects', function () {
|
||||
expect(new HasProperties())
|
||||
->name->toEqual('foo')->not->toEqual('world')
|
||||
->posts->toHaveCount(2)->each(function ($post) { $post->is_published->toBeTrue(); })
|
||||
->posts->toHaveCount(2)->each(function ($post) {
|
||||
$post->is_published->toBeTrue();
|
||||
})
|
||||
->posts->sequence(
|
||||
function ($post) { $post->title->toEqual('Foo'); },
|
||||
function ($post) { $post->title->toEqual('Bar'); },
|
||||
function ($post) {
|
||||
$post->title->toEqual('Foo');
|
||||
},
|
||||
function ($post) {
|
||||
$post->title->toEqual('Bar');
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@ -82,7 +82,9 @@ it('runs with falsy', function () {
|
||||
it('runs with truthy closure condition', function () {
|
||||
expect('foo')
|
||||
->match(
|
||||
function () { return '1'; }, [
|
||||
function () {
|
||||
return '1';
|
||||
}, [
|
||||
'bar' => function ($value) {
|
||||
$this->matched = 'bar';
|
||||
|
||||
@ -103,7 +105,9 @@ it('runs with truthy closure condition', function () {
|
||||
it('runs with falsy closure condition', function () {
|
||||
expect('foo')
|
||||
->match(
|
||||
function () { return '0'; }, [
|
||||
function () {
|
||||
return '0';
|
||||
}, [
|
||||
'bar' => function ($value) {
|
||||
$this->matched = 'bar';
|
||||
|
||||
@ -137,7 +141,9 @@ it('fails with unhandled match', function () {
|
||||
it('can be used in higher order tests')
|
||||
->expect(true)
|
||||
->match(
|
||||
function () { return true; }, [
|
||||
function () {
|
||||
return true;
|
||||
}, [
|
||||
false => function ($value) {
|
||||
return $value->toBeFalse();
|
||||
},
|
||||
|
||||
@ -37,6 +37,7 @@ class Symbol
|
||||
class State
|
||||
{
|
||||
public array $runCount = [];
|
||||
|
||||
public array $appliedCount = [];
|
||||
|
||||
public function __construct()
|
||||
|
||||
@ -9,9 +9,15 @@ test('an exception is thrown if the the type is not iterable', function () {
|
||||
test('allows for sequences of checks to be run on iterable data', function () {
|
||||
expect([1, 2, 3])
|
||||
->sequence(
|
||||
function ($expectation) { $expectation->toBeInt()->toEqual(1); },
|
||||
function ($expectation) { $expectation->toBeInt()->toEqual(2); },
|
||||
function ($expectation) { $expectation->toBeInt()->toEqual(3); },
|
||||
function ($expectation) {
|
||||
$expectation->toBeInt()->toEqual(1);
|
||||
},
|
||||
function ($expectation) {
|
||||
$expectation->toBeInt()->toEqual(2);
|
||||
},
|
||||
function ($expectation) {
|
||||
$expectation->toBeInt()->toEqual(3);
|
||||
},
|
||||
);
|
||||
|
||||
expect(static::getCount())->toBe(6);
|
||||
@ -20,9 +26,15 @@ test('allows for sequences of checks to be run on iterable data', function () {
|
||||
test('loops back to the start if it runs out of sequence items', function () {
|
||||
expect([1, 2, 3, 1, 2, 3, 1, 2])
|
||||
->sequence(
|
||||
function ($expectation) { $expectation->toBeInt()->toEqual(1); },
|
||||
function ($expectation) { $expectation->toBeInt()->toEqual(2); },
|
||||
function ($expectation) { $expectation->toBeInt()->toEqual(3); },
|
||||
function ($expectation) {
|
||||
$expectation->toBeInt()->toEqual(1);
|
||||
},
|
||||
function ($expectation) {
|
||||
$expectation->toBeInt()->toEqual(2);
|
||||
},
|
||||
function ($expectation) {
|
||||
$expectation->toBeInt()->toEqual(3);
|
||||
},
|
||||
);
|
||||
|
||||
expect(static::getCount())->toBe(16);
|
||||
@ -31,9 +43,15 @@ test('loops back to the start if it runs out of sequence items', function () {
|
||||
test('fails if the number of iterable items is greater than the number of expectations', function () {
|
||||
expect([1, 2])
|
||||
->sequence(
|
||||
function ($expectation) { $expectation->toBeInt()->toEqual(1); },
|
||||
function ($expectation) { $expectation->toBeInt()->toEqual(2); },
|
||||
function ($expectation) { $expectation->toBeInt()->toEqual(3); },
|
||||
function ($expectation) {
|
||||
$expectation->toBeInt()->toEqual(1);
|
||||
},
|
||||
function ($expectation) {
|
||||
$expectation->toBeInt()->toEqual(2);
|
||||
},
|
||||
function ($expectation) {
|
||||
$expectation->toBeInt()->toEqual(3);
|
||||
},
|
||||
);
|
||||
})->throws(ExpectationFailedException::class);
|
||||
|
||||
@ -60,7 +78,9 @@ test('it can be passed non-callable values', function () {
|
||||
test('it can be passed a mixture of value types', function () {
|
||||
expect(['foo', 'bar', 'baz'])->sequence(
|
||||
'foo',
|
||||
function ($expectation) { $expectation->toEqual('bar')->toBeString(); },
|
||||
function ($expectation) {
|
||||
$expectation->toEqual('bar')->toBeString();
|
||||
},
|
||||
'baz'
|
||||
);
|
||||
|
||||
|
||||
@ -3,7 +3,8 @@
|
||||
use PHPUnit\Framework\ExpectationFailedException;
|
||||
|
||||
test('pass', function () {
|
||||
expect(function () {})->toBeCallable();
|
||||
expect(function () {
|
||||
})->toBeCallable();
|
||||
expect(null)->not->toBeCallable();
|
||||
});
|
||||
|
||||
@ -14,5 +15,7 @@ test('failures', function () {
|
||||
})->throws(ExpectationFailedException::class);
|
||||
|
||||
test('not failures', function () {
|
||||
expect(function () { return 42; })->not->toBeCallable();
|
||||
expect(function () {
|
||||
return 42;
|
||||
})->not->toBeCallable();
|
||||
})->throws(ExpectationFailedException::class);
|
||||
|
||||
@ -20,6 +20,7 @@ test('pass', function () {
|
||||
test('pass with class', function () {
|
||||
expect(new class() {
|
||||
public $name = 'Nuno';
|
||||
|
||||
public $email = 'enunomaduro@gmail.com';
|
||||
})->toMatchObject([
|
||||
'name' => 'Nuno',
|
||||
|
||||
@ -3,60 +3,98 @@
|
||||
use PHPUnit\Framework\ExpectationFailedException;
|
||||
|
||||
test('passes', function () {
|
||||
expect(function () { throw new RuntimeException(); })->toThrow(RuntimeException::class);
|
||||
expect(function () { throw new RuntimeException(); })->toThrow(Exception::class);
|
||||
expect(function () { throw new RuntimeException(); })->toThrow(function (RuntimeException $e) {});
|
||||
expect(function () { throw new RuntimeException('actual message'); })->toThrow(function (Exception $e) {
|
||||
expect(function () {
|
||||
throw new RuntimeException();
|
||||
})->toThrow(RuntimeException::class);
|
||||
expect(function () {
|
||||
throw new RuntimeException();
|
||||
})->toThrow(Exception::class);
|
||||
expect(function () {
|
||||
throw new RuntimeException();
|
||||
})->toThrow(function (RuntimeException $e) {
|
||||
});
|
||||
expect(function () {
|
||||
throw new RuntimeException('actual message');
|
||||
})->toThrow(function (Exception $e) {
|
||||
expect($e->getMessage())->toBe('actual message');
|
||||
});
|
||||
expect(function () {})->not->toThrow(Exception::class);
|
||||
expect(function () { throw new RuntimeException('actual message'); })->toThrow('actual message');
|
||||
expect(function () { throw new Exception(); })->not->toThrow(RuntimeException::class);
|
||||
expect(function () { throw new RuntimeException('actual message'); })->toThrow(RuntimeException::class, 'actual message');
|
||||
expect(function () { throw new RuntimeException('actual message'); })->toThrow(function (RuntimeException $e) {}, 'actual message');
|
||||
expect(function () {
|
||||
})->not->toThrow(Exception::class);
|
||||
expect(function () {
|
||||
throw new RuntimeException('actual message');
|
||||
})->toThrow('actual message');
|
||||
expect(function () {
|
||||
throw new Exception();
|
||||
})->not->toThrow(RuntimeException::class);
|
||||
expect(function () {
|
||||
throw new RuntimeException('actual message');
|
||||
})->toThrow(RuntimeException::class, 'actual message');
|
||||
expect(function () {
|
||||
throw new RuntimeException('actual message');
|
||||
})->toThrow(function (RuntimeException $e) {
|
||||
}, 'actual message');
|
||||
});
|
||||
|
||||
test('failures 1', function () {
|
||||
expect(function () {})->toThrow(RuntimeException::class);
|
||||
expect(function () {
|
||||
})->toThrow(RuntimeException::class);
|
||||
})->throws(ExpectationFailedException::class, 'Exception "' . RuntimeException::class . '" not thrown.');
|
||||
|
||||
test('failures 2', function () {
|
||||
expect(function () {})->toThrow(function (RuntimeException $e) {});
|
||||
expect(function () {
|
||||
})->toThrow(function (RuntimeException $e) {
|
||||
});
|
||||
})->throws(ExpectationFailedException::class, 'Exception "' . RuntimeException::class . '" not thrown.');
|
||||
|
||||
test('failures 3', function () {
|
||||
expect(function () { throw new Exception(); })->toThrow(function (RuntimeException $e) {});
|
||||
expect(function () {
|
||||
throw new Exception();
|
||||
})->toThrow(function (RuntimeException $e) {
|
||||
});
|
||||
})->throws(ExpectationFailedException::class, 'Failed asserting that Exception Object');
|
||||
|
||||
test('failures 4', function () {
|
||||
expect(function () { throw new Exception('actual message'); })
|
||||
expect(function () {
|
||||
throw new Exception('actual message');
|
||||
})
|
||||
->toThrow(function (Exception $e) {
|
||||
expect($e->getMessage())->toBe('expected message');
|
||||
});
|
||||
})->throws(ExpectationFailedException::class, 'Failed asserting that two strings are identical');
|
||||
|
||||
test('failures 5', function () {
|
||||
expect(function () { throw new Exception('actual message'); })->toThrow('expected message');
|
||||
expect(function () {
|
||||
throw new Exception('actual message');
|
||||
})->toThrow('expected message');
|
||||
})->throws(ExpectationFailedException::class, 'Failed asserting that \'actual message\' contains "expected message".');
|
||||
|
||||
test('failures 6', function () {
|
||||
expect(function () {})->toThrow('actual message');
|
||||
expect(function () {
|
||||
})->toThrow('actual message');
|
||||
})->throws(ExpectationFailedException::class, 'Exception with message "actual message" not thrown');
|
||||
|
||||
test('failures 7', function () {
|
||||
expect(function () { throw new RuntimeException('actual message'); })->toThrow(RuntimeException::class, 'expected message');
|
||||
expect(function () {
|
||||
throw new RuntimeException('actual message');
|
||||
})->toThrow(RuntimeException::class, 'expected message');
|
||||
})->throws(ExpectationFailedException::class);
|
||||
|
||||
test('not failures', function () {
|
||||
expect(function () { throw new RuntimeException(); })->not->toThrow(RuntimeException::class);
|
||||
expect(function () {
|
||||
throw new RuntimeException();
|
||||
})->not->toThrow(RuntimeException::class);
|
||||
})->throws(ExpectationFailedException::class);
|
||||
|
||||
test('closure missing parameter', function () {
|
||||
expect(function () {})->toThrow(function () {});
|
||||
expect(function () {
|
||||
})->toThrow(function () {
|
||||
});
|
||||
})->throws(InvalidArgumentException::class, 'The given closure must have a single parameter type-hinted as the class string.');
|
||||
|
||||
test('closure missing type-hint', function () {
|
||||
expect(function () {})->toThrow(function ($e) {});
|
||||
expect(function () {
|
||||
})->toThrow(function ($e) {
|
||||
});
|
||||
})->throws(InvalidArgumentException::class, 'The given closure\'s parameter must be type-hinted as the class string.');
|
||||
|
||||
it('can handle a non-defined exception', function () {
|
||||
|
||||
@ -67,7 +67,9 @@ it('skips with falsy', function () {
|
||||
it('runs with truthy closure condition', function () {
|
||||
expect($this->unlessObject)
|
||||
->unless(
|
||||
function () { return '0'; },
|
||||
function () {
|
||||
return '0';
|
||||
},
|
||||
function ($value) {
|
||||
return $value->trueValue->toBeTrue();
|
||||
}
|
||||
@ -80,7 +82,9 @@ it('runs with truthy closure condition', function () {
|
||||
it('skips with falsy closure condition', function () {
|
||||
expect($this->unlessObject)
|
||||
->unless(
|
||||
function () { return '1'; },
|
||||
function () {
|
||||
return '1';
|
||||
},
|
||||
function ($value) {
|
||||
return $value->trueValue->toBeFalse(); // fails
|
||||
}
|
||||
@ -93,7 +97,9 @@ it('skips with falsy closure condition', function () {
|
||||
it('can be used in higher order tests')
|
||||
->expect(true)
|
||||
->unless(
|
||||
function () { return false; },
|
||||
function () {
|
||||
return false;
|
||||
},
|
||||
function ($value) {
|
||||
return $value->toBeFalse();
|
||||
}
|
||||
|
||||
@ -67,7 +67,9 @@ it('skips with falsy', function () {
|
||||
it('runs with truthy closure condition', function () {
|
||||
expect($this->whenObject)
|
||||
->when(
|
||||
function () { return '1'; },
|
||||
function () {
|
||||
return '1';
|
||||
},
|
||||
function ($value) {
|
||||
return $value->trueValue->toBeTrue();
|
||||
}
|
||||
@ -80,7 +82,9 @@ it('runs with truthy closure condition', function () {
|
||||
it('skips with falsy closure condition', function () {
|
||||
expect($this->whenObject)
|
||||
->when(
|
||||
function () { return '0'; },
|
||||
function () {
|
||||
return '0';
|
||||
},
|
||||
function ($value) {
|
||||
return $value->trueValue->toBeFalse(); // fails
|
||||
}
|
||||
@ -93,7 +97,9 @@ it('skips with falsy closure condition', function () {
|
||||
it('can be used in higher order tests')
|
||||
->expect(false)
|
||||
->when(
|
||||
function () { return true; },
|
||||
function () {
|
||||
return true;
|
||||
},
|
||||
function ($value) {
|
||||
return $value->toBeTrue();
|
||||
}
|
||||
|
||||
@ -11,7 +11,9 @@ it('is capable doing multiple assertions')
|
||||
->assertFalse(false);
|
||||
|
||||
it('resolves expect callables correctly')
|
||||
->expect(function () { return 'foo'; })
|
||||
->expect(function () {
|
||||
return 'foo';
|
||||
})
|
||||
->toBeString()
|
||||
->toBe('foo')
|
||||
->and('bar')
|
||||
@ -23,24 +25,38 @@ test('does not treat method names as callables')
|
||||
|
||||
it('can defer a method until after test setup')
|
||||
->expect('foo')->toBeString()
|
||||
->defer(function () { expect($this)->toBeInstanceOf(TestCase::class); })
|
||||
->defer(function () {
|
||||
expect($this)->toBeInstanceOf(TestCase::class);
|
||||
})
|
||||
->toBe('foo')
|
||||
->and('hello world')->toBeString();
|
||||
|
||||
it('can pass datasets into the expect callables')
|
||||
->with([[1, 2, 3]])
|
||||
->expect(function (...$numbers) { return $numbers; })->toBe([1, 2, 3])
|
||||
->and(function (...$numbers) { return $numbers; })->toBe([1, 2, 3]);
|
||||
->expect(function (...$numbers) {
|
||||
return $numbers;
|
||||
})->toBe([1, 2, 3])
|
||||
->and(function (...$numbers) {
|
||||
return $numbers;
|
||||
})->toBe([1, 2, 3]);
|
||||
|
||||
it('can pass datasets into the defer callable')
|
||||
->with([[1, 2, 3]])
|
||||
->defer(function (...$numbers) { expect($numbers)->toBe([1, 2, 3]); });
|
||||
->defer(function (...$numbers) {
|
||||
expect($numbers)->toBe([1, 2, 3]);
|
||||
});
|
||||
|
||||
it('can pass shared datasets into callables')
|
||||
->with('numbers.closure.wrapped')
|
||||
->expect(function ($value) { return $value; })
|
||||
->and(function ($value) { return $value; })
|
||||
->defer(function ($value) { expect($value)->toBeInt(); })
|
||||
->expect(function ($value) {
|
||||
return $value;
|
||||
})
|
||||
->and(function ($value) {
|
||||
return $value;
|
||||
})
|
||||
->defer(function ($value) {
|
||||
expect($value)->toBeInt();
|
||||
})
|
||||
->toBeInt();
|
||||
|
||||
afterEach()->assertTrue(true);
|
||||
|
||||
@ -21,11 +21,15 @@ it('skips with message')
|
||||
->assertTrue(false);
|
||||
|
||||
it('skips with truthy closure condition')
|
||||
->skip(function () { return '1'; })
|
||||
->skip(function () {
|
||||
return '1';
|
||||
})
|
||||
->assertTrue(false);
|
||||
|
||||
it('do not skips with falsy closure condition')
|
||||
->skip(function () { return false; })
|
||||
->skip(function () {
|
||||
return false;
|
||||
})
|
||||
->assertTrue(true);
|
||||
|
||||
it('skips with condition and message')
|
||||
@ -37,10 +41,16 @@ it('skips when skip after assertion')
|
||||
->skip();
|
||||
|
||||
it('can use something in the test case as a condition')
|
||||
->skip(function () { return $this->shouldSkip; }, 'This test was skipped')
|
||||
->skip(function () {
|
||||
return $this->shouldSkip;
|
||||
}, 'This test was skipped')
|
||||
->assertTrue(false);
|
||||
|
||||
it('can user higher order callables and skip')
|
||||
->skip(function () { return $this->shouldSkip; })
|
||||
->expect(function () { return $this->shouldSkip; })
|
||||
->skip(function () {
|
||||
return $this->shouldSkip;
|
||||
})
|
||||
->expect(function () {
|
||||
return $this->shouldSkip;
|
||||
})
|
||||
->toBeFalse();
|
||||
|
||||
@ -10,8 +10,8 @@ it('show only the names of named datasets in their description', function () {
|
||||
],
|
||||
]));
|
||||
|
||||
expect($descriptions[0])->toBe('test description with data set "one"');
|
||||
expect($descriptions[1])->toBe('test description with data set "two"');
|
||||
expect($descriptions[0])->toBe('data set "one"')
|
||||
->and($descriptions[1])->toBe('data set "two"');
|
||||
});
|
||||
|
||||
it('show the actual dataset of non-named datasets in their description', function () {
|
||||
@ -22,8 +22,8 @@ it('show the actual dataset of non-named datasets in their description', functio
|
||||
],
|
||||
]));
|
||||
|
||||
expect($descriptions[0])->toBe('test description with (1)');
|
||||
expect($descriptions[1])->toBe('test description with (array(2))');
|
||||
expect($descriptions[0])->toBe('(1)');
|
||||
expect($descriptions[1])->toBe('(array(2))');
|
||||
});
|
||||
|
||||
it('show only the names of multiple named datasets in their description', function () {
|
||||
@ -38,10 +38,10 @@ it('show only the names of multiple named datasets in their description', functi
|
||||
],
|
||||
]));
|
||||
|
||||
expect($descriptions[0])->toBe('test description with data set "one" / data set "three"');
|
||||
expect($descriptions[1])->toBe('test description with data set "one" / data set "four"');
|
||||
expect($descriptions[2])->toBe('test description with data set "two" / data set "three"');
|
||||
expect($descriptions[3])->toBe('test description with data set "two" / data set "four"');
|
||||
expect($descriptions[0])->toBe('data set "one" / data set "three"');
|
||||
expect($descriptions[1])->toBe('data set "one" / data set "four"');
|
||||
expect($descriptions[2])->toBe('data set "two" / data set "three"');
|
||||
expect($descriptions[3])->toBe('data set "two" / data set "four"');
|
||||
});
|
||||
|
||||
it('show the actual dataset of multiple non-named datasets in their description', function () {
|
||||
@ -56,10 +56,10 @@ it('show the actual dataset of multiple non-named datasets in their description'
|
||||
],
|
||||
]));
|
||||
|
||||
expect($descriptions[0])->toBe('test description with (1) / (3)');
|
||||
expect($descriptions[1])->toBe('test description with (1) / (array(4))');
|
||||
expect($descriptions[2])->toBe('test description with (array(2)) / (3)');
|
||||
expect($descriptions[3])->toBe('test description with (array(2)) / (array(4))');
|
||||
expect($descriptions[0])->toBe('(1) / (3)');
|
||||
expect($descriptions[1])->toBe('(1) / (array(4))');
|
||||
expect($descriptions[2])->toBe('(array(2)) / (3)');
|
||||
expect($descriptions[3])->toBe('(array(2)) / (array(4))');
|
||||
});
|
||||
|
||||
it('show the correct description for mixed named and not-named datasets', function () {
|
||||
@ -74,8 +74,8 @@ it('show the correct description for mixed named and not-named datasets', functi
|
||||
],
|
||||
]));
|
||||
|
||||
expect($descriptions[0])->toBe('test description with data set "one" / (3)');
|
||||
expect($descriptions[1])->toBe('test description with data set "one" / data set "four"');
|
||||
expect($descriptions[2])->toBe('test description with (array(2)) / (3)');
|
||||
expect($descriptions[3])->toBe('test description with (array(2)) / data set "four"');
|
||||
expect($descriptions[0])->toBe('data set "one" / (3)');
|
||||
expect($descriptions[1])->toBe('data set "one" / data set "four"');
|
||||
expect($descriptions[2])->toBe('(array(2)) / (3)');
|
||||
expect($descriptions[3])->toBe('(array(2)) / data set "four"');
|
||||
});
|
||||
|
||||
@ -20,7 +20,8 @@ it('does not allow to add the same test description twice', function () {
|
||||
it('alerts users about tests with arguments but no input', function () {
|
||||
$testSuite = new TestSuite(getcwd(), 'tests');
|
||||
|
||||
$method = new TestCaseMethodFactory('foo', 'bar', function (int $arg) {});
|
||||
$method = new TestCaseMethodFactory('foo', 'bar', function (int $arg) {
|
||||
});
|
||||
|
||||
$testSuite->tests->set($method);
|
||||
})->throws(
|
||||
@ -29,7 +30,7 @@ it('alerts users about tests with arguments but no input', function () {
|
||||
);
|
||||
|
||||
it('can return an array of all test suite filenames', function () {
|
||||
$testSuite = TestSuite::getInstance(getcwd(), 'tests');
|
||||
$testSuite = new TestSuite(getcwd(), 'tests');
|
||||
|
||||
$testSuite->tests->set(new TestCaseMethodFactory('a', 'b', null));
|
||||
$testSuite->tests->set(new TestCaseMethodFactory('c', 'd', null));
|
||||
@ -57,9 +58,10 @@ it('can filter the test suite filenames to those with the only method', function
|
||||
it('does not filter the test suite filenames to those with the only method when working in CI pipeline', function () {
|
||||
$previousEnvironment = Environment::name();
|
||||
Environment::name(Environment::CI);
|
||||
$testSuite = TestSuite::getInstance(getcwd(), 'tests');
|
||||
$testSuite = new TestSuite(getcwd(), 'tests');
|
||||
|
||||
$test = function () {};
|
||||
$test = function () {
|
||||
};
|
||||
|
||||
$testWithOnly = new TestCaseMethodFactory('a', 'b', null);
|
||||
$testWithOnly->only = true;
|
||||
|
||||
@ -24,4 +24,4 @@ test('visual snapshot of help command output', function () {
|
||||
};
|
||||
|
||||
expect($output())->toContain(file_get_contents($snapshot));
|
||||
})->skip(PHP_OS_FAMILY === 'Windows');
|
||||
})->skip(PHP_OS_FAMILY === 'Windows')->skip('Not supported yet.');
|
||||
|
||||
@ -22,7 +22,7 @@ it('is can successfully call all public methods', function () {
|
||||
$junit->endTest($this, 0);
|
||||
$junit->endTestSuite(new TestSuite());
|
||||
$this->expectNotToPerformAssertions();
|
||||
});
|
||||
})->skip('Not supported yet.');
|
||||
|
||||
afterEach(function () {
|
||||
unlink(__DIR__ . '/junit.html');
|
||||
|
||||
@ -9,7 +9,11 @@ test('visual snapshot of test suite on success', function () {
|
||||
]);
|
||||
|
||||
$output = function () use ($testsPath) {
|
||||
$process = (new Symfony\Component\Process\Process(['php', 'bin/pest'], dirname($testsPath), ['EXCLUDE' => 'integration', 'REBUILD_SNAPSHOTS' => false, 'PARATEST' => 0]));
|
||||
$process = (new Symfony\Component\Process\Process(
|
||||
['php', 'bin/pest'],
|
||||
dirname($testsPath),
|
||||
['EXCLUDE' => 'integration', 'REBUILD_SNAPSHOTS' => false, 'PARATEST' => 0, 'COLLISION_PRINTER' => 'DefaultPrinter'],
|
||||
));
|
||||
|
||||
$process->run();
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ it('is can successfully call all public methods', function () {
|
||||
$teamCity->endTest($this, 0);
|
||||
$teamCity->printResult(new TestResult());
|
||||
$teamCity->endTestSuite(new TestSuite());
|
||||
});
|
||||
})->skip('Not supported yet.');
|
||||
|
||||
afterEach(function () {
|
||||
unlink(__DIR__ . '/output.txt');
|
||||
|
||||
Reference in New Issue
Block a user