mirror of
https://github.com/pestphp/pest.git
synced 2026-03-06 07:47:22 +01:00
Merge branch 'master' into datasets-scope
# Conflicts: # tests/.snapshots/success.txt
This commit is contained in:
@ -26,7 +26,7 @@ We would like to extend our thanks to the following sponsors for funding Pest de
|
||||
### Platinum Sponsors
|
||||
|
||||
- **[Advent](https://advent.dev)**
|
||||
- **[Localazy](https://localazy.com)**
|
||||
- **[Forge](https://forge.laravel.com)**
|
||||
- **[Spatie](https://spatie.be)**
|
||||
- **[Worksome](https://www.worksome.com/)**
|
||||
|
||||
@ -36,6 +36,7 @@ We would like to extend our thanks to the following sponsors for funding Pest de
|
||||
- [Auth0](https://auth0.com)
|
||||
- [Codecourse](https://codecourse.com/)
|
||||
- [Laracasts](https://laracasts.com/)
|
||||
- [Localazy](https://localazy.com)
|
||||
- [Hyvor](https://hyvor.com/)
|
||||
- [Fathom Analytics](https://usefathom.com/)
|
||||
- [Meema](https://meema.io)
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
"require": {
|
||||
"php": "^8.1.0",
|
||||
"nunomaduro/collision": "^7.0.0",
|
||||
"nunomaduro/termwind": "^1.14.0",
|
||||
"nunomaduro/termwind": "^1.14.2",
|
||||
"pestphp/pest-plugin": "^2.0.0",
|
||||
"phpunit/phpunit": "10.0.x-dev"
|
||||
},
|
||||
|
||||
@ -156,7 +156,7 @@ final class NameFilterIterator extends RecursiveFilterIterator
|
||||
if ($test instanceof HasPrintableTestCaseName) {
|
||||
return [
|
||||
$test::getPrintableTestCaseName(),
|
||||
$test::getPrintableTestCaseMethodName(),
|
||||
$test->getPrintableTestCaseMethodName(),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@ parameters:
|
||||
reportUnmatchedIgnoredErrors: true
|
||||
|
||||
ignoreErrors:
|
||||
- '#Cannot instantiate interface PHPUnit\\Util\\Exception#'
|
||||
- "#with a nullable type declaration#"
|
||||
- "#type mixed is not subtype of native#"
|
||||
- "#is not allowed to extend#"
|
||||
|
||||
@ -22,7 +22,12 @@ trait Testable
|
||||
/**
|
||||
* Test method description.
|
||||
*/
|
||||
private static string $__description;
|
||||
private string $__description;
|
||||
|
||||
/**
|
||||
* Test "latest" method description.
|
||||
*/
|
||||
private static string $__latestDescription;
|
||||
|
||||
/**
|
||||
* The Test Case "test" closure.
|
||||
@ -69,7 +74,7 @@ trait Testable
|
||||
|
||||
if ($test->hasMethod($name)) {
|
||||
$method = $test->getMethod($name);
|
||||
self::$__description = $method->description;
|
||||
$this->__description = self::$__latestDescription = $method->description;
|
||||
$this->__test = $method->getClosure($this);
|
||||
}
|
||||
}
|
||||
@ -169,7 +174,7 @@ trait Testable
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
self::$__description = $this->name();
|
||||
$this->__description = self::$__latestDescription = $this->name();
|
||||
|
||||
TestSuite::getInstance()->test = $this;
|
||||
|
||||
@ -221,7 +226,7 @@ trait Testable
|
||||
{
|
||||
$method = TestSuite::getInstance()->tests->get(self::$__filename)->getMethod($this->name());
|
||||
|
||||
self::$__description = $this->dataName() ? $method->description.' with '.$this->dataName() : $method->description;
|
||||
$this->__description = self::$__latestDescription = $this->dataName() ? $method->description.' with '.$this->dataName() : $method->description;
|
||||
|
||||
if (count($arguments) !== 1) {
|
||||
return $arguments;
|
||||
@ -258,7 +263,7 @@ trait Testable
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Test Case name that should be used by printers.
|
||||
* The printable test case name.
|
||||
*/
|
||||
public static function getPrintableTestCaseName(): string
|
||||
{
|
||||
@ -266,10 +271,18 @@ trait Testable
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Test Case name that should be used by printers.
|
||||
* The printable test case method name.
|
||||
*/
|
||||
public static function getPrintableTestCaseMethodName(): string
|
||||
public function getPrintableTestCaseMethodName(): string
|
||||
{
|
||||
return self::$__description;
|
||||
return $this->__description;
|
||||
}
|
||||
|
||||
/**
|
||||
* The latest printable test case method name.
|
||||
*/
|
||||
public static function getLatestPrintableTestCaseMethodName(): string
|
||||
{
|
||||
return self::$__latestDescription;
|
||||
}
|
||||
}
|
||||
|
||||
24
src/Exceptions/TestDescriptionMissing.php
Normal file
24
src/Exceptions/TestDescriptionMissing.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Pest\Exceptions;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use NunoMaduro\Collision\Contracts\RenderlessEditor;
|
||||
use NunoMaduro\Collision\Contracts\RenderlessTrace;
|
||||
use Symfony\Component\Console\Exception\ExceptionInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class TestDescriptionMissing extends InvalidArgumentException implements ExceptionInterface, RenderlessEditor, RenderlessTrace
|
||||
{
|
||||
/**
|
||||
* Creates a new Exception instance.
|
||||
*/
|
||||
public function __construct(string $fileName)
|
||||
{
|
||||
parent::__construct(sprintf('Test misses description in the filename `%s`.', $fileName));
|
||||
}
|
||||
}
|
||||
@ -161,7 +161,6 @@ final class HigherOrderExpectation
|
||||
*/
|
||||
private function getValue(): mixed
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
return $this->shouldReset ? $this->original->value : $this->expectation->value;
|
||||
}
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@ use Pest\Contracts\HasPrintableTestCaseName;
|
||||
use Pest\Exceptions\DatasetMissing;
|
||||
use Pest\Exceptions\ShouldNotHappen;
|
||||
use Pest\Exceptions\TestAlreadyExist;
|
||||
use Pest\Exceptions\TestDescriptionMissing;
|
||||
use Pest\Factories\Concerns\HigherOrderable;
|
||||
use Pest\Plugins\Environment;
|
||||
use Pest\Support\Reflection;
|
||||
@ -122,6 +123,8 @@ final class TestCaseFactory
|
||||
$rootPath = TestSuite::getInstance()->rootPath;
|
||||
$relativePath = str_replace($rootPath.DIRECTORY_SEPARATOR, '', $filename);
|
||||
|
||||
$relativePath = ltrim($relativePath, DIRECTORY_SEPARATOR);
|
||||
|
||||
$basename = basename($relativePath, '.php');
|
||||
|
||||
$dotPos = strpos($basename, '.');
|
||||
@ -208,7 +211,11 @@ final class TestCaseFactory
|
||||
|
||||
eval($classCode);
|
||||
} 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. \n %s",
|
||||
$filename,
|
||||
$classCode
|
||||
), 1, $caught);
|
||||
}
|
||||
}
|
||||
|
||||
@ -218,7 +225,7 @@ final class TestCaseFactory
|
||||
public function addMethod(TestCaseMethodFactory $method): void
|
||||
{
|
||||
if ($method->description === null) {
|
||||
throw ShouldNotHappen::fromMessage('The test description may not be empty.');
|
||||
throw new TestDescriptionMissing($method->filename);
|
||||
}
|
||||
|
||||
if (array_key_exists($method->description, $this->methods)) {
|
||||
|
||||
@ -524,7 +524,6 @@ final class Expectation
|
||||
{
|
||||
Assert::assertIsString($this->value, $message);
|
||||
|
||||
// @phpstan-ignore-next-line
|
||||
Assert::assertJson($this->value, $message);
|
||||
|
||||
return $this;
|
||||
|
||||
@ -156,7 +156,7 @@ final class DatasetsRepository
|
||||
}
|
||||
|
||||
if ($datasets[$index] instanceof Traversable) {
|
||||
$datasets[$index] = iterator_to_array($datasets[$index]);
|
||||
$datasets[$index] = iterator_to_array($datasets[$index], false);
|
||||
}
|
||||
|
||||
// @phpstan-ignore-next-line
|
||||
|
||||
@ -84,6 +84,9 @@ final class TestRepository
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the test case factory from the given filename.
|
||||
*/
|
||||
public function get(string $filename): TestCaseFactory
|
||||
{
|
||||
return $this->testCases[$filename];
|
||||
|
||||
@ -28,7 +28,9 @@ final class Backtrace
|
||||
foreach (debug_backtrace(self::BACKTRACE_OPTIONS) as $trace) {
|
||||
assert(array_key_exists(self::FILE, $trace));
|
||||
|
||||
if (Str::endsWith($trace[self::FILE], 'overrides/Runner/TestSuiteLoader.php')) {
|
||||
$traceFile = str_replace(DIRECTORY_SEPARATOR, '/', $trace[self::FILE]);
|
||||
|
||||
if (Str::endsWith($traceFile, 'overrides/Runner/TestSuiteLoader.php')) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -85,7 +85,7 @@ final class Coverage
|
||||
|
||||
$totalWidth = (new Terminal())->getWidth();
|
||||
|
||||
$dottedLineLength = $totalWidth <= 70 ? $totalWidth : 70;
|
||||
$dottedLineLength = $totalWidth - 6;
|
||||
|
||||
$totalCoverage = $codeCoverage->getReport()->percentageOfExecutedLines();
|
||||
|
||||
|
||||
@ -60,6 +60,9 @@
|
||||
--columns <n> .................... Number of columns to use for progress output
|
||||
--columns max ............ Use maximum number of columns for progress output
|
||||
--stderr ................................. Write to STDERR instead of STDOUT
|
||||
--no-progress .................... Disable output of test execution progress
|
||||
--no-results ................................ Disable output of test results
|
||||
--no-output ............................................. Disable all output
|
||||
--display-incomplete .................. Display details for incomplete tests
|
||||
--display-skipped ........................ Display details for skipped tests
|
||||
--display-deprecations . Display details for deprecations triggered by tests
|
||||
@ -68,8 +71,7 @@
|
||||
--display-warnings ......... Display details for warnings triggered by tests
|
||||
--reverse-list .............................. Print defects in reverse order
|
||||
--teamcity ............... Report test execution progress in TeamCity format
|
||||
--testdox ................. Report test execution progress in TestDox format
|
||||
--no-interaction ........................ Disable TestDox progress animation
|
||||
--testdox ............................ Report test results in TestDox format
|
||||
|
||||
LOGGING OPTIONS:
|
||||
--log-junit <file> ................ Log test execution in JUnit XML format to file
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
✓ it does not append CoversNothing to other methods
|
||||
✓ it throws exception if no class nor method has been found
|
||||
|
||||
PASS Tests\Features\DatasetsTests
|
||||
PASS Tests\Features\Datasets
|
||||
✓ it throws exception if dataset does not exist
|
||||
✓ it throws exception if dataset already exist
|
||||
✓ it sets closures
|
||||
@ -102,6 +102,11 @@
|
||||
✓ more than two datasets with (2) / (4) / (5)
|
||||
✓ more than two datasets with (2) / (4) / (6)
|
||||
✓ more than two datasets did the job right
|
||||
✓ eager registered wrapped datasets with Generator functions with (1)
|
||||
✓ eager registered wrapped datasets with Generator functions with (2)
|
||||
✓ eager registered wrapped datasets with Generator functions with (3)
|
||||
✓ eager registered wrapped datasets with Generator functions with (4)
|
||||
✓ eager registered wrapped datasets with Generator functions did the job right
|
||||
✓ it can resolve a dataset after the test case is available with (Closure Object (...)) #1
|
||||
✓ it can resolve a dataset after the test case is available with (Closure Object (...)) #2
|
||||
✓ it can resolve a dataset after the test case is available with shared yield sets with (Closure Object (...)) #1
|
||||
@ -116,7 +121,6 @@
|
||||
✓ it will not resolve a closure if it is type hinted as a callable with (Closure Object (...)) #2
|
||||
✓ it can correctly resolve a bound dataset that returns an array with (Closure Object (...))
|
||||
✓ it can correctly resolve a bound dataset that returns an array but wants to be spread with (Closure Object (...))
|
||||
↓ forbids to define tests in Datasets dirs and Datasets.php files
|
||||
|
||||
PASS Tests\Features\Depends
|
||||
✓ first
|
||||
@ -664,47 +668,6 @@
|
||||
✓ get 'foo' → get 'bar' → expect true → toBeTrue
|
||||
✓ get 'foo' → expect true → toBeTrue
|
||||
|
||||
PASS Tests\Features\ScopedDatasets\Directory\NestedDirectory1\TestFileInNestedDirectoryWithDatasetsFile
|
||||
✓ uses dataset with (1)
|
||||
✓ uses dataset with (2)
|
||||
✓ uses dataset with (3)
|
||||
✓ uses dataset with (4)
|
||||
✓ uses dataset with (5)
|
||||
✓ uses dataset with ('ScopedDatasets/NestedDirector...ts.php')
|
||||
✓ the right dataset is taken
|
||||
|
||||
PASS Tests\Features\ScopedDatasets\Directory\NestedDirectory2\TestFileInNestedDirectory
|
||||
✓ uses dataset with (1)
|
||||
✓ uses dataset with (2)
|
||||
✓ uses dataset with (3)
|
||||
✓ uses dataset with (4)
|
||||
✓ uses dataset with (5)
|
||||
✓ uses dataset with ('ScopedDatasets/Datasets/Scoped.php')
|
||||
✓ the right dataset is taken
|
||||
|
||||
PASS Tests\Features\ScopedDatasets\Directory\TestFileWithLocallyDefinedDataset
|
||||
✓ uses dataset with (1)
|
||||
✓ uses dataset with (2)
|
||||
✓ uses dataset with (3)
|
||||
✓ uses dataset with (4)
|
||||
✓ uses dataset with (5)
|
||||
✓ uses dataset with ('ScopedDatasets/ScopedDatasets.php')
|
||||
✓ the right dataset is taken
|
||||
|
||||
PASS Tests\Features\ScopedDatasets\Directory\TestFileWithScopedDataset
|
||||
✓ uses dataset with (1)
|
||||
✓ uses dataset with (2)
|
||||
✓ uses dataset with (3)
|
||||
✓ uses dataset with (4)
|
||||
✓ uses dataset with (5)
|
||||
✓ uses dataset with ('ScopedDatasets/Datasets/Scoped.php')
|
||||
✓ the right dataset is taken
|
||||
|
||||
PASS Tests\Features\ScopedDatasets\TestFileOutOfScope
|
||||
✓ uses dataset with (1)
|
||||
✓ uses dataset with (2)
|
||||
✓ the right dataset is taken
|
||||
|
||||
WARN Tests\Features\Skip
|
||||
✓ it do not skips
|
||||
- it skips with truthy → 1
|
||||
@ -803,7 +766,7 @@
|
||||
PASS Tests\Unit\Console\Help
|
||||
✓ it outputs the help information when --help is used
|
||||
|
||||
PASS Tests\Unit\DatasetsTests
|
||||
PASS Tests\Unit\Datasets
|
||||
✓ it show only the names of named datasets in their description
|
||||
✓ it show the actual dataset of non-named datasets in their description
|
||||
✓ it show only the names of multiple named datasets in their description
|
||||
@ -829,26 +792,6 @@
|
||||
✓ it can resolve builtin value types
|
||||
✓ it cannot resolve a parameter without type
|
||||
|
||||
PASS Tests\Unit\Support\DatasetInfo
|
||||
✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Datase...rs.php', true)
|
||||
✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Datasets.php', false)
|
||||
✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Featur...rs.php', true)
|
||||
✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Featur...rs.php', false)
|
||||
✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Featur...ts.php', false)
|
||||
✓ it can check if dataset is defined inside a Datasets.php file with ('/var/www/project/tests/Datase...rs.php', false)
|
||||
✓ it can check if dataset is defined inside a Datasets.php file with ('/var/www/project/tests/Datasets.php', true)
|
||||
✓ it can check if dataset is defined inside a Datasets.php file with ('/var/www/project/tests/Featur...rs.php', false) #1
|
||||
✓ it can check if dataset is defined inside a Datasets.php file with ('/var/www/project/tests/Featur...rs.php', false) #2
|
||||
✓ it can check if dataset is defined inside a Datasets.php file with ('/var/www/project/tests/Featur...ts.php', true)
|
||||
✓ it computes the dataset scope with ('/var/www/project/tests/Datase...rs.php', '/var/www/project/tests')
|
||||
✓ it computes the dataset scope with ('/var/www/project/tests/Datasets.php', '/var/www/project/tests')
|
||||
✓ it computes the dataset scope with ('/var/www/project/tests/Featur...rs.php', '/var/www/project/tests/Features')
|
||||
✓ it computes the dataset scope with ('/var/www/project/tests/Featur...rs.php', '/var/www/project/tests/Featur...rs.php') #1
|
||||
✓ it computes the dataset scope with ('/var/www/project/tests/Featur...ts.php', '/var/www/project/tests/Features')
|
||||
✓ it computes the dataset scope with ('/var/www/project/tests/Featur...rs.php', '/var/www/project/tests/Featur...ollers')
|
||||
✓ it computes the dataset scope with ('/var/www/project/tests/Featur...rs.php', '/var/www/project/tests/Featur...rs.php') #2
|
||||
✓ it computes the dataset scope with ('/var/www/project/tests/Featur...ts.php', '/var/www/project/tests/Featur...ollers')
|
||||
|
||||
PASS Tests\Unit\Support\Reflection
|
||||
✓ it gets file name from closure
|
||||
✓ it gets property values
|
||||
@ -880,4 +823,4 @@
|
||||
PASS Tests\Visual\Version
|
||||
✓ visual snapshot of help command output
|
||||
|
||||
Tests: 4 incomplete, 2 todos, 18 skipped, 611 passed (1521 assertions)
|
||||
Tests: 4 incomplete, 1 todo, 18 skipped, 567 passed (1465 assertions)
|
||||
@ -13,3 +13,20 @@ dataset('numbers.closure.wrapped', function () {
|
||||
dataset('numbers.array', [[1], [2]]);
|
||||
|
||||
dataset('numbers.array.wrapped', [1, 2]);
|
||||
|
||||
dataset('numbers.generators.wrapped', function () {
|
||||
yield from firstSetOfNumbers();
|
||||
yield from secondSetOfNumbers();
|
||||
});
|
||||
|
||||
function firstSetOfNumbers(): Generator
|
||||
{
|
||||
yield 1;
|
||||
yield 2;
|
||||
}
|
||||
|
||||
function secondSetOfNumbers(): Generator
|
||||
{
|
||||
yield 3;
|
||||
yield 4;
|
||||
}
|
||||
|
||||
@ -230,6 +230,25 @@ test('more than two datasets did the job right', function () use ($state) {
|
||||
expect($state->text)->toBe('121212121212131423241314232411122122111221221112212213142324135136145146235236245246');
|
||||
});
|
||||
|
||||
$wrapped_generator_state = new stdClass();
|
||||
$wrapped_generator_state->text = '';
|
||||
$wrapped_generator_function_datasets = [1, 2, 3, 4];
|
||||
|
||||
test(
|
||||
'eager registered wrapped datasets with Generator functions',
|
||||
function (int $text) use (
|
||||
$wrapped_generator_state,
|
||||
$wrapped_generator_function_datasets
|
||||
) {
|
||||
$wrapped_generator_state->text .= $text;
|
||||
expect(in_array($text, $wrapped_generator_function_datasets))->toBe(true);
|
||||
}
|
||||
)->with('numbers.generators.wrapped');
|
||||
|
||||
test('eager registered wrapped datasets with Generator functions did the job right', function () use ($wrapped_generator_state) {
|
||||
expect($wrapped_generator_state->text)->toBe('1234');
|
||||
});
|
||||
|
||||
it('can resolve a dataset after the test case is available', function ($result) {
|
||||
expect($result)->toBe('bar');
|
||||
})->with([
|
||||
|
||||
Reference in New Issue
Block a user