Compare commits

...

36 Commits

Author SHA1 Message Date
918a8fc169 release: 3.6.0 2024-12-01 22:46:00 +00:00
5d32dd0641 feat: option to coverage 2024-12-01 22:45:31 +00:00
982353fb38 release: 3.5.2 2024-12-01 21:28:14 +00:00
2eefa8b88d chore: adds phpunit 11.4.4 support 2024-12-01 21:26:11 +00:00
787d5492ac chore: ignores temporary file 2024-12-01 20:41:34 +00:00
06a0bd9b0b Bumps dependencies 2024-11-21 10:46:27 +00:00
91afc81222 Updates sponsors 2024-11-09 14:20:12 +00:00
179d46ce97 release: v3.5.1 2024-10-31 12:12:45 -04:00
fa2bc1e536 chore: bumps dependencies 2024-10-31 12:12:37 -04:00
eaeb133c77 release: v3.5.0 2024-10-22 15:33:27 +01:00
cf57ea1f94 Merge pull request #1295 from jshayes/nested-describe
Support for nested describe blocks
2024-10-22 13:41:38 +01:00
0b7f4f2384 Merge pull request #1301 from faissaloux/update-tests-badge
Update tests badge to v3
2024-10-20 12:48:07 +01:00
2903a7e621 release: v3.4.2 2024-10-20 12:47:25 +01:00
b8964375c7 release: v3.4.1 2024-10-20 12:43:35 +01:00
bdcb883829 chore: bumps phpunit version 2024-10-20 12:43:28 +01:00
8a7e7f39ef update tests badge to v3 2024-10-17 02:33:25 +01:00
67f217852c chore: uses stable version of collision and termwind 2024-10-15 17:17:09 +01:00
1bad148487 release: v3.4.0 2024-10-15 15:13:19 +01:00
e24f137b8e fix: deprecation 2024-10-15 15:09:26 +01:00
6d9189f3f5 feat: php 8.4 support 2024-10-15 15:04:30 +01:00
6968094e2b Add tests 2024-10-13 10:39:17 -04:00
9510d4a2f9 Change array type hint 2024-10-13 09:54:19 -04:00
cd2eb3504b Add helper to get last element of array 2024-10-13 09:47:54 -04:00
7c639cdbbd Add more tests 2024-10-13 00:41:04 -04:00
1513ede73b release: v3.3.2 2024-10-12 12:36:44 +01:00
8c65197881 chore: bumps depndencies 2024-10-12 12:33:57 +01:00
a6cd83665c Execute all parent beforeEach and afterEach functions for each test 2024-10-11 23:51:18 -04:00
0c57142c03 Fix an issue where a describe block will prevent a beforeEach call from executing 2024-10-11 21:24:08 -04:00
3f65af9fdf Merge pull request #1292 from olivernybroe/policy-suffix
Add Policy suffix to policies
2024-10-11 09:34:05 +01:00
42d89814e3 Merge pull request #1293 from AbdellahBoutmad/dir
modify test command in contrbuting.md
2024-10-11 09:33:41 +01:00
1e3156a5b6 release: v3.3.1 2024-10-11 09:31:24 +01:00
97713c0832 chore: bumps dependencies 2024-10-11 09:31:16 +01:00
62b0e3c9df modify test command in contrbuting.md 2024-10-10 12:34:04 +01:00
647de2f1cf Add Policy suffix to policies 2024-10-10 08:08:10 +02:00
0a7bff0d24 release: v3.3.0 2024-10-06 19:25:27 +01:00
7618434580 chore: uses phpunit v11.4.0 2024-10-06 19:25:20 +01:00
45 changed files with 945 additions and 76 deletions

View File

@ -37,12 +37,7 @@ jobs:
- name: Install PHP dependencies
shell: bash
run: |
if [[ "${{ matrix.php }}" == "8.4" ]]; then
composer update --${{ matrix.dependency_version }} --no-interaction --no-progress --ansi --with="symfony/console:^${{ matrix.symfony }}" --ignore-platform-req=php
else
composer update --${{ matrix.dependency_version }} --no-interaction --no-progress --ansi --with="symfony/console:^${{ matrix.symfony }}"
fi
run: composer update --${{ matrix.dependency_version }} --no-interaction --no-progress --ansi --with="symfony/console:^${{ matrix.symfony }}"
- name: Unit Tests
run: composer test:unit
@ -51,5 +46,4 @@ jobs:
run: composer test:parallel
- name: Integration Tests
if: ${{ matrix.php != '8.4' }}
run: composer test:integration

2
.gitignore vendored
View File

@ -12,3 +12,5 @@ coverage.xml
*.swp
*.swo
.vscode/
.STREAM.md

View File

@ -42,7 +42,7 @@ composer test
Check types:
```bash
composer test:types
composer test:type:check
```
Unit tests:

View File

@ -1,7 +1,7 @@
<p align="center">
<img src="https://raw.githubusercontent.com/pestphp/art/master/v3/banner.png" width="600" alt="PEST">
<p align="center">
<a href="https://github.com/pestphp/pest/actions"><img alt="GitHub Workflow Status (master)" src="https://img.shields.io/github/actions/workflow/status/pestphp/pest/tests.yml?branch=2.x&label=Tests%202.x"></a>
<a href="https://github.com/pestphp/pest/actions"><img alt="GitHub Workflow Status (master)" src="https://img.shields.io/github/actions/workflow/status/pestphp/pest/tests.yml?branch=3.x&label=Tests%203.x"></a>
<a href="https://packagist.org/packages/pestphp/pest"><img alt="Total Downloads" src="https://img.shields.io/packagist/dt/pestphp/pest"></a>
<a href="https://packagist.org/packages/pestphp/pest"><img alt="Latest Version" src="https://img.shields.io/packagist/v/pestphp/pest"></a>
<a href="https://packagist.org/packages/pestphp/pest"><img alt="License" src="https://img.shields.io/packagist/l/pestphp/pest"></a>
@ -24,11 +24,10 @@ We cannot thank our sponsors enough for their incredible support in funding Pest
### Platinum Sponsors
- **[CodeRabbit](https://coderabbit.ai)**
- **[LaraJobs](https://larajobs.com)**
- **[Brokerchooser](https://brokerchooser.com)**
- **[Forge](https://forge.laravel.com)**
- **[Spatie](https://spatie.be)**
- **[Worksome](https://www.worksome.com/)**
### Premium Sponsors
@ -38,6 +37,8 @@ We cannot thank our sponsors enough for their incredible support in funding Pest
- [Laracasts](https://laracasts.com/?ref=pestphp)
- [Localazy](https://localazy.com/?ref=pestphp)
- [Route4Me](https://www.route4me.com/?ref=pestphp)
- [Spatie](https://spatie.be)
- [Worksome](https://www.worksome.com/)
- [Zapiet](https://www.zapiet.com/?ref=pestphp)
Pest is an open-sourced software licensed under the **[MIT license](https://opensource.org/licenses/MIT)**.

View File

@ -18,16 +18,17 @@
],
"require": {
"php": "^8.2.0",
"brianium/paratest": "^7.5.5",
"nunomaduro/collision": "^8.4.0",
"nunomaduro/termwind": "^2.1.0",
"brianium/paratest": "^7.6.0",
"nunomaduro/collision": "^8.5.0",
"nunomaduro/termwind": "^2.3.0",
"pestphp/pest-plugin": "^3.0.0",
"pestphp/pest-plugin-arch": "^3.0.0",
"pestphp/pest-plugin-mutate": "^3.0.5",
"phpunit/phpunit": "^11.3.6"
"phpunit/phpunit": "^11.4.4"
},
"conflict": {
"phpunit/phpunit": ">11.3.6",
"filp/whoops": "<2.16.0",
"phpunit/phpunit": ">11.4.4",
"sebastian/exporter": "<6.0.0",
"webmozart/assert": "<1.11.0"
},
@ -52,9 +53,9 @@
]
},
"require-dev": {
"pestphp/pest-dev-tools": "^3.0.0",
"pestphp/pest-plugin-type-coverage": "^3.0.1",
"symfony/process": "^7.1.5"
"pestphp/pest-dev-tools": "^3.3.0",
"pestphp/pest-plugin-type-coverage": "^3.2.0",
"symfony/process": "^7.1.8"
},
"minimum-stability": "dev",
"prefer-stable": true,

View File

@ -1,6 +1,5 @@
includes:
- vendor/phpstan/phpstan-strict-rules/rules.neon
- vendor/ergebnis/phpstan-rules/rules.neon
- vendor/thecodingmachine/phpstan-strict-rules/phpstan-strict-rules.neon
parameters:
@ -12,12 +11,4 @@ parameters:
reportUnmatchedIgnoredErrors: true
ignoreErrors:
- "#has a nullable return type declaration.#"
- "#Language construct isset\\(\\) should not be used.#"
- "#is not allowed to extend#"
- "#is concrete, but does not have a Test suffix#"
- "#with a nullable type declaration#"
- "#type mixed is not subtype of native#"
- "# with null as default value#"
- "#has parameter \\$closure with default value.#"
- "#has parameter \\$description with default value.#"

View File

@ -162,5 +162,9 @@ final class Laravel extends AbstractPreset
'exit',
'ray',
])->not->toBeUsed();
$this->expectations[] = expect('App\Policies')
->classes()
->toHaveSuffix('Policy');
}
}

View File

@ -18,14 +18,14 @@ final class BootOverrides implements Bootstrapper
* @var array<string, string>
*/
public const FILES = [
'c96b1cb57d7fc8e649f4c13a8abe418c2541bcfab194fb6702b99f777f52ee84' => 'Runner/Filter/NameFilterIterator.php',
'53c246e5f416a39817ac81124cdd64ea8403038d01d7a202e1ffa486fbdf3fa7' => 'Runner/Filter/NameFilterIterator.php',
'a4a43de01f641c6944ee83d963795a46d32b5206b5ab3bbc6cce76e67190acbf' => 'Runner/ResultCache/DefaultResultCache.php',
'd0e81317889ad88c707db4b08a94cadee4c9010d05ff0a759f04e71af5efed89' => 'Runner/TestSuiteLoader.php',
'3bb609b0d3bf6dee8df8d6cd62a3c8ece823c4bb941eaaae39e3cb267171b9d2' => 'TextUI/Command/Commands/WarmCodeCoverageCacheCommand.php',
'8abdad6413329c6fe0d7d44a8b9926e390af32c0b3123f3720bb9c5bbc6fbb7e' => 'TextUI/Output/Default/ProgressPrinter/Subscriber/TestSkippedSubscriber.php',
'43883b7e5811886cf3731c8ed6304d5a77078d9731e1e505abc2da36bde19f3e' => 'TextUI/TestSuiteFilterProcessor.php',
'b4250fc3ffad5954624cb5e682fd940b874e8d3422fa1ee298bd7225e1aa5fc2' => 'TextUI/TestSuiteFilterProcessor.php',
'357d5cd7007f8559b26e1b8cdf43bb6fb15b51b79db981779da6f31b7ec39dad' => 'Event/Value/ThrowableBuilder.php',
'676273f1fe483877cf2d95c5aedbf9ae5d6a8e2f4c12d6ce716df6591e6db023' => 'Logging/JUnit/JunitXmlLogger.php',
'ede161507d4c9c27805f55a05a32c3bb528e53b6e1fc092bfafdb8207e0019e9' => 'Logging/JUnit/JunitXmlLogger.php',
];
/**

View File

@ -61,8 +61,10 @@ trait Testable
/**
* The test's describing, if any.
*
* @var array<int, string>
*/
public ?string $__describing = null;
public array $__describing = [];
/**
* Whether the test has ran or not.

View File

@ -166,7 +166,7 @@ final class TestCaseFactory
}
PHP;
eval($classCode); // @phpstan-ignore-line
eval($classCode);
} catch (ParseError $caught) {
throw new RuntimeException(sprintf(
"Unable to create test case for test file at %s. \n %s",

View File

@ -31,8 +31,10 @@ final class TestCaseMethodFactory
/**
* The test's describing, if any.
*
* @var array<int, string>
*/
public ?string $describing = null;
public array $describing = [];
/**
* The test's description, if any.
@ -201,7 +203,7 @@ final class TestCaseMethodFactory
];
foreach ($this->depends as $depend) {
$depend = Str::evaluable($this->describing !== null ? Str::describe($this->describing, $depend) : $depend);
$depend = Str::evaluable($this->describing === [] ? $depend : Str::describe($this->describing, $depend));
$this->attributes[] = new Attribute(
\PHPUnit\Framework\Attributes\Depends::class,

View File

@ -43,7 +43,7 @@ if (! function_exists('beforeAll')) {
*/
function beforeAll(Closure $closure): void
{
if (! is_null(DescribeCall::describing())) {
if (DescribeCall::describing() !== []) {
$filename = Backtrace::file();
throw new BeforeAllWithinDescribe($filename);
@ -205,7 +205,7 @@ if (! function_exists('afterAll')) {
*/
function afterAll(Closure $closure): void
{
if (! is_null(DescribeCall::describing())) {
if (DescribeCall::describing() !== []) {
$filename = Backtrace::file();
throw new AfterAllWithinDescribe($filename);

View File

@ -40,7 +40,7 @@ final class KernelDump
*/
public function disable(): void
{
@ob_clean(); // @phpstan-ignore-line
@ob_clean();
if ($this->buffer !== '') {
$this->flush();

View File

@ -6,6 +6,7 @@ namespace Pest\PendingCalls;
use Closure;
use Pest\PendingCalls\Concerns\Describable;
use Pest\Support\Arr;
use Pest\Support\Backtrace;
use Pest\Support\ChainableClosure;
use Pest\Support\HigherOrderMessageCollection;
@ -54,7 +55,7 @@ final class AfterEachCall
$proxies = $this->proxies;
$afterEachTestCase = ChainableClosure::boundWhen(
fn (): bool => is_null($describing) || $this->__describing === $describing,
fn (): bool => $describing === [] || in_array(Arr::last($describing), $this->__describing, true),
ChainableClosure::bound(fn () => $proxies->chain($this), $this->closure)->bindTo($this, self::class), // @phpstan-ignore-line
)->bindTo($this, self::class);

View File

@ -7,6 +7,7 @@ namespace Pest\PendingCalls;
use Closure;
use Pest\Exceptions\AfterBeforeTestFunction;
use Pest\PendingCalls\Concerns\Describable;
use Pest\Support\Arr;
use Pest\Support\Backtrace;
use Pest\Support\ChainableClosure;
use Pest\Support\HigherOrderMessageCollection;
@ -63,12 +64,12 @@ final class BeforeEachCall
$beforeEachTestCall = function (TestCall $testCall) use ($describing): void {
if ($this->describing !== null) {
if ($describing !== $this->describing) {
if ($this->describing !== []) {
if (Arr::last($describing) !== Arr::last($this->describing)) {
return;
}
if ($describing !== $testCall->describing) {
if (! in_array(Arr::last($describing), $testCall->describing, true)) {
return;
}
}
@ -77,7 +78,7 @@ final class BeforeEachCall
};
$beforeEachTestCase = ChainableClosure::boundWhen(
fn (): bool => is_null($describing) || $this->__describing === $describing,
fn (): bool => $describing === [] || in_array(Arr::last($describing), $this->__describing, true),
ChainableClosure::bound(fn () => $testCaseProxies->chain($this), $this->closure)->bindTo($this, self::class), // @phpstan-ignore-line
)->bindTo($this, self::class);
@ -96,7 +97,7 @@ final class BeforeEachCall
*/
public function after(Closure $closure): self
{
if ($this->describing === null) {
if ($this->describing === []) {
throw new AfterBeforeTestFunction($this->filename);
}

View File

@ -11,11 +11,15 @@ trait Describable
{
/**
* Note: this is property is not used; however, it gets added automatically by rector php.
*
* @var array<int, string>
*/
public string $__describing;
public array $__describing;
/**
* The describing of the test case.
*
* @var array<int, string>
*/
public ?string $describing = null;
public array $describing = [];
}

View File

@ -15,8 +15,10 @@ final class DescribeCall
{
/**
* The current describe call.
*
* @var array<int, string>
*/
private static ?string $describing = null;
private static array $describing = [];
/**
* The describe "before each" call.
@ -37,8 +39,10 @@ final class DescribeCall
/**
* What is the current describing.
*
* @return array<int, string>
*/
public static function describing(): ?string
public static function describing(): array
{
return self::$describing;
}
@ -50,12 +54,12 @@ final class DescribeCall
{
unset($this->currentBeforeEachCall);
self::$describing = $this->description;
self::$describing[] = $this->description;
try {
($this->tests)();
} finally {
self::$describing = null;
array_pop(self::$describing);
}
}
@ -71,7 +75,7 @@ final class DescribeCall
if (! $this->currentBeforeEachCall instanceof \Pest\PendingCalls\BeforeEachCall) {
$this->currentBeforeEachCall = new BeforeEachCall(TestSuite::getInstance(), $filename);
$this->currentBeforeEachCall->describing = $this->description;
$this->currentBeforeEachCall->describing[] = $this->description;
}
$this->currentBeforeEachCall->{$name}(...$arguments); // @phpstan-ignore-line

View File

@ -76,7 +76,7 @@ final class TestCall // @phpstan-ignore-line
throw new TestDescriptionMissing($this->filename);
}
$description = is_null($this->describing)
$description = $this->describing === []
? $this->description
: Str::describe($this->describing, $this->description);
@ -683,7 +683,7 @@ final class TestCall // @phpstan-ignore-line
throw new TestDescriptionMissing($this->filename);
}
if (! is_null($this->describing)) {
if ($this->describing !== []) {
$this->testCaseMethod->describing = $this->describing;
$this->testCaseMethod->description = Str::describe($this->describing, $this->description);
} else {

View File

@ -6,7 +6,7 @@ namespace Pest;
function version(): string
{
return '3.2.5';
return '3.6.0';
}
function testDirectory(string $file = ''): string

View File

@ -27,6 +27,11 @@ final class Coverage implements AddsOutput, HandlesArguments
*/
private const MIN_OPTION = 'min';
/**
* @var string
*/
private const EXACTLY_OPTION = 'exactly';
/**
* Whether it should show the coverage or not.
*/
@ -37,6 +42,11 @@ final class Coverage implements AddsOutput, HandlesArguments
*/
public float $coverageMin = 0.0;
/**
* The exactly coverage.
*/
public ?float $coverageExactly = null;
/**
* Creates a new Plugin instance.
*/
@ -51,7 +61,7 @@ final class Coverage implements AddsOutput, HandlesArguments
public function handleArguments(array $originals): array
{
$arguments = [...[''], ...array_values(array_filter($originals, function (string $original): bool {
foreach ([self::COVERAGE_OPTION, self::MIN_OPTION] as $option) {
foreach ([self::COVERAGE_OPTION, self::MIN_OPTION, self::EXACTLY_OPTION] as $option) {
if ($original === sprintf('--%s', $option)) {
return true;
}
@ -73,6 +83,7 @@ final class Coverage implements AddsOutput, HandlesArguments
$inputs = [];
$inputs[] = new InputOption(self::COVERAGE_OPTION, null, InputOption::VALUE_NONE);
$inputs[] = new InputOption(self::MIN_OPTION, null, InputOption::VALUE_REQUIRED);
$inputs[] = new InputOption(self::EXACTLY_OPTION, null, InputOption::VALUE_REQUIRED);
$input = new ArgvInput($arguments, new InputDefinition($inputs));
if ((bool) $input->getOption(self::COVERAGE_OPTION)) {
@ -106,6 +117,13 @@ final class Coverage implements AddsOutput, HandlesArguments
$this->coverageMin = (float) $minOption;
}
if ($input->getOption(self::EXACTLY_OPTION) !== null) {
/** @var int|float $exactlyOption */
$exactlyOption = $input->getOption(self::EXACTLY_OPTION);
$this->coverageExactly = (float) $exactlyOption;
}
return $originals;
}
@ -127,10 +145,22 @@ final class Coverage implements AddsOutput, HandlesArguments
}
$coverage = \Pest\Support\Coverage::report($this->output);
$exitCode = (int) ($coverage < $this->coverageMin);
if ($exitCode === 1) {
if ($exitCode === 0 && $this->coverageExactly !== null) {
$comparableCoverage = $this->computeComparableCoverage($coverage);
$comparableCoverageExactly = $this->computeComparableCoverage($this->coverageExactly);
$exitCode = $comparableCoverage === $comparableCoverageExactly ? 0 : 1;
if ($exitCode === 1) {
$this->output->writeln(sprintf(
"\n <fg=white;bg=red;options=bold> FAIL </> Code coverage not exactly <fg=white;options=bold> %s %%</>, currently <fg=red;options=bold> %s %%</>.",
number_format($this->coverageExactly, 1),
number_format(floor($coverage * 10) / 10, 1),
));
}
} elseif ($exitCode === 1) {
$this->output->writeln(sprintf(
"\n <fg=white;bg=red;options=bold> FAIL </> Code coverage below expected <fg=white;options=bold> %s %%</>, currently <fg=red;options=bold> %s %%</>.",
number_format($this->coverageMin, 1),
@ -143,4 +173,12 @@ final class Coverage implements AddsOutput, HandlesArguments
return $exitCode;
}
/**
* Computes the comparable coverage to a percentage with one decimal.
*/
private function computeComparableCoverage(float $coverage): float
{
return floor($coverage * 10) / 10;
}
}

View File

@ -81,4 +81,14 @@ final class Arr
return $results;
}
/**
* Returns the value of the last element or false for empty array
*
* @param array<array-key, mixed> $array
*/
public static function last(array $array): mixed
{
return end($array);
}
}

View File

@ -103,10 +103,14 @@ final class Str
/**
* Creates a describe block as `$describeDescription` → `$testDescription` format.
*
* @param array<int, string> $describeDescriptions
*/
public static function describe(string $describeDescription, string $testDescription): string
public static function describe(array $describeDescriptions, string $testDescription): string
{
return sprintf('`%s` → %s', $describeDescription, $testDescription);
$descriptionComponents = [...$describeDescriptions, $testDescription];
return sprintf(str_repeat('`%s` → ', count($describeDescriptions)).'%s', ...$descriptionComponents);
}
/**

View File

@ -1,5 +1,5 @@
Pest Testing Framework 3.2.5.
Pest Testing Framework 3.5.2.
USAGE: pest <file> [options]
@ -35,6 +35,7 @@
--exclude-group [name] ........... Exclude tests from the specified group(s)
--covers [name] ................. Only run tests that intend to cover [name]
--uses [name] ..................... Only run tests that intend to use [name]
--requires-php-extension [name] Only run tests that require PHP extension [name]
--list-test-files ................................ List available test files
--list-tests .......................................... List available tests
--list-tests-xml [file] ................. List available tests in XML format

View File

@ -15,7 +15,7 @@
↓ todo on describe → should not fail
↓ todo on describe → should run
TODO Tests\Features\Todo - 7 todos
TODO Tests\Features\Todo - 28 todos
↓ something todo later
↓ something todo later chained
↓ something todo later chained and with function body
@ -24,6 +24,52 @@
↓ it may have an associated PR #1
↓ it may have an associated note
// a note
↓ todo on describe → todo block → nested inside todo block → it should not execute
↓ todo on describe → todo block → nested inside todo block → it should set the note
// hi
↓ todo on describe → todo block → describe with note → it should apply the note to a test without a todo
// describe note
↓ todo on describe → todo block → describe with note → it should apply the note to a test with a todo
// describe note
↓ todo on describe → todo block → describe with note → it should apply the note as well as the note from the test
// describe note
// test note
↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes to a test without a todo
// describe note
// nested describe note
↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes to a test with a todo
// describe note
// nested describe note
↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes as well as the note from the test
// describe note
// nested describe note
// test note
↓ todo on describe → todo block → it should not execute
↓ todo on test after describe block
↓ todo with note on test after describe block
// test note
↓ todo on beforeEach → todo block → nested inside todo block → it should not execute
↓ todo on beforeEach → todo block → describe with note → it should apply the note to a test without a todo
// describe note
↓ todo on beforeEach → todo block → describe with note → it should apply the note to a test with a todo
// describe note
↓ todo on beforeEach → todo block → describe with note → it should apply the note as well as the note from the test
// describe note
// test note
↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes to a test without a todo
// describe note
// nested describe note
↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes to a test with a todo
// describe note
// nested describe note
↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes as well as the note from the test
// describe note
// nested describe note
// test note
↓ todo on beforeEach → todo block → it should not execute
↓ todo on test after describe block with beforeEach
↓ todo with note on test after describe block with beforeEach
// test note
PASS Tests\CustomTestCase\ChildTest
✓ override method
@ -34,6 +80,6 @@
PASS Tests\CustomTestCase\ParentTest
✓ override method
Tests: 17 todos, 3 passed (3 assertions)
Tests: 38 todos, 3 passed (20 assertions)
Duration: x.xxs

View File

@ -15,7 +15,7 @@
↓ todo on describe → should not fail
↓ todo on describe → should run
TODO Tests\Features\Todo - 7 todos
TODO Tests\Features\Todo - 28 todos
↓ something todo later
↓ something todo later chained
↓ something todo later chained and with function body
@ -24,6 +24,52 @@
↓ it may have an associated PR #1
↓ it may have an associated note
// a note
↓ todo on describe → todo block → nested inside todo block → it should not execute
↓ todo on describe → todo block → nested inside todo block → it should set the note
// hi
↓ todo on describe → todo block → describe with note → it should apply the note to a test without a todo
// describe note
↓ todo on describe → todo block → describe with note → it should apply the note to a test with a todo
// describe note
↓ todo on describe → todo block → describe with note → it should apply the note as well as the note from the test
// describe note
// test note
↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes to a test without a todo
// describe note
// nested describe note
↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes to a test with a todo
// describe note
// nested describe note
↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes as well as the note from the test
// describe note
// nested describe note
// test note
↓ todo on describe → todo block → it should not execute
↓ todo on test after describe block
↓ todo with note on test after describe block
// test note
↓ todo on beforeEach → todo block → nested inside todo block → it should not execute
↓ todo on beforeEach → todo block → describe with note → it should apply the note to a test without a todo
// describe note
↓ todo on beforeEach → todo block → describe with note → it should apply the note to a test with a todo
// describe note
↓ todo on beforeEach → todo block → describe with note → it should apply the note as well as the note from the test
// describe note
// test note
↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes to a test without a todo
// describe note
// nested describe note
↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes to a test with a todo
// describe note
// nested describe note
↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes as well as the note from the test
// describe note
// nested describe note
// test note
↓ todo on beforeEach → todo block → it should not execute
↓ todo on test after describe block with beforeEach
↓ todo with note on test after describe block with beforeEach
// test note
PASS Tests\CustomTestCase\ChildTest
✓ override method
@ -34,6 +80,6 @@
PASS Tests\CustomTestCase\ParentTest
✓ override method
Tests: 17 todos, 3 passed (3 assertions)
Tests: 38 todos, 3 passed (20 assertions)
Duration: x.xxs

View File

@ -15,7 +15,7 @@
↓ todo on describe → should not fail
↓ todo on describe → should run
TODO Tests\Features\Todo - 7 todos
TODO Tests\Features\Todo - 28 todos
↓ something todo later
↓ something todo later chained
↓ something todo later chained and with function body
@ -24,6 +24,52 @@
↓ it may have an associated PR #1
↓ it may have an associated note
// a note
↓ todo on describe → todo block → nested inside todo block → it should not execute
↓ todo on describe → todo block → nested inside todo block → it should set the note
// hi
↓ todo on describe → todo block → describe with note → it should apply the note to a test without a todo
// describe note
↓ todo on describe → todo block → describe with note → it should apply the note to a test with a todo
// describe note
↓ todo on describe → todo block → describe with note → it should apply the note as well as the note from the test
// describe note
// test note
↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes to a test without a todo
// describe note
// nested describe note
↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes to a test with a todo
// describe note
// nested describe note
↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes as well as the note from the test
// describe note
// nested describe note
// test note
↓ todo on describe → todo block → it should not execute
↓ todo on test after describe block
↓ todo with note on test after describe block
// test note
↓ todo on beforeEach → todo block → nested inside todo block → it should not execute
↓ todo on beforeEach → todo block → describe with note → it should apply the note to a test without a todo
// describe note
↓ todo on beforeEach → todo block → describe with note → it should apply the note to a test with a todo
// describe note
↓ todo on beforeEach → todo block → describe with note → it should apply the note as well as the note from the test
// describe note
// test note
↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes to a test without a todo
// describe note
// nested describe note
↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes to a test with a todo
// describe note
// nested describe note
↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes as well as the note from the test
// describe note
// nested describe note
// test note
↓ todo on beforeEach → todo block → it should not execute
↓ todo on test after describe block with beforeEach
↓ todo with note on test after describe block with beforeEach
// test note
PASS Tests\CustomTestCase\ChildTest
✓ override method
@ -34,6 +80,6 @@
PASS Tests\CustomTestCase\ParentTest
✓ override method
Tests: 17 todos, 3 passed (3 assertions)
Tests: 38 todos, 3 passed (20 assertions)
Duration: x.xxs

View File

@ -15,7 +15,7 @@
↓ todo on describe → should not fail
↓ todo on describe → should run
TODO Tests\Features\Todo - 7 todos
TODO Tests\Features\Todo - 28 todos
↓ something todo later
↓ something todo later chained
↓ something todo later chained and with function body
@ -24,6 +24,52 @@
↓ it may have an associated PR #1
↓ it may have an associated note
// a note
↓ todo on describe → todo block → nested inside todo block → it should not execute
↓ todo on describe → todo block → nested inside todo block → it should set the note
// hi
↓ todo on describe → todo block → describe with note → it should apply the note to a test without a todo
// describe note
↓ todo on describe → todo block → describe with note → it should apply the note to a test with a todo
// describe note
↓ todo on describe → todo block → describe with note → it should apply the note as well as the note from the test
// describe note
// test note
↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes to a test without a todo
// describe note
// nested describe note
↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes to a test with a todo
// describe note
// nested describe note
↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes as well as the note from the test
// describe note
// nested describe note
// test note
↓ todo on describe → todo block → it should not execute
↓ todo on test after describe block
↓ todo with note on test after describe block
// test note
↓ todo on beforeEach → todo block → nested inside todo block → it should not execute
↓ todo on beforeEach → todo block → describe with note → it should apply the note to a test without a todo
// describe note
↓ todo on beforeEach → todo block → describe with note → it should apply the note to a test with a todo
// describe note
↓ todo on beforeEach → todo block → describe with note → it should apply the note as well as the note from the test
// describe note
// test note
↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes to a test without a todo
// describe note
// nested describe note
↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes to a test with a todo
// describe note
// nested describe note
↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes as well as the note from the test
// describe note
// nested describe note
// test note
↓ todo on beforeEach → todo block → it should not execute
↓ todo on test after describe block with beforeEach
↓ todo with note on test after describe block with beforeEach
// test note
PASS Tests\CustomTestCase\ChildTest
✓ override method
@ -34,6 +80,6 @@
PASS Tests\CustomTestCase\ParentTest
✓ override method
Tests: 17 todos, 3 passed (3 assertions)
Tests: 38 todos, 3 passed (20 assertions)
Duration: x.xxs

View File

@ -1,3 +1,3 @@
Pest Testing Framework 3.2.5.
Pest Testing Framework 3.5.2.

View File

@ -27,6 +27,8 @@
PASS Tests\Features\AfterEach
✓ it does not get executed before the test
✓ it gets executed after the test
✓ outer → inner → it does not get executed before the test
✓ outer → inner → it should call all parent afterEach functions
PASS Tests\Features\Assignee
✓ it may be associated with an assignee [@nunomaduro, @taylorotwell]
@ -40,6 +42,9 @@
PASS Tests\Features\BeforeEach
✓ it gets executed before each test
✓ it gets executed before each test once again
✓ outer → inner → it should call all parent beforeEach functions
✓ with expectations → nested block → test
✓ with expectations → test
PASS Tests\Features\BeforeEachProxiesToTestCallWithExpectations
✓ runs 1
@ -178,6 +183,14 @@
✓ it may be used with high order with dataset "informal"
✓ it may be used with high order even when bound with dataset "formal"
✓ it may be used with high order even when bound with dataset "informal"
✓ with on nested describe → nested → before inner describe block with (1)
✓ with on nested describe → nested → describe → it should include the with value from all parent describe blocks with (1) / (2)
✓ with on nested describe → nested → describe → should include the with value from all parent describe blocks and the test with (1) / (2) / (3)
✓ with on nested describe → nested → after inner describe block with (1)
✓ after describe block with (5)
✓ it may be used with high order after describe block with dataset "formal"
✓ it may be used with high order after describe block with dataset "informal"
✓ after describe block with named dataset with ('after')
PASS Tests\Features\Depends
✓ first
@ -188,6 +201,13 @@
✓ depends run test only once
✓ it asserts true is true
✓ depends works with the correct test name
✓ describe block → first in describe
✓ describe block → second in describe
✓ describe block → third in describe
✓ describe block → nested describe → first in nested describe
✓ describe block → nested describe → second in nested describe
✓ describe block → nested describe → third in nested describe
✓ depends on test after describe block
PASS Tests\Features\DependsInheritance
✓ it is a test
@ -215,6 +235,7 @@
✓ depends on describe → bar
✓ depends on describe using with → foo with (3)
✓ depends on describe using with → bar with (3)
✓ with test after describe → it should run the before each
PASS Tests\Features\DescriptionLess
✓ get 'foo'
@ -1067,9 +1088,22 @@
✓ nested → it may have static note and runtime note
// This is before each static note
// This is describe static note
// This is before each describe static note
// This is a static note within describe
// This is before each runtime note
// This is before each describe runtime note
// This is a runtime note within describe
✓ nested → describe nested within describe → it may have a static note and runtime note
// This is before each static note
// This is describe static note
// This is before each describe static note
// This is a nested describe static note
// This is before each nested describe static note
// This is a static note within a nested describe
// This is before each runtime note
// This is before each describe runtime note
// This is before each nested describe runtime note
// This is a runtime note within a nested describe
✓ multiple notes
// This is before each static note
// This is before each runtime note
@ -1199,6 +1233,23 @@
✓ multiple times with repeat iterator with multiple dataset ('c') / ('d') @ repetition 2 of 2
✓ multiple times with repeat iterator with multiple dataset ('c') / ('e') @ repetition 2 of 2
✓ multiple times with repeat iterator with multiple dataset ('c') / ('f') @ repetition 2 of 2
✓ describe blocks → multiple times @ repetition 1 of 3
✓ describe blocks → multiple times @ repetition 2 of 3
✓ describe blocks → multiple times @ repetition 3 of 3
✓ describe blocks → describe with repeat → test with no repeat should repeat the number of times specified in the parent describe block @ repetition 1 of 3
✓ describe blocks → describe with repeat → test with no repeat should repeat the number of times specified in the parent describe block @ repetition 2 of 3
✓ describe blocks → describe with repeat → test with no repeat should repeat the number of times specified in the parent describe block @ repetition 3 of 3
✓ describe blocks → describe with repeat → test with repeat should repeat the number of times specified in the test @ repetition 1 of 2
✓ describe blocks → describe with repeat → test with repeat should repeat the number of times specified in the test @ repetition 2 of 2
✓ describe blocks → describe with repeat → nested describe without repeat → test with no repeat should repeat the number of times specified in the parent's parent describe block @ repetition 1 of 3
✓ describe blocks → describe with repeat → nested describe without repeat → test with no repeat should repeat the number of times specified in the parent's parent describe block @ repetition 2 of 3
✓ describe blocks → describe with repeat → nested describe without repeat → test with no repeat should repeat the number of times specified in the parent's parent describe block @ repetition 3 of 3
✓ describe blocks → describe with repeat → nested describe without repeat → test with repeat should repeat the number of times specified in the test @ repetition 1 of 2
✓ describe blocks → describe with repeat → nested describe without repeat → test with repeat should repeat the number of times specified in the test @ repetition 2 of 2
✓ describe blocks → describe with repeat → nested describe with repeat → test with no repeat should repeat the number of times specified in the parent describe block @ repetition 1 of 2
✓ describe blocks → describe with repeat → nested describe with repeat → test with no repeat should repeat the number of times specified in the parent describe block @ repetition 2 of 2
✓ describe blocks → describe with repeat → nested describe with repeat → test with repeat should repeat the number of times specified in the test @ repetition 1 of 2
✓ describe blocks → describe with repeat → nested describe with repeat → test with repeat should repeat the number of times specified in the test @ repetition 2 of 2
PASS Tests\Features\ScopedDatasets\Directory\NestedDirectory1\TestFileInNestedDirectoryWithDatasetsFile
✓ uses dataset with (1)
@ -1255,6 +1306,14 @@
- 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
- skip on describe → skipped tests → nested inside skipped block → it should not execute
- skip on describe → skipped tests → it should not execute
✓ skip on describe → it should execute
- skip on beforeEach → skipped tests → nested inside skipped block → it should not execute
- skip on beforeEach → skipped tests → it should not execute
✓ skip on beforeEach → it should execute
✓ it does not skip after the describe block
- it can skip after the describe block
WARN Tests\Features\SkipOnPhp
✓ it can run on php version
@ -1275,7 +1334,7 @@
✓ nested → it may be associated with an ticket #1, #4, #5, #6, #3
// an note between an the ticket
PASS Tests\Features\Todo - 7 todos
PASS Tests\Features\Todo - 28 todos
↓ something todo later
↓ something todo later chained
↓ something todo later chained and with function body
@ -1285,6 +1344,54 @@
↓ it may have an associated PR #1
↓ it may have an associated note
// a note
↓ todo on describe → todo block → nested inside todo block → it should not execute
↓ todo on describe → todo block → nested inside todo block → it should set the note
// hi
↓ todo on describe → todo block → describe with note → it should apply the note to a test without a todo
// describe note
↓ todo on describe → todo block → describe with note → it should apply the note to a test with a todo
// describe note
↓ todo on describe → todo block → describe with note → it should apply the note as well as the note from the test
// describe note
// test note
↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes to a test without a todo
// describe note
// nested describe note
↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes to a test with a todo
// describe note
// nested describe note
↓ todo on describe → todo block → describe with note → nested describe with note → it should apply all parent notes as well as the note from the test
// describe note
// nested describe note
// test note
↓ todo on describe → todo block → it should not execute
✓ todo on describe → it should execute
↓ todo on test after describe block
↓ todo with note on test after describe block
// test note
↓ todo on beforeEach → todo block → nested inside todo block → it should not execute
↓ todo on beforeEach → todo block → describe with note → it should apply the note to a test without a todo
// describe note
↓ todo on beforeEach → todo block → describe with note → it should apply the note to a test with a todo
// describe note
↓ todo on beforeEach → todo block → describe with note → it should apply the note as well as the note from the test
// describe note
// test note
↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes to a test without a todo
// describe note
// nested describe note
↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes to a test with a todo
// describe note
// nested describe note
↓ todo on beforeEach → todo block → describe with note → nested describe with note → it should apply all parent notes as well as the note from the test
// describe note
// nested describe note
// test note
↓ todo on beforeEach → todo block → it should not execute
✓ todo on beforeEach → it should execute
↓ todo on test after describe block with beforeEach
↓ todo with note on test after describe block with beforeEach
// test note
WARN Tests\Features\Warnings
! warning → Undefined property: P\Tests\Features\Warnings::$fooqwdfwqdfqw
@ -1433,6 +1540,13 @@
✓ preset invalid name
✓ preset → myFramework
PASS Tests\Unit\Support\Arr
✓ last → it should return false for an empty arary
✓ last → it should return the last element for an array with a single element
✓ last → it should return the last element for an array without changing the internal pointer
✓ last → it should return the last element for an associative array without changing the internal pointer
✓ last → it should return the last element for an mixed key array without changing the internal pointer
PASS Tests\Unit\Support\Backtrace
✓ it gets file name from called file
@ -1584,4 +1698,4 @@
WARN Tests\Visual\Version
- visual snapshot of help command output
Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 17 todos, 28 skipped, 1095 passed (2648 assertions)
Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 38 todos, 24 skipped, 1142 passed (2720 assertions)

View File

@ -26,3 +26,25 @@ it('gets executed after the test', function () {
afterEach(function () {
$this->state->bar = 2;
});
describe('outer', function () {
afterEach(function () {
$this->state->bar++;
});
describe('inner', function () {
afterEach(function () {
$this->state->bar++;
});
it('does not get executed before the test', function () {
expect($this->state)->toHaveProperty('bar');
expect($this->state->bar)->toBe(2);
});
it('should call all parent afterEach functions', function () {
expect($this->state)->toHaveProperty('bar');
expect($this->state->bar)->toBe(4);
});
});
});

View File

@ -25,3 +25,29 @@ it('gets executed before each test once again', function () {
beforeEach(function () {
$this->bar++;
});
describe('outer', function () {
beforeEach(function () {
$this->bar++;
});
describe('inner', function () {
beforeEach(function () {
$this->bar++;
});
it('should call all parent beforeEach functions', function () {
expect($this->bar)->toBe(3);
});
});
});
describe('with expectations', function () {
beforeEach()->expect(true)->toBeTrue();
describe('nested block', function () {
test('test', function () {});
});
test('test', function () {});
});

View File

@ -392,3 +392,40 @@ it('may be used with high order even when bound')
->with('greeting-bound')
->expect(fn (string $greeting) => $greeting)
->throws(InvalidArgumentException::class);
describe('with on nested describe', function () {
describe('nested', function () {
test('before inner describe block', function (...$args) {
expect($args)->toBe([1]);
});
describe('describe', function () {
it('should include the with value from all parent describe blocks', function (...$args) {
expect($args)->toBe([1, 2]);
});
test('should include the with value from all parent describe blocks and the test', function (...$args) {
expect($args)->toBe([1, 2, 3]);
})->with([3]);
})->with([2]);
test('after inner describe block', function (...$args) {
expect($args)->toBe([1]);
});
})->with([1]);
});
test('after describe block', function (...$args) {
expect($args)->toBe([5]);
})->with([5]);
it('may be used with high order after describe block')
->with('greeting-string')
->expect(fn (string $greeting) => $greeting)
->throwsNoExceptions();
dataset('after-describe', ['after']);
test('after describe block with named dataset', function (...$args) {
expect($args)->toBe(['after']);
})->with('after-describe');

View File

@ -36,3 +36,43 @@ test('depends run test only once', function () use (&$runCounter) {
// Regression tests. See https://github.com/pestphp/pest/pull/216
it('asserts true is true')->assertTrue(true);
test('depends works with the correct test name')->assertTrue(true)->depends('it asserts true is true');
describe('describe block', function () {
$runCounter = 0;
test('first in describe', function () use (&$runCounter) {
$runCounter++;
expect(true)->toBeTrue();
});
test('second in describe', function () use (&$runCounter) {
expect($runCounter)->toBe(1);
$runCounter++;
})->depends('first in describe');
test('third in describe', function () use (&$runCounter) {
expect($runCounter)->toBe(2);
})->depends('second in describe');
describe('nested describe', function () {
$runCounter = 0;
test('first in nested describe', function () use (&$runCounter) {
$runCounter++;
expect(true)->toBeTrue();
});
test('second in nested describe', function () use (&$runCounter) {
expect($runCounter)->toBe(1);
$runCounter++;
})->depends('first in nested describe');
test('third in nested describe', function () use (&$runCounter) {
expect($runCounter)->toBe(2);
})->depends('second in nested describe');
});
});
test('depends on test after describe block', function () use (&$runCounter) {
expect($runCounter)->toBe(2);
})->depends('first', 'second');

View File

@ -96,3 +96,15 @@ describe('depends on describe using with', function () {
expect($foo + $foo)->toBe(6);
})->depends('foo');
})->with([3]);
describe('with test after describe', function () {
beforeEach(function () {
$this->count++;
});
describe('foo', function () {});
it('should run the before each', function () {
expect($this->count)->toBe(2);
});
});

View File

@ -21,11 +21,27 @@ it('may have static note and runtime note', function () {
})->note('This is a static note');
describe('nested', function () {
beforeEach(function () {
$this->note('This is before each describe runtime note');
})->note('This is before each describe static note');
it('may have static note and runtime note', function () {
expect(true)->toBeTrue(true);
$this->note('This is a runtime note within describe');
})->note('This is a static note within describe');
describe('describe nested within describe', function () {
beforeEach(function () {
$this->note('This is before each nested describe runtime note');
})->note('This is before each nested describe static note');
it('may have a static note and runtime note', function () {
expect(true)->toBeTrue(true);
$this->note('This is a runtime note within a nested describe');
})->note('This is a static note within a nested describe');
})->note('This is a nested describe static note');
})->note('This is describe static note');
test('multiple notes', function () {

View File

@ -43,3 +43,39 @@ test('multiple times with repeat iterator with multiple dataset', function (stri
->toBeNumeric()
->toBeGreaterThan(0);
})->repeat(times: 2)->with(['a', 'b', 'c'], ['d', 'e', 'f']);
describe('describe blocks', function () {
test('multiple times', function () {
expect(true)->toBeTrue();
})->repeat(times: 3);
describe('describe with repeat', function () {
test('test with no repeat should repeat the number of times specified in the parent describe block', function () {
expect(true)->toBeTrue();
});
test('test with repeat should repeat the number of times specified in the test', function () {
expect(true)->toBeTrue();
})->repeat(times: 2);
describe('nested describe without repeat', function () {
test("test with no repeat should repeat the number of times specified in the parent's parent describe block", function () {
expect(true)->toBeTrue();
});
test('test with repeat should repeat the number of times specified in the test', function () {
expect(true)->toBeTrue();
})->repeat(times: 2);
});
describe('nested describe with repeat', function () {
test('test with no repeat should repeat the number of times specified in the parent describe block', function () {
expect(true)->toBeTrue();
});
test('test with repeat should repeat the number of times specified in the test', function () {
expect(true)->toBeTrue();
})->repeat(times: 2);
})->repeat(times: 2);
})->repeat(times: 3);
});

View File

@ -54,3 +54,81 @@ it('can user higher order callables and skip')
return $this->shouldSkip;
})
->toBeFalse();
describe('skip on describe', function () {
beforeEach(function () {
$this->ran = false;
});
afterEach(function () {
match ($this->name()) {
'__pest_evaluable__skip_on_describe__→__skipped_tests__→__nested_inside_skipped_block__→_it_should_not_execute' => expect($this->ran)->toBe(false),
'__pest_evaluable__skip_on_describe__→__skipped_tests__→_it_should_not_execute' => expect($this->ran)->toBe(false),
'__pest_evaluable__skip_on_describe__→_it_should_execute' => expect($this->ran)->toBe(true),
default => $this->fail('Unexpected test name: '.$this->name()),
};
});
describe('skipped tests', function () {
describe('nested inside skipped block', function () {
it('should not execute', function () {
$this->ran = true;
$this->fail();
});
});
it('should not execute', function () {
$this->ran = true;
$this->fail();
});
})->skip();
it('should execute', function () {
$this->ran = true;
expect($this->ran)->toBe(true);
});
});
describe('skip on beforeEach', function () {
beforeEach(function () {
$this->ran = false;
});
afterEach(function () {
match ($this->name()) {
'__pest_evaluable__skip_on_beforeEach__→__skipped_tests__→__nested_inside_skipped_block__→_it_should_not_execute' => expect($this->ran)->toBe(false),
'__pest_evaluable__skip_on_beforeEach__→__skipped_tests__→_it_should_not_execute' => expect($this->ran)->toBe(false),
'__pest_evaluable__skip_on_beforeEach__→_it_should_execute' => expect($this->ran)->toBe(true),
default => $this->fail('Unexpected test name: '.$this->name()),
};
});
describe('skipped tests', function () {
beforeEach()->skip();
describe('nested inside skipped block', function () {
it('should not execute', function () {
$this->ran = true;
$this->fail();
});
});
it('should not execute', function () {
$this->ran = true;
$this->fail();
});
});
it('should execute', function () {
$this->ran = true;
expect($this->ran)->toBe(true);
});
});
it('does not skip after the describe block', function () {
expect(true)->toBeTrue();
});
it('can skip after the describe block', function () {
expect(true)->toBeTrue();
})->skip();

View File

@ -27,3 +27,175 @@ it('may have an associated PR', function () {
it('may have an associated note', function () {
expect(true)->toBeTrue();
})->todo(note: 'a note');
describe('todo on describe', function () {
beforeEach(function () {
$this->ran = false;
});
afterEach(function () {
match ($this->name()) {
'__pest_evaluable__todo_on_describe__→__todo_block__→__nested_inside_todo_block__→_it_should_not_execute' => expect($this->ran)->toBe(false),
'__pest_evaluable__todo_on_describe__→__todo_block__→__nested_inside_todo_block__→_it_should_set_the_note' => expect($this->ran)->toBe(false),
'__pest_evaluable__todo_on_describe__→__todo_block__→__describe_with_note__→_it_should_apply_the_note_to_a_test_without_a_todo' => expect($this->ran)->toBe(false),
'__pest_evaluable__todo_on_describe__→__todo_block__→__describe_with_note__→_it_should_apply_the_note_to_a_test_with_a_todo' => expect($this->ran)->toBe(false),
'__pest_evaluable__todo_on_describe__→__todo_block__→__describe_with_note__→_it_should_apply_the_note_as_well_as_the_note_from_the_test' => expect($this->ran)->toBe(false),
'__pest_evaluable__todo_on_describe__→__todo_block__→__describe_with_note__→__nested_describe_with_note__→_it_should_apply_all_parent_notes_to_a_test_without_a_todo' => expect($this->ran)->toBe(false),
'__pest_evaluable__todo_on_describe__→__todo_block__→__describe_with_note__→__nested_describe_with_note__→_it_should_apply_all_parent_notes_to_a_test_with_a_todo' => expect($this->ran)->toBe(false),
'__pest_evaluable__todo_on_describe__→__todo_block__→__describe_with_note__→__nested_describe_with_note__→_it_should_apply_all_parent_notes_as_well_as_the_note_from_the_test' => expect($this->ran)->toBe(false),
'__pest_evaluable__todo_on_describe__→__todo_block__→_it_should_not_execute' => expect($this->ran)->toBe(false),
'__pest_evaluable__todo_on_describe__→_it_should_execute' => expect($this->ran)->toBe(true),
default => $this->fail('Unexpected test name: '.$this->name()),
};
});
describe('todo block', function () {
describe('nested inside todo block', function () {
it('should not execute', function () {
$this->ran = true;
$this->fail();
});
it('should set the note', function () {
$this->ran = true;
$this->fail();
})->todo(note: 'hi');
});
describe('describe with note', function () {
it('should apply the note to a test without a todo', function () {
$this->ran = true;
$this->fail();
});
it('should apply the note to a test with a todo', function () {
$this->ran = true;
$this->fail();
})->todo();
it('should apply the note as well as the note from the test', function () {
$this->ran = true;
$this->fail();
})->todo(note: 'test note');
describe('nested describe with note', function () {
it('should apply all parent notes to a test without a todo', function () {
$this->ran = true;
$this->fail();
});
it('should apply all parent notes to a test with a todo', function () {
$this->ran = true;
$this->fail();
})->todo();
it('should apply all parent notes as well as the note from the test', function () {
$this->ran = true;
$this->fail();
})->todo(note: 'test note');
})->todo(note: 'nested describe note');
})->todo(note: 'describe note');
it('should not execute', function () {
$this->ran = true;
$this->fail();
});
})->todo();
it('should execute', function () {
$this->ran = true;
expect($this->ran)->toBe(true);
});
});
test('todo on test after describe block', function () {
$this->fail();
})->todo();
test('todo with note on test after describe block', function () {
$this->fail();
})->todo(note: 'test note');
describe('todo on beforeEach', function () {
beforeEach(function () {
$this->ran = false;
});
afterEach(function () {
match ($this->name()) {
'__pest_evaluable__todo_on_beforeEach__→__todo_block__→__nested_inside_todo_block__→_it_should_not_execute' => expect($this->ran)->toBe(false),
'__pest_evaluable__todo_on_beforeEach__→__todo_block__→_it_should_not_execute' => expect($this->ran)->toBe(false),
'__pest_evaluable__todo_on_beforeEach__→__todo_block__→__describe_with_note__→_it_should_apply_the_note_to_a_test_without_a_todo' => expect($this->ran)->toBe(false),
'__pest_evaluable__todo_on_beforeEach__→__todo_block__→__describe_with_note__→_it_should_apply_the_note_to_a_test_with_a_todo' => expect($this->ran)->toBe(false),
'__pest_evaluable__todo_on_beforeEach__→__todo_block__→__describe_with_note__→_it_should_apply_the_note_as_well_as_the_note_from_the_test' => expect($this->ran)->toBe(false),
'__pest_evaluable__todo_on_beforeEach__→__todo_block__→__describe_with_note__→__nested_describe_with_note__→_it_should_apply_all_parent_notes_to_a_test_without_a_todo' => expect($this->ran)->toBe(false),
'__pest_evaluable__todo_on_beforeEach__→__todo_block__→__describe_with_note__→__nested_describe_with_note__→_it_should_apply_all_parent_notes_to_a_test_with_a_todo' => expect($this->ran)->toBe(false),
'__pest_evaluable__todo_on_beforeEach__→__todo_block__→__describe_with_note__→__nested_describe_with_note__→_it_should_apply_all_parent_notes_as_well_as_the_note_from_the_test' => expect($this->ran)->toBe(false),
'__pest_evaluable__todo_on_beforeEach__→_it_should_execute' => expect($this->ran)->toBe(true),
default => $this->fail('Unexpected test name: '.$this->name()),
};
});
describe('todo block', function () {
beforeEach()->todo();
describe('nested inside todo block', function () {
it('should not execute', function () {
$this->ran = true;
$this->fail();
});
});
describe('describe with note', function () {
it('should apply the note to a test without a todo', function () {
$this->ran = true;
$this->fail();
});
it('should apply the note to a test with a todo', function () {
$this->ran = true;
$this->fail();
})->todo();
it('should apply the note as well as the note from the test', function () {
$this->ran = true;
$this->fail();
})->todo(note: 'test note');
describe('nested describe with note', function () {
it('should apply all parent notes to a test without a todo', function () {
$this->ran = true;
$this->fail();
});
it('should apply all parent notes to a test with a todo', function () {
$this->ran = true;
$this->fail();
})->todo();
it('should apply all parent notes as well as the note from the test', function () {
$this->ran = true;
$this->fail();
})->todo(note: 'test note');
})->todo(note: 'nested describe note');
})->todo(note: 'describe note');
it('should not execute', function () {
$this->ran = true;
$this->fail();
});
});
it('should execute', function () {
$this->ran = true;
expect($this->ran)->toBe(true);
});
});
test('todo on test after describe block with beforeEach', function () {
$this->fail();
})->todo();
test('todo with note on test after describe block with beforeEach', function () {
$this->fail();
})->todo(note: 'test note');

View File

@ -6,7 +6,7 @@ use PHPUnit\Framework\TestCase;
class ExampleTest extends TestCase
{
public function testExample()
public function test_example()
{
$this->markTestSkipped();
}

View File

@ -6,7 +6,7 @@ class ExampleTest extends Base\ExampleTest
{
protected $foo;
public function testExample()
public function test_example()
{
$this->assertTrue(true);
}

View File

@ -13,7 +13,7 @@ class ExecutedTest extends TestCase
public static $executed = false;
#[Test]
public function testThatGetsExecuted(): void
public function test_that_gets_executed(): void
{
self::$executed = true;

View File

@ -17,7 +17,7 @@ class ParentTest extends TestCase
}
#[Test]
public function testOverrideMethod(): void
public function test_override_method(): void
{
assertTrue($this->getEntity() || true);
}

View File

@ -0,0 +1,23 @@
<?php
use Pest\Plugins\Coverage;
use Symfony\Component\Console\Output\NullOutput;
test('compute comparable coverage', function (float $givenValue, float $expectedValue) {
$output = new NullOutput();
$plugin = new Coverage($output);
$comparableCoverage = (fn () => $this->computeComparableCoverage($givenValue))->call($plugin);
expect($comparableCoverage)->toBe($expectedValue);
})->with([
[0, 0],
[0.5, 0.5],
[1.0, 1.0],
[32.51, 32.5],
[32.12312321312312, 32.1],
[32.53333333333333, 32.5],
[32.57777771232132, 32.5],
[100.0, 100.0],
]);

View File

@ -0,0 +1,49 @@
<?php
use Pest\Support\Arr;
describe('last', function () {
it('should return false for an empty arary', function () {
expect(Arr::last([]))->toBeFalse();
});
it('should return the last element for an array with a single element', function () {
expect(Arr::last([1]))->toBe(1);
});
it('should return the last element for an array without changing the internal pointer', function () {
$array = [1, 2, 3];
expect(Arr::last($array))->toBe(3);
expect(current($array))->toBe(1);
next($array);
expect(current($array))->toBe(2);
expect(Arr::last($array))->toBe(3);
expect(current($array))->toBe(2);
});
it('should return the last element for an associative array without changing the internal pointer', function () {
$array = ['first' => 1, 'second' => 2, 'third' => 3];
expect(Arr::last($array))->toBe(3);
expect(current($array))->toBe(1);
next($array);
expect(current($array))->toBe(2);
expect(Arr::last($array))->toBe(3);
expect(current($array))->toBe(2);
});
it('should return the last element for an mixed key array without changing the internal pointer', function () {
$array = ['first' => 1, 2, 'third' => 3];
expect(Arr::last($array))->toBe(3);
expect(current($array))->toBe(1);
next($array);
expect(current($array))->toBe(2);
expect(Arr::last($array))->toBe(3);
expect(current($array))->toBe(2);
});
});

View File

@ -16,7 +16,7 @@ $run = function () {
test('parallel', function () use ($run) {
expect($run('--exclude-group=integration'))
->toContain('Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 17 todos, 19 skipped, 1085 passed (2624 assertions)')
->toContain('Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 38 todos, 24 skipped, 1142 passed (2720 assertions)')
->toContain('Parallel: 3 processes');
})->skipOnWindows();