mirror of
https://github.com/pestphp/pest.git
synced 2026-03-06 07:47:22 +01:00
Merge branch 'master' into teamcity-styling
This commit is contained in:
25
CHANGELOG.md
25
CHANGELOG.md
@ -4,6 +4,31 @@ 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/).
|
||||
|
||||
## [v1.13.0 (2021-07-28)](https://github.com/pestphp/pest/compare/v1.12.0...v1.13.0)
|
||||
### Added
|
||||
- `toBeIn` expectation ([#363](https://github.com/pestphp/pest/pull/363))
|
||||
|
||||
### Fixed
|
||||
- `skip` with false condition marking test as skipped ([22b822c](https://github.com/pestphp/pest/commit/22b822ce87a3d19d84960fa5c93eb286820b525d))
|
||||
|
||||
## [v1.12.0 (2021-07-26)](https://github.com/pestphp/pest/compare/v1.11.0...v1.12.0)
|
||||
### Added
|
||||
- `--force` option to override tests in `pest:test` artisan command ([#353](https://github.com/pestphp/pest/pull/353))
|
||||
- Support for PHPUnit `^9.3.7` ([ca9d783](https://github.com/pestphp/pest/commit/ca9d783cf942a2caabc85ff7a728c7f28350c67a))
|
||||
|
||||
### Fixed
|
||||
- `beforeAll` and `afterAll` behind called multiple times per test ([#357](https://github.com/pestphp/pest/pull/357))
|
||||
|
||||
## [v1.11.0 (2021-07-21)](https://github.com/pestphp/pest/compare/v1.10.0...v1.11.0)
|
||||
### Added
|
||||
- Support for interacting with datasets in higher order tests ([#352](https://github.com/pestphp/pest/pull/352))
|
||||
|
||||
### Changed
|
||||
- The unit test stub now uses the expectation API ([#348](https://github.com/pestphp/pest/pull/348))
|
||||
|
||||
### Fixed
|
||||
- PhpStorm will no longer show 0 assertions in the output ([#349](https://github.com/pestphp/pest/pull/349))
|
||||
|
||||
## [v1.10.0 (2021-07-12)](https://github.com/pestphp/pest/compare/v1.9.1...v1.10.0)
|
||||
### Added
|
||||
- The ability to use higher order expectations inside higher order tests ([#341](https://github.com/pestphp/pest/pull/341))
|
||||
|
||||
@ -21,8 +21,10 @@ We would like to extend our thanks to the following sponsors for funding Pest de
|
||||
|
||||
### Premium Sponsors
|
||||
|
||||
- **[Scout APM](https://scoutapm.com)**
|
||||
- **[Akaunting](https://akaunting.com)**
|
||||
- **[Codecourse](https://codecourse.com/)**
|
||||
- **[Meema](https://meema.io/)**
|
||||
- **[Scout APM](https://scoutapm.com)**
|
||||
- **[Spatie](https://spatie.be/)**
|
||||
|
||||
Pest was created by **[Nuno Maduro](https://twitter.com/enunomaduro)** under the **[Sponsorware license](https://github.com/sponsorware/docs)**. It got open-sourced and is now licensed under the **[MIT license](https://opensource.org/licenses/MIT)**.
|
||||
Pest is an open-sourced software licensed under the **[MIT license](https://opensource.org/licenses/MIT)**.
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
"php": "^7.3 || ^8.0",
|
||||
"nunomaduro/collision": "^5.4.0",
|
||||
"pestphp/pest-plugin": "^1.0.0",
|
||||
"phpunit/phpunit": ">= 9.3.7 <= 9.5.6"
|
||||
"phpunit/phpunit": "^9.3.7"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
||||
@ -73,6 +73,8 @@ trait Testable
|
||||
{
|
||||
$this->__test = $test;
|
||||
$this->__description = $description;
|
||||
self::$beforeAll = null;
|
||||
self::$afterAll = null;
|
||||
|
||||
parent::__construct('__test', $data);
|
||||
}
|
||||
|
||||
36
src/Exceptions/DatasetMissing.php
Normal file
36
src/Exceptions/DatasetMissing.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Pest\Exceptions;
|
||||
|
||||
use BadFunctionCallException;
|
||||
use NunoMaduro\Collision\Contracts\RenderlessEditor;
|
||||
use NunoMaduro\Collision\Contracts\RenderlessTrace;
|
||||
use Symfony\Component\Console\Exception\ExceptionInterface;
|
||||
|
||||
/**
|
||||
* Creates a new instance of dataset is not present for test that has arguments.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class DatasetMissing extends BadFunctionCallException implements ExceptionInterface, RenderlessEditor, RenderlessTrace
|
||||
{
|
||||
/**
|
||||
* Create new exception instance.
|
||||
*
|
||||
* @param array<string, string> $args A map of argument names to their typee
|
||||
*/
|
||||
public function __construct(string $file, string $name, array $args)
|
||||
{
|
||||
parent::__construct(sprintf(
|
||||
"A test with the description '%s' has %d argument(s) ([%s]) and no dataset(s) provided in %s",
|
||||
$name,
|
||||
count($args),
|
||||
implode(', ', array_map(static function (string $arg, string $type): string {
|
||||
return sprintf('%s $%s', $type, $arg);
|
||||
}, array_keys($args), $args)),
|
||||
$file,
|
||||
));
|
||||
}
|
||||
}
|
||||
@ -371,6 +371,18 @@ final class Expectation
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the value is one of the given values.
|
||||
*
|
||||
* @param iterable<int|string, mixed> $values
|
||||
*/
|
||||
public function toBeIn(iterable $values): Expectation
|
||||
{
|
||||
Assert::assertContains($this->value, $values);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the value is infinite.
|
||||
*/
|
||||
|
||||
@ -228,4 +228,13 @@ final class TestCaseFactory
|
||||
|
||||
return $classFQN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the test case will receive argument input from Pest, or not.
|
||||
*/
|
||||
public function receivesArguments(): bool
|
||||
{
|
||||
return count($this->datasets) > 0
|
||||
|| $this->factoryProxies->count('addDependencies') > 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ final class PestTestCommand extends Command
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'pest:test {name : The name of the file} {--unit : Create a unit test} {--dusk : Create a Dusk test} {--test-directory=tests : The name of the tests directory}';
|
||||
protected $signature = 'pest:test {name : The name of the file} {--unit : Create a unit test} {--dusk : Create a Dusk test} {--test-directory=tests : The name of the tests directory} {--force : Overwrite the existing test file with the same name}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
@ -56,7 +56,7 @@ final class PestTestCommand extends Command
|
||||
File::makeDirectory(dirname($target), 0777, true, true);
|
||||
}
|
||||
|
||||
if (File::exists($target)) {
|
||||
if (File::exists($target) && !(bool) $this->option('force')) {
|
||||
throw new InvalidConsoleArgument(sprintf('%s already exist', $target));
|
||||
}
|
||||
|
||||
|
||||
@ -148,6 +148,9 @@ final class TestCall
|
||||
? $conditionOrMessage
|
||||
: $message;
|
||||
|
||||
/** @var callable(): bool $condition */
|
||||
$condition = $condition->bindTo(null);
|
||||
|
||||
$this->testCaseFactory
|
||||
->chains
|
||||
->addWhen($condition, Backtrace::file(), Backtrace::line(), 'markTestSkipped', [$message]);
|
||||
|
||||
@ -6,7 +6,7 @@ namespace Pest;
|
||||
|
||||
function version(): string
|
||||
{
|
||||
return '1.10.0';
|
||||
return '1.13.0';
|
||||
}
|
||||
|
||||
function testDirectory(string $file = ''): string
|
||||
|
||||
@ -5,11 +5,13 @@ declare(strict_types=1);
|
||||
namespace Pest\Repositories;
|
||||
|
||||
use Closure;
|
||||
use Pest\Exceptions\DatasetMissing;
|
||||
use Pest\Exceptions\ShouldNotHappen;
|
||||
use Pest\Exceptions\TestAlreadyExist;
|
||||
use Pest\Exceptions\TestCaseAlreadyInUse;
|
||||
use Pest\Exceptions\TestCaseClassOrTraitNotFound;
|
||||
use Pest\Factories\TestCaseFactory;
|
||||
use Pest\Support\Reflection;
|
||||
use Pest\Support\Str;
|
||||
use Pest\TestSuite;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
@ -140,6 +142,14 @@ final class TestRepository
|
||||
throw new TestAlreadyExist($test->filename, $test->description);
|
||||
}
|
||||
|
||||
if (!$test->receivesArguments()) {
|
||||
$arguments = Reflection::getFunctionArguments($test->test);
|
||||
|
||||
if (count($arguments) > 0) {
|
||||
throw new DatasetMissing($test->filename, $test->description, $arguments);
|
||||
}
|
||||
}
|
||||
|
||||
$this->state[sprintf('%s%s%s', $test->filename, self::SEPARATOR, $test->description)] = $test;
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@ final class HigherOrderCallables
|
||||
*/
|
||||
public function expect($value)
|
||||
{
|
||||
return new Expectation($value instanceof Closure ? Reflection::bindCallable($value) : $value);
|
||||
return new Expectation($value instanceof Closure ? Reflection::bindCallableWithData($value) : $value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -59,7 +59,7 @@ final class HigherOrderCallables
|
||||
*/
|
||||
public function tap(callable $callable)
|
||||
{
|
||||
Reflection::bindCallable($callable);
|
||||
Reflection::bindCallableWithData($callable);
|
||||
|
||||
return $this->target;
|
||||
}
|
||||
|
||||
@ -53,4 +53,20 @@ final class HigherOrderMessageCollection
|
||||
$message->call($target);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the number of messages with the given name.
|
||||
*
|
||||
* @param string $name A higher order message name (usually a method name)
|
||||
*/
|
||||
public function count(string $name): int
|
||||
{
|
||||
return array_reduce(
|
||||
$this->messages,
|
||||
static function (int $total, HigherOrderMessage $message) use ($name): int {
|
||||
return $total + (int) ($name === $message->name);
|
||||
},
|
||||
0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ use ReflectionException;
|
||||
use ReflectionFunction;
|
||||
use ReflectionNamedType;
|
||||
use ReflectionParameter;
|
||||
use ReflectionUnionType;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
@ -60,6 +61,21 @@ final class Reflection
|
||||
return Closure::fromCallable($callable)->bindTo(TestSuite::getInstance()->test)(...$args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind a callable to the TestCase and return the result,
|
||||
* passing in the current dataset values as arguments.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function bindCallableWithData(callable $callable)
|
||||
{
|
||||
$test = TestSuite::getInstance()->test;
|
||||
|
||||
return $test === null
|
||||
? static::bindCallable($callable)
|
||||
: Closure::fromCallable($callable)->bindTo($test)(...$test->getProvidedData());
|
||||
}
|
||||
|
||||
/**
|
||||
* Infers the file name from the given closure.
|
||||
*/
|
||||
@ -94,10 +110,6 @@ final class Reflection
|
||||
}
|
||||
}
|
||||
|
||||
if ($reflectionProperty === null) {
|
||||
throw ShouldNotHappen::fromMessage('Reflection property not found.');
|
||||
}
|
||||
|
||||
$reflectionProperty->setAccessible(true);
|
||||
|
||||
return $reflectionProperty->getValue($object);
|
||||
@ -128,10 +140,6 @@ final class Reflection
|
||||
}
|
||||
}
|
||||
|
||||
if ($reflectionProperty === null) {
|
||||
throw ShouldNotHappen::fromMessage('Reflection property not found.');
|
||||
}
|
||||
|
||||
$reflectionProperty->setAccessible(true);
|
||||
$reflectionProperty->setValue($object, $value);
|
||||
}
|
||||
@ -163,4 +171,37 @@ final class Reflection
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive a map of function argument names to their types.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public static function getFunctionArguments(Closure $function): array
|
||||
{
|
||||
$parameters = (new ReflectionFunction($function))->getParameters();
|
||||
$arguments = [];
|
||||
|
||||
foreach ($parameters as $parameter) {
|
||||
/** @var ReflectionNamedType|ReflectionUnionType|null $types */
|
||||
$types = ($parameter->hasType()) ? $parameter->getType() : null;
|
||||
|
||||
if (is_null($types)) {
|
||||
$arguments[$parameter->getName()] = 'mixed';
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$arguments[$parameter->getName()] = implode('|', array_map(
|
||||
static function (ReflectionNamedType $type): string {
|
||||
return $type->getName();
|
||||
},
|
||||
($types instanceof ReflectionNamedType)
|
||||
? [$types] // NOTE: normalize as list of to handle unions
|
||||
: $types->getTypes(),
|
||||
));
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,6 +101,7 @@
|
||||
✓ it gives access the the underlying expectException
|
||||
✓ it catch exceptions
|
||||
✓ it catch exceptions and messages
|
||||
✓ it can just define the message
|
||||
|
||||
PASS Tests\Features\Expect\HigherOrder\methods
|
||||
✓ it can access methods
|
||||
@ -112,11 +113,14 @@
|
||||
✓ it works with sequence
|
||||
✓ it can compose complex expectations
|
||||
✓ it can handle nested method calls
|
||||
✓ it works with higher order tests
|
||||
|
||||
PASS Tests\Features\Expect\HigherOrder\methodsAndProperties
|
||||
✓ it can access methods and properties
|
||||
✓ it can handle nested methods and properties
|
||||
✓ it works with higher order tests
|
||||
✓ it can start a new higher order expectation using the and syntax
|
||||
✓ it can start a new higher order expectation using the and syntax in higher order tests
|
||||
|
||||
PASS Tests\Features\Expect\HigherOrder\properties
|
||||
✓ it allows properties to be accessed from the value
|
||||
@ -128,6 +132,7 @@
|
||||
✓ it can compose complex expectations
|
||||
✓ it works with objects
|
||||
✓ it works with nested properties
|
||||
✓ it works with higher order tests
|
||||
|
||||
PASS Tests\Features\Expect\each
|
||||
✓ an exception is thrown if the the type is not iterable
|
||||
@ -216,6 +221,11 @@
|
||||
PASS Tests\Features\Expect\toBeGreatherThanOrEqual
|
||||
✓ passes
|
||||
✓ failures
|
||||
✓ not failures
|
||||
|
||||
PASS Tests\Features\Expect\toBeIn
|
||||
✓ passes
|
||||
✓ failures
|
||||
✓ not failures
|
||||
|
||||
PASS Tests\Features\Expect\toBeInfinite
|
||||
@ -411,7 +421,12 @@
|
||||
✓ it proxies calls to object
|
||||
✓ it is capable doing multiple assertions
|
||||
✓ it resolves expect callables correctly
|
||||
✓ does not treat method names as callables
|
||||
✓ it can tap into the test
|
||||
✓ it can 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 shared datasets into callables with (1)
|
||||
✓ it can pass shared datasets into callables with (2)
|
||||
|
||||
WARN Tests\Features\Incompleted
|
||||
… incompleted
|
||||
@ -444,6 +459,8 @@
|
||||
✓ it do not skips with falsy closure condition
|
||||
- it skips with condition and message → skipped because foo
|
||||
- it skips when skip after assertion
|
||||
- it can use something in the test case as a condition → This test was skipped
|
||||
- it can user higher order callables and skip
|
||||
|
||||
PASS Tests\Features\Test
|
||||
✓ a test
|
||||
@ -457,12 +474,14 @@
|
||||
|
||||
PASS Tests\Hooks\AfterAllTest
|
||||
✓ global afterAll execution order
|
||||
✓ it only gets called once per file
|
||||
|
||||
PASS Tests\Hooks\AfterEachTest
|
||||
✓ global afterEach execution order
|
||||
|
||||
PASS Tests\Hooks\BeforeAllTest
|
||||
✓ global beforeAll execution order
|
||||
✓ it only gets called once per file
|
||||
|
||||
PASS Tests\Hooks\BeforeEachTest
|
||||
✓ global beforeEach execution order
|
||||
@ -554,6 +573,7 @@
|
||||
|
||||
PASS Tests\Unit\TestSuite
|
||||
✓ it does not allow to add the same test description twice
|
||||
✓ it alerts users about tests with arguments but no input
|
||||
|
||||
PASS Tests\Visual\Help
|
||||
✓ visual snapshot of help command output
|
||||
@ -581,5 +601,5 @@
|
||||
✓ it is a test
|
||||
✓ it uses correct parent class
|
||||
|
||||
Tests: 4 incompleted, 7 skipped, 365 passed
|
||||
Tests: 4 incompleted, 9 skipped, 381 passed
|
||||
|
||||
16
tests/Features/Expect/toBeIn.php
Normal file
16
tests/Features/Expect/toBeIn.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
use PHPUnit\Framework\ExpectationFailedException;
|
||||
|
||||
test('passes', function () {
|
||||
expect('a')->toBeIn(['a', 'b', 'c']);
|
||||
expect('d')->not->toBeIn(['a', 'b', 'c']);
|
||||
});
|
||||
|
||||
test('failures', function () {
|
||||
expect('d')->toBeIn(['a', 'b', 'c']);
|
||||
})->throws(ExpectationFailedException::class);
|
||||
|
||||
test('not failures', function () {
|
||||
expect('a')->not->toBeIn(['a', 'b', 'c']);
|
||||
})->throws(ExpectationFailedException::class);
|
||||
@ -27,4 +27,20 @@ it('can tap into the test')
|
||||
->toBe('foo')
|
||||
->and('hello world')->toBeString();
|
||||
|
||||
it('can pass datasets into the expect callables')
|
||||
->with([[1, 2, 3]])
|
||||
->expect(function (...$numbers) { return $numbers; })->toBe([1, 2, 3])
|
||||
->and(function (...$numbers) { return $numbers; })->toBe([1, 2, 3]);
|
||||
|
||||
it('can pass datasets into the tap callable')
|
||||
->with([[1, 2, 3]])
|
||||
->tap(function (...$numbers) { expect($numbers)->toBe([1, 2, 3]); });
|
||||
|
||||
it('can pass shared datasets into callables')
|
||||
->with('numbers.closure.wrapped')
|
||||
->expect(function ($value) { return $value; })
|
||||
->and(function ($value) { return $value; })
|
||||
->tap(function ($value) { expect($value)->toBeInt(); })
|
||||
->toBeInt();
|
||||
|
||||
afterEach()->assertTrue(true);
|
||||
|
||||
@ -2,26 +2,50 @@
|
||||
|
||||
global $globalHook;
|
||||
|
||||
// NOTE: this test does not have a $globalHook->calls offset since it is first
|
||||
// in the directory and thus will always run before the others. See also the
|
||||
// BeforeAllTest.php for details.
|
||||
|
||||
uses()->afterAll(function () use ($globalHook) {
|
||||
expect($globalHook)
|
||||
->toHaveProperty('afterAll')
|
||||
->and($globalHook->afterAll)
|
||||
->toBe(0);
|
||||
->toBe(0)
|
||||
->and($globalHook->calls)
|
||||
->afterAll
|
||||
->toBe(1);
|
||||
|
||||
$globalHook->afterAll = 1;
|
||||
$globalHook->calls->afterAll++;
|
||||
});
|
||||
|
||||
afterAll(function () use ($globalHook) {
|
||||
expect($globalHook)
|
||||
->toHaveProperty('afterAll')
|
||||
->and($globalHook->afterAll)
|
||||
->toBe(1);
|
||||
->toBe(1)
|
||||
->and($globalHook->calls)
|
||||
->afterAll
|
||||
->toBe(2);
|
||||
|
||||
$globalHook->afterAll = 2;
|
||||
$globalHook->calls->afterAll++;
|
||||
});
|
||||
|
||||
test('global afterAll execution order', function () use ($globalHook) {
|
||||
expect($globalHook)
|
||||
->not()
|
||||
->toHaveProperty('afterAll');
|
||||
->toHaveProperty('afterAll')
|
||||
->and($globalHook->calls)
|
||||
->afterAll
|
||||
->toBe(0);
|
||||
});
|
||||
|
||||
it('only gets called once per file', function () use ($globalHook) {
|
||||
expect($globalHook)
|
||||
->not()
|
||||
->toHaveProperty('afterAll')
|
||||
->and($globalHook->calls)
|
||||
->afterAll
|
||||
->toBe(0);
|
||||
});
|
||||
|
||||
@ -1,28 +1,56 @@
|
||||
<?php
|
||||
|
||||
use Pest\Support\Str;
|
||||
|
||||
global $globalHook;
|
||||
|
||||
uses()->beforeAll(function () use ($globalHook) {
|
||||
// HACK: we have to determine our $globalHook->calls baseline. This is because
|
||||
// two other tests are executed before this one due to filename ordering.
|
||||
$args = $_SERVER['argv'] ?? [];
|
||||
$single = isset($args[1]) && Str::endsWith(__FILE__, $args[1]);
|
||||
$offset = $single ? 0 : 2;
|
||||
|
||||
uses()->beforeAll(function () use ($globalHook, $offset) {
|
||||
expect($globalHook)
|
||||
->toHaveProperty('beforeAll')
|
||||
->and($globalHook->beforeAll)
|
||||
->toBe(0);
|
||||
->toBe(0)
|
||||
->and($globalHook->calls)
|
||||
->beforeAll
|
||||
->toBe(1 + $offset);
|
||||
|
||||
$globalHook->beforeAll = 1;
|
||||
$globalHook->calls->beforeAll++;
|
||||
});
|
||||
|
||||
beforeAll(function () use ($globalHook) {
|
||||
beforeAll(function () use ($globalHook, $offset) {
|
||||
expect($globalHook)
|
||||
->toHaveProperty('beforeAll')
|
||||
->and($globalHook->beforeAll)
|
||||
->toBe(1);
|
||||
->toBe(1)
|
||||
->and($globalHook->calls)
|
||||
->beforeAll
|
||||
->toBe(2 + $offset);
|
||||
|
||||
$globalHook->beforeAll = 2;
|
||||
$globalHook->calls->beforeAll++;
|
||||
});
|
||||
|
||||
test('global beforeAll execution order', function () use ($globalHook) {
|
||||
test('global beforeAll execution order', function () use ($globalHook, $offset) {
|
||||
expect($globalHook)
|
||||
->toHaveProperty('beforeAll')
|
||||
->and($globalHook->beforeAll)
|
||||
->toBe(2);
|
||||
->toBe(2)
|
||||
->and($globalHook->calls)
|
||||
->beforeAll
|
||||
->toBe(3 + $offset);
|
||||
});
|
||||
|
||||
it('only gets called once per file', function () use ($globalHook, $offset) {
|
||||
expect($globalHook)
|
||||
->beforeAll
|
||||
->toBe(2)
|
||||
->and($globalHook->calls)
|
||||
->beforeAll
|
||||
->toBe(3 + $offset);
|
||||
});
|
||||
|
||||
@ -2,7 +2,8 @@
|
||||
|
||||
uses()->group('integration')->in('Visual');
|
||||
|
||||
$globalHook = (object) []; // NOTE: global test value container to be mutated and checked across files, as needed
|
||||
// NOTE: global test value container to be mutated and checked across files, as needed
|
||||
$globalHook = (object) ['calls' => (object) ['beforeAll' => 0, 'afterAll' => 0]];
|
||||
|
||||
uses()
|
||||
->beforeEach(function () {
|
||||
@ -10,11 +11,13 @@ uses()
|
||||
})
|
||||
->beforeAll(function () use ($globalHook) {
|
||||
$globalHook->beforeAll = 0;
|
||||
$globalHook->calls->beforeAll++;
|
||||
})
|
||||
->afterEach(function () {
|
||||
$this->ith = 0;
|
||||
})
|
||||
->afterAll(function () use ($globalHook) {
|
||||
$globalHook->afterAll = 0;
|
||||
$globalHook->calls->afterAll++;
|
||||
})
|
||||
->in('Hooks');
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
use Pest\Exceptions\DatasetMissing;
|
||||
use Pest\Exceptions\TestAlreadyExist;
|
||||
use Pest\TestSuite;
|
||||
|
||||
@ -7,7 +8,17 @@ it('does not allow to add the same test description twice', function () {
|
||||
$testSuite = new TestSuite(getcwd(), 'tests');
|
||||
$test = function () {};
|
||||
$testSuite->tests->set(new \Pest\Factories\TestCaseFactory(__FILE__, 'foo', $test));
|
||||
$this->expectException(TestAlreadyExist::class);
|
||||
$this->expectExceptionMessage(sprintf('A test with the description `%s` already exist in the filename `%s`.', 'foo', __FILE__));
|
||||
$testSuite->tests->set(new \Pest\Factories\TestCaseFactory(__FILE__, 'foo', $test));
|
||||
});
|
||||
})->throws(
|
||||
TestAlreadyExist::class,
|
||||
sprintf('A test with the description `%s` already exist in the filename `%s`.', 'foo', __FILE__),
|
||||
);
|
||||
|
||||
it('alerts users about tests with arguments but no input', function () {
|
||||
$testSuite = new TestSuite(getcwd(), 'tests');
|
||||
$test = function (int $arg) {};
|
||||
$testSuite->tests->set(new \Pest\Factories\TestCaseFactory(__FILE__, 'foo', $test));
|
||||
})->throws(
|
||||
DatasetMissing::class,
|
||||
sprintf("A test with the description '%s' has %d argument(s) ([%s]) and no dataset(s) provided in %s", 'foo', 1, 'int $arg', __FILE__),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user