Uses Collision ^7.0

This commit is contained in:
Nuno Maduro
2022-09-15 01:07:15 +01:00
parent eab944023c
commit 3ff95faaaa
47 changed files with 646 additions and 308 deletions

View File

@ -2,3 +2,6 @@
2. Support for `default` printer. 2. Support for `default` printer.
3. Support for `TeamCity` printer. 3. Support for `TeamCity` printer.
4. Support for `JUnit` log. 4. Support for `JUnit` log.
5. Plugins
6. Parallel
7. Collision's todo...

View File

@ -11,6 +11,9 @@ use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
(static function () { (static function () {
// Ensures Collision's Printer is registered.
$_SERVER['COLLISION_PRINTER'] = 'DefaultPrinter';
// Used when Pest is required using composer. // Used when Pest is required using composer.
$vendorPath = dirname(__DIR__, 4) . '/vendor/autoload.php'; $vendorPath = dirname(__DIR__, 4) . '/vendor/autoload.php';

View File

@ -18,7 +18,7 @@
], ],
"require": { "require": {
"php": "^8.1.0", "php": "^8.1.0",
"nunomaduro/collision": "^6.3", "nunomaduro/collision": "dev-next",
"pestphp/pest-plugin": "^1.0.0", "pestphp/pest-plugin": "^1.0.0",
"phpunit/phpunit": "10.0.x-dev" "phpunit/phpunit": "10.0.x-dev"
}, },
@ -86,6 +86,7 @@
"Pest\\Plugins\\Init", "Pest\\Plugins\\Init",
"Pest\\Plugins\\Environment", "Pest\\Plugins\\Environment",
"Pest\\Plugins\\Memory", "Pest\\Plugins\\Memory",
"Pest\\Plugins\\Printer",
"Pest\\Plugins\\Retry", "Pest\\Plugins\\Retry",
"Pest\\Plugins\\Version" "Pest\\Plugins\\Version"
] ]

View File

@ -44,14 +44,13 @@ use function basename;
use function class_exists; use function class_exists;
use function get_declared_classes; use function get_declared_classes;
use Pest\Contracts\HasPrintableTestCaseName;
use Pest\TestCases\IgnorableTestCase; use Pest\TestCases\IgnorableTestCase;
use Pest\TestSuite; use Pest\TestSuite;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use ReflectionClass; use ReflectionClass;
use ReflectionException; use ReflectionException;
use function stripos;
use function strlen;
use function substr; use function substr;
/** /**
@ -83,36 +82,43 @@ final class TestSuiteLoader
{ {
$suiteClassName = $this->classNameFromFileName($suiteClassFile); $suiteClassName = $this->classNameFromFileName($suiteClassFile);
if (!class_exists($suiteClassName, false)) { (static function () use ($suiteClassFile) {
(static function () use ($suiteClassFile) { include_once $suiteClassFile;
include_once $suiteClassFile;
TestSuite::getInstance()->tests->makeIfNeeded($suiteClassFile); TestSuite::getInstance()->tests->makeIfNeeded($suiteClassFile);
})(); })();
$loadedClasses = array_values( $loadedClasses = array_values(
array_diff( array_diff(
get_declared_classes(), get_declared_classes(),
array_merge( array_merge(
self::$declaredClasses, self::$declaredClasses,
self::$loadedClasses self::$loadedClasses
)
) )
); )
);
self::$loadedClasses = array_merge($loadedClasses, self::$loadedClasses); self::$loadedClasses = array_merge($loadedClasses, self::$loadedClasses);
if (empty(self::$loadedClasses)) { if (empty(self::$loadedClasses)) {
return $this->exceptionFor($suiteClassName, $suiteClassFile); return $this->exceptionFor($suiteClassName, $suiteClassFile);
}
$testCaseFound = false;
foreach (self::$loadedClasses as $loadedClass) {
if (is_subclass_of($loadedClass, HasPrintableTestCaseName::class)) {
$suiteClassName = $loadedClass;
$testCaseFound = true;
break;
} }
} }
if (!class_exists($suiteClassName, false)) { if (!$testCaseFound) {
// this block will handle namespaced classes
$offset = 0 - strlen($suiteClassName);
foreach (self::$loadedClasses as $loadedClass) { foreach (self::$loadedClasses as $loadedClass) {
if (stripos(substr($loadedClass, $offset - 1), '\\' . $suiteClassName) === 0) { if (is_subclass_of($loadedClass, TestCase::class)) {
$suiteClassName = $loadedClass; $suiteClassName = $loadedClass;
break; break;

View File

@ -1,8 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.0/phpunit.xsd" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.0/phpunit.xsd"
backupGlobals="false"
beStrictAboutTestsThatDoNotTestAnything="true"
beStrictAboutOutputDuringTests="true"
bootstrap="vendor/autoload.php"
cacheResult="false"
colors="true" colors="true"
failOnRisky="true"
failOnWarning="true"
processIsolation="false"
stopOnError="false"
stopOnFailure="false"
cacheDirectory=".phpunit.cache" cacheDirectory=".phpunit.cache"
backupStaticProperties="false"
displayDetailsOnIncompleteTests="true"
displayDetailsOnSkippedTests="true"
displayDetailsOnTestsThatTriggerDeprecations="true"
displayDetailsOnTestsThatTriggerErrors="true"
displayDetailsOnTestsThatTriggerNotices="true"
displayDetailsOnTestsThatTriggerWarnings="true"
> >
<testsuites> <testsuites>
<testsuite name="default"> <testsuite name="default">

View File

@ -9,13 +9,21 @@ use Pest\Support\ChainableClosure;
use Pest\Support\ExceptionTrace; use Pest\Support\ExceptionTrace;
use Pest\Support\Reflection; use Pest\Support\Reflection;
use Pest\TestSuite; use Pest\TestSuite;
use PHPUnit\Framework\TestCase;
use Throwable; use Throwable;
/** /**
* @internal * @internal
*
* @mixin TestCase
*/ */
trait Testable trait Testable
{ {
/**
* Test method description.
*/
private static string $__description;
/** /**
* The Test Case "test" closure. * The Test Case "test" closure.
*/ */
@ -118,14 +126,6 @@ trait Testable
: $hook; : $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. * 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 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) { if (count($arguments) !== 1) {
return $arguments; return $arguments;
} }
@ -246,8 +253,16 @@ trait Testable
/** /**
* Gets the Test Case name that should be used by printers. * 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\\'); return ltrim(self::class, 'P\\');
} }
/**
* Gets the Test Case name that should be used by printers.
*/
public static function getPrintableTestCaseMethodName(): string
{
return self::$__description;
}
} }

View File

@ -12,9 +12,9 @@ interface HandlesArguments
/** /**
* Adds arguments before of the Test Suite execution. * Adds arguments before of the Test Suite execution.
* *
* @param array<int, string> $argv * @param array<int, string> $arguments
* *
* @return array<int, string> * @return array<int, string>
*/ */
public function handleArguments(array $argv): array; public function handleArguments(array $arguments): array;
} }

View File

@ -19,7 +19,7 @@ final class ShouldNotHappen extends RuntimeException
{ {
$message = $exception->getMessage(); $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. This should not happen - please create an new issue here: https://github.com/pestphp/pest.

View File

@ -186,6 +186,7 @@ final class Expectation
foreach ($values as $key => $item) { foreach ($values as $key => $item) {
if ($callbacks[$key] instanceof Closure) { if ($callbacks[$key] instanceof Closure) {
call_user_func($callbacks[$key], new self($item), new self($keys[$key])); call_user_func($callbacks[$key], new self($item), new self($keys[$key]));
continue; continue;
} }
@ -220,6 +221,7 @@ final class Expectation
if (is_callable($callback)) { if (is_callable($callback)) {
$callback(new self($this->value)); $callback(new self($this->value));
continue; continue;
} }

View File

@ -37,7 +37,7 @@ final class HigherOrderExpectation
*/ */
public function __construct(private Expectation $original, mixed $value) public function __construct(private Expectation $original, mixed $value)
{ {
$this->expectation = $this->expect($value); $this->expectation = $this->expect($value);
} }
/** /**

View File

@ -121,7 +121,17 @@ final class TestCaseFactory
$filename = str_replace('\\\\', '\\', addslashes((string) realpath($filename))); $filename = str_replace('\\\\', '\\', addslashes((string) realpath($filename)));
$rootPath = TestSuite::getInstance()->rootPath; $rootPath = TestSuite::getInstance()->rootPath;
$relativePath = str_replace($rootPath . DIRECTORY_SEPARATOR, '', $filename); $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); $relativePath = str_replace(DIRECTORY_SEPARATOR, '\\', $relativePath);
// Strip out any %-encoded octets. // Strip out any %-encoded octets.
@ -132,6 +142,7 @@ final class TestCaseFactory
$relativePath = (string) preg_replace('/[^A-Za-z0-9\\\\]/', '', $relativePath); $relativePath = (string) preg_replace('/[^A-Za-z0-9\\\\]/', '', $relativePath);
$classFQN = 'P\\' . $relativePath; $classFQN = 'P\\' . $relativePath;
if (class_exists($classFQN)) { if (class_exists($classFQN)) {
return; return;
} }
@ -174,27 +185,28 @@ final class TestCaseFactory
)); ));
$classAttributesCode = implode('', array_map( $classAttributesCode = implode('', array_map(
static fn (string $attribute) => sprintf("\n %s", $attribute), static fn (string $attribute) => sprintf("\n%s", $attribute),
array_unique($classAttributes), array_unique($classAttributes),
)); ));
try { try {
eval(" $classCode = <<<PHP
namespace $namespace; namespace $namespace;
use Pest\Repositories\DatasetsRepository as __PestDatasets; use Pest\Repositories\DatasetsRepository as __PestDatasets;
use Pest\TestSuite as __PestTestSuite; use Pest\TestSuite as __PestTestSuite;
$classAttributesCode
#[\AllowDynamicProperties]
final class $className extends $baseClass implements $hasPrintableTestCaseClassFQN {
$traitsCode
$classAttributesCode private static \$__filename = '$filename';
#[\AllowDynamicProperties]
final class $className extends $baseClass implements $hasPrintableTestCaseClassFQN {
$traitsCode
private static \$__filename = '$filename'; $methodsCode
}
PHP;
$methodsCode eval($classCode);
}
");
} catch (ParseError $caught) { } catch (ParseError $caught) {
throw new RuntimeException(sprintf('Unable to create test case for test file at %s', $filename), 1, $caught); throw new RuntimeException(sprintf('Unable to create test case for test file at %s', $filename), 1, $caught);
} }

View File

@ -91,7 +91,6 @@ final class TestCaseMethodFactory
return function () use ($testCase, $method, $closure): mixed { // @phpstan-ignore-line return function () use ($testCase, $method, $closure): mixed { // @phpstan-ignore-line
/* @var TestCase $this */ /* @var TestCase $this */
$testCase->proxies->proxy($this); $testCase->proxies->proxy($this);
$method->proxies->proxy($this); $method->proxies->proxy($this);
@ -148,28 +147,29 @@ final class TestCaseMethodFactory
} }
$annotations = implode('', array_map( $annotations = implode('', array_map(
static fn ($annotation) => sprintf("\n * %s", $annotation), $annotations, static fn ($annotation) => sprintf("\n * %s", $annotation), $annotations,
)); ));
$attributes = implode('', array_map( $attributes = implode('', array_map(
static fn ($attribute) => sprintf("\n %s", $attribute), $attributes, static fn ($attribute) => sprintf("\n %s", $attribute), $attributes,
)); ));
return <<<EOF return <<<PHP
/**$annotations /**$annotations
*/ */
$attributes $attributes
public function $methodName() public function $methodName()
{ {
\$test = \Pest\TestSuite::getInstance()->tests->get(self::\$__filename)->getMethod(\$this->name())->getClosure(\$this);
return \$this->__runTest( return \$this->__runTest(
\$this->__test, \$test,
...func_get_args(), ...func_get_args(),
); );
} }
$datasetsCode $datasetsCode
EOF; PHP;
} }
/** /**

View File

@ -44,10 +44,10 @@ final class PestDatasetCommand extends Command
/** @var string $name */ /** @var string $name */
$name = $this->argument('name'); $name = $this->argument('name');
$relativePath = sprintf(testDirectory('DatasetsRepository/%s.php'), ucfirst($name)); $relativePath = sprintf(testDirectory('DatasetsRepository/%s.php'), ucfirst($name));
/* @phpstan-ignore-next-line */ /* @phpstan-ignore-next-line */
$target = base_path($relativePath); $target = base_path($relativePath);
if (File::exists($target)) { if (File::exists($target)) {
throw new InvalidConsoleArgument(sprintf('%s already exist', $target)); throw new InvalidConsoleArgument(sprintf('%s already exist', $target));

View File

@ -41,8 +41,8 @@ final class PestInstallCommand extends Command
TestSuite::getInstance(base_path(), $this->option('test-directory')); TestSuite::getInstance(base_path(), $this->option('test-directory'));
/* @phpstan-ignore-next-line */ /* @phpstan-ignore-next-line */
$pest = base_path(testDirectory('Pest.php')); $pest = base_path(testDirectory('Pest.php'));
$stubs = 'stubs/Laravel'; $stubs = 'stubs/Laravel';
if (File::exists($pest)) { if (File::exists($pest)) {
throw new InvalidConsoleArgument(sprintf('%s already exist', $pest)); throw new InvalidConsoleArgument(sprintf('%s already exist', $pest));

View File

@ -19,6 +19,20 @@ trait HandleArguments
return in_array($argument, $arguments, true); 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. * Pops the given argument from the arguments.
* *

View File

@ -14,7 +14,7 @@ final class Environment implements HandlesArguments
/** /**
* The continuous integration environment. * The continuous integration environment.
*/ */
public const CI = 'ci'; public const CI = 'ci';
/** /**
* The local environment. * The local environment.

27
src/Plugins/Printer.php Normal file
View 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);
}
}

View File

@ -57,6 +57,11 @@ final class DatasetsRepository
self::$withs[$filename . '>>>' . $description] = $with; 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 * @return Closure|iterable<int|string, mixed>|never
* *
@ -107,7 +112,7 @@ final class DatasetsRepository
$values = array_merge($values, $datasetCombinationElement['values']); $values = array_merge($values, $datasetCombinationElement['values']);
} }
$datasetDescriptions[] = $description . ' with ' . implode(' / ', $partialDescriptions); $datasetDescriptions[] = implode(' / ', $partialDescriptions);
$datasetValues[] = $values; $datasetValues[] = $values;
} }

View File

@ -56,7 +56,7 @@ final class ExceptionTrace
$cleanedTrace = []; $cleanedTrace = [];
foreach ($trace as $item) { 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; continue;
} }

View File

@ -13,6 +13,7 @@ abstract class Printer implements \PHPUnit\Util\Printer
private $stream; private $stream;
private bool $isPhpStream; private bool $isPhpStream;
private bool $isOpen; private bool $isOpen;
private function __construct(string $out) private function __construct(string $out)

View File

@ -12,11 +12,4 @@ use PHPUnit\Framework\TestCase;
*/ */
class IgnorableTestCase extends TestCase class IgnorableTestCase extends TestCase
{ {
/**
* @test
*/
public function fake(): void
{
self::markTestIncomplete();
}
} }

View File

@ -70,12 +70,12 @@ final class TestSuite
string $rootPath, string $rootPath,
public string $testPath) public string $testPath)
{ {
$this->beforeAll = new BeforeAllRepository(); $this->beforeAll = new BeforeAllRepository();
$this->beforeEach = new BeforeEachRepository(); $this->beforeEach = new BeforeEachRepository();
$this->tests = new TestRepository(); $this->tests = new TestRepository();
$this->afterEach = new AfterEachRepository(); $this->afterEach = new AfterEachRepository();
$this->afterAll = new AfterAllRepository(); $this->afterAll = new AfterAllRepository();
$this->retryTempRepository = new TempRepository('retry'); $this->retryTempRepository = new TempRepository('retry');
$this->rootPath = (string) realpath($rootPath); $this->rootPath = (string) realpath($rootPath);
} }

View File

@ -1,7 +1,4 @@
PASS Tests\CustomTestCase\ExecutedTest
✓ that gets executed
PASS Tests\Features\AfterAll PASS Tests\Features\AfterAll
✓ deletes file after all ✓ deletes file after all
@ -23,6 +20,15 @@
✓ it adds coverage if --min exist ✓ it adds coverage if --min exist
✓ it generates coverage based on file input ✓ 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 PASS Tests\Features\Datasets
✓ it throws exception if dataset does not exist ✓ it throws exception if dataset does not exist
✓ it throws exception if dataset already 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 with (Closure Object (...))
✓ it can correctly resolve a bound dataset that returns an array but wants to be spread 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 PASS Tests\Features\Exceptions
✓ it gives access the the underlying expectException ✓ it gives access the the underlying expectException
✓ it catch exceptions ✓ it catch exceptions
✓ it catch exceptions and messages ✓ it catch exceptions and messages
✓ it catch exceptions, messages and code
✓ it can just define the message ✓ it can just define the message
✓ it can just define the code
✓ it not catch exceptions if given condition is false ✓ it not catch exceptions if given condition is false
✓ it catch exceptions if given condition is true ✓ it catch exceptions if given condition is true
✓ it catch exceptions and messages 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 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 message if given condition is 1
✓ it can just define the code if given condition is 1
PASS Tests\Features\Expect\HigherOrder\methods PASS Tests\Features\Expect\HigherOrder\methods
✓ it can access methods ✓ it can access methods
@ -133,6 +158,8 @@
✓ it can compose complex expectations ✓ it can compose complex expectations
✓ it can handle nested method calls ✓ it can handle nested method calls
✓ it works with higher order tests ✓ 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 PASS Tests\Features\Expect\HigherOrder\methodsAndProperties
✓ it can access methods and properties ✓ it can access methods and properties
@ -140,6 +167,7 @@
✓ it works with higher order tests ✓ 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
✓ 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 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 PASS Tests\Features\Expect\HigherOrder\properties
✓ it allows properties to be accessed from the value ✓ it allows properties to be accessed from the value
@ -161,6 +189,7 @@
✓ chained opposite and non-opposite expectations ✓ chained opposite and non-opposite expectations
✓ it can add expectations via "and" ✓ it can add expectations via "and"
✓ it accepts callables ✓ it accepts callables
✓ it passes the key of the current item to callables
PASS Tests\Features\Expect\extend PASS Tests\Features\Expect\extend
✓ it macros true is true ✓ it macros true is true
@ -186,15 +215,16 @@
PASS Tests\Features\Expect\not PASS Tests\Features\Expect\not
✓ not property calls ✓ not property calls
PASS Tests\Features\Expect\pipe PASS Tests\Features\Expect\pipes
✓ pipe is applied and can stop pipeline ✓ 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 ✓ pipe is run and can let the pipeline keep going
intercept is applied pipe works with negated expectation
✓ intercept stops the pipeline ✓ interceptor is applied
✓ interception is called only when filter is met ✓ interceptor stops the pipeline
✓ intercept can be filtered with a closure ✓ 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 ✓ intercept can add new parameters to the expectation
PASS Tests\Features\Expect\ray PASS Tests\Features\Expect\ray
@ -405,6 +435,11 @@
✓ not failures with multiple needles (all failing) ✓ not failures with multiple needles (all failing)
✓ not failures with multiple needles (some failing) ✓ not failures with multiple needles (some failing)
PASS Tests\Features\Expect\toContainOnlyInstancesOf
✓ pass
✓ failures
✓ not failures
PASS Tests\Features\Expect\toEndWith PASS Tests\Features\Expect\toEndWith
✓ pass ✓ pass
✓ failures ✓ failures
@ -452,8 +487,11 @@
PASS Tests\Features\Expect\toHaveKeys PASS Tests\Features\Expect\toHaveKeys
✓ pass ✓ pass
✓ pass with multi-dimensional arrays
✓ failures ✓ failures
✓ failures with multi-dimensional arrays
✓ not failures ✓ not failures
✓ not failures with multi-dimensional arrays
PASS Tests\Features\Expect\toHaveLength PASS Tests\Features\Expect\toHaveLength
✓ it passes with ('Fortaleza') ✓ it passes with ('Fortaleza')
@ -496,6 +534,7 @@
PASS Tests\Features\Expect\toMatchObject PASS Tests\Features\Expect\toMatchObject
✓ pass ✓ pass
✓ pass with class
✓ failures ✓ failures
✓ not failures ✓ not failures
@ -516,6 +555,8 @@
✓ not failures ✓ not failures
✓ closure missing parameter ✓ closure missing parameter
✓ closure missing type-hint ✓ closure missing type-hint
✓ it can handle a non-defined exception
✓ it can handle a class not found Error
PASS Tests\Features\Expect\unless PASS Tests\Features\Expect\unless
✓ it pass ✓ it pass
@ -548,9 +589,9 @@
✓ it is capable doing multiple assertions ✓ it is capable doing multiple assertions
✓ it resolves expect callables correctly ✓ it resolves expect callables correctly
✓ does not treat method names as callables ✓ 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 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 (1)
✓ it can pass shared datasets into callables with (2) ✓ it can pass shared datasets into callables with (2)
@ -578,7 +619,7 @@
WARN Tests\Features\Skip WARN Tests\Features\Skip
✓ it do not skips ✓ it do not skips
- it skips with truthy - it skips with truthy → 1
- it skips with truthy condition by default - it skips with truthy condition by default
- it skips with message → skipped because bar - it skips with message → skipped because bar
- it skips with truthy closure condition - it skips with truthy closure condition
@ -592,6 +633,10 @@
✓ a test ✓ a test
✓ higher order message 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 PASS Tests\Fixtures\DirectoryWithTests\ExampleTest
✓ it example 1 ✓ it example 1
@ -618,14 +663,14 @@
PASS Tests\PHPUnit\CustomAffixes\ATestWithSpaces PASS Tests\PHPUnit\CustomAffixes\ATestWithSpaces
✓ it runs file names like `A Test With Spaces.php` ✓ 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` ✓ it runs file names like `AdditionalFileExtension.spec.php`
PASS Tests\PHPUnit\CustomAffixes\FolderWithAn\ExampleTest PASS Tests\PHPUnit\CustomAffixes\FolderWithAn\ExampleTest
✓ custom traits can be used ✓ custom traits can be used
✓ trait applied in this file ✓ trait applied in this file
PASS Tests\PHPUnit\CustomAffixes\ManyExtensionsclasstest PASS Tests\PHPUnit\CustomAffixes\ManyExtensions
✓ it runs file names like `ManyExtensions.class.test.php` ✓ it runs file names like `ManyExtensions.class.test.php`
PASS Tests\PHPUnit\CustomAffixes\TestCaseWithQuotes PASS Tests\PHPUnit\CustomAffixes\TestCaseWithQuotes
@ -654,18 +699,14 @@
✓ it allows global uses ✓ it allows global uses
✓ it allows multiple global uses registered in the same path ✓ it allows multiple global uses registered in the same path
PASS Tests\Unit\Actions\AddsDefaults WARN Tests\Unit\ConfigLoader
✓ it sets defaults ✓ it fallbacks to default path if no phpunit file is found
it does not override options - it fallbacks to default path if phpunit is not a valid XML
- it fallbacks to default path if failing to read phpunit content
PASS Tests\Unit\Actions\AddsTests - it fallbacks to default path if there is no test suites directory
✓ default php unit tests - it fallbacks to default path if test suite directory has no value
it removes warnings - 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\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
PASS Tests\Unit\Console\Help PASS Tests\Unit\Console\Help
✓ it outputs the help information when --help is used ✓ 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 CI when --ci option is used
✓ environment is set to Local when --ci option is not 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 PASS Tests\Unit\Plugins\Version
✓ it outputs the version when --version is used ✓ it outputs the version when --version is used
✓ it do not outputs version when --version is not 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 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 ✓ it does not filter the test suite filenames to those with the only method when working in CI pipeline
PASS Tests\Visual\Help WARN Tests\Visual\Help
visual snapshot of help command output - visual snapshot of help command output → Not supported yet.
PASS Tests\Visual\JUnit WARN Tests\Visual\JUnit
it is can successfully call all public methods - 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 single test
✓ allows to run a directory ✓ allows to run a directory
it has ascii chars it has ascii chars
✓ it disable decorating printer when colors is set to never ✓ it disable decorating printer when colors is set to never
WARN Tests\Visual\Success WARN Tests\Visual\Success
- visual snapshot of test suite on success - visual snapshot of test suite on success
PASS Tests\Visual\TeamCity WARN Tests\Visual\TeamCity
it is can successfully call all public methods - it is can successfully call all public methods → Not supported yet.
PASS Tests\Features\Depends PHPUnit\Framework\ExpectationFailedException
✓ 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
PASS Tests\Features\DependsInheritance Failed asserting that '\n
✓ it is a test PASS Tests\Fixtures\DirectoryWithTests\ExampleTest\n
✓ it uses correct parent class ✓ it example 1\n
\n
Tests: 1 passed\n
Time: 0.00s\n
\n
' contains "
PASS Tests\Fixtures\DirectoryWithTests\ExampleTest
✓ it example 1
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
Tests: 4 incompleted, 9 skipped, 487 passed 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

View File

@ -1,11 +1,19 @@
<?php <?php
dataset('bound.closure', function () { dataset('bound.closure', function () {
yield function () { return 1; }; yield function () {
yield function () { return 2; }; return 1;
};
yield function () {
return 2;
};
}); });
dataset('bound.array', [ dataset('bound.array', [
function () { return 1; }, function () {
function () { return 2; }, return 1;
},
function () {
return 2;
},
]); ]);

View File

@ -9,7 +9,6 @@ it('has plugin')->assertTrue(class_exists(CoveragePlugin::class));
it('adds coverage if --coverage exist', function () { it('adds coverage if --coverage exist', function () {
$plugin = new CoveragePlugin(new ConsoleOutput()); $plugin = new CoveragePlugin(new ConsoleOutput());
$testSuite = TestSuite::getInstance();
expect($plugin->coverage)->toBeFalse(); expect($plugin->coverage)->toBeFalse();
$arguments = $plugin->handleArguments([]); $arguments = $plugin->handleArguments([]);

View File

@ -28,23 +28,23 @@ it('sets closures', function () {
yield [1]; yield [1];
}); });
expect(DatasetsRepository::resolve('foo', ['foo']))->toBe(['foo with (1)' => [1]]); expect(DatasetsRepository::resolve('foo', ['foo']))->toBe(['(1)' => [1]]);
}); });
it('sets arrays', function () { it('sets arrays', function () {
DatasetsRepository::set('bar', [[2]]); 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); $this->assertTrue(true);
})->with([['a'], ['b']]); })->with([['a'], ['b']]);
test('it truncates the description', function () { test('it truncates the description', function () {
expect(true)->toBe(true); expect(true)->toBe(true);
// it gets tested by the integration test // it gets tested by the integration test
})->with([str_repeat('Fooo', 10000000)]); })->with([str_repeat('Fooo', 10)]);
$state = new stdClass(); $state = new stdClass();
$state->text = ''; $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) { it('can resolve a dataset after the test case is available', function ($result) {
expect($result)->toBe('bar'); expect($result)->toBe('bar');
})->with([ })->with([
function () { return $this->foo; }, function () {
[function () { return $this->foo; }], return $this->foo;
},
[function () {
return $this->foo;
}],
]); ]);
it('can resolve a dataset after the test case is available with shared yield sets', function ($result) { 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($foo)->toBe('foo');
expect($bar())->toBe('bar'); expect($bar())->toBe('bar');
})->with([ })->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) { it('resolves a potential bound dataset logically even when the closure comes first', function ($foo, $bar) {
expect($foo())->toBe('foo'); expect($foo())->toBe('foo');
expect($bar)->toBe('bar'); expect($bar)->toBe('bar');
})->with([ })->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) { it('will not resolve a closure if it is type hinted as a closure', function (Closure $data) {
expect($data())->toBeString(); expect($data())->toBeString();
})->with([ })->with([
function () { return 'foo'; }, function () {
function () { return 'bar'; }, return 'foo';
},
function () {
return 'bar';
},
]); ]);
it('will not resolve a closure if it is type hinted as a callable', function (callable $data) { it('will not resolve a closure if it is type hinted as a callable', function (callable $data) {
expect($data())->toBeString(); expect($data())->toBeString();
})->with([ })->with([
function () { return 'foo'; }, function () {
function () { return 'bar'; }, return 'foo';
},
function () {
return 'bar';
},
]); ]);
it('can correctly resolve a bound dataset that returns an array', function (array $data) { it('can correctly resolve a bound dataset that returns an array', function (array $data) {
expect($data)->toBe(['foo', 'bar', 'baz']); expect($data)->toBe(['foo', 'bar', 'baz']);
})->with([ })->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) { 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']); expect([$foo, $bar, $baz])->toBe(['foo', 'bar', 'baz']);
})->with([ })->with([
function () { return ['foo', 'bar', 'baz']; }, function () {
return ['foo', 'bar', 'baz'];
},
]); ]);

View File

@ -32,7 +32,9 @@ it('not catch exceptions if given condition is false', function () {
it('catch exceptions if given condition is true', function () { it('catch exceptions if given condition is true', function () {
throw new Exception('Something bad happened'); 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 () { it('catch exceptions and messages if given condition is true', function () {
throw new Exception('Something bad happened'); throw new Exception('Something bad happened');

View File

@ -40,8 +40,12 @@ it('works inside of each', function () {
it('works with sequence', function () { it('works with sequence', function () {
expect(new HasMethods()) expect(new HasMethods())
->books()->sequence( ->books()->sequence(
function ($book) { $book->title->toEqual('Foo')->cost->toEqual(20); }, function ($book) {
function ($book) { $book->title->toEqual('Bar')->cost->toEqual(30); }, $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() ->attributes()->toBeArray()
->books()->toBeArray->each->not->toBeEmpty ->books()->toBeArray->each->not->toBeEmpty
->books()->sequence( ->books()->sequence(
function ($book) { $book->title->toEqual('Foo')->cost->toEqual(20); }, function ($book) {
function ($book) { $book->title->toEqual('Bar')->cost->toEqual(30); }, $book->title->toEqual('Foo')->cost->toEqual(20);
},
function ($book) {
$book->title->toEqual('Bar')->cost->toEqual(30);
},
); );
}); });

View File

@ -9,8 +9,12 @@ it('can access methods and properties', function () {
})->books()->toBeArray() })->books()->toBeArray()
->posts->toBeArray->each->not->toBeEmpty ->posts->toBeArray->each->not->toBeEmpty
->books()->sequence( ->books()->sequence(
function ($book) { $book->title->toEqual('Foo')->cost->toEqual(20); }, function ($book) {
function ($book) { $book->title->toEqual('Bar')->cost->toEqual(30); }, $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) ->toBeInstanceOf(HasMethodsAndProperties::class)
->meta ->meta
->sequence( ->sequence(
function ($value, $key) { $value->toBeArray()->and($key)->toBe('foo'); }, function ($value, $key) {
$value->toBeArray()->and($key)->toBe('foo');
},
); );
}); });

View File

@ -35,8 +35,12 @@ it('works inside of each', function () {
it('works with sequence', function () { it('works with sequence', function () {
expect(['books' => [['title' => 'Foo', 'cost' => 20], ['title' => 'Bar', 'cost' => 30]]]) expect(['books' => [['title' => 'Foo', 'cost' => 20], ['title' => 'Bar', 'cost' => 30]]])
->books->sequence( ->books->sequence(
function ($book) { $book->title->toEqual('Foo')->cost->toEqual(20); }, function ($book) {
function ($book) { $book->title->toEqual('Bar')->cost->toEqual(30); }, $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 () { it('works with objects', function () {
expect(new HasProperties()) expect(new HasProperties())
->name->toEqual('foo')->not->toEqual('world') ->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( ->posts->sequence(
function ($post) { $post->title->toEqual('Foo'); }, function ($post) {
function ($post) { $post->title->toEqual('Bar'); }, $post->title->toEqual('Foo');
},
function ($post) {
$post->title->toEqual('Bar');
},
); );
}); });

View File

@ -9,17 +9,17 @@ beforeEach(function () {
it('pass', function () { it('pass', function () {
expect('baz') expect('baz')
->match('foo', [ ->match('foo', [
'bar' => function ($value) { 'bar' => function ($value) {
$this->matched = 'bar'; $this->matched = 'bar';
return $value->toEqual('bar'); return $value->toEqual('bar');
}, },
'foo' => function ($value) { 'foo' => function ($value) {
$this->matched = 'baz'; $this->matched = 'baz';
return $value->toEqual('baz'); return $value->toEqual('baz');
}, },
] ]
) )
->toEqual($this->matched); ->toEqual($this->matched);
@ -29,30 +29,30 @@ it('pass', function () {
it('failures', function () { it('failures', function () {
expect(true) expect(true)
->match('foo', [ ->match('foo', [
'bar' => function ($value) { 'bar' => function ($value) {
return $value->toBeTrue(); return $value->toBeTrue();
}, },
'foo' => function ($value) { 'foo' => function ($value) {
return $value->toBeFalse(); return $value->toBeFalse();
}, },
] ]
); );
})->throws(ExpectationFailedException::class, 'true is false'); })->throws(ExpectationFailedException::class, 'true is false');
it('runs with truthy', function () { it('runs with truthy', function () {
expect('foo') expect('foo')
->match(1, [ ->match(1, [
'bar' => function ($value) { 'bar' => function ($value) {
$this->matched = 'bar'; $this->matched = 'bar';
return $value->toEqual('bar'); return $value->toEqual('bar');
}, },
true => function ($value) { true => function ($value) {
$this->matched = 'foo'; $this->matched = 'foo';
return $value->toEqual('foo'); return $value->toEqual('foo');
}, },
] ]
) )
->toEqual($this->matched); ->toEqual($this->matched);
@ -62,17 +62,17 @@ it('runs with truthy', function () {
it('runs with falsy', function () { it('runs with falsy', function () {
expect('foo') expect('foo')
->match(false, [ ->match(false, [
'bar' => function ($value) { 'bar' => function ($value) {
$this->matched = 'bar'; $this->matched = 'bar';
return $value->toEqual('bar'); return $value->toEqual('bar');
}, },
false => function ($value) { false => function ($value) {
$this->matched = 'foo'; $this->matched = 'foo';
return $value->toEqual('foo'); return $value->toEqual('foo');
}, },
] ]
) )
->toEqual($this->matched); ->toEqual($this->matched);
@ -82,7 +82,9 @@ it('runs with falsy', function () {
it('runs with truthy closure condition', function () { it('runs with truthy closure condition', function () {
expect('foo') expect('foo')
->match( ->match(
function () { return '1'; }, [ function () {
return '1';
}, [
'bar' => function ($value) { 'bar' => function ($value) {
$this->matched = 'bar'; $this->matched = 'bar';
@ -103,7 +105,9 @@ it('runs with truthy closure condition', function () {
it('runs with falsy closure condition', function () { it('runs with falsy closure condition', function () {
expect('foo') expect('foo')
->match( ->match(
function () { return '0'; }, [ function () {
return '0';
}, [
'bar' => function ($value) { 'bar' => function ($value) {
$this->matched = 'bar'; $this->matched = 'bar';
@ -124,9 +128,9 @@ it('runs with falsy closure condition', function () {
it('can be passed non-callable values', function () { it('can be passed non-callable values', function () {
expect('foo') expect('foo')
->match('pest', [ ->match('pest', [
'bar' => 'foo', 'bar' => 'foo',
'pest' => 'baz', 'pest' => 'baz',
] ]
); );
})->throws(ExpectationFailedException::class, 'two strings are equal'); })->throws(ExpectationFailedException::class, 'two strings are equal');
@ -137,7 +141,9 @@ it('fails with unhandled match', function () {
it('can be used in higher order tests') it('can be used in higher order tests')
->expect(true) ->expect(true)
->match( ->match(
function () { return true; }, [ function () {
return true;
}, [
false => function ($value) { false => function ($value) {
return $value->toBeFalse(); return $value->toBeFalse();
}, },

View File

@ -36,7 +36,8 @@ class Symbol
class State class State
{ {
public array $runCount = []; public array $runCount = [];
public array $appliedCount = []; public array $appliedCount = [];
public function __construct() public function __construct()
@ -132,16 +133,16 @@ test('pipe is applied and can stop pipeline', function () use ($state) {
expect($char)->toBe(new Char('A')) expect($char)->toBe(new Char('A'))
->and($state) ->and($state)
->runCount->toMatchArray([ ->runCount->toMatchArray([
'char' => 1, 'char' => 1,
'number' => 0, 'number' => 0,
'wildcard' => 0, 'wildcard' => 0,
'symbol' => 0, 'symbol' => 0,
]) ])
->appliedCount->toMatchArray([ ->appliedCount->toMatchArray([
'char' => 1, 'char' => 1,
'number' => 0, 'number' => 0,
'wildcard' => 0, 'wildcard' => 0,
'symbol' => 0, 'symbol' => 0,
]); ]);
}); });
@ -151,16 +152,16 @@ test('pipe is run and can let the pipeline keep going', function () use ($state)
expect(3)->toBe(3) expect(3)->toBe(3)
->and($state) ->and($state)
->runCount->toMatchArray([ ->runCount->toMatchArray([
'char' => 1, 'char' => 1,
'number' => 0, 'number' => 0,
'wildcard' => 0, 'wildcard' => 0,
'symbol' => 1, 'symbol' => 1,
]) ])
->appliedCount->toMatchArray([ ->appliedCount->toMatchArray([
'char' => 0, 'char' => 0,
'number' => 0, 'number' => 0,
'wildcard' => 0, 'wildcard' => 0,
'symbol' => 0, 'symbol' => 0,
]); ]);
}); });
@ -172,16 +173,16 @@ test('pipe works with negated expectation', function () use ($state) {
expect($char)->not->toBe(new Char('B')) expect($char)->not->toBe(new Char('B'))
->and($state) ->and($state)
->runCount->toMatchArray([ ->runCount->toMatchArray([
'char' => 1, 'char' => 1,
'number' => 0, 'number' => 0,
'wildcard' => 0, 'wildcard' => 0,
'symbol' => 0, 'symbol' => 0,
]) ])
->appliedCount->toMatchArray([ ->appliedCount->toMatchArray([
'char' => 1, 'char' => 1,
'number' => 0, 'number' => 0,
'wildcard' => 0, 'wildcard' => 0,
'symbol' => 0, 'symbol' => 0,
]); ]);
}); });
@ -204,16 +205,16 @@ test('interceptor stops the pipeline', function () use ($state) {
expect($number)->toBe(new Number(1)) expect($number)->toBe(new Number(1))
->and($state) ->and($state)
->runCount->toMatchArray([ ->runCount->toMatchArray([
'char' => 1, 'char' => 1,
'number' => 1, 'number' => 1,
'wildcard' => 0, 'wildcard' => 0,
'symbol' => 0, 'symbol' => 0,
]) ])
->appliedCount->toMatchArray([ ->appliedCount->toMatchArray([
'char' => 0, 'char' => 0,
'number' => 1, 'number' => 1,
'wildcard' => 0, 'wildcard' => 0,
'symbol' => 0, 'symbol' => 0,
]); ]);
}); });

View File

@ -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 () { test('allows for sequences of checks to be run on iterable data', function () {
expect([1, 2, 3]) expect([1, 2, 3])
->sequence( ->sequence(
function ($expectation) { $expectation->toBeInt()->toEqual(1); }, function ($expectation) {
function ($expectation) { $expectation->toBeInt()->toEqual(2); }, $expectation->toBeInt()->toEqual(1);
function ($expectation) { $expectation->toBeInt()->toEqual(3); }, },
function ($expectation) {
$expectation->toBeInt()->toEqual(2);
},
function ($expectation) {
$expectation->toBeInt()->toEqual(3);
},
); );
expect(static::getCount())->toBe(6); 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 () { test('loops back to the start if it runs out of sequence items', function () {
expect([1, 2, 3, 1, 2, 3, 1, 2]) expect([1, 2, 3, 1, 2, 3, 1, 2])
->sequence( ->sequence(
function ($expectation) { $expectation->toBeInt()->toEqual(1); }, function ($expectation) {
function ($expectation) { $expectation->toBeInt()->toEqual(2); }, $expectation->toBeInt()->toEqual(1);
function ($expectation) { $expectation->toBeInt()->toEqual(3); }, },
function ($expectation) {
$expectation->toBeInt()->toEqual(2);
},
function ($expectation) {
$expectation->toBeInt()->toEqual(3);
},
); );
expect(static::getCount())->toBe(16); 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 () { test('fails if the number of iterable items is greater than the number of expectations', function () {
expect([1, 2]) expect([1, 2])
->sequence( ->sequence(
function ($expectation) { $expectation->toBeInt()->toEqual(1); }, function ($expectation) {
function ($expectation) { $expectation->toBeInt()->toEqual(2); }, $expectation->toBeInt()->toEqual(1);
function ($expectation) { $expectation->toBeInt()->toEqual(3); }, },
function ($expectation) {
$expectation->toBeInt()->toEqual(2);
},
function ($expectation) {
$expectation->toBeInt()->toEqual(3);
},
); );
})->throws(ExpectationFailedException::class); })->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 () { test('it can be passed a mixture of value types', function () {
expect(['foo', 'bar', 'baz'])->sequence( expect(['foo', 'bar', 'baz'])->sequence(
'foo', 'foo',
function ($expectation) { $expectation->toEqual('bar')->toBeString(); }, function ($expectation) {
$expectation->toEqual('bar')->toBeString();
},
'baz' 'baz'
); );

View File

@ -3,7 +3,8 @@
use PHPUnit\Framework\ExpectationFailedException; use PHPUnit\Framework\ExpectationFailedException;
test('pass', function () { test('pass', function () {
expect(function () {})->toBeCallable(); expect(function () {
})->toBeCallable();
expect(null)->not->toBeCallable(); expect(null)->not->toBeCallable();
}); });
@ -14,5 +15,7 @@ test('failures', function () {
})->throws(ExpectationFailedException::class); })->throws(ExpectationFailedException::class);
test('not failures', function () { test('not failures', function () {
expect(function () { return 42; })->not->toBeCallable(); expect(function () {
return 42;
})->not->toBeCallable();
})->throws(ExpectationFailedException::class); })->throws(ExpectationFailedException::class);

View File

@ -3,10 +3,10 @@
use PHPUnit\Framework\ExpectationFailedException; use PHPUnit\Framework\ExpectationFailedException;
$test_array = [ $test_array = [
'a' => 1, 'a' => 1,
'b', 'b',
'c' => 'world', 'c' => 'world',
'd' => [ 'd' => [
'e' => 'hello', 'e' => 'hello',
], ],
'key.with.dots' => false, 'key.with.dots' => false,

View File

@ -19,7 +19,8 @@ test('pass', function () {
test('pass with class', function () { test('pass with class', function () {
expect(new class() { expect(new class() {
public $name = 'Nuno'; public $name = 'Nuno';
public $email = 'enunomaduro@gmail.com'; public $email = 'enunomaduro@gmail.com';
})->toMatchObject([ })->toMatchObject([
'name' => 'Nuno', 'name' => 'Nuno',

View File

@ -3,60 +3,98 @@
use PHPUnit\Framework\ExpectationFailedException; use PHPUnit\Framework\ExpectationFailedException;
test('passes', function () { test('passes', function () {
expect(function () { throw new RuntimeException(); })->toThrow(RuntimeException::class); expect(function () {
expect(function () { throw new RuntimeException(); })->toThrow(Exception::class); throw new RuntimeException();
expect(function () { throw new RuntimeException(); })->toThrow(function (RuntimeException $e) {}); })->toThrow(RuntimeException::class);
expect(function () { throw new RuntimeException('actual message'); })->toThrow(function (Exception $e) { 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($e->getMessage())->toBe('actual message');
}); });
expect(function () {})->not->toThrow(Exception::class); expect(function () {
expect(function () { throw new RuntimeException('actual message'); })->toThrow('actual message'); })->not->toThrow(Exception::class);
expect(function () { throw new Exception(); })->not->toThrow(RuntimeException::class); expect(function () {
expect(function () { throw new RuntimeException('actual message'); })->toThrow(RuntimeException::class, 'actual message'); throw new RuntimeException('actual message');
expect(function () { throw new RuntimeException('actual message'); })->toThrow(function (RuntimeException $e) {}, '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 () { test('failures 1', function () {
expect(function () {})->toThrow(RuntimeException::class); expect(function () {
})->toThrow(RuntimeException::class);
})->throws(ExpectationFailedException::class, 'Exception "' . RuntimeException::class . '" not thrown.'); })->throws(ExpectationFailedException::class, 'Exception "' . RuntimeException::class . '" not thrown.');
test('failures 2', function () { test('failures 2', function () {
expect(function () {})->toThrow(function (RuntimeException $e) {}); expect(function () {
})->toThrow(function (RuntimeException $e) {
});
})->throws(ExpectationFailedException::class, 'Exception "' . RuntimeException::class . '" not thrown.'); })->throws(ExpectationFailedException::class, 'Exception "' . RuntimeException::class . '" not thrown.');
test('failures 3', function () { 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'); })->throws(ExpectationFailedException::class, 'Failed asserting that Exception Object');
test('failures 4', function () { test('failures 4', function () {
expect(function () { throw new Exception('actual message'); }) expect(function () {
throw new Exception('actual message');
})
->toThrow(function (Exception $e) { ->toThrow(function (Exception $e) {
expect($e->getMessage())->toBe('expected message'); expect($e->getMessage())->toBe('expected message');
}); });
})->throws(ExpectationFailedException::class, 'Failed asserting that two strings are identical'); })->throws(ExpectationFailedException::class, 'Failed asserting that two strings are identical');
test('failures 5', function () { 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".'); })->throws(ExpectationFailedException::class, 'Failed asserting that \'actual message\' contains "expected message".');
test('failures 6', function () { test('failures 6', function () {
expect(function () {})->toThrow('actual message'); expect(function () {
})->toThrow('actual message');
})->throws(ExpectationFailedException::class, 'Exception with message "actual message" not thrown'); })->throws(ExpectationFailedException::class, 'Exception with message "actual message" not thrown');
test('failures 7', function () { 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); })->throws(ExpectationFailedException::class);
test('not failures', function () { 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); })->throws(ExpectationFailedException::class);
test('closure missing parameter', function () { 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.'); })->throws(InvalidArgumentException::class, 'The given closure must have a single parameter type-hinted as the class string.');
test('closure missing type-hint', function () { 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.'); })->throws(InvalidArgumentException::class, 'The given closure\'s parameter must be type-hinted as the class string.');
it('can handle a non-defined exception', function () { it('can handle a non-defined exception', function () {

View File

@ -67,7 +67,9 @@ it('skips with falsy', function () {
it('runs with truthy closure condition', function () { it('runs with truthy closure condition', function () {
expect($this->unlessObject) expect($this->unlessObject)
->unless( ->unless(
function () { return '0'; }, function () {
return '0';
},
function ($value) { function ($value) {
return $value->trueValue->toBeTrue(); return $value->trueValue->toBeTrue();
} }
@ -80,7 +82,9 @@ it('runs with truthy closure condition', function () {
it('skips with falsy closure condition', function () { it('skips with falsy closure condition', function () {
expect($this->unlessObject) expect($this->unlessObject)
->unless( ->unless(
function () { return '1'; }, function () {
return '1';
},
function ($value) { function ($value) {
return $value->trueValue->toBeFalse(); // fails return $value->trueValue->toBeFalse(); // fails
} }
@ -93,7 +97,9 @@ it('skips with falsy closure condition', function () {
it('can be used in higher order tests') it('can be used in higher order tests')
->expect(true) ->expect(true)
->unless( ->unless(
function () { return false; }, function () {
return false;
},
function ($value) { function ($value) {
return $value->toBeFalse(); return $value->toBeFalse();
} }

View File

@ -67,7 +67,9 @@ it('skips with falsy', function () {
it('runs with truthy closure condition', function () { it('runs with truthy closure condition', function () {
expect($this->whenObject) expect($this->whenObject)
->when( ->when(
function () { return '1'; }, function () {
return '1';
},
function ($value) { function ($value) {
return $value->trueValue->toBeTrue(); return $value->trueValue->toBeTrue();
} }
@ -80,7 +82,9 @@ it('runs with truthy closure condition', function () {
it('skips with falsy closure condition', function () { it('skips with falsy closure condition', function () {
expect($this->whenObject) expect($this->whenObject)
->when( ->when(
function () { return '0'; }, function () {
return '0';
},
function ($value) { function ($value) {
return $value->trueValue->toBeFalse(); // fails return $value->trueValue->toBeFalse(); // fails
} }
@ -93,7 +97,9 @@ it('skips with falsy closure condition', function () {
it('can be used in higher order tests') it('can be used in higher order tests')
->expect(false) ->expect(false)
->when( ->when(
function () { return true; }, function () {
return true;
},
function ($value) { function ($value) {
return $value->toBeTrue(); return $value->toBeTrue();
} }

View File

@ -11,7 +11,9 @@ it('is capable doing multiple assertions')
->assertFalse(false); ->assertFalse(false);
it('resolves expect callables correctly') it('resolves expect callables correctly')
->expect(function () { return 'foo'; }) ->expect(function () {
return 'foo';
})
->toBeString() ->toBeString()
->toBe('foo') ->toBe('foo')
->and('bar') ->and('bar')
@ -23,24 +25,38 @@ test('does not treat method names as callables')
it('can defer a method until after test setup') it('can defer a method until after test setup')
->expect('foo')->toBeString() ->expect('foo')->toBeString()
->defer(function () { expect($this)->toBeInstanceOf(TestCase::class); }) ->defer(function () {
expect($this)->toBeInstanceOf(TestCase::class);
})
->toBe('foo') ->toBe('foo')
->and('hello world')->toBeString(); ->and('hello world')->toBeString();
it('can pass datasets into the expect callables') it('can pass datasets into the expect callables')
->with([[1, 2, 3]]) ->with([[1, 2, 3]])
->expect(function (...$numbers) { return $numbers; })->toBe([1, 2, 3]) ->expect(function (...$numbers) {
->and(function (...$numbers) { return $numbers; })->toBe([1, 2, 3]); return $numbers;
})->toBe([1, 2, 3])
->and(function (...$numbers) {
return $numbers;
})->toBe([1, 2, 3]);
it('can pass datasets into the defer callable') it('can pass datasets into the defer callable')
->with([[1, 2, 3]]) ->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') it('can pass shared datasets into callables')
->with('numbers.closure.wrapped') ->with('numbers.closure.wrapped')
->expect(function ($value) { return $value; }) ->expect(function ($value) {
->and(function ($value) { return $value; }) return $value;
->defer(function ($value) { expect($value)->toBeInt(); }) })
->and(function ($value) {
return $value;
})
->defer(function ($value) {
expect($value)->toBeInt();
})
->toBeInt(); ->toBeInt();
afterEach()->assertTrue(true); afterEach()->assertTrue(true);

View File

@ -21,11 +21,15 @@ it('skips with message')
->assertTrue(false); ->assertTrue(false);
it('skips with truthy closure condition') it('skips with truthy closure condition')
->skip(function () { return '1'; }) ->skip(function () {
return '1';
})
->assertTrue(false); ->assertTrue(false);
it('do not skips with falsy closure condition') it('do not skips with falsy closure condition')
->skip(function () { return false; }) ->skip(function () {
return false;
})
->assertTrue(true); ->assertTrue(true);
it('skips with condition and message') it('skips with condition and message')
@ -37,10 +41,16 @@ it('skips when skip after assertion')
->skip(); ->skip();
it('can use something in the test case as a condition') 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); ->assertTrue(false);
it('can user higher order callables and skip') it('can user higher order callables and skip')
->skip(function () { return $this->shouldSkip; }) ->skip(function () {
->expect(function () { return $this->shouldSkip; }) return $this->shouldSkip;
})
->expect(function () {
return $this->shouldSkip;
})
->toBeFalse(); ->toBeFalse();

View File

@ -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[0])->toBe('data set "one"')
expect($descriptions[1])->toBe('test description with data set "two"'); ->and($descriptions[1])->toBe('data set "two"');
}); });
it('show the actual dataset of non-named datasets in their description', function () { 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[0])->toBe('(1)');
expect($descriptions[1])->toBe('test description with (array(2))'); expect($descriptions[1])->toBe('(array(2))');
}); });
it('show only the names of multiple named datasets in their description', function () { 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[0])->toBe('data set "one" / data set "three"');
expect($descriptions[1])->toBe('test description with data set "one" / data set "four"'); expect($descriptions[1])->toBe('data set "one" / data set "four"');
expect($descriptions[2])->toBe('test description with data set "two" / data set "three"'); expect($descriptions[2])->toBe('data set "two" / data set "three"');
expect($descriptions[3])->toBe('test description with data set "two" / data set "four"'); expect($descriptions[3])->toBe('data set "two" / data set "four"');
}); });
it('show the actual dataset of multiple non-named datasets in their description', function () { 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[0])->toBe('(1) / (3)');
expect($descriptions[1])->toBe('test description with (1) / (array(4))'); expect($descriptions[1])->toBe('(1) / (array(4))');
expect($descriptions[2])->toBe('test description with (array(2)) / (3)'); expect($descriptions[2])->toBe('(array(2)) / (3)');
expect($descriptions[3])->toBe('test description with (array(2)) / (array(4))'); expect($descriptions[3])->toBe('(array(2)) / (array(4))');
}); });
it('show the correct description for mixed named and not-named datasets', function () { 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[0])->toBe('data set "one" / (3)');
expect($descriptions[1])->toBe('test description with data set "one" / data set "four"'); expect($descriptions[1])->toBe('data set "one" / data set "four"');
expect($descriptions[2])->toBe('test description with (array(2)) / (3)'); expect($descriptions[2])->toBe('(array(2)) / (3)');
expect($descriptions[3])->toBe('test description with (array(2)) / data set "four"'); expect($descriptions[3])->toBe('(array(2)) / data set "four"');
}); });

View File

@ -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 () { it('alerts users about tests with arguments but no input', function () {
$testSuite = new TestSuite(getcwd(), 'tests'); $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); $testSuite->tests->set($method);
})->throws( })->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 () { 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('a', 'b', null));
$testSuite->tests->set(new TestCaseMethodFactory('c', 'd', 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 () { it('does not filter the test suite filenames to those with the only method when working in CI pipeline', function () {
$previousEnvironment = Environment::name(); $previousEnvironment = Environment::name();
Environment::name(Environment::CI); 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 = new TestCaseMethodFactory('a', 'b', null);
$testWithOnly->only = true; $testWithOnly->only = true;

View File

@ -24,4 +24,4 @@ test('visual snapshot of help command output', function () {
}; };
expect($output())->toContain(file_get_contents($snapshot)); expect($output())->toContain(file_get_contents($snapshot));
})->skip(PHP_OS_FAMILY === 'Windows'); })->skip(PHP_OS_FAMILY === 'Windows')->skip('Not supported yet.');

View File

@ -22,7 +22,7 @@ it('is can successfully call all public methods', function () {
$junit->endTest($this, 0); $junit->endTest($this, 0);
$junit->endTestSuite(new TestSuite()); $junit->endTestSuite(new TestSuite());
$this->expectNotToPerformAssertions(); $this->expectNotToPerformAssertions();
}); })->skip('Not supported yet.');
afterEach(function () { afterEach(function () {
unlink(__DIR__ . '/junit.html'); unlink(__DIR__ . '/junit.html');

View File

@ -9,7 +9,11 @@ test('visual snapshot of test suite on success', function () {
]); ]);
$output = function () use ($testsPath) { $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(); $process->run();

View File

@ -25,7 +25,7 @@ it('is can successfully call all public methods', function () {
$teamCity->endTest($this, 0); $teamCity->endTest($this, 0);
$teamCity->printResult(new TestResult()); $teamCity->printResult(new TestResult());
$teamCity->endTestSuite(new TestSuite()); $teamCity->endTestSuite(new TestSuite());
}); })->skip('Not supported yet.');
afterEach(function () { afterEach(function () {
unlink(__DIR__ . '/output.txt'); unlink(__DIR__ . '/output.txt');