mirror of
https://github.com/pestphp/pest.git
synced 2026-03-06 07:47:22 +01:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 17d407a26a | |||
| cdc3bd3f45 | |||
| 95b4192c0d | |||
| 4c911cd0eb | |||
| bb13bdaa80 | |||
| 10e7cbe006 | |||
| 0ad232e9de | |||
| 574cd11a40 | |||
| c04d6d946d | |||
| 91eff755fd | |||
| c05d287fcc | |||
| 9133b88d65 | |||
| 93b9afbd27 | |||
| 6c6bba2a04 | |||
| dd24b7e347 | |||
| ce896b9c83 | |||
| a3c1a61b59 | |||
| 98c62f4b1d | |||
| dd78cc9a50 | |||
| 9027411004 | |||
| 9394aa4649 | |||
| 88dc74bbe4 | |||
| 7023cec432 | |||
| 99d6fb9f5f | |||
| c9f723530d |
18
CHANGELOG.md
18
CHANGELOG.md
@ -4,6 +4,24 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [v.1.3.2 (2021-06-07)](https://github.com/pestphp/pest/compare/v1.3.1...v1.3.2)
|
||||
### Fixed
|
||||
- Test cases with the @ symbol in the directory fail ([#308](https://github.com/pestphp/pest/pull/308))
|
||||
|
||||
## [v1.3.1 (2021-06-06)](https://github.com/pestphp/pest/compare/v1.3.0...v1.3.1)
|
||||
### Added
|
||||
- Added for PHPUnit 9.5.5 ([#310](https://github.com/pestphp/pest/pull/310))
|
||||
|
||||
### Changed
|
||||
- Lock minimum Pest plugin versions ([#306](https://github.com/pestphp/pest/pull/306))
|
||||
|
||||
## [v1.3.0 (2021-05-23)](https://github.com/pestphp/pest/compare/v1.2.1...v1.3.0)
|
||||
### Added
|
||||
- Named datasets no longer show the arguments ([#302](https://github.com/pestphp/pest/pull/302))
|
||||
|
||||
### Fixed
|
||||
- Wraps global functions within `function_exists` ([#300](https://github.com/pestphp/pest/pull/300))
|
||||
|
||||
## [v1.2.1 (2021-05-14)](https://github.com/pestphp/pest/compare/v1.2.0...v1.2.1)
|
||||
### Fixed
|
||||
- Laravel commands failing with new `--test-directory` option ([#297](https://github.com/pestphp/pest/pull/297))
|
||||
|
||||
@ -21,9 +21,9 @@
|
||||
"nunomaduro/collision": "^5.0",
|
||||
"pestphp/pest-plugin": "^1.0",
|
||||
"pestphp/pest-plugin-coverage": "^1.0",
|
||||
"pestphp/pest-plugin-expectations": "^1.0",
|
||||
"pestphp/pest-plugin-init": "^1.0",
|
||||
"phpunit/phpunit": ">= 9.3.7 <= 9.5.4"
|
||||
"pestphp/pest-plugin-expectations": "^1.3",
|
||||
"pestphp/pest-plugin-init": "^1.1",
|
||||
"phpunit/phpunit": ">= 9.3.7 <= 9.5.5"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
@ -46,7 +46,6 @@
|
||||
"illuminate/console": "^8.32.1",
|
||||
"illuminate/support": "^8.32.1",
|
||||
"laravel/dusk": "^6.13.0",
|
||||
"mockery/mockery": "^1.4.3",
|
||||
"pestphp/pest-dev-tools": "dev-master"
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
|
||||
@ -111,8 +111,10 @@ final class Datasets
|
||||
{
|
||||
$exporter = new Exporter();
|
||||
|
||||
$nameInsert = is_string($key) ? \sprintf('data set "%s" ', $key) : '';
|
||||
if (is_int($key)) {
|
||||
return \sprintf(' with (%s)', $exporter->shortenedRecursiveExport($data));
|
||||
}
|
||||
|
||||
return \sprintf(' with %s(%s)', $nameInsert, $exporter->shortenedRecursiveExport($data));
|
||||
return \sprintf(' with data set "%s"', $key);
|
||||
}
|
||||
}
|
||||
|
||||
24
src/Exceptions/MissingDependency.php
Normal file
24
src/Exceptions/MissingDependency.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 MissingDependency extends InvalidArgumentException implements ExceptionInterface, RenderlessEditor, RenderlessTrace
|
||||
{
|
||||
/**
|
||||
* Creates a new instance of missing dependency.
|
||||
*/
|
||||
public function __construct(string $feature, string $dependency)
|
||||
{
|
||||
parent::__construct(sprintf('The feature "%s" requires "%s".', $feature, $dependency));
|
||||
}
|
||||
}
|
||||
@ -12,95 +12,111 @@ use Pest\Support\HigherOrderTapProxy;
|
||||
use Pest\TestSuite;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* Runs the given closure before all tests in the current file.
|
||||
*/
|
||||
function beforeAll(Closure $closure): void
|
||||
{
|
||||
TestSuite::getInstance()->beforeAll->set($closure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the given closure before each test in the current file.
|
||||
*
|
||||
* @return BeforeEachCall|TestCase|mixed
|
||||
*/
|
||||
function beforeEach(Closure $closure = null): BeforeEachCall
|
||||
{
|
||||
$filename = Backtrace::file();
|
||||
|
||||
return new BeforeEachCall(TestSuite::getInstance(), $filename, $closure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the given dataset.
|
||||
*
|
||||
* @param Closure|iterable<int|string, mixed> $dataset
|
||||
*/
|
||||
function dataset(string $name, $dataset): void
|
||||
{
|
||||
Datasets::set($name, $dataset);
|
||||
}
|
||||
|
||||
/**
|
||||
* The uses function binds the given
|
||||
* arguments to test closures.
|
||||
*/
|
||||
function uses(string ...$classAndTraits): UsesCall
|
||||
{
|
||||
$filename = Backtrace::file();
|
||||
|
||||
return new UsesCall($filename, $classAndTraits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given closure as a test. The first argument
|
||||
* is the test description; the second argument is
|
||||
* a closure that contains the test expectations.
|
||||
*
|
||||
* @return TestCall|TestCase|mixed
|
||||
*/
|
||||
function test(string $description = null, Closure $closure = null)
|
||||
{
|
||||
if ($description === null && TestSuite::getInstance()->test !== null) {
|
||||
return new HigherOrderTapProxy(TestSuite::getInstance()->test);
|
||||
if (!function_exists('beforeAll')) {
|
||||
/**
|
||||
* Runs the given closure before all tests in the current file.
|
||||
*/
|
||||
function beforeAll(Closure $closure): void
|
||||
{
|
||||
TestSuite::getInstance()->beforeAll->set($closure);
|
||||
}
|
||||
|
||||
$filename = Backtrace::testFile();
|
||||
|
||||
return new TestCall(TestSuite::getInstance(), $filename, $description, $closure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given closure as a test. The first argument
|
||||
* is the test description; the second argument is
|
||||
* a closure that contains the test expectations.
|
||||
*
|
||||
* @return TestCall|TestCase|mixed
|
||||
*/
|
||||
function it(string $description, Closure $closure = null): TestCall
|
||||
{
|
||||
$description = sprintf('it %s', $description);
|
||||
if (!function_exists('beforeEach')) {
|
||||
/**
|
||||
* Runs the given closure before each test in the current file.
|
||||
*
|
||||
* @return BeforeEachCall|TestCase|mixed
|
||||
*/
|
||||
function beforeEach(Closure $closure = null): BeforeEachCall
|
||||
{
|
||||
$filename = Backtrace::file();
|
||||
|
||||
return test($description, $closure);
|
||||
return new BeforeEachCall(TestSuite::getInstance(), $filename, $closure);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the given closure after each test in the current file.
|
||||
*
|
||||
* @return AfterEachCall|TestCase|mixed
|
||||
*/
|
||||
function afterEach(Closure $closure = null): AfterEachCall
|
||||
{
|
||||
$filename = Backtrace::file();
|
||||
|
||||
return new AfterEachCall(TestSuite::getInstance(), $filename, $closure);
|
||||
if (!function_exists('dataset')) {
|
||||
/**
|
||||
* Registers the given dataset.
|
||||
*
|
||||
* @param Closure|iterable<int|string, mixed> $dataset
|
||||
*/
|
||||
function dataset(string $name, $dataset): void
|
||||
{
|
||||
Datasets::set($name, $dataset);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the given closure after all tests in the current file.
|
||||
*/
|
||||
function afterAll(Closure $closure): void
|
||||
{
|
||||
TestSuite::getInstance()->afterAll->set($closure);
|
||||
if (!function_exists('uses')) {
|
||||
/**
|
||||
* The uses function binds the given
|
||||
* arguments to test closures.
|
||||
*/
|
||||
function uses(string ...$classAndTraits): UsesCall
|
||||
{
|
||||
$filename = Backtrace::file();
|
||||
|
||||
return new UsesCall($filename, $classAndTraits);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('test')) {
|
||||
/**
|
||||
* Adds the given closure as a test. The first argument
|
||||
* is the test description; the second argument is
|
||||
* a closure that contains the test expectations.
|
||||
*
|
||||
* @return TestCall|TestCase|mixed
|
||||
*/
|
||||
function test(string $description = null, Closure $closure = null)
|
||||
{
|
||||
if ($description === null && TestSuite::getInstance()->test !== null) {
|
||||
return new HigherOrderTapProxy(TestSuite::getInstance()->test);
|
||||
}
|
||||
|
||||
$filename = Backtrace::testFile();
|
||||
|
||||
return new TestCall(TestSuite::getInstance(), $filename, $description, $closure);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('it')) {
|
||||
/**
|
||||
* Adds the given closure as a test. The first argument
|
||||
* is the test description; the second argument is
|
||||
* a closure that contains the test expectations.
|
||||
*
|
||||
* @return TestCall|TestCase|mixed
|
||||
*/
|
||||
function it(string $description, Closure $closure = null): TestCall
|
||||
{
|
||||
$description = sprintf('it %s', $description);
|
||||
|
||||
return test($description, $closure);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('afterEach')) {
|
||||
/**
|
||||
* Runs the given closure after each test in the current file.
|
||||
*
|
||||
* @return AfterEachCall|TestCase|mixed
|
||||
*/
|
||||
function afterEach(Closure $closure = null): AfterEachCall
|
||||
{
|
||||
$filename = Backtrace::file();
|
||||
|
||||
return new AfterEachCall(TestSuite::getInstance(), $filename, $closure);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('afterAll')) {
|
||||
/**
|
||||
* Runs the given closure after all tests in the current file.
|
||||
*/
|
||||
function afterAll(Closure $closure): void
|
||||
{
|
||||
TestSuite::getInstance()->afterAll->set($closure);
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ namespace Pest;
|
||||
|
||||
function version(): string
|
||||
{
|
||||
return '1.2.1';
|
||||
return '1.3.2';
|
||||
}
|
||||
|
||||
function testDirectory(string $file = ''): string
|
||||
|
||||
@ -41,7 +41,6 @@ final class AfterEachRepository
|
||||
|
||||
return ChainableClosure::from(function (): void {
|
||||
if (class_exists(Mockery::class)) {
|
||||
/* @phpstan-ignore-next-line */
|
||||
if ($container = Mockery::getContainer()) {
|
||||
/* @phpstan-ignore-next-line */
|
||||
$this->addToAssertionCount($container->mockery_getExpectationCount());
|
||||
|
||||
@ -19,6 +19,11 @@ use PHPUnit\Framework\TestCase;
|
||||
*/
|
||||
final class TestRepository
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private const SEPARATOR = '>>>';
|
||||
|
||||
/**
|
||||
* @var array<string, TestCaseFactory>
|
||||
*/
|
||||
@ -50,7 +55,7 @@ final class TestRepository
|
||||
[$classOrTraits, $groups, $hooks] = $uses;
|
||||
|
||||
$setClassName = function (TestCaseFactory $testCase, string $key) use ($path, $classOrTraits, $groups, $startsWith, $hooks): void {
|
||||
[$filename] = explode('@', $key);
|
||||
[$filename] = explode(self::SEPARATOR, $key);
|
||||
|
||||
if ((!is_dir($path) && $filename === $path) || (is_dir($path) && $startsWith($filename, $path))) {
|
||||
foreach ($classOrTraits as $class) { /** @var string $class */
|
||||
@ -131,10 +136,10 @@ final class TestRepository
|
||||
throw ShouldNotHappen::fromMessage('Trying to create a test without description.');
|
||||
}
|
||||
|
||||
if (array_key_exists(sprintf('%s@%s', $test->filename, $test->description), $this->state)) {
|
||||
if (array_key_exists(sprintf('%s%s%s', $test->filename, self::SEPARATOR, $test->description), $this->state)) {
|
||||
throw new TestAlreadyExist($test->filename, $test->description);
|
||||
}
|
||||
|
||||
$this->state[sprintf('%s@%s', $test->filename, $test->description)] = $test;
|
||||
$this->state[sprintf('%s%s%s', $test->filename, self::SEPARATOR, $test->description)] = $test;
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,8 +40,8 @@
|
||||
✓ eager wrapped registered datasets with (1)
|
||||
✓ eager wrapped registered datasets with (2)
|
||||
✓ eager registered wrapped datasets did the job right
|
||||
✓ named datasets with data set "one" (1)
|
||||
✓ named datasets with data set "two" (2)
|
||||
✓ named datasets with data set "one"
|
||||
✓ named datasets with data set "two"
|
||||
✓ named datasets did the job right
|
||||
✓ lazy named datasets with (Bar Object (...))
|
||||
✓ it creates unique test case names with ('Name 1', Pest\Plugin Object (), true) #1
|
||||
@ -63,6 +63,7 @@
|
||||
✓ it allows to call underlying protected/private methods
|
||||
✓ it throws error if method do not exist
|
||||
✓ it can forward unexpected calls to any global function
|
||||
✓ it can use helpers from helpers file
|
||||
|
||||
PASS Tests\Features\HigherOrderTests
|
||||
✓ it proxies calls to object
|
||||
@ -76,9 +77,6 @@
|
||||
✓ it can call chained macro method
|
||||
✓ it will throw exception from call if no macro exists
|
||||
|
||||
PASS Tests\Features\Mocks
|
||||
✓ it has bar
|
||||
|
||||
PASS Tests\Features\PendingHigherOrderTests
|
||||
✓ get 'foo' → get 'bar' → expect true → toBeTrue
|
||||
✓ get 'foo' → expect true → toBeTrue
|
||||
@ -124,6 +122,10 @@
|
||||
PASS Tests\PHPUnit\CustomAffixes\AdditionalFileExtensionspec
|
||||
✓ it runs file names like `AdditionalFileExtension.spec.php`
|
||||
|
||||
PASS Tests\PHPUnit\CustomAffixes\FolderWithAn\ExampleTest
|
||||
✓ custom traits can be used
|
||||
✓ trait applied in this file
|
||||
|
||||
PASS Tests\PHPUnit\CustomAffixes\ManyExtensionsclasstest
|
||||
✓ it runs file names like `ManyExtensions.class.test.php`
|
||||
|
||||
@ -170,7 +172,8 @@
|
||||
✓ it outputs the help information when --help is used
|
||||
|
||||
PASS Tests\Unit\Datasets
|
||||
✓ it show the names of named datasets in their description
|
||||
✓ it show only the names of named datasets in their description
|
||||
✓ it show the actual dataset of non-named datasets in their description
|
||||
|
||||
PASS Tests\Unit\Plugins\Version
|
||||
✓ it outputs the version when --version is used
|
||||
@ -221,5 +224,5 @@
|
||||
✓ it is a test
|
||||
✓ it uses correct parent class
|
||||
|
||||
Tests: 7 skipped, 119 passed
|
||||
Tests: 7 skipped, 122 passed
|
||||
|
||||
@ -42,3 +42,5 @@ it('throws error if method do not exist', function () {
|
||||
})->throws(\ReflectionException::class, 'Call to undefined method PHPUnit\Framework\TestCase::name()');
|
||||
|
||||
it('can forward unexpected calls to any global function')->_assertThat();
|
||||
|
||||
it('can use helpers from helpers file')->myAssertTrue(true);
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
<?php
|
||||
|
||||
use function Tests\mock;
|
||||
|
||||
interface Foo
|
||||
{
|
||||
public function bar(): int;
|
||||
}
|
||||
|
||||
it('has bar', function () {
|
||||
$mock = mock(Foo::class);
|
||||
$mock->shouldReceive('bar')
|
||||
->times(1)
|
||||
->andReturn(2);
|
||||
|
||||
$mock->bar();
|
||||
});
|
||||
@ -1,11 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use Mockery;
|
||||
use Mockery\MockInterface;
|
||||
|
||||
function mock(string $class): MockInterface
|
||||
function myAssertTrue($value)
|
||||
{
|
||||
return Mockery::mock($class);
|
||||
test()->assertTrue($value);
|
||||
}
|
||||
|
||||
19
tests/PHPUnit/CustomAffixes/FolderWithAn@/ExampleTest.php
Normal file
19
tests/PHPUnit/CustomAffixes/FolderWithAn@/ExampleTest.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
class MyCustomClassTest extends PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function assertTrueIsTrue()
|
||||
{
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
uses(MyCustomClassTest::class);
|
||||
|
||||
test('custom traits can be used', function () {
|
||||
$this->assertTrueIsTrue();
|
||||
});
|
||||
|
||||
test('trait applied in this file')->assertTrueIsTrue();
|
||||
@ -2,12 +2,22 @@
|
||||
|
||||
use Pest\Datasets;
|
||||
|
||||
it('show the names of named datasets in their description', function () {
|
||||
it('show only the names of named datasets in their description', function () {
|
||||
$descriptions = array_keys(Datasets::resolve('test description', [
|
||||
'one' => [1],
|
||||
'two' => [[2]],
|
||||
]));
|
||||
|
||||
expect($descriptions[0])->toBe('test description with data set "one" (1)');
|
||||
expect($descriptions[1])->toBe('test description with data set "two" (array(2))');
|
||||
expect($descriptions[0])->toBe('test description with data set "one"');
|
||||
expect($descriptions[1])->toBe('test description with data set "two"');
|
||||
});
|
||||
|
||||
it('show the actual dataset of non-named datasets in their description', function () {
|
||||
$descriptions = array_keys(Datasets::resolve('test description', [
|
||||
[1],
|
||||
[[2]],
|
||||
]));
|
||||
|
||||
expect($descriptions[0])->toBe('test description with (1)');
|
||||
expect($descriptions[1])->toBe('test description with (array(2))');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user