feat(pending-higher-order-tests): adds code and tests

This commit is contained in:
Nuno Maduro
2020-06-04 01:34:03 +02:00
parent c81dce0f6d
commit aa1917c28d
6 changed files with 103 additions and 26 deletions

View File

@ -8,6 +8,7 @@ use Closure;
use Pest\Concerns;
use Pest\Contracts\HasPrintableTestCaseName;
use Pest\Datasets;
use Pest\Exceptions\ShouldNotHappen;
use Pest\Support\HigherOrderMessageCollection;
use Pest\Support\NullClosure;
use Pest\TestSuite;
@ -39,9 +40,10 @@ final class TestCaseFactory
/**
* Holds the test description.
*
* @readonly
* If the description is null, means that it
* will be created with the given assertions.
*
* @var string
* @var string|null
*/
public $description;
@ -104,7 +106,7 @@ final class TestCaseFactory
/**
* Creates a new anonymous test case pending object.
*/
public function __construct(string $filename, string $description, Closure $closure = null)
public function __construct(string $filename, string $description = null, Closure $closure = null)
{
$this->filename = $filename;
$this->description = $description;
@ -122,6 +124,10 @@ final class TestCaseFactory
*/
public function build(TestSuite $testSuite): array
{
if ($this->description === null) {
throw ShouldNotHappen::fromMessage('Description can not be empty.');
}
$chains = $this->chains;
$proxies = $this->proxies;
$factoryTest = $this->test;

View File

@ -9,12 +9,22 @@ use Pest\Factories\TestCaseFactory;
use Pest\Support\Backtrace;
use Pest\Support\NullClosure;
use Pest\TestSuite;
use SebastianBergmann\Exporter\Exporter;
/**
* @internal
*/
final class TestCall
{
/**
* Holds the test suite.
*
* @readonly
*
* @var TestSuite
*/
private $testSuite;
/**
* Holds the test case factory.
*
@ -24,14 +34,23 @@ final class TestCall
*/
private $testCaseFactory;
/**
* If test call is descriptionLess.
*
* @readonly
*
* @var bool
*/
private $descriptionLess = false;
/**
* Creates a new instance of a pending test call.
*/
public function __construct(TestSuite $testSuite, string $filename, string $description, Closure $closure = null)
public function __construct(TestSuite $testSuite, string $filename, string $description = null, Closure $closure = null)
{
$this->testCaseFactory = new TestCaseFactory($filename, $description, $closure);
$testSuite->tests->set($this->testCaseFactory);
$this->testSuite = $testSuite;
$this->descriptionLess = $description === null;
}
/**
@ -128,6 +147,23 @@ final class TestCall
->chains
->add(Backtrace::file(), Backtrace::line(), $name, $arguments);
if ($this->descriptionLess) {
$exporter = new Exporter();
if ($this->testCaseFactory->description !== null) {
$this->testCaseFactory->description .= ' → ';
}
$this->testCaseFactory->description .= sprintf('%s %s', $name, $exporter->shortenedRecursiveExport($arguments));
}
return $this;
}
/**
* Adds the current test case factory
* to the tests repository.
*/
public function __destruct()
{
$this->testSuite->tests->set($this->testCaseFactory);
}
}

View File

@ -4,17 +4,46 @@ declare(strict_types=1);
namespace Pest\Support;
use Pest\Exceptions\ShouldNotHappen;
/**
* @internal
*/
final class Backtrace
{
/**
* @var string
*/
private const FILE = 'file';
/**
* Returns the current test file.
*/
public static function testFile(): string
{
$current = null;
foreach (debug_backtrace() as $trace) {
if (Str::endsWith($trace[self::FILE], 'vendor/phpunit/phpunit/src/Util/FileLoader.php')) {
break;
}
$current = $trace;
}
if ($current === null) {
throw ShouldNotHappen::fromMessage('Test file not found.');
}
return $current[self::FILE];
}
/**
* Returns the filename that called the current function/method.
*/
public static function file(): string
{
return debug_backtrace()[1]['file'];
return debug_backtrace()[1][self::FILE];
}
/**
@ -22,7 +51,7 @@ final class Backtrace
*/
public static function dirname(): string
{
return dirname(debug_backtrace()[1]['file']);
return dirname(debug_backtrace()[1][self::FILE]);
}
/**

View File

@ -78,7 +78,9 @@ final class HigherOrderMessage
if ($throwable->getMessage() === sprintf(self::UNDEFINED_METHOD, $this->methodName)) {
/** @var \ReflectionClass $reflection */
$reflection = (new ReflectionClass($target))->getParentClass();
$reflection = new ReflectionClass($target);
/* @phpstan-ignore-next-line */
$reflection = $reflection->getParentClass() ?: $reflection;
Reflection::setPropertyValue($throwable, 'message', sprintf('Call to undefined method %s::%s()', $reflection->getName(), $this->methodName));
}

View File

@ -66,7 +66,7 @@ function test(string $description = null, Closure $closure = null)
return new HigherOrderTapProxy(TestSuite::getInstance()->test);
}
$filename = Backtrace::file();
$filename = Backtrace::testFile();
return new TestCall(TestSuite::getInstance(), $filename, $description, $closure);
}
@ -80,9 +80,9 @@ function test(string $description = null, Closure $closure = null)
*/
function it(string $description, Closure $closure = null): TestCall
{
$filename = Backtrace::file();
$description = sprintf('it %s', $description);
return new TestCall(TestSuite::getInstance(), $filename, sprintf('it %s', $description), $closure);
return test($description, $closure);
}
/**

View File

@ -53,7 +53,7 @@
✓ it allows to call underlying protected/private methods
✓ it throws error if method do not exist
PASS Tests\Features\HigherOrderMessages
PASS Tests\Features\HigherOrderTests
✓ it proxies calls to object
PASS Tests\Features\It
@ -63,6 +63,10 @@
PASS Tests\Features\Mocks
✓ it has bar
PASS Tests\Features\PendingHigherOrderTests
✓ get 'foo' → get 'bar' → assert true true
✓ get 'foo' → assert true true
WARN Tests\Features\Skip
✓ it do not skips
s it skips with truthy
@ -130,5 +134,5 @@
WARN Tests\Visual\Success
s visual snapshot of test suite on success
Tests: 6 skipped, 69 passed
Time: 2.34s
Tests: 6 skipped, 71 passed
Time: 2.89s