mirror of
https://github.com/pestphp/pest.git
synced 2026-03-06 15:57:21 +01:00
Compare commits
92 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e4aab77a34 | |||
| 709ecb1ba2 | |||
| 6afb36519d | |||
| 150bb9478d | |||
| bf3178473d | |||
| d2eb94d723 | |||
| 9688b83a3d | |||
| 675372c794 | |||
| c18636b3d5 | |||
| 145294a4a3 | |||
| c2cabaeae6 | |||
| 918a8fc169 | |||
| 5d32dd0641 | |||
| 982353fb38 | |||
| 2eefa8b88d | |||
| 787d5492ac | |||
| 06a0bd9b0b | |||
| 91afc81222 | |||
| 179d46ce97 | |||
| fa2bc1e536 | |||
| eaeb133c77 | |||
| cf57ea1f94 | |||
| 0b7f4f2384 | |||
| 2903a7e621 | |||
| b8964375c7 | |||
| bdcb883829 | |||
| 8a7e7f39ef | |||
| 67f217852c | |||
| 1bad148487 | |||
| e24f137b8e | |||
| 6d9189f3f5 | |||
| 6968094e2b | |||
| 9510d4a2f9 | |||
| cd2eb3504b | |||
| 7c639cdbbd | |||
| 1513ede73b | |||
| 8c65197881 | |||
| a6cd83665c | |||
| 0c57142c03 | |||
| 3f65af9fdf | |||
| 42d89814e3 | |||
| 1e3156a5b6 | |||
| 97713c0832 | |||
| 62b0e3c9df | |||
| 647de2f1cf | |||
| 0a7bff0d24 | |||
| 7618434580 | |||
| 1e0bb88b73 | |||
| 83b76d7c2e | |||
| 5a870b3940 | |||
| 1115c64186 | |||
| e38a271ca2 | |||
| 43703ab40a | |||
| 86452765a4 | |||
| b8a1b7e5cc | |||
| 5fe79d9c18 | |||
| 2744da4292 | |||
| 87f4e5e7b3 | |||
| bb3decf3cc | |||
| 4e2987d438 | |||
| a25158bce8 | |||
| 49e77b1d4c | |||
| 989e43d1a0 | |||
| 7cd42aafd8 | |||
| 48a1de273f | |||
| 970e16e949 | |||
| 432ff221c6 | |||
| a55da85dd2 | |||
| f291cd1603 | |||
| 5de0c2254a | |||
| b98ce0ced3 | |||
| 28772c2609 | |||
| 452ffaf8df | |||
| e8338405b5 | |||
| 1b014e4b18 | |||
| 034715e8b1 | |||
| 09eff785c4 | |||
| 22cc7805d7 | |||
| 669dc0da71 | |||
| 689da4ed4e | |||
| 2f15861b0d | |||
| 0d50d35b5e | |||
| ce61ced8e1 | |||
| 7227d24611 | |||
| 45f16484d5 | |||
| b16e8650da | |||
| c2f30e0148 | |||
| 47ce45de56 | |||
| 32881774d2 | |||
| ea72461f1b | |||
| 49f15521e0 | |||
| 95c5394b66 |
7
.github/workflows/tests.yml
vendored
7
.github/workflows/tests.yml
vendored
@ -13,8 +13,8 @@ jobs:
|
|||||||
fail-fast: true
|
fail-fast: true
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
symfony: ['7.0']
|
symfony: ['7.1']
|
||||||
php: ['8.2', '8.3']
|
php: ['8.2', '8.3', '8.4']
|
||||||
dependency_version: [prefer-lowest, prefer-stable]
|
dependency_version: [prefer-lowest, prefer-stable]
|
||||||
|
|
||||||
name: PHP ${{ matrix.php }} - Symfony ^${{ matrix.symfony }} - ${{ matrix.os }} - ${{ matrix.dependency_version }}
|
name: PHP ${{ matrix.php }} - Symfony ^${{ matrix.symfony }} - ${{ matrix.os }} - ${{ matrix.dependency_version }}
|
||||||
@ -36,7 +36,8 @@ jobs:
|
|||||||
echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
|
echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
|
||||||
|
|
||||||
- name: Install PHP dependencies
|
- name: Install PHP dependencies
|
||||||
run: composer update --${{ matrix.dependency_version }} --no-interaction --no-progress --ansi --with="symfony/console:~${{ matrix.symfony }}"
|
shell: bash
|
||||||
|
run: composer update --${{ matrix.dependency_version }} --no-interaction --no-progress --ansi --with="symfony/console:^${{ matrix.symfony }}"
|
||||||
|
|
||||||
- name: Unit Tests
|
- name: Unit Tests
|
||||||
run: composer test:unit
|
run: composer test:unit
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -12,3 +12,5 @@ coverage.xml
|
|||||||
*.swp
|
*.swp
|
||||||
*.swo
|
*.swo
|
||||||
.vscode/
|
.vscode/
|
||||||
|
.STREAM.md
|
||||||
|
|
||||||
|
|||||||
@ -42,7 +42,7 @@ composer test
|
|||||||
|
|
||||||
Check types:
|
Check types:
|
||||||
```bash
|
```bash
|
||||||
composer test:types
|
composer test:type:check
|
||||||
```
|
```
|
||||||
|
|
||||||
Unit tests:
|
Unit tests:
|
||||||
|
|||||||
19
README.md
19
README.md
@ -1,7 +1,7 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="https://raw.githubusercontent.com/pestphp/art/master/v3/banner.png" width="600" alt="PEST">
|
<img src="https://raw.githubusercontent.com/pestphp/art/master/v3/banner.png" width="600" alt="PEST">
|
||||||
<p align="center">
|
<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="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="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>
|
<a href="https://packagist.org/packages/pestphp/pest"><img alt="License" src="https://img.shields.io/packagist/l/pestphp/pest"></a>
|
||||||
@ -22,22 +22,27 @@
|
|||||||
|
|
||||||
We cannot thank our sponsors enough for their incredible support in funding Pest's development. Their contributions have been instrumental in making Pest the best it can be. For those who are interested in becoming a sponsor, please visit Nuno Maduro's Sponsor page at **[github.com/sponsors/nunomaduro](https://github.com/sponsors/nunomaduro)**.
|
We cannot thank our sponsors enough for their incredible support in funding Pest's development. Their contributions have been instrumental in making Pest the best it can be. For those who are interested in becoming a sponsor, please visit Nuno Maduro's Sponsor page at **[github.com/sponsors/nunomaduro](https://github.com/sponsors/nunomaduro)**.
|
||||||
|
|
||||||
|
|
||||||
### Platinum Sponsors
|
### Platinum Sponsors
|
||||||
|
|
||||||
- **[LaraJobs](https://larajobs.com)**
|
- **[Laracasts](https://laracasts.com/?ref=pestphp)**
|
||||||
- **[Brokerchooser](https://brokerchooser.com)**
|
|
||||||
- **[Forge](https://forge.laravel.com)**
|
### Gold Sponsors
|
||||||
- **[Spatie](https://spatie.be)**
|
|
||||||
- **[Worksome](https://www.worksome.com/)**
|
- **[CodeRabbit](https://coderabbit.ai/?ref=pestphp)**
|
||||||
|
- **[LaraJobs](https://larajobs.com/?ref=pestphp)**
|
||||||
|
- **[Brokerchooser](https://brokerchooser.com/?ref=pestphp)**
|
||||||
|
- **[Forge](https://forge.laravel.com/?ref=pestphp)**
|
||||||
|
|
||||||
### Premium Sponsors
|
### Premium Sponsors
|
||||||
|
|
||||||
- [Akaunting](https://akaunting.com/?ref=pestphp)
|
- [Akaunting](https://akaunting.com/?ref=pestphp)
|
||||||
- [Codecourse](https://codecourse.com/?ref=pestphp)
|
- [Codecourse](https://codecourse.com/?ref=pestphp)
|
||||||
- [DocuWriter.ai](https://www.docuwriter.ai/?ref=pestphp)
|
- [DocuWriter.ai](https://www.docuwriter.ai/?ref=pestphp)
|
||||||
- [Laracasts](https://laracasts.com/?ref=pestphp)
|
|
||||||
- [Localazy](https://localazy.com/?ref=pestphp)
|
- [Localazy](https://localazy.com/?ref=pestphp)
|
||||||
- [Route4Me](https://www.route4me.com/?ref=pestphp)
|
- [Route4Me](https://www.route4me.com/?ref=pestphp)
|
||||||
|
- [Spatie](https://spatie.be/?ref=pestphp)
|
||||||
|
- [Worksome](https://www.worksome.com/?ref=pestphp)
|
||||||
- [Zapiet](https://www.zapiet.com/?ref=pestphp)
|
- [Zapiet](https://www.zapiet.com/?ref=pestphp)
|
||||||
|
|
||||||
Pest is an open-sourced software 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)**.
|
||||||
|
|||||||
23
bin/pest
23
bin/pest
@ -1,5 +1,7 @@
|
|||||||
#!/usr/bin/env php
|
#!/usr/bin/env php
|
||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use Pest\Kernel;
|
use Pest\Kernel;
|
||||||
use Pest\Panic;
|
use Pest\Panic;
|
||||||
@ -37,7 +39,7 @@ use Symfony\Component\Console\Output\ConsoleOutput;
|
|||||||
|
|
||||||
if (str_contains($value, '--test-directory=')) {
|
if (str_contains($value, '--test-directory=')) {
|
||||||
unset($arguments[$key]);
|
unset($arguments[$key]);
|
||||||
} else if ($value === '--test-directory') {
|
} elseif ($value === '--test-directory') {
|
||||||
unset($arguments[$key]);
|
unset($arguments[$key]);
|
||||||
|
|
||||||
if (isset($arguments[$key + 1])) {
|
if (isset($arguments[$key + 1])) {
|
||||||
@ -62,7 +64,7 @@ use Symfony\Component\Console\Output\ConsoleOutput;
|
|||||||
|
|
||||||
if (str_contains($value, '--assignee=')) {
|
if (str_contains($value, '--assignee=')) {
|
||||||
unset($arguments[$key]);
|
unset($arguments[$key]);
|
||||||
} else if ($value === '--assignee') {
|
} elseif ($value === '--assignee') {
|
||||||
unset($arguments[$key]);
|
unset($arguments[$key]);
|
||||||
|
|
||||||
if (isset($arguments[$key + 1])) {
|
if (isset($arguments[$key + 1])) {
|
||||||
@ -72,7 +74,7 @@ use Symfony\Component\Console\Output\ConsoleOutput;
|
|||||||
|
|
||||||
if (str_contains($value, '--issue=')) {
|
if (str_contains($value, '--issue=')) {
|
||||||
unset($arguments[$key]);
|
unset($arguments[$key]);
|
||||||
} else if ($value === '--issue') {
|
} elseif ($value === '--issue') {
|
||||||
unset($arguments[$key]);
|
unset($arguments[$key]);
|
||||||
|
|
||||||
if (isset($arguments[$key + 1])) {
|
if (isset($arguments[$key + 1])) {
|
||||||
@ -82,7 +84,7 @@ use Symfony\Component\Console\Output\ConsoleOutput;
|
|||||||
|
|
||||||
if (str_contains($value, '--ticket=')) {
|
if (str_contains($value, '--ticket=')) {
|
||||||
unset($arguments[$key]);
|
unset($arguments[$key]);
|
||||||
} else if ($value === '--ticket') {
|
} elseif ($value === '--ticket') {
|
||||||
unset($arguments[$key]);
|
unset($arguments[$key]);
|
||||||
|
|
||||||
if (isset($arguments[$key + 1])) {
|
if (isset($arguments[$key + 1])) {
|
||||||
@ -92,7 +94,7 @@ use Symfony\Component\Console\Output\ConsoleOutput;
|
|||||||
|
|
||||||
if (str_contains($value, '--pr=')) {
|
if (str_contains($value, '--pr=')) {
|
||||||
unset($arguments[$key]);
|
unset($arguments[$key]);
|
||||||
} else if ($value === '--pr') {
|
} elseif ($value === '--pr') {
|
||||||
unset($arguments[$key]);
|
unset($arguments[$key]);
|
||||||
|
|
||||||
if (isset($arguments[$key + 1])) {
|
if (isset($arguments[$key + 1])) {
|
||||||
@ -102,7 +104,7 @@ use Symfony\Component\Console\Output\ConsoleOutput;
|
|||||||
|
|
||||||
if (str_contains($value, '--pull-request=')) {
|
if (str_contains($value, '--pull-request=')) {
|
||||||
unset($arguments[$key]);
|
unset($arguments[$key]);
|
||||||
} else if ($value === '--pull-request') {
|
} elseif ($value === '--pull-request') {
|
||||||
unset($arguments[$key]);
|
unset($arguments[$key]);
|
||||||
|
|
||||||
if (isset($arguments[$key + 1])) {
|
if (isset($arguments[$key + 1])) {
|
||||||
@ -117,7 +119,6 @@ use Symfony\Component\Console\Output\ConsoleOutput;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Used when Pest is required using composer.
|
// Used when Pest is required using composer.
|
||||||
$vendorPath = dirname(__DIR__, 4).'/vendor/autoload.php';
|
$vendorPath = dirname(__DIR__, 4).'/vendor/autoload.php';
|
||||||
|
|
||||||
@ -134,7 +135,7 @@ use Symfony\Component\Console\Output\ConsoleOutput;
|
|||||||
|
|
||||||
// Get $rootPath based on $autoloadPath
|
// Get $rootPath based on $autoloadPath
|
||||||
$rootPath = dirname($autoloadPath, 2);
|
$rootPath = dirname($autoloadPath, 2);
|
||||||
$input = new ArgvInput();
|
$input = new ArgvInput;
|
||||||
|
|
||||||
$testSuite = TestSuite::getInstance(
|
$testSuite = TestSuite::getInstance(
|
||||||
$rootPath,
|
$rootPath,
|
||||||
@ -146,11 +147,11 @@ use Symfony\Component\Console\Output\ConsoleOutput;
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($todo) {
|
if ($todo) {
|
||||||
$testSuite->tests->addTestCaseMethodFilter(new TodoTestCaseFilter());
|
$testSuite->tests->addTestCaseMethodFilter(new TodoTestCaseFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($notes) {
|
if ($notes) {
|
||||||
$testSuite->tests->addTestCaseMethodFilter(new NotesTestCaseFilter());
|
$testSuite->tests->addTestCaseMethodFilter(new NotesTestCaseFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($assignee = $input->getParameterOption('--assignee')) {
|
if ($assignee = $input->getParameterOption('--assignee')) {
|
||||||
|
|||||||
@ -32,10 +32,13 @@ $bootPest = (static function (): void {
|
|||||||
'status-file:',
|
'status-file:',
|
||||||
'progress-file:',
|
'progress-file:',
|
||||||
'unexpected-output-file:',
|
'unexpected-output-file:',
|
||||||
'testresult-file:',
|
'test-result-file:',
|
||||||
|
'result-cache-file:',
|
||||||
'teamcity-file:',
|
'teamcity-file:',
|
||||||
'testdox-file:',
|
'testdox-file:',
|
||||||
'testdox-color',
|
'testdox-color',
|
||||||
|
'testdox-columns:',
|
||||||
|
'testdox-summary',
|
||||||
'phpunit-argv:',
|
'phpunit-argv:',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -61,7 +64,8 @@ $bootPest = (static function (): void {
|
|||||||
|
|
||||||
assert(isset($getopt['progress-file']) && is_string($getopt['progress-file']));
|
assert(isset($getopt['progress-file']) && is_string($getopt['progress-file']));
|
||||||
assert(isset($getopt['unexpected-output-file']) && is_string($getopt['unexpected-output-file']));
|
assert(isset($getopt['unexpected-output-file']) && is_string($getopt['unexpected-output-file']));
|
||||||
assert(isset($getopt['testresult-file']) && is_string($getopt['testresult-file']));
|
assert(isset($getopt['test-result-file']) && is_string($getopt['test-result-file']));
|
||||||
|
assert(! isset($getopt['result-cache-file']) || is_string($getopt['result-cache-file']));
|
||||||
assert(! isset($getopt['teamcity-file']) || is_string($getopt['teamcity-file']));
|
assert(! isset($getopt['teamcity-file']) || is_string($getopt['teamcity-file']));
|
||||||
assert(! isset($getopt['testdox-file']) || is_string($getopt['testdox-file']));
|
assert(! isset($getopt['testdox-file']) || is_string($getopt['testdox-file']));
|
||||||
|
|
||||||
@ -77,7 +81,8 @@ $bootPest = (static function (): void {
|
|||||||
$phpunitArgv,
|
$phpunitArgv,
|
||||||
$getopt['progress-file'],
|
$getopt['progress-file'],
|
||||||
$getopt['unexpected-output-file'],
|
$getopt['unexpected-output-file'],
|
||||||
$getopt['testresult-file'],
|
$getopt['test-result-file'],
|
||||||
|
$getopt['result-cache-file'] ?? null,
|
||||||
$getopt['teamcity-file'] ?? null,
|
$getopt['teamcity-file'] ?? null,
|
||||||
$getopt['testdox-file'] ?? null,
|
$getopt['testdox-file'] ?? null,
|
||||||
isset($getopt['testdox-color']),
|
isset($getopt['testdox-color']),
|
||||||
|
|||||||
@ -18,16 +18,17 @@
|
|||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.2.0",
|
"php": "^8.2.0",
|
||||||
"brianium/paratest": "^7.5.4",
|
"brianium/paratest": "^7.7.0",
|
||||||
"nunomaduro/collision": "^8.4.0",
|
"nunomaduro/collision": "^8.6.0",
|
||||||
"nunomaduro/termwind": "^2.1.0",
|
"nunomaduro/termwind": "^2.3.0",
|
||||||
"pestphp/pest-plugin": "^3.0.0",
|
"pestphp/pest-plugin": "^3.0.0",
|
||||||
"pestphp/pest-plugin-arch": "^3.0.0",
|
"pestphp/pest-plugin-arch": "^3.0.0",
|
||||||
"pestphp/pest-plugin-mutate": "^3.0.2",
|
"pestphp/pest-plugin-mutate": "^3.0.5",
|
||||||
"phpunit/phpunit": "^11.3.4"
|
"phpunit/phpunit": "^11.5.3"
|
||||||
},
|
},
|
||||||
"conflict": {
|
"conflict": {
|
||||||
"phpunit/phpunit": ">11.3.4",
|
"filp/whoops": "<2.16.0",
|
||||||
|
"phpunit/phpunit": ">11.5.3",
|
||||||
"sebastian/exporter": "<6.0.0",
|
"sebastian/exporter": "<6.0.0",
|
||||||
"webmozart/assert": "<1.11.0"
|
"webmozart/assert": "<1.11.0"
|
||||||
},
|
},
|
||||||
@ -52,9 +53,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"pestphp/pest-dev-tools": "^3.0.0",
|
"pestphp/pest-dev-tools": "^3.3.0",
|
||||||
"pestphp/pest-plugin-type-coverage": "^3.0.0",
|
"pestphp/pest-plugin-type-coverage": "^3.2.3",
|
||||||
"symfony/process": "^7.1.3"
|
"symfony/process": "^7.2.0"
|
||||||
},
|
},
|
||||||
"minimum-stability": "dev",
|
"minimum-stability": "dev",
|
||||||
"prefer-stable": true,
|
"prefer-stable": true,
|
||||||
|
|||||||
@ -68,7 +68,7 @@ final readonly class ThrowableBuilder
|
|||||||
$previous = self::from($previous);
|
$previous = self::from($previous);
|
||||||
}
|
}
|
||||||
|
|
||||||
$trace = Filter::getFilteredStacktrace($t);
|
$trace = Filter::stackTraceFromThrowableAsString($t);
|
||||||
|
|
||||||
if ($t instanceof RenderableOnCollisionEditor && $frame = $t->toCollisionEditor()) {
|
if ($t instanceof RenderableOnCollisionEditor && $frame = $t->toCollisionEditor()) {
|
||||||
$file = $frame->getFile();
|
$file = $frame->getFile();
|
||||||
|
|||||||
@ -446,7 +446,7 @@ final class JunitXmlLogger
|
|||||||
if ($test->isTestMethod()) {
|
if ($test->isTestMethod()) {
|
||||||
assert($test instanceof TestMethod);
|
assert($test instanceof TestMethod);
|
||||||
|
|
||||||
//$testCase->setAttribute('line', (string) $test->line()); // pest-removed
|
// $testCase->setAttribute('line', (string) $test->line()); // pest-removed
|
||||||
$className = $this->converter->getTrimmedTestClassName($test); // pest-added
|
$className = $this->converter->getTrimmedTestClassName($test); // pest-added
|
||||||
$testCase->setAttribute('class', $className); // pest-changed
|
$testCase->setAttribute('class', $className); // pest-changed
|
||||||
$testCase->setAttribute('classname', str_replace('\\', '.', $className)); // pest-changed
|
$testCase->setAttribute('classname', str_replace('\\', '.', $className)); // pest-changed
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
includes:
|
includes:
|
||||||
- vendor/phpstan/phpstan-strict-rules/rules.neon
|
- vendor/phpstan/phpstan-strict-rules/rules.neon
|
||||||
- vendor/ergebnis/phpstan-rules/rules.neon
|
|
||||||
- vendor/thecodingmachine/phpstan-strict-rules/phpstan-strict-rules.neon
|
- vendor/thecodingmachine/phpstan-strict-rules/phpstan-strict-rules.neon
|
||||||
|
|
||||||
parameters:
|
parameters:
|
||||||
@ -12,12 +11,4 @@ parameters:
|
|||||||
reportUnmatchedIgnoredErrors: true
|
reportUnmatchedIgnoredErrors: true
|
||||||
|
|
||||||
ignoreErrors:
|
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#"
|
- "#type mixed is not subtype of native#"
|
||||||
- "# with null as default value#"
|
|
||||||
- "#has parameter \\$closure with default value.#"
|
|
||||||
- "#has parameter \\$description with default value.#"
|
|
||||||
|
|||||||
@ -27,17 +27,20 @@ final class Laravel extends AbstractPreset
|
|||||||
->ignoring('App\Enums');
|
->ignoring('App\Enums');
|
||||||
|
|
||||||
$this->expectations[] = expect('App\Enums')
|
$this->expectations[] = expect('App\Enums')
|
||||||
->toBeEnums();
|
->toBeEnums()
|
||||||
|
->ignoring('App\Enums\Concerns');
|
||||||
|
|
||||||
$this->expectations[] = expect('App\Features')
|
$this->expectations[] = expect('App\Features')
|
||||||
->toBeClasses();
|
->toBeClasses()
|
||||||
|
->ignoring('App\Features\Concerns');
|
||||||
|
|
||||||
$this->expectations[] = expect('App\Features')
|
$this->expectations[] = expect('App\Features')
|
||||||
->toHaveMethod('resolve');
|
->toHaveMethod('resolve');
|
||||||
|
|
||||||
$this->expectations[] = expect('App\Exceptions')
|
$this->expectations[] = expect('App\Exceptions')
|
||||||
->classes()
|
->classes()
|
||||||
->toImplement('Throwable');
|
->toImplement('Throwable')
|
||||||
|
->ignoring('App\Exceptions\Handler');
|
||||||
|
|
||||||
$this->expectations[] = expect('App')
|
$this->expectations[] = expect('App')
|
||||||
->not->toImplement(Throwable::class)
|
->not->toImplement(Throwable::class)
|
||||||
@ -149,7 +152,7 @@ final class Laravel extends AbstractPreset
|
|||||||
->toOnlyBeUsedIn('App\Http');
|
->toOnlyBeUsedIn('App\Http');
|
||||||
|
|
||||||
$this->expectations[] = expect('App\Http\Controllers')
|
$this->expectations[] = expect('App\Http\Controllers')
|
||||||
->not->toHavePublicMethodsBesides(['__construct', '__invoke', 'index', 'show', 'create', 'store', 'edit', 'update', 'destroy']);
|
->not->toHavePublicMethodsBesides(['__construct', '__invoke', 'index', 'show', 'create', 'store', 'edit', 'update', 'destroy', 'middleware']);
|
||||||
|
|
||||||
$this->expectations[] = expect([
|
$this->expectations[] = expect([
|
||||||
'dd',
|
'dd',
|
||||||
@ -159,5 +162,9 @@ final class Laravel extends AbstractPreset
|
|||||||
'exit',
|
'exit',
|
||||||
'ray',
|
'ray',
|
||||||
])->not->toBeUsed();
|
])->not->toBeUsed();
|
||||||
|
|
||||||
|
$this->expectations[] = expect('App\Policies')
|
||||||
|
->classes()
|
||||||
|
->toHaveSuffix('Policy');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,6 +21,7 @@ final class Strict extends AbstractPreset
|
|||||||
fn (Expectation $namespace): ArchExpectation => $namespace->classes()->not->toHaveProtectedMethods(),
|
fn (Expectation $namespace): ArchExpectation => $namespace->classes()->not->toHaveProtectedMethods(),
|
||||||
fn (Expectation $namespace): ArchExpectation => $namespace->classes()->not->toBeAbstract(),
|
fn (Expectation $namespace): ArchExpectation => $namespace->classes()->not->toBeAbstract(),
|
||||||
fn (Expectation $namespace): ArchExpectation => $namespace->toUseStrictTypes(),
|
fn (Expectation $namespace): ArchExpectation => $namespace->toUseStrictTypes(),
|
||||||
|
fn (Expectation $namespace): ArchExpectation => $namespace->toUseStrictEquality(),
|
||||||
fn (Expectation $namespace): ArchExpectation => $namespace->classes()->toBeFinal(),
|
fn (Expectation $namespace): ArchExpectation => $namespace->classes()->toBeFinal(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -18,14 +18,14 @@ final class BootOverrides implements Bootstrapper
|
|||||||
* @var array<string, string>
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
public const FILES = [
|
public const FILES = [
|
||||||
'c96b1cb57d7fc8e649f4c13a8abe418c2541bcfab194fb6702b99f777f52ee84' => 'Runner/Filter/NameFilterIterator.php',
|
'53c246e5f416a39817ac81124cdd64ea8403038d01d7a202e1ffa486fbdf3fa7' => 'Runner/Filter/NameFilterIterator.php',
|
||||||
'a4a43de01f641c6944ee83d963795a46d32b5206b5ab3bbc6cce76e67190acbf' => 'Runner/ResultCache/DefaultResultCache.php',
|
'77ffb7647b583bd82e37962c6fbdc4b04d3344d8a2c1ed103e625ed1ff7cb5c2' => 'Runner/ResultCache/DefaultResultCache.php',
|
||||||
'd0e81317889ad88c707db4b08a94cadee4c9010d05ff0a759f04e71af5efed89' => 'Runner/TestSuiteLoader.php',
|
'd0e81317889ad88c707db4b08a94cadee4c9010d05ff0a759f04e71af5efed89' => 'Runner/TestSuiteLoader.php',
|
||||||
'3bb609b0d3bf6dee8df8d6cd62a3c8ece823c4bb941eaaae39e3cb267171b9d2' => 'TextUI/Command/Commands/WarmCodeCoverageCacheCommand.php',
|
'3bb609b0d3bf6dee8df8d6cd62a3c8ece823c4bb941eaaae39e3cb267171b9d2' => 'TextUI/Command/Commands/WarmCodeCoverageCacheCommand.php',
|
||||||
'8abdad6413329c6fe0d7d44a8b9926e390af32c0b3123f3720bb9c5bbc6fbb7e' => 'TextUI/Output/Default/ProgressPrinter/Subscriber/TestSkippedSubscriber.php',
|
'8abdad6413329c6fe0d7d44a8b9926e390af32c0b3123f3720bb9c5bbc6fbb7e' => 'TextUI/Output/Default/ProgressPrinter/Subscriber/TestSkippedSubscriber.php',
|
||||||
'43883b7e5811886cf3731c8ed6304d5a77078d9731e1e505abc2da36bde19f3e' => 'TextUI/TestSuiteFilterProcessor.php',
|
'b4250fc3ffad5954624cb5e682fd940b874e8d3422fa1ee298bd7225e1aa5fc2' => 'TextUI/TestSuiteFilterProcessor.php',
|
||||||
'357d5cd7007f8559b26e1b8cdf43bb6fb15b51b79db981779da6f31b7ec39dad' => 'Event/Value/ThrowableBuilder.php',
|
'8cfcb4999af79463eca51a42058e502ea4ddc776cba5677bf2f8eb6093e21a5c' => 'Event/Value/ThrowableBuilder.php',
|
||||||
'01974a686eba69b5fbb87a904d936eae2176e39567616898c5b758db71d87a22' => 'Logging/JUnit/JunitXmlLogger.php',
|
'86cd9bcaa53cdd59c5b13e58f30064a015c549501e7629d93b96893d4dee1eb1' => 'Logging/JUnit/JunitXmlLogger.php',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -61,8 +61,10 @@ trait Testable
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The test's describing, if any.
|
* The test's describing, if any.
|
||||||
|
*
|
||||||
|
* @var array<int, string>
|
||||||
*/
|
*/
|
||||||
public ?string $__describing = null;
|
public array $__describing = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the test has ran or not.
|
* Whether the test has ran or not.
|
||||||
@ -116,7 +118,7 @@ trait Testable
|
|||||||
self::$__latestIssues = $method->issues;
|
self::$__latestIssues = $method->issues;
|
||||||
self::$__latestPrs = $method->prs;
|
self::$__latestPrs = $method->prs;
|
||||||
$this->__describing = $method->describing;
|
$this->__describing = $method->describing;
|
||||||
$this->__test = $method->getClosure($this);
|
$this->__test = $method->getClosure();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,6 +242,8 @@ trait Testable
|
|||||||
|
|
||||||
$method = TestSuite::getInstance()->tests->get(self::$__filename)->getMethod($this->name());
|
$method = TestSuite::getInstance()->tests->get(self::$__filename)->getMethod($this->name());
|
||||||
|
|
||||||
|
$method->setUp($this);
|
||||||
|
|
||||||
$description = $method->description;
|
$description = $method->description;
|
||||||
if ($this->dataName()) {
|
if ($this->dataName()) {
|
||||||
$description = str_contains((string) $description, ':dataset')
|
$description = str_contains((string) $description, ':dataset')
|
||||||
@ -298,6 +302,9 @@ trait Testable
|
|||||||
parent::tearDown();
|
parent::tearDown();
|
||||||
|
|
||||||
TestSuite::getInstance()->test = null;
|
TestSuite::getInstance()->test = null;
|
||||||
|
|
||||||
|
$method = TestSuite::getInstance()->tests->get(self::$__filename)->getMethod($this->name());
|
||||||
|
$method->tearDown($this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,11 +399,12 @@ trait Testable
|
|||||||
fn (ReflectionParameter $reflectionParameter): string => $reflectionParameter->getName(),
|
fn (ReflectionParameter $reflectionParameter): string => $reflectionParameter->getName(),
|
||||||
array_filter($testReflection->getParameters(), fn (ReflectionParameter $reflectionParameter): bool => ! $reflectionParameter->isOptional()),
|
array_filter($testReflection->getParameters(), fn (ReflectionParameter $reflectionParameter): bool => ! $reflectionParameter->isOptional()),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (array_diff($testParameterNames, $datasetParameterNames) === []) {
|
if (array_diff($testParameterNames, $datasetParameterNames) === []) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isset($testParameterNames[0])
|
|
||||||
&& $suppliedParametersCount >= $requiredParametersCount) {
|
if (isset($testParameterNames[0]) && $suppliedParametersCount >= $requiredParametersCount) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -79,11 +79,11 @@ final readonly class Configuration
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the theme configuration.
|
* Gets the printer configuration.
|
||||||
*/
|
*/
|
||||||
public function theme(): Configuration\Theme
|
public function printer(): Configuration\Printer
|
||||||
{
|
{
|
||||||
return new Configuration\Theme;
|
return new Configuration\Printer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -9,7 +9,7 @@ use NunoMaduro\Collision\Adapters\Phpunit\Printers\DefaultPrinter;
|
|||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
final readonly class Theme
|
final readonly class Printer
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Sets the theme to compact.
|
* Sets the theme to compact.
|
||||||
@ -89,7 +89,7 @@ final class Project
|
|||||||
{
|
{
|
||||||
$this->issues = "https://{$namespace}.atlassian.net/browse/{$project}-%s";
|
$this->issues = "https://{$namespace}.atlassian.net/browse/{$project}-%s";
|
||||||
|
|
||||||
$this->assignees = "https://{$namespace}.atlassian.net/secure/ViewProfile?name=%s";
|
$this->assignees = "https://{$namespace}.atlassian.net/secure/ViewProfile.jspa?name=%s";
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -223,7 +223,7 @@ final class Expectation
|
|||||||
throw new BadMethodCallException('Expectation value is not iterable.');
|
throw new BadMethodCallException('Expectation value is not iterable.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($callbacks) == 0) {
|
if ($callbacks === []) {
|
||||||
throw new InvalidArgumentException('No sequence expectations defined.');
|
throw new InvalidArgumentException('No sequence expectations defined.');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,7 +264,7 @@ final class Expectation
|
|||||||
$matched = false;
|
$matched = false;
|
||||||
|
|
||||||
foreach ($expressions as $key => $callback) {
|
foreach ($expressions as $key => $callback) {
|
||||||
if ($subject != $key) {
|
if ($subject != $key) { // @pest-arch-ignore-line
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,7 +380,7 @@ final class Expectation
|
|||||||
if (self::hasExtend($name)) {
|
if (self::hasExtend($name)) {
|
||||||
$extend = self::$extends[$name]->bindTo($this, Expectation::class);
|
$extend = self::$extends[$name]->bindTo($this, Expectation::class);
|
||||||
|
|
||||||
if ($extend != false) {
|
if ($extend != false) { // @pest-arch-ignore-line
|
||||||
return $extend;
|
return $extend;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -509,12 +509,25 @@ final class Expectation
|
|||||||
{
|
{
|
||||||
return Targeted::make(
|
return Targeted::make(
|
||||||
$this,
|
$this,
|
||||||
fn (ObjectDescription $object): bool => (bool) preg_match('/^<\?php\s+declare\(.*?strict_types\s?=\s?1.*?\);/', (string) file_get_contents($object->path)),
|
fn (ObjectDescription $object): bool => (bool) preg_match('/^<\?php\s*(\/\*[\s\S]*?\*\/|\/\/[^\r\n]*(?:\r?\n|$)|\s)*declare\s*\(\s*strict_types\s*=\s*1\s*\)\s*;/m', (string) file_get_contents($object->path)),
|
||||||
'to use strict types',
|
'to use strict types',
|
||||||
FileLineFinder::where(fn (string $line): bool => str_contains($line, '<?php')),
|
FileLineFinder::where(fn (string $line): bool => str_contains($line, '<?php')),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that the given expectation target uses strict equality.
|
||||||
|
*/
|
||||||
|
public function toUseStrictEquality(): ArchExpectation
|
||||||
|
{
|
||||||
|
return Targeted::make(
|
||||||
|
$this,
|
||||||
|
fn (ObjectDescription $object): bool => ! str_contains((string) file_get_contents($object->path), ' == ') && ! str_contains((string) file_get_contents($object->path), ' != '),
|
||||||
|
'to use strict equality',
|
||||||
|
FileLineFinder::where(fn (string $line): bool => str_contains($line, ' == ') || str_contains($line, ' != ')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asserts that the given expectation target is final.
|
* Asserts that the given expectation target is final.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -152,6 +152,19 @@ final readonly class OppositeExpectation
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that the given expectation target does not use the strict equality operator.
|
||||||
|
*/
|
||||||
|
public function toUseStrictEquality(): ArchExpectation
|
||||||
|
{
|
||||||
|
return Targeted::make(
|
||||||
|
$this->original,
|
||||||
|
fn (ObjectDescription $object): bool => ! str_contains((string) file_get_contents($object->path), ' === ') && ! str_contains((string) file_get_contents($object->path), ' !== '),
|
||||||
|
'to use strict equality',
|
||||||
|
FileLineFinder::where(fn (string $line): bool => str_contains($line, ' === ') || str_contains($line, ' !== ')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asserts that the given expectation target is not final.
|
* Asserts that the given expectation target is not final.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -166,7 +166,7 @@ final class TestCaseFactory
|
|||||||
}
|
}
|
||||||
PHP;
|
PHP;
|
||||||
|
|
||||||
eval($classCode); // @phpstan-ignore-line
|
eval($classCode);
|
||||||
} catch (ParseError $caught) {
|
} catch (ParseError $caught) {
|
||||||
throw new RuntimeException(sprintf(
|
throw new RuntimeException(sprintf(
|
||||||
"Unable to create test case for test file at %s. \n %s",
|
"Unable to create test case for test file at %s. \n %s",
|
||||||
|
|||||||
@ -31,8 +31,10 @@ final class TestCaseMethodFactory
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The test's describing, if any.
|
* The test's describing, if any.
|
||||||
|
*
|
||||||
|
* @var array<int, string>
|
||||||
*/
|
*/
|
||||||
public ?string $describing = null;
|
public array $describing = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The test's description, if any.
|
* The test's description, if any.
|
||||||
@ -118,9 +120,9 @@ final class TestCaseMethodFactory
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the test's closure.
|
* Sets the test's hooks, and runs any proxy to the test case.
|
||||||
*/
|
*/
|
||||||
public function getClosure(TestCase $concrete): Closure
|
public function setUp(TestCase $concrete): void
|
||||||
{
|
{
|
||||||
$concrete::flush(); // @phpstan-ignore-line
|
$concrete::flush(); // @phpstan-ignore-line
|
||||||
|
|
||||||
@ -128,14 +130,29 @@ final class TestCaseMethodFactory
|
|||||||
throw ShouldNotHappen::fromMessage('Description can not be empty.');
|
throw ShouldNotHappen::fromMessage('Description can not be empty.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$closure = $this->closure;
|
|
||||||
|
|
||||||
$testCase = TestSuite::getInstance()->tests->get($this->filename);
|
$testCase = TestSuite::getInstance()->tests->get($this->filename);
|
||||||
|
|
||||||
assert($testCase instanceof TestCaseFactory);
|
assert($testCase instanceof TestCaseFactory);
|
||||||
$testCase->factoryProxies->proxy($concrete);
|
$testCase->factoryProxies->proxy($concrete);
|
||||||
$this->factoryProxies->proxy($concrete);
|
$this->factoryProxies->proxy($concrete);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flushes the test case.
|
||||||
|
*/
|
||||||
|
public function tearDown(TestCase $concrete): void
|
||||||
|
{
|
||||||
|
$concrete::flush(); // @phpstan-ignore-line
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the test's closure.
|
||||||
|
*/
|
||||||
|
public function getClosure(): Closure
|
||||||
|
{
|
||||||
|
$closure = $this->closure;
|
||||||
|
$testCase = TestSuite::getInstance()->tests->get($this->filename);
|
||||||
|
assert($testCase instanceof TestCaseFactory);
|
||||||
$method = $this;
|
$method = $this;
|
||||||
|
|
||||||
return function (...$arguments) use ($testCase, $method, $closure): mixed { // @phpstan-ignore-line
|
return function (...$arguments) use ($testCase, $method, $closure): mixed { // @phpstan-ignore-line
|
||||||
@ -186,7 +203,7 @@ final class TestCaseMethodFactory
|
|||||||
];
|
];
|
||||||
|
|
||||||
foreach ($this->depends as $depend) {
|
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(
|
$this->attributes[] = new Attribute(
|
||||||
\PHPUnit\Framework\Attributes\Depends::class,
|
\PHPUnit\Framework\Attributes\Depends::class,
|
||||||
@ -209,10 +226,8 @@ final class TestCaseMethodFactory
|
|||||||
$attributesCode
|
$attributesCode
|
||||||
public function $methodName(...\$arguments)
|
public function $methodName(...\$arguments)
|
||||||
{
|
{
|
||||||
\$test = \Pest\TestSuite::getInstance()->tests->get(self::\$__filename)->getMethod(\$this->name())->getClosure(\$this);
|
|
||||||
|
|
||||||
return \$this->__runTest(
|
return \$this->__runTest(
|
||||||
\$test,
|
\$this->__test,
|
||||||
...\$arguments,
|
...\$arguments,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,7 +43,7 @@ if (! function_exists('beforeAll')) {
|
|||||||
*/
|
*/
|
||||||
function beforeAll(Closure $closure): void
|
function beforeAll(Closure $closure): void
|
||||||
{
|
{
|
||||||
if (! is_null(DescribeCall::describing())) {
|
if (DescribeCall::describing() !== []) {
|
||||||
$filename = Backtrace::file();
|
$filename = Backtrace::file();
|
||||||
|
|
||||||
throw new BeforeAllWithinDescribe($filename);
|
throw new BeforeAllWithinDescribe($filename);
|
||||||
@ -205,7 +205,7 @@ if (! function_exists('afterAll')) {
|
|||||||
*/
|
*/
|
||||||
function afterAll(Closure $closure): void
|
function afterAll(Closure $closure): void
|
||||||
{
|
{
|
||||||
if (! is_null(DescribeCall::describing())) {
|
if (DescribeCall::describing() !== []) {
|
||||||
$filename = Backtrace::file();
|
$filename = Backtrace::file();
|
||||||
|
|
||||||
throw new AfterAllWithinDescribe($filename);
|
throw new AfterAllWithinDescribe($filename);
|
||||||
@ -217,7 +217,7 @@ if (! function_exists('afterAll')) {
|
|||||||
|
|
||||||
if (! function_exists('covers')) {
|
if (! function_exists('covers')) {
|
||||||
/**
|
/**
|
||||||
* Specifies which classes, or functions, a test method covers.
|
* Specifies which classes, or functions, a test case covers.
|
||||||
*
|
*
|
||||||
* @param array<int, string>|string $classesOrFunctions
|
* @param array<int, string>|string $classesOrFunctions
|
||||||
*/
|
*/
|
||||||
@ -243,3 +243,38 @@ if (! function_exists('covers')) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (! function_exists('mutates')) {
|
||||||
|
/**
|
||||||
|
* Specifies which classes, enums, or traits a test case mutates.
|
||||||
|
*
|
||||||
|
* @param array<int, string>|string $targets
|
||||||
|
*/
|
||||||
|
function mutates(array|string ...$targets): void
|
||||||
|
{
|
||||||
|
$filename = Backtrace::file();
|
||||||
|
|
||||||
|
$beforeEachCall = (new BeforeEachCall(TestSuite::getInstance(), $filename));
|
||||||
|
$beforeEachCall->group('__pest_mutate_only');
|
||||||
|
|
||||||
|
/** @var MutationTestRunner $runner */
|
||||||
|
$runner = Container::getInstance()->get(MutationTestRunner::class);
|
||||||
|
/** @var \Pest\Mutate\Repositories\ConfigurationRepository $configurationRepository */
|
||||||
|
$configurationRepository = Container::getInstance()->get(ConfigurationRepository::class);
|
||||||
|
$everything = $configurationRepository->cliConfiguration->toArray()['everything'] ?? false;
|
||||||
|
$classes = $configurationRepository->cliConfiguration->toArray()['classes'] ?? false;
|
||||||
|
$paths = $configurationRepository->cliConfiguration->toArray()['paths'] ?? false;
|
||||||
|
|
||||||
|
if ($runner->isEnabled() && ! $everything && ! is_array($classes) && ! is_array($paths)) {
|
||||||
|
$beforeEachCall->only('__pest_mutate_only');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var ConfigurationRepository $configurationRepository */
|
||||||
|
$configurationRepository = Container::getInstance()->get(ConfigurationRepository::class);
|
||||||
|
$paths = $configurationRepository->cliConfiguration->toArray()['paths'] ?? false;
|
||||||
|
|
||||||
|
if (! is_array($paths)) {
|
||||||
|
$configurationRepository->globalConfiguration('default')->class(...$targets); // @phpstan-ignore-line
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -40,7 +40,7 @@ final class KernelDump
|
|||||||
*/
|
*/
|
||||||
public function disable(): void
|
public function disable(): void
|
||||||
{
|
{
|
||||||
@ob_clean(); // @phpstan-ignore-line
|
@ob_clean();
|
||||||
|
|
||||||
if ($this->buffer !== '') {
|
if ($this->buffer !== '') {
|
||||||
$this->flush();
|
$this->flush();
|
||||||
|
|||||||
@ -11,6 +11,7 @@ use Pest\Support\Str;
|
|||||||
use PHPUnit\Event\Code\Test;
|
use PHPUnit\Event\Code\Test;
|
||||||
use PHPUnit\Event\Code\TestMethod;
|
use PHPUnit\Event\Code\TestMethod;
|
||||||
use PHPUnit\Event\Code\Throwable;
|
use PHPUnit\Event\Code\Throwable;
|
||||||
|
use PHPUnit\Event\Test\AfterLastTestMethodErrored;
|
||||||
use PHPUnit\Event\Test\BeforeFirstTestMethodErrored;
|
use PHPUnit\Event\Test\BeforeFirstTestMethodErrored;
|
||||||
use PHPUnit\Event\Test\ConsideredRisky;
|
use PHPUnit\Event\Test\ConsideredRisky;
|
||||||
use PHPUnit\Event\Test\Errored;
|
use PHPUnit\Event\Test\Errored;
|
||||||
@ -18,6 +19,7 @@ use PHPUnit\Event\Test\Failed;
|
|||||||
use PHPUnit\Event\Test\MarkedIncomplete;
|
use PHPUnit\Event\Test\MarkedIncomplete;
|
||||||
use PHPUnit\Event\Test\Skipped;
|
use PHPUnit\Event\Test\Skipped;
|
||||||
use PHPUnit\Event\TestSuite\TestSuite;
|
use PHPUnit\Event\TestSuite\TestSuite;
|
||||||
|
use PHPUnit\Event\TestSuite\TestSuiteForTestMethodWithDataProvider;
|
||||||
use PHPUnit\Framework\Exception as FrameworkException;
|
use PHPUnit\Framework\Exception as FrameworkException;
|
||||||
use PHPUnit\TestRunner\TestResult\TestResult as PhpUnitTestResult;
|
use PHPUnit\TestRunner\TestResult\TestResult as PhpUnitTestResult;
|
||||||
|
|
||||||
@ -147,6 +149,13 @@ final readonly class Converter
|
|||||||
*/
|
*/
|
||||||
public function getTestSuiteName(TestSuite $testSuite): string
|
public function getTestSuiteName(TestSuite $testSuite): string
|
||||||
{
|
{
|
||||||
|
if ($testSuite instanceof TestSuiteForTestMethodWithDataProvider) {
|
||||||
|
$firstTest = $this->getFirstTest($testSuite);
|
||||||
|
if ($firstTest instanceof \PHPUnit\Event\Code\TestMethod) {
|
||||||
|
return $this->getTestMethodNameWithoutDatasetSuffix($firstTest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$name = $testSuite->name();
|
$name = $testSuite->name();
|
||||||
|
|
||||||
if (! str_starts_with($name, self::PREFIX)) {
|
if (! str_starts_with($name, self::PREFIX)) {
|
||||||
@ -168,6 +177,35 @@ final readonly class Converter
|
|||||||
* Gets the test suite location.
|
* Gets the test suite location.
|
||||||
*/
|
*/
|
||||||
public function getTestSuiteLocation(TestSuite $testSuite): ?string
|
public function getTestSuiteLocation(TestSuite $testSuite): ?string
|
||||||
|
{
|
||||||
|
$firstTest = $this->getFirstTest($testSuite);
|
||||||
|
if (! $firstTest instanceof \PHPUnit\Event\Code\TestMethod) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$path = $firstTest->testDox()->prettifiedClassName();
|
||||||
|
$classRelativePath = $this->toRelativePath($path);
|
||||||
|
|
||||||
|
if ($testSuite instanceof TestSuiteForTestMethodWithDataProvider) {
|
||||||
|
$methodName = $this->getTestMethodNameWithoutDatasetSuffix($firstTest);
|
||||||
|
|
||||||
|
return "$classRelativePath::$methodName";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $classRelativePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the prettified test method name without dataset-related suffix.
|
||||||
|
*/
|
||||||
|
private function getTestMethodNameWithoutDatasetSuffix(TestMethod $testMethod): string
|
||||||
|
{
|
||||||
|
return Str::beforeLast($testMethod->testDox()->prettifiedMethodName(), ' with data set ');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the first test from the test suite.
|
||||||
|
*/
|
||||||
|
private function getFirstTest(TestSuite $testSuite): ?TestMethod
|
||||||
{
|
{
|
||||||
$tests = $testSuite->tests()->asArray();
|
$tests = $testSuite->tests()->asArray();
|
||||||
|
|
||||||
@ -181,9 +219,7 @@ final readonly class Converter
|
|||||||
throw ShouldNotHappen::fromMessage('Not an instance of TestMethod');
|
throw ShouldNotHappen::fromMessage('Not an instance of TestMethod');
|
||||||
}
|
}
|
||||||
|
|
||||||
$path = $firstTest->testDox()->prettifiedClassName();
|
return $firstTest;
|
||||||
|
|
||||||
return $this->toRelativePath($path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -219,8 +255,9 @@ final readonly class Converter
|
|||||||
$numberOfNotPassedTests = count(
|
$numberOfNotPassedTests = count(
|
||||||
array_unique(
|
array_unique(
|
||||||
array_map(
|
array_map(
|
||||||
function (BeforeFirstTestMethodErrored|Errored|Failed|Skipped|ConsideredRisky|MarkedIncomplete $event): string {
|
function (AfterLastTestMethodErrored|BeforeFirstTestMethodErrored|Errored|Failed|Skipped|ConsideredRisky|MarkedIncomplete $event): string {
|
||||||
if ($event instanceof BeforeFirstTestMethodErrored) {
|
if ($event instanceof BeforeFirstTestMethodErrored
|
||||||
|
|| $event instanceof AfterLastTestMethodErrored) {
|
||||||
return $event->testClassName();
|
return $event->testClassName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -38,7 +38,7 @@ final class ServiceMessage
|
|||||||
{
|
{
|
||||||
return new self('testSuiteStarted', [
|
return new self('testSuiteStarted', [
|
||||||
'name' => $name,
|
'name' => $name,
|
||||||
'locationHint' => $location === null ? null : "file://$location",
|
'locationHint' => $location === null ? null : "pest_qn://$location",
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,7 @@ namespace Pest\PendingCalls;
|
|||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
use Pest\PendingCalls\Concerns\Describable;
|
use Pest\PendingCalls\Concerns\Describable;
|
||||||
|
use Pest\Support\Arr;
|
||||||
use Pest\Support\Backtrace;
|
use Pest\Support\Backtrace;
|
||||||
use Pest\Support\ChainableClosure;
|
use Pest\Support\ChainableClosure;
|
||||||
use Pest\Support\HigherOrderMessageCollection;
|
use Pest\Support\HigherOrderMessageCollection;
|
||||||
@ -54,8 +55,8 @@ final class AfterEachCall
|
|||||||
$proxies = $this->proxies;
|
$proxies = $this->proxies;
|
||||||
|
|
||||||
$afterEachTestCase = ChainableClosure::boundWhen(
|
$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
|
ChainableClosure::bound(fn () => $proxies->chain($this), $this->closure)->bindTo($this, self::class),
|
||||||
)->bindTo($this, self::class);
|
)->bindTo($this, self::class);
|
||||||
|
|
||||||
assert($afterEachTestCase instanceof Closure);
|
assert($afterEachTestCase instanceof Closure);
|
||||||
|
|||||||
@ -7,6 +7,7 @@ namespace Pest\PendingCalls;
|
|||||||
use Closure;
|
use Closure;
|
||||||
use Pest\Exceptions\AfterBeforeTestFunction;
|
use Pest\Exceptions\AfterBeforeTestFunction;
|
||||||
use Pest\PendingCalls\Concerns\Describable;
|
use Pest\PendingCalls\Concerns\Describable;
|
||||||
|
use Pest\Support\Arr;
|
||||||
use Pest\Support\Backtrace;
|
use Pest\Support\Backtrace;
|
||||||
use Pest\Support\ChainableClosure;
|
use Pest\Support\ChainableClosure;
|
||||||
use Pest\Support\HigherOrderMessageCollection;
|
use Pest\Support\HigherOrderMessageCollection;
|
||||||
@ -63,12 +64,12 @@ final class BeforeEachCall
|
|||||||
|
|
||||||
$beforeEachTestCall = function (TestCall $testCall) use ($describing): void {
|
$beforeEachTestCall = function (TestCall $testCall) use ($describing): void {
|
||||||
|
|
||||||
if ($this->describing !== null) {
|
if ($this->describing !== []) {
|
||||||
if ($describing !== $this->describing) {
|
if (Arr::last($describing) !== Arr::last($this->describing)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($describing !== $testCall->describing) {
|
if (! in_array(Arr::last($describing), $testCall->describing, true)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -77,8 +78,8 @@ final class BeforeEachCall
|
|||||||
};
|
};
|
||||||
|
|
||||||
$beforeEachTestCase = ChainableClosure::boundWhen(
|
$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
|
ChainableClosure::bound(fn () => $testCaseProxies->chain($this), $this->closure)->bindTo($this, self::class),
|
||||||
)->bindTo($this, self::class);
|
)->bindTo($this, self::class);
|
||||||
|
|
||||||
assert($beforeEachTestCase instanceof Closure);
|
assert($beforeEachTestCase instanceof Closure);
|
||||||
@ -96,7 +97,7 @@ final class BeforeEachCall
|
|||||||
*/
|
*/
|
||||||
public function after(Closure $closure): self
|
public function after(Closure $closure): self
|
||||||
{
|
{
|
||||||
if ($this->describing === null) {
|
if ($this->describing === []) {
|
||||||
throw new AfterBeforeTestFunction($this->filename);
|
throw new AfterBeforeTestFunction($this->filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -11,11 +11,15 @@ trait Describable
|
|||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Note: this is property is not used; however, it gets added automatically by rector php.
|
* 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.
|
* The describing of the test case.
|
||||||
|
*
|
||||||
|
* @var array<int, string>
|
||||||
*/
|
*/
|
||||||
public ?string $describing = null;
|
public array $describing = [];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,8 +15,10 @@ final class DescribeCall
|
|||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The current describe call.
|
* The current describe call.
|
||||||
|
*
|
||||||
|
* @var array<int, string>
|
||||||
*/
|
*/
|
||||||
private static ?string $describing = null;
|
private static array $describing = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The describe "before each" call.
|
* The describe "before each" call.
|
||||||
@ -37,8 +39,10 @@ final class DescribeCall
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* What is the current describing.
|
* What is the current describing.
|
||||||
|
*
|
||||||
|
* @return array<int, string>
|
||||||
*/
|
*/
|
||||||
public static function describing(): ?string
|
public static function describing(): array
|
||||||
{
|
{
|
||||||
return self::$describing;
|
return self::$describing;
|
||||||
}
|
}
|
||||||
@ -50,12 +54,12 @@ final class DescribeCall
|
|||||||
{
|
{
|
||||||
unset($this->currentBeforeEachCall);
|
unset($this->currentBeforeEachCall);
|
||||||
|
|
||||||
self::$describing = $this->description;
|
self::$describing[] = $this->description;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
($this->tests)();
|
($this->tests)();
|
||||||
} finally {
|
} finally {
|
||||||
self::$describing = null;
|
array_pop(self::$describing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,7 +75,7 @@ final class DescribeCall
|
|||||||
if (! $this->currentBeforeEachCall instanceof \Pest\PendingCalls\BeforeEachCall) {
|
if (! $this->currentBeforeEachCall instanceof \Pest\PendingCalls\BeforeEachCall) {
|
||||||
$this->currentBeforeEachCall = new BeforeEachCall(TestSuite::getInstance(), $filename);
|
$this->currentBeforeEachCall = new BeforeEachCall(TestSuite::getInstance(), $filename);
|
||||||
|
|
||||||
$this->currentBeforeEachCall->describing = $this->description;
|
$this->currentBeforeEachCall->describing[] = $this->description;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->currentBeforeEachCall->{$name}(...$arguments); // @phpstan-ignore-line
|
$this->currentBeforeEachCall->{$name}(...$arguments); // @phpstan-ignore-line
|
||||||
|
|||||||
@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||||||
namespace Pest\PendingCalls;
|
namespace Pest\PendingCalls;
|
||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
|
use Pest\Concerns\Testable;
|
||||||
use Pest\Exceptions\InvalidArgumentException;
|
use Pest\Exceptions\InvalidArgumentException;
|
||||||
use Pest\Exceptions\TestDescriptionMissing;
|
use Pest\Exceptions\TestDescriptionMissing;
|
||||||
use Pest\Factories\Attribute;
|
use Pest\Factories\Attribute;
|
||||||
@ -25,9 +26,9 @@ use PHPUnit\Framework\TestCase;
|
|||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*
|
*
|
||||||
* @mixin HigherOrderCallables|TestCase
|
* @mixin HigherOrderCallables|TestCase|Testable
|
||||||
*/
|
*/
|
||||||
final class TestCall
|
final class TestCall // @phpstan-ignore-line
|
||||||
{
|
{
|
||||||
use Describable;
|
use Describable;
|
||||||
|
|
||||||
@ -75,7 +76,7 @@ final class TestCall
|
|||||||
throw new TestDescriptionMissing($this->filename);
|
throw new TestDescriptionMissing($this->filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
$description = is_null($this->describing)
|
$description = $this->describing === []
|
||||||
? $this->description
|
? $this->description
|
||||||
: Str::describe($this->describing, $this->description);
|
: Str::describe($this->describing, $this->description);
|
||||||
|
|
||||||
@ -358,8 +359,8 @@ final class TestCall
|
|||||||
public function todo(// @phpstan-ignore-line
|
public function todo(// @phpstan-ignore-line
|
||||||
array|string|null $note = null,
|
array|string|null $note = null,
|
||||||
array|string|null $assignee = null,
|
array|string|null $assignee = null,
|
||||||
array|string|null $issue = null,
|
array|string|int|null $issue = null,
|
||||||
array|string|null $pr = null,
|
array|string|int|null $pr = null,
|
||||||
): self {
|
): self {
|
||||||
$this->skip('__TODO__');
|
$this->skip('__TODO__');
|
||||||
|
|
||||||
@ -390,8 +391,8 @@ final class TestCall
|
|||||||
public function wip(// @phpstan-ignore-line
|
public function wip(// @phpstan-ignore-line
|
||||||
array|string|null $note = null,
|
array|string|null $note = null,
|
||||||
array|string|null $assignee = null,
|
array|string|null $assignee = null,
|
||||||
array|string|null $issue = null,
|
array|string|int|null $issue = null,
|
||||||
array|string|null $pr = null,
|
array|string|int|null $pr = null,
|
||||||
): self {
|
): self {
|
||||||
if ($issue !== null) {
|
if ($issue !== null) {
|
||||||
$this->issue($issue);
|
$this->issue($issue);
|
||||||
@ -418,8 +419,8 @@ final class TestCall
|
|||||||
public function done(// @phpstan-ignore-line
|
public function done(// @phpstan-ignore-line
|
||||||
array|string|null $note = null,
|
array|string|null $note = null,
|
||||||
array|string|null $assignee = null,
|
array|string|null $assignee = null,
|
||||||
array|string|null $issue = null,
|
array|string|int|null $issue = null,
|
||||||
array|string|null $pr = null,
|
array|string|int|null $pr = null,
|
||||||
): self {
|
): self {
|
||||||
if ($issue !== null) {
|
if ($issue !== null) {
|
||||||
$this->issue($issue);
|
$this->issue($issue);
|
||||||
@ -682,7 +683,7 @@ final class TestCall
|
|||||||
throw new TestDescriptionMissing($this->filename);
|
throw new TestDescriptionMissing($this->filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! is_null($this->describing)) {
|
if ($this->describing !== []) {
|
||||||
$this->testCaseMethod->describing = $this->describing;
|
$this->testCaseMethod->describing = $this->describing;
|
||||||
$this->testCaseMethod->description = Str::describe($this->describing, $this->description);
|
$this->testCaseMethod->description = Str::describe($this->describing, $this->description);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -54,7 +54,7 @@ final class UsesCall
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use `pest()->theme()->compact()` instead.
|
* @deprecated Use `pest()->printer()->compact()` instead.
|
||||||
*/
|
*/
|
||||||
public function compact(): self
|
public function compact(): self
|
||||||
{
|
{
|
||||||
|
|||||||
@ -6,7 +6,7 @@ namespace Pest;
|
|||||||
|
|
||||||
function version(): string
|
function version(): string
|
||||||
{
|
{
|
||||||
return '3.0.1';
|
return '3.7.3';
|
||||||
}
|
}
|
||||||
|
|
||||||
function testDirectory(string $file = ''): string
|
function testDirectory(string $file = ''): string
|
||||||
|
|||||||
@ -27,6 +27,11 @@ final class Coverage implements AddsOutput, HandlesArguments
|
|||||||
*/
|
*/
|
||||||
private const MIN_OPTION = 'min';
|
private const MIN_OPTION = 'min';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private const EXACTLY_OPTION = 'exactly';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether it should show the coverage or not.
|
* Whether it should show the coverage or not.
|
||||||
*/
|
*/
|
||||||
@ -37,6 +42,11 @@ final class Coverage implements AddsOutput, HandlesArguments
|
|||||||
*/
|
*/
|
||||||
public float $coverageMin = 0.0;
|
public float $coverageMin = 0.0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The exactly coverage.
|
||||||
|
*/
|
||||||
|
public ?float $coverageExactly = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new Plugin instance.
|
* Creates a new Plugin instance.
|
||||||
*/
|
*/
|
||||||
@ -51,7 +61,7 @@ final class Coverage implements AddsOutput, HandlesArguments
|
|||||||
public function handleArguments(array $originals): array
|
public function handleArguments(array $originals): array
|
||||||
{
|
{
|
||||||
$arguments = [...[''], ...array_values(array_filter($originals, function (string $original): bool {
|
$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)) {
|
if ($original === sprintf('--%s', $option)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -73,6 +83,7 @@ final class Coverage implements AddsOutput, HandlesArguments
|
|||||||
$inputs = [];
|
$inputs = [];
|
||||||
$inputs[] = new InputOption(self::COVERAGE_OPTION, null, InputOption::VALUE_NONE);
|
$inputs[] = new InputOption(self::COVERAGE_OPTION, null, InputOption::VALUE_NONE);
|
||||||
$inputs[] = new InputOption(self::MIN_OPTION, null, InputOption::VALUE_REQUIRED);
|
$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));
|
$input = new ArgvInput($arguments, new InputDefinition($inputs));
|
||||||
if ((bool) $input->getOption(self::COVERAGE_OPTION)) {
|
if ((bool) $input->getOption(self::COVERAGE_OPTION)) {
|
||||||
@ -106,6 +117,13 @@ final class Coverage implements AddsOutput, HandlesArguments
|
|||||||
$this->coverageMin = (float) $minOption;
|
$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;
|
return $originals;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,10 +145,22 @@ final class Coverage implements AddsOutput, HandlesArguments
|
|||||||
}
|
}
|
||||||
|
|
||||||
$coverage = \Pest\Support\Coverage::report($this->output);
|
$coverage = \Pest\Support\Coverage::report($this->output);
|
||||||
|
|
||||||
$exitCode = (int) ($coverage < $this->coverageMin);
|
$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(
|
$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 %%</>.",
|
"\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),
|
number_format($this->coverageMin, 1),
|
||||||
@ -143,4 +173,12 @@ final class Coverage implements AddsOutput, HandlesArguments
|
|||||||
|
|
||||||
return $exitCode;
|
return $exitCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the comparable coverage to a percentage with one decimal.
|
||||||
|
*/
|
||||||
|
private function computeComparableCoverage(float $coverage): float
|
||||||
|
{
|
||||||
|
return floor($coverage * 10) / 10;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,6 +19,7 @@ use Pest\TestSuite;
|
|||||||
use PHPUnit\Event\Facade as EventFacade;
|
use PHPUnit\Event\Facade as EventFacade;
|
||||||
use PHPUnit\Event\TestRunner\WarningTriggered;
|
use PHPUnit\Event\TestRunner\WarningTriggered;
|
||||||
use PHPUnit\Runner\CodeCoverage;
|
use PHPUnit\Runner\CodeCoverage;
|
||||||
|
use PHPUnit\Runner\ResultCache\DefaultResultCache;
|
||||||
use PHPUnit\TestRunner\TestResult\Facade as TestResultFacade;
|
use PHPUnit\TestRunner\TestResult\Facade as TestResultFacade;
|
||||||
use PHPUnit\TestRunner\TestResult\TestResult;
|
use PHPUnit\TestRunner\TestResult\TestResult;
|
||||||
use PHPUnit\TextUI\Configuration\CodeCoverageFilterRegistry;
|
use PHPUnit\TextUI\Configuration\CodeCoverageFilterRegistry;
|
||||||
@ -79,7 +80,10 @@ final class WrapperRunner implements RunnerInterface
|
|||||||
private array $unexpectedOutputFiles = [];
|
private array $unexpectedOutputFiles = [];
|
||||||
|
|
||||||
/** @var list<SplFileInfo> */
|
/** @var list<SplFileInfo> */
|
||||||
private array $testresultFiles = [];
|
private array $resultCacheFiles = [];
|
||||||
|
|
||||||
|
/** @var list<SplFileInfo> */
|
||||||
|
private array $testResultFiles = [];
|
||||||
|
|
||||||
/** @var list<SplFileInfo> */
|
/** @var list<SplFileInfo> */
|
||||||
private array $coverageFiles = [];
|
private array $coverageFiles = [];
|
||||||
@ -122,6 +126,9 @@ final class WrapperRunner implements RunnerInterface
|
|||||||
$parameters = array_merge($parameters, $options->passthruPhp);
|
$parameters = array_merge($parameters, $options->passthruPhp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @var array<int, non-empty-string> $parameters */
|
||||||
|
$parameters = $this->handleLaravelHerd($parameters);
|
||||||
|
|
||||||
$parameters[] = $wrapper;
|
$parameters[] = $wrapper;
|
||||||
|
|
||||||
$this->parameters = $parameters;
|
$this->parameters = $parameters;
|
||||||
@ -153,6 +160,21 @@ final class WrapperRunner implements RunnerInterface
|
|||||||
return $this->complete($result);
|
return $this->complete($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles Laravel Herd's debug and coverage modes.
|
||||||
|
*
|
||||||
|
* @param array<string> $parameters
|
||||||
|
* @return array<string>
|
||||||
|
*/
|
||||||
|
private function handleLaravelHerd(array $parameters): array
|
||||||
|
{
|
||||||
|
if (isset($_ENV['HERD_DEBUG_INI'])) {
|
||||||
|
return array_merge($parameters, ['-c', $_ENV['HERD_DEBUG_INI']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $parameters;
|
||||||
|
}
|
||||||
|
|
||||||
private function startWorkers(): void
|
private function startWorkers(): void
|
||||||
{
|
{
|
||||||
for ($token = 1; $token <= $this->options->processes; $token++) {
|
for ($token = 1; $token <= $this->options->processes; $token++) {
|
||||||
@ -246,7 +268,8 @@ final class WrapperRunner implements RunnerInterface
|
|||||||
$this->batches[$token] = 0;
|
$this->batches[$token] = 0;
|
||||||
|
|
||||||
$this->unexpectedOutputFiles[] = $worker->unexpectedOutputFile;
|
$this->unexpectedOutputFiles[] = $worker->unexpectedOutputFile;
|
||||||
$this->testresultFiles[] = $worker->testresultFile;
|
$this->unexpectedOutputFiles[] = $worker->unexpectedOutputFile;
|
||||||
|
$this->testResultFiles[] = $worker->testResultFile;
|
||||||
|
|
||||||
if (isset($worker->junitFile)) {
|
if (isset($worker->junitFile)) {
|
||||||
$this->junitFiles[] = $worker->junitFile;
|
$this->junitFiles[] = $worker->junitFile;
|
||||||
@ -280,12 +303,12 @@ final class WrapperRunner implements RunnerInterface
|
|||||||
|
|
||||||
private function complete(TestResult $testResultSum): int
|
private function complete(TestResult $testResultSum): int
|
||||||
{
|
{
|
||||||
foreach ($this->testresultFiles as $testresultFile) {
|
foreach ($this->testResultFiles as $testResultFile) {
|
||||||
if (! $testresultFile->isFile()) {
|
if (! $testResultFile->isFile()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$contents = file_get_contents($testresultFile->getPathname());
|
$contents = file_get_contents($testResultFile->getPathname());
|
||||||
assert($contents !== false);
|
assert($contents !== false);
|
||||||
$testResult = unserialize($contents);
|
$testResult = unserialize($contents);
|
||||||
assert($testResult instanceof TestResult);
|
assert($testResult instanceof TestResult);
|
||||||
@ -342,9 +365,20 @@ final class WrapperRunner implements RunnerInterface
|
|||||||
$testResultSum->phpNotices(),
|
$testResultSum->phpNotices(),
|
||||||
$testResultSum->phpWarnings(),
|
$testResultSum->phpWarnings(),
|
||||||
$testResultSum->numberOfIssuesIgnoredByBaseline(),
|
$testResultSum->numberOfIssuesIgnoredByBaseline(),
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if ($this->options->configuration->cacheResult()) {
|
||||||
|
$resultCacheSum = new DefaultResultCache($this->options->configuration->testResultCacheFile());
|
||||||
|
foreach ($this->resultCacheFiles as $resultCacheFile) {
|
||||||
|
$resultCache = new DefaultResultCache($resultCacheFile->getPathname());
|
||||||
|
$resultCache->load();
|
||||||
|
|
||||||
|
$resultCacheSum->mergeWith($resultCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
$resultCacheSum->persist();
|
||||||
|
}
|
||||||
|
|
||||||
$this->printer->printResults(
|
$this->printer->printResults(
|
||||||
$testResultSum,
|
$testResultSum,
|
||||||
$this->teamcityFiles,
|
$this->teamcityFiles,
|
||||||
@ -357,7 +391,7 @@ final class WrapperRunner implements RunnerInterface
|
|||||||
$exitcode = Result::exitCode($this->options->configuration, $testResultSum);
|
$exitcode = Result::exitCode($this->options->configuration, $testResultSum);
|
||||||
|
|
||||||
$this->clearFiles($this->unexpectedOutputFiles);
|
$this->clearFiles($this->unexpectedOutputFiles);
|
||||||
$this->clearFiles($this->testresultFiles);
|
$this->clearFiles($this->testResultFiles);
|
||||||
$this->clearFiles($this->coverageFiles);
|
$this->clearFiles($this->coverageFiles);
|
||||||
$this->clearFiles($this->junitFiles);
|
$this->clearFiles($this->junitFiles);
|
||||||
$this->clearFiles($this->teamcityFiles);
|
$this->clearFiles($this->teamcityFiles);
|
||||||
|
|||||||
@ -81,4 +81,14 @@ final class Arr
|
|||||||
|
|
||||||
return $results;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,13 +20,13 @@ final class Closure
|
|||||||
*/
|
*/
|
||||||
public static function bind(?BaseClosure $closure, ?object $newThis, object|string|null $newScope = 'static'): BaseClosure
|
public static function bind(?BaseClosure $closure, ?object $newThis, object|string|null $newScope = 'static'): BaseClosure
|
||||||
{
|
{
|
||||||
if ($closure == null) {
|
if (! $closure instanceof \Closure) {
|
||||||
throw ShouldNotHappen::fromMessage('Could not bind null closure.');
|
throw ShouldNotHappen::fromMessage('Could not bind null closure.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$closure = BaseClosure::bind($closure, $newThis, $newScope);
|
$closure = BaseClosure::bind($closure, $newThis, $newScope);
|
||||||
|
|
||||||
if ($closure == false) {
|
if (! $closure instanceof \Closure) {
|
||||||
throw ShouldNotHappen::fromMessage('Could not bind closure.');
|
throw ShouldNotHappen::fromMessage('Could not bind closure.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -30,6 +30,7 @@ final class StateGenerator
|
|||||||
$testResultEvent->throwable()
|
$testResultEvent->throwable()
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
|
// @phpstan-ignore-next-line
|
||||||
$state->add(TestResult::fromBeforeFirstTestMethodErrored($testResultEvent));
|
$state->add(TestResult::fromBeforeFirstTestMethodErrored($testResultEvent));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -103,10 +103,14 @@ final class Str
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a describe block as `$describeDescription` → `$testDescription` format.
|
* 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
Pest Testing Framework 3.0.1.
|
Pest Testing Framework 3.7.3.
|
||||||
|
|
||||||
USAGE: pest <file> [options]
|
USAGE: pest <file> [options]
|
||||||
|
|
||||||
@ -35,6 +35,7 @@
|
|||||||
--exclude-group [name] ........... Exclude tests from the specified group(s)
|
--exclude-group [name] ........... Exclude tests from the specified group(s)
|
||||||
--covers [name] ................. Only run tests that intend to cover [name]
|
--covers [name] ................. Only run tests that intend to cover [name]
|
||||||
--uses [name] ..................... Only run tests that intend to use [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-test-files ................................ List available test files
|
||||||
--list-tests .......................................... List available tests
|
--list-tests .......................................... List available tests
|
||||||
--list-tests-xml [file] ................. List available tests in XML format
|
--list-tests-xml [file] ................. List available tests in XML format
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
↓ todo on describe → should not fail
|
↓ todo on describe → should not fail
|
||||||
↓ todo on describe → should run
|
↓ todo on describe → should run
|
||||||
|
|
||||||
TODO Tests\Features\Todo - 7 todos
|
TODO Tests\Features\Todo - 28 todos
|
||||||
↓ something todo later
|
↓ something todo later
|
||||||
↓ something todo later chained
|
↓ something todo later chained
|
||||||
↓ something todo later chained and with function body
|
↓ something todo later chained and with function body
|
||||||
@ -24,6 +24,52 @@
|
|||||||
↓ it may have an associated PR #1
|
↓ it may have an associated PR #1
|
||||||
↓ it may have an associated note
|
↓ it may have an associated note
|
||||||
// a 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
|
PASS Tests\CustomTestCase\ChildTest
|
||||||
✓ override method
|
✓ override method
|
||||||
@ -34,6 +80,6 @@
|
|||||||
PASS Tests\CustomTestCase\ParentTest
|
PASS Tests\CustomTestCase\ParentTest
|
||||||
✓ override method
|
✓ override method
|
||||||
|
|
||||||
Tests: 17 todos, 3 passed (3 assertions)
|
Tests: 38 todos, 3 passed (20 assertions)
|
||||||
Duration: x.xxs
|
Duration: x.xxs
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
↓ todo on describe → should not fail
|
↓ todo on describe → should not fail
|
||||||
↓ todo on describe → should run
|
↓ todo on describe → should run
|
||||||
|
|
||||||
TODO Tests\Features\Todo - 7 todos
|
TODO Tests\Features\Todo - 28 todos
|
||||||
↓ something todo later
|
↓ something todo later
|
||||||
↓ something todo later chained
|
↓ something todo later chained
|
||||||
↓ something todo later chained and with function body
|
↓ something todo later chained and with function body
|
||||||
@ -24,6 +24,52 @@
|
|||||||
↓ it may have an associated PR #1
|
↓ it may have an associated PR #1
|
||||||
↓ it may have an associated note
|
↓ it may have an associated note
|
||||||
// a 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
|
PASS Tests\CustomTestCase\ChildTest
|
||||||
✓ override method
|
✓ override method
|
||||||
@ -34,6 +80,6 @@
|
|||||||
PASS Tests\CustomTestCase\ParentTest
|
PASS Tests\CustomTestCase\ParentTest
|
||||||
✓ override method
|
✓ override method
|
||||||
|
|
||||||
Tests: 17 todos, 3 passed (3 assertions)
|
Tests: 38 todos, 3 passed (20 assertions)
|
||||||
Duration: x.xxs
|
Duration: x.xxs
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
↓ todo on describe → should not fail
|
↓ todo on describe → should not fail
|
||||||
↓ todo on describe → should run
|
↓ todo on describe → should run
|
||||||
|
|
||||||
TODO Tests\Features\Todo - 7 todos
|
TODO Tests\Features\Todo - 28 todos
|
||||||
↓ something todo later
|
↓ something todo later
|
||||||
↓ something todo later chained
|
↓ something todo later chained
|
||||||
↓ something todo later chained and with function body
|
↓ something todo later chained and with function body
|
||||||
@ -24,6 +24,52 @@
|
|||||||
↓ it may have an associated PR #1
|
↓ it may have an associated PR #1
|
||||||
↓ it may have an associated note
|
↓ it may have an associated note
|
||||||
// a 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
|
PASS Tests\CustomTestCase\ChildTest
|
||||||
✓ override method
|
✓ override method
|
||||||
@ -34,6 +80,6 @@
|
|||||||
PASS Tests\CustomTestCase\ParentTest
|
PASS Tests\CustomTestCase\ParentTest
|
||||||
✓ override method
|
✓ override method
|
||||||
|
|
||||||
Tests: 17 todos, 3 passed (3 assertions)
|
Tests: 38 todos, 3 passed (20 assertions)
|
||||||
Duration: x.xxs
|
Duration: x.xxs
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
↓ todo on describe → should not fail
|
↓ todo on describe → should not fail
|
||||||
↓ todo on describe → should run
|
↓ todo on describe → should run
|
||||||
|
|
||||||
TODO Tests\Features\Todo - 7 todos
|
TODO Tests\Features\Todo - 28 todos
|
||||||
↓ something todo later
|
↓ something todo later
|
||||||
↓ something todo later chained
|
↓ something todo later chained
|
||||||
↓ something todo later chained and with function body
|
↓ something todo later chained and with function body
|
||||||
@ -24,6 +24,52 @@
|
|||||||
↓ it may have an associated PR #1
|
↓ it may have an associated PR #1
|
||||||
↓ it may have an associated note
|
↓ it may have an associated note
|
||||||
// a 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
|
PASS Tests\CustomTestCase\ChildTest
|
||||||
✓ override method
|
✓ override method
|
||||||
@ -34,6 +80,6 @@
|
|||||||
PASS Tests\CustomTestCase\ParentTest
|
PASS Tests\CustomTestCase\ParentTest
|
||||||
✓ override method
|
✓ override method
|
||||||
|
|
||||||
Tests: 17 todos, 3 passed (3 assertions)
|
Tests: 38 todos, 3 passed (20 assertions)
|
||||||
Duration: x.xxs
|
Duration: x.xxs
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
|
|
||||||
Pest Testing Framework 3.0.1.
|
Pest Testing Framework 3.7.3.
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
##teamcity[testSuiteStarted name='Tests/tests/Failure' locationHint='file://tests/.tests/Failure.php' flowId='1234']
|
##teamcity[testSuiteStarted name='Tests/tests/Failure' locationHint='pest_qn://tests/.tests/Failure.php' flowId='1234']
|
||||||
##teamcity[testCount count='8' flowId='1234']
|
##teamcity[testCount count='8' flowId='1234']
|
||||||
##teamcity[testStarted name='it can fail with comparison' locationHint='pest_qn://tests/.tests/Failure.php::it can fail with comparison' flowId='1234']
|
##teamcity[testStarted name='it can fail with comparison' locationHint='pest_qn://tests/.tests/Failure.php::it can fail with comparison' flowId='1234']
|
||||||
##teamcity[testFailed name='it can fail with comparison' message='Failed asserting that true matches expected false.' details='at tests/.tests/Failure.php:6' type='comparisonFailure' actual='true' expected='false' flowId='1234']
|
##teamcity[testFailed name='it can fail with comparison' message='Failed asserting that true matches expected false.' details='at tests/.tests/Failure.php:6' type='comparisonFailure' actual='true' expected='false' flowId='1234']
|
||||||
|
|||||||
@ -1,11 +1,15 @@
|
|||||||
##teamcity[testSuiteStarted name='Tests/tests/SuccessOnly' locationHint='file://tests/.tests/SuccessOnly.php' flowId='1234']
|
##teamcity[testSuiteStarted name='Tests/tests/SuccessOnly' locationHint='pest_qn://tests/.tests/SuccessOnly.php' flowId='1234']
|
||||||
##teamcity[testCount count='2' flowId='1234']
|
##teamcity[testCount count='3' flowId='1234']
|
||||||
##teamcity[testStarted name='it can pass with comparison' locationHint='pest_qn://tests/.tests/SuccessOnly.php::it can pass with comparison' flowId='1234']
|
##teamcity[testStarted name='it can pass with comparison' locationHint='pest_qn://tests/.tests/SuccessOnly.php::it can pass with comparison' flowId='1234']
|
||||||
##teamcity[testFinished name='it can pass with comparison' duration='100000' flowId='1234']
|
##teamcity[testFinished name='it can pass with comparison' duration='100000' flowId='1234']
|
||||||
##teamcity[testStarted name='can also pass' locationHint='pest_qn://tests/.tests/SuccessOnly.php::can also pass' flowId='1234']
|
##teamcity[testStarted name='can also pass' locationHint='pest_qn://tests/.tests/SuccessOnly.php::can also pass' flowId='1234']
|
||||||
##teamcity[testFinished name='can also pass' duration='100000' flowId='1234']
|
##teamcity[testFinished name='can also pass' duration='100000' flowId='1234']
|
||||||
|
##teamcity[testSuiteStarted name='can pass with dataset' locationHint='pest_qn://tests/.tests/SuccessOnly.php::can pass with dataset' flowId='1234']
|
||||||
|
##teamcity[testStarted name='can pass with dataset with data set "(true)"' locationHint='pest_qn://tests/.tests/SuccessOnly.php::can pass with dataset with data set "(true)"' flowId='1234']
|
||||||
|
##teamcity[testFinished name='can pass with dataset with data set "(true)"' duration='100000' flowId='1234']
|
||||||
|
##teamcity[testSuiteFinished name='can pass with dataset' flowId='1234']
|
||||||
##teamcity[testSuiteFinished name='Tests/tests/SuccessOnly' flowId='1234']
|
##teamcity[testSuiteFinished name='Tests/tests/SuccessOnly' flowId='1234']
|
||||||
|
|
||||||
[90mTests:[39m [32;1m2 passed[39;22m[90m (2 assertions)[39m
|
[90mTests:[39m [32;1m3 passed[39;22m[90m (3 assertions)[39m
|
||||||
[90mDuration:[39m [39m1.00s[39m
|
[90mDuration:[39m [39m1.00s[39m
|
||||||
|
|
||||||
|
|||||||
@ -27,6 +27,8 @@
|
|||||||
PASS Tests\Features\AfterEach
|
PASS Tests\Features\AfterEach
|
||||||
✓ it does not get executed before the test
|
✓ it does not get executed before the test
|
||||||
✓ it gets executed after 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
|
PASS Tests\Features\Assignee
|
||||||
✓ it may be associated with an assignee [@nunomaduro, @taylorotwell]
|
✓ it may be associated with an assignee [@nunomaduro, @taylorotwell]
|
||||||
@ -40,6 +42,9 @@
|
|||||||
PASS Tests\Features\BeforeEach
|
PASS Tests\Features\BeforeEach
|
||||||
✓ it gets executed before each test
|
✓ it gets executed before each test
|
||||||
✓ it gets executed before each test once again
|
✓ 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
|
PASS Tests\Features\BeforeEachProxiesToTestCallWithExpectations
|
||||||
✓ runs 1
|
✓ runs 1
|
||||||
@ -178,6 +183,14 @@
|
|||||||
✓ it may be used with high order with dataset "informal"
|
✓ 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 "formal"
|
||||||
✓ it may be used with high order even when bound with dataset "informal"
|
✓ 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
|
PASS Tests\Features\Depends
|
||||||
✓ first
|
✓ first
|
||||||
@ -188,6 +201,13 @@
|
|||||||
✓ depends run test only once
|
✓ depends run test only once
|
||||||
✓ it asserts true is true
|
✓ it asserts true is true
|
||||||
✓ depends works with the correct test name
|
✓ 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
|
PASS Tests\Features\DependsInheritance
|
||||||
✓ it is a test
|
✓ it is a test
|
||||||
@ -215,6 +235,7 @@
|
|||||||
✓ depends on describe → bar
|
✓ depends on describe → bar
|
||||||
✓ depends on describe using with → foo with (3)
|
✓ depends on describe using with → foo with (3)
|
||||||
✓ depends on describe using with → bar with (3)
|
✓ depends on describe using with → bar with (3)
|
||||||
|
✓ with test after describe → it should run the before each
|
||||||
|
|
||||||
PASS Tests\Features\DescriptionLess
|
PASS Tests\Features\DescriptionLess
|
||||||
✓ get 'foo'
|
✓ get 'foo'
|
||||||
@ -968,6 +989,16 @@
|
|||||||
✓ it can handle a non-defined exception
|
✓ it can handle a non-defined exception
|
||||||
✓ it can handle a class not found Error
|
✓ it can handle a class not found Error
|
||||||
|
|
||||||
|
PASS Tests\Features\Expect\toUseStrictEquality
|
||||||
|
✓ missing strict equality
|
||||||
|
✓ has strict equality
|
||||||
|
✓ opposite missing strict equality
|
||||||
|
✓ opposite has strict equality
|
||||||
|
|
||||||
|
PASS Tests\Features\Expect\toUseStrictTypes
|
||||||
|
✓ pass
|
||||||
|
✓ failures
|
||||||
|
|
||||||
PASS Tests\Features\Expect\toUseTrait
|
PASS Tests\Features\Expect\toUseTrait
|
||||||
✓ pass
|
✓ pass
|
||||||
✓ failures
|
✓ failures
|
||||||
@ -1057,9 +1088,22 @@
|
|||||||
✓ nested → it may have static note and runtime note
|
✓ nested → it may have static note and runtime note
|
||||||
// This is before each static note
|
// This is before each static note
|
||||||
// This is describe static note
|
// This is describe static note
|
||||||
|
// This is before each describe static note
|
||||||
// This is a static note within describe
|
// This is a static note within describe
|
||||||
// This is before each runtime note
|
// This is before each runtime note
|
||||||
|
// This is before each describe runtime note
|
||||||
// This is a runtime note within describe
|
// 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
|
✓ multiple notes
|
||||||
// This is before each static note
|
// This is before each static note
|
||||||
// This is before each runtime note
|
// This is before each runtime note
|
||||||
@ -1189,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') / ('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') / ('e') @ repetition 2 of 2
|
||||||
✓ multiple times with repeat iterator with multiple dataset ('c') / ('f') @ 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
|
PASS Tests\Features\ScopedDatasets\Directory\NestedDirectory1\TestFileInNestedDirectoryWithDatasetsFile
|
||||||
✓ uses dataset with (1)
|
✓ uses dataset with (1)
|
||||||
@ -1245,6 +1306,14 @@
|
|||||||
- it skips when skip after assertion
|
- it skips when skip after assertion
|
||||||
- it can use something in the test case as a condition → This test was skipped
|
- it can use something in the test case as a condition → This test was skipped
|
||||||
- it can user higher order callables and skip
|
- 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
|
WARN Tests\Features\SkipOnPhp
|
||||||
✓ it can run on php version
|
✓ it can run on php version
|
||||||
@ -1265,7 +1334,7 @@
|
|||||||
✓ nested → it may be associated with an ticket #1, #4, #5, #6, #3
|
✓ nested → it may be associated with an ticket #1, #4, #5, #6, #3
|
||||||
// an note between an the ticket
|
// an note between an the ticket
|
||||||
|
|
||||||
PASS Tests\Features\Todo - 7 todos
|
PASS Tests\Features\Todo - 28 todos
|
||||||
↓ something todo later
|
↓ something todo later
|
||||||
↓ something todo later chained
|
↓ something todo later chained
|
||||||
↓ something todo later chained and with function body
|
↓ something todo later chained and with function body
|
||||||
@ -1275,6 +1344,54 @@
|
|||||||
↓ it may have an associated PR #1
|
↓ it may have an associated PR #1
|
||||||
↓ it may have an associated note
|
↓ it may have an associated note
|
||||||
// a 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
|
WARN Tests\Features\Warnings
|
||||||
! warning → Undefined property: P\Tests\Features\Warnings::$fooqwdfwqdfqw
|
! warning → Undefined property: P\Tests\Features\Warnings::$fooqwdfwqdfqw
|
||||||
@ -1305,6 +1422,7 @@
|
|||||||
✓ it executes tests in the Helpers directory
|
✓ it executes tests in the Helpers directory
|
||||||
|
|
||||||
PASS Tests\Hooks\AfterEachTest
|
PASS Tests\Hooks\AfterEachTest
|
||||||
|
✓ nested → nested afterEach execution order
|
||||||
✓ global afterEach execution order
|
✓ global afterEach execution order
|
||||||
|
|
||||||
PASS Tests\Hooks\BeforeEachTest
|
PASS Tests\Hooks\BeforeEachTest
|
||||||
@ -1373,6 +1491,16 @@
|
|||||||
PASS Tests\Playground
|
PASS Tests\Playground
|
||||||
✓ basic
|
✓ basic
|
||||||
|
|
||||||
|
PASS Tests\Plugins\Coverage
|
||||||
|
✓ compute comparable coverage with (0, 0)
|
||||||
|
✓ compute comparable coverage with (0.5, 0.5)
|
||||||
|
✓ compute comparable coverage with (1.0, 1.0)
|
||||||
|
✓ compute comparable coverage with (32.51, 32.5)
|
||||||
|
✓ compute comparable coverage with (32.12312321312312, 32.1)
|
||||||
|
✓ compute comparable coverage with (32.53333333333333, 32.5)
|
||||||
|
✓ compute comparable coverage with (32.57777771232132, 32.5)
|
||||||
|
✓ compute comparable coverage with (100.0, 100.0)
|
||||||
|
|
||||||
PASS Tests\Plugins\Traits
|
PASS Tests\Plugins\Traits
|
||||||
✓ it allows global uses
|
✓ it allows global uses
|
||||||
✓ it allows multiple global uses registered in the same path
|
✓ it allows multiple global uses registered in the same path
|
||||||
@ -1381,7 +1509,7 @@
|
|||||||
✓ it proxies to uses call
|
✓ it proxies to uses call
|
||||||
|
|
||||||
PASS Tests\Unit\Configuration\Theme
|
PASS Tests\Unit\Configuration\Theme
|
||||||
✓ it creates a theme instance
|
✓ it creates a printer instance
|
||||||
|
|
||||||
PASS Tests\Unit\Console\Help
|
PASS Tests\Unit\Console\Help
|
||||||
✓ it outputs the help information when --help is used
|
✓ it outputs the help information when --help is used
|
||||||
@ -1422,6 +1550,13 @@
|
|||||||
✓ preset invalid name
|
✓ preset invalid name
|
||||||
✓ preset → myFramework
|
✓ 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
|
PASS Tests\Unit\Support\Backtrace
|
||||||
✓ it gets file name from called file
|
✓ it gets file name from called file
|
||||||
|
|
||||||
@ -1573,4 +1708,4 @@
|
|||||||
WARN Tests\Visual\Version
|
WARN Tests\Visual\Version
|
||||||
- visual snapshot of help command output
|
- visual snapshot of help command output
|
||||||
|
|
||||||
Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 17 todos, 28 skipped, 1088 passed (2615 assertions)
|
Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 38 todos, 33 skipped, 1152 passed (2744 assertions)
|
||||||
@ -9,3 +9,7 @@ it('can pass with comparison', function () {
|
|||||||
test('can also pass', function () {
|
test('can also pass', function () {
|
||||||
expect("string")->toBeString();
|
expect("string")->toBeString();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('can pass with dataset', function ($value) {
|
||||||
|
expect($value)->toEqual(true);
|
||||||
|
})->with([true]);
|
||||||
|
|||||||
@ -26,3 +26,25 @@ it('gets executed after the test', function () {
|
|||||||
afterEach(function () {
|
afterEach(function () {
|
||||||
$this->state->bar = 2;
|
$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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@ -25,3 +25,29 @@ it('gets executed before each test once again', function () {
|
|||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
$this->bar++;
|
$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 () {});
|
||||||
|
});
|
||||||
|
|||||||
@ -392,3 +392,40 @@ it('may be used with high order even when bound')
|
|||||||
->with('greeting-bound')
|
->with('greeting-bound')
|
||||||
->expect(fn (string $greeting) => $greeting)
|
->expect(fn (string $greeting) => $greeting)
|
||||||
->throws(InvalidArgumentException::class);
|
->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');
|
||||||
|
|||||||
@ -36,3 +36,43 @@ test('depends run test only once', function () use (&$runCounter) {
|
|||||||
// Regression tests. See https://github.com/pestphp/pest/pull/216
|
// Regression tests. See https://github.com/pestphp/pest/pull/216
|
||||||
it('asserts true is true')->assertTrue(true);
|
it('asserts true is true')->assertTrue(true);
|
||||||
test('depends works with the correct test name')->assertTrue(true)->depends('it asserts true is 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');
|
||||||
|
|||||||
@ -96,3 +96,15 @@ describe('depends on describe using with', function () {
|
|||||||
expect($foo + $foo)->toBe(6);
|
expect($foo + $foo)->toBe(6);
|
||||||
})->depends('foo');
|
})->depends('foo');
|
||||||
})->with([3]);
|
})->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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
21
tests/Features/Expect/toUseStrictEquality.php
Normal file
21
tests/Features/Expect/toUseStrictEquality.php
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Pest\Arch\Exceptions\ArchExpectationFailedException;
|
||||||
|
|
||||||
|
test('missing strict equality')
|
||||||
|
->throws(ArchExpectationFailedException::class)
|
||||||
|
->expect('Tests\\Fixtures\\Arch\\ToUseStrictEquality\\NotStrictEquality')
|
||||||
|
->toUseStrictEquality();
|
||||||
|
|
||||||
|
test('has strict equality')
|
||||||
|
->expect('Tests\\Fixtures\\Arch\\ToUseStrictEquality\\StrictEquality')
|
||||||
|
->toUseStrictEquality();
|
||||||
|
|
||||||
|
test('opposite missing strict equality')
|
||||||
|
->throws(ArchExpectationFailedException::class)
|
||||||
|
->expect('Tests\\Fixtures\\Arch\\ToUseStrictEquality\\StrictEquality')
|
||||||
|
->not->toUseStrictEquality();
|
||||||
|
|
||||||
|
test('opposite has strict equality')
|
||||||
|
->expect('Tests\\Fixtures\\Arch\\ToUseStrictEquality\\NotStrictEquality')
|
||||||
|
->not->toUseStrictEquality();
|
||||||
17
tests/Features/Expect/toUseStrictTypes.php
Normal file
17
tests/Features/Expect/toUseStrictTypes.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Pest\Arch\Exceptions\ArchExpectationFailedException;
|
||||||
|
use Tests\Fixtures\Arch\ToUseStrictTypes\HasNoStrictType;
|
||||||
|
use Tests\Fixtures\Arch\ToUseStrictTypes\HasStrictType;
|
||||||
|
use Tests\Fixtures\Arch\ToUseStrictTypes\HasStrictTypeWithCommentsAbove;
|
||||||
|
|
||||||
|
test('pass', function () {
|
||||||
|
expect(HasStrictType::class)->toUseStrictTypes()
|
||||||
|
->and(HasStrictTypeWithCommentsAbove::class)->toUseStrictTypes();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('failures', function () {
|
||||||
|
expect(HasNoStrictType::class)->toUseStrictTypes();
|
||||||
|
})->throws(ArchExpectationFailedException::class);
|
||||||
@ -21,11 +21,27 @@ it('may have static note and runtime note', function () {
|
|||||||
})->note('This is a static note');
|
})->note('This is a static note');
|
||||||
|
|
||||||
describe('nested', function () {
|
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 () {
|
it('may have static note and runtime note', function () {
|
||||||
expect(true)->toBeTrue(true);
|
expect(true)->toBeTrue(true);
|
||||||
|
|
||||||
$this->note('This is a runtime note within describe');
|
$this->note('This is a runtime note within describe');
|
||||||
})->note('This is a static 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');
|
})->note('This is describe static note');
|
||||||
|
|
||||||
test('multiple notes', function () {
|
test('multiple notes', function () {
|
||||||
|
|||||||
@ -43,3 +43,39 @@ test('multiple times with repeat iterator with multiple dataset', function (stri
|
|||||||
->toBeNumeric()
|
->toBeNumeric()
|
||||||
->toBeGreaterThan(0);
|
->toBeGreaterThan(0);
|
||||||
})->repeat(times: 2)->with(['a', 'b', 'c'], ['d', 'e', 'f']);
|
})->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);
|
||||||
|
});
|
||||||
|
|||||||
@ -54,3 +54,81 @@ it('can user higher order callables and skip')
|
|||||||
return $this->shouldSkip;
|
return $this->shouldSkip;
|
||||||
})
|
})
|
||||||
->toBeFalse();
|
->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();
|
||||||
|
|||||||
@ -27,3 +27,175 @@ it('may have an associated PR', function () {
|
|||||||
it('may have an associated note', function () {
|
it('may have an associated note', function () {
|
||||||
expect(true)->toBeTrue();
|
expect(true)->toBeTrue();
|
||||||
})->todo(note: 'a note');
|
})->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');
|
||||||
|
|||||||
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Tests\Fixtures\Arch\ToUseStrictEquality;
|
||||||
|
|
||||||
|
class NotStrictEquality
|
||||||
|
{
|
||||||
|
public function test(): void
|
||||||
|
{
|
||||||
|
$a = 1;
|
||||||
|
$b = '1';
|
||||||
|
|
||||||
|
if ($a == $b) {
|
||||||
|
echo 'Equal';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($a != $b) {
|
||||||
|
echo 'Equal';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
22
tests/Fixtures/Arch/ToUseStrictEquality/StrictEquality.php
Normal file
22
tests/Fixtures/Arch/ToUseStrictEquality/StrictEquality.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Tests\Fixtures\Arch\ToUseStrictEquality;
|
||||||
|
|
||||||
|
class StrictEquality
|
||||||
|
{
|
||||||
|
public function test(): void
|
||||||
|
{
|
||||||
|
$a = 1;
|
||||||
|
$b = '1';
|
||||||
|
|
||||||
|
if ($a === $b) {
|
||||||
|
echo 'Equal';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($a !== $b) {
|
||||||
|
echo 'Equal';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
5
tests/Fixtures/Arch/ToUseStrictTypes/HasNoStrictType.php
Normal file
5
tests/Fixtures/Arch/ToUseStrictTypes/HasNoStrictType.php
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Fixtures\Arch\ToUseStrictTypes;
|
||||||
|
|
||||||
|
class HasNoStrictType {}
|
||||||
7
tests/Fixtures/Arch/ToUseStrictTypes/HasStrictType.php
Normal file
7
tests/Fixtures/Arch/ToUseStrictTypes/HasStrictType.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Tests\Fixtures\Arch\ToUseStrictTypes;
|
||||||
|
|
||||||
|
class HasStrictType {}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/** @noinspection PhpUnused */
|
||||||
|
|
||||||
|
// some other comment
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Tests\Fixtures\Arch\ToUseStrictTypes;
|
||||||
|
|
||||||
|
class HasStrictTypeWithCommentsAbove {}
|
||||||
@ -6,7 +6,7 @@ use PHPUnit\Framework\TestCase;
|
|||||||
|
|
||||||
class ExampleTest extends TestCase
|
class ExampleTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testExample()
|
public function test_example()
|
||||||
{
|
{
|
||||||
$this->markTestSkipped();
|
$this->markTestSkipped();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ class ExampleTest extends Base\ExampleTest
|
|||||||
{
|
{
|
||||||
protected $foo;
|
protected $foo;
|
||||||
|
|
||||||
public function testExample()
|
public function test_example()
|
||||||
{
|
{
|
||||||
$this->assertTrue(true);
|
$this->assertTrue(true);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,23 +1,79 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
$this->ith = 0;
|
||||||
|
});
|
||||||
|
|
||||||
pest()->afterEach(function () {
|
pest()->afterEach(function () {
|
||||||
expect($this)
|
expect($this)
|
||||||
->toHaveProperty('ith')
|
->toHaveProperty('ith')
|
||||||
->and($this->ith)
|
->and($this->ith)
|
||||||
->toBe(1);
|
->toBe(3);
|
||||||
|
|
||||||
$this->ith = 2;
|
$this->ith++;
|
||||||
|
});
|
||||||
|
|
||||||
|
pest()->afterEach(function () {
|
||||||
|
expect($this)
|
||||||
|
->toHaveProperty('ith')
|
||||||
|
->and($this->ith)
|
||||||
|
->toBe(4);
|
||||||
|
|
||||||
|
$this->ith++;
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function () {
|
afterEach(function () {
|
||||||
expect($this)
|
expect($this)
|
||||||
->toHaveProperty('ith')
|
->toHaveProperty('ith')
|
||||||
->and($this->ith)
|
->and($this->ith)
|
||||||
->toBe(2);
|
->toBe(5);
|
||||||
|
|
||||||
|
$this->ith++;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('nested', function () {
|
||||||
|
afterEach(function () {
|
||||||
|
expect($this)
|
||||||
|
->toHaveProperty('ith')
|
||||||
|
->and($this->ith)
|
||||||
|
->toBe(6);
|
||||||
|
|
||||||
|
$this->ith++;
|
||||||
|
});
|
||||||
|
|
||||||
|
test('nested afterEach execution order', function () {
|
||||||
|
expect($this)
|
||||||
|
->toHaveProperty('ith')
|
||||||
|
->and($this->ith)
|
||||||
|
->toBe(0);
|
||||||
|
|
||||||
|
$this->ith++;
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
expect($this)
|
||||||
|
->toHaveProperty('ith')
|
||||||
|
->and($this->ith)
|
||||||
|
->toBe(7);
|
||||||
|
|
||||||
|
$this->ith++;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
expect($this)
|
||||||
|
->toHaveProperty('ith')
|
||||||
|
->and($this->ith)
|
||||||
|
->toBeBetween(6, 8);
|
||||||
|
|
||||||
|
$this->ith++;
|
||||||
});
|
});
|
||||||
|
|
||||||
test('global afterEach execution order', function () {
|
test('global afterEach execution order', function () {
|
||||||
expect($this)
|
expect($this)
|
||||||
->not()
|
->toHaveProperty('ith')
|
||||||
->toHaveProperty('ith');
|
->and($this->ith)
|
||||||
|
->toBe(0);
|
||||||
|
|
||||||
|
$this->ith++;
|
||||||
});
|
});
|
||||||
|
|||||||
@ -13,7 +13,7 @@ class ExecutedTest extends TestCase
|
|||||||
public static $executed = false;
|
public static $executed = false;
|
||||||
|
|
||||||
#[Test]
|
#[Test]
|
||||||
public function testThatGetsExecuted(): void
|
public function test_that_gets_executed(): void
|
||||||
{
|
{
|
||||||
self::$executed = true;
|
self::$executed = true;
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@ class ParentTest extends TestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Test]
|
#[Test]
|
||||||
public function testOverrideMethod(): void
|
public function test_override_method(): void
|
||||||
{
|
{
|
||||||
assertTrue($this->getEntity() || true);
|
assertTrue($this->getEntity() || true);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,7 +32,12 @@ pest()
|
|||||||
$_SERVER['globalHook']->calls->beforeAll++;
|
$_SERVER['globalHook']->calls->beforeAll++;
|
||||||
})
|
})
|
||||||
->afterEach(function () {
|
->afterEach(function () {
|
||||||
$this->ith = 0;
|
if (! isset($this->ith)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert($this->ith === 1, 'Expected $this->ith to be 1, but got '.$this->ith);
|
||||||
|
$this->ith++;
|
||||||
})
|
})
|
||||||
->afterAll(function () {
|
->afterAll(function () {
|
||||||
$_SERVER['globalHook']->afterAll = 0;
|
$_SERVER['globalHook']->afterAll = 0;
|
||||||
@ -57,12 +62,12 @@ pest()->in('Hooks')
|
|||||||
$_SERVER['globalHook']->beforeAll = 1;
|
$_SERVER['globalHook']->beforeAll = 1;
|
||||||
})
|
})
|
||||||
->afterEach(function () {
|
->afterEach(function () {
|
||||||
expect($this)
|
if (! isset($this->ith)) {
|
||||||
->toHaveProperty('ith')
|
return;
|
||||||
->and($this->ith)
|
}
|
||||||
->toBe(0);
|
|
||||||
|
|
||||||
$this->ith = 1;
|
assert($this->ith === 2, 'Expected $this->ith to be 1, but got '.$this->ith);
|
||||||
|
$this->ith++;
|
||||||
})
|
})
|
||||||
->afterAll(function () {
|
->afterAll(function () {
|
||||||
expect($_SERVER['globalHook'])
|
expect($_SERVER['globalHook'])
|
||||||
|
|||||||
23
tests/Plugins/Coverage.php
Normal file
23
tests/Plugins/Coverage.php
Normal 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],
|
||||||
|
]);
|
||||||
@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
it('creates a theme instance', function () {
|
it('creates a printer instance', function () {
|
||||||
$theme = pest()->theme();
|
$theme = pest()->printer();
|
||||||
|
|
||||||
expect($theme)->toBeInstanceOf(Pest\Configuration\Theme::class);
|
expect($theme)->toBeInstanceOf(Pest\Configuration\Printer::class);
|
||||||
});
|
});
|
||||||
|
|||||||
49
tests/Unit/Support/Arr.php
Normal file
49
tests/Unit/Support/Arr.php
Normal 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);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -36,8 +36,8 @@ test('junit output', function () use ($normalizedPath, $run) {
|
|||||||
expect($result['testsuite']['@attributes'])
|
expect($result['testsuite']['@attributes'])
|
||||||
->name->toBe('Tests\tests\SuccessOnly')
|
->name->toBe('Tests\tests\SuccessOnly')
|
||||||
->file->toBe($normalizedPath('tests/.tests/SuccessOnly.php'))
|
->file->toBe($normalizedPath('tests/.tests/SuccessOnly.php'))
|
||||||
->tests->toBe('2')
|
->tests->toBe('3')
|
||||||
->assertions->toBe('2')
|
->assertions->toBe('3')
|
||||||
->errors->toBe('0')
|
->errors->toBe('0')
|
||||||
->failures->toBe('0')
|
->failures->toBe('0')
|
||||||
->skipped->toBe('0');
|
->skipped->toBe('0');
|
||||||
|
|||||||
@ -16,7 +16,7 @@ $run = function () {
|
|||||||
|
|
||||||
test('parallel', function () use ($run) {
|
test('parallel', function () use ($run) {
|
||||||
expect($run('--exclude-group=integration'))
|
expect($run('--exclude-group=integration'))
|
||||||
->toContain('Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 17 todos, 19 skipped, 1078 passed (2591 assertions)')
|
->toContain('Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 38 todos, 24 skipped, 1142 passed (2720 assertions)')
|
||||||
->toContain('Parallel: 3 processes');
|
->toContain('Parallel: 3 processes');
|
||||||
})->skipOnWindows();
|
})->skipOnWindows();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user