mirror of
https://github.com/pestphp/pest.git
synced 2026-03-06 15:57:21 +01:00
Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6c8970e0a3 | |||
| 2f2b51ce3d | |||
| 33f596bcce | |||
| 50a96dcb8f | |||
| d9a4fa33b9 | |||
| cc6bd59df9 | |||
| 3ce6408195 | |||
| 1c673fcff9 | |||
| ff82596158 | |||
| 0539d2ba62 | |||
| 221ac62f03 | |||
| 4b6c949032 | |||
| 1915ad368a | |||
| 1408cffc02 | |||
| 95b5379945 | |||
| a4833bbfe4 | |||
| cb1c777b9b | |||
| 7433cc5565 | |||
| 4c769fac66 | |||
| 176d3efbc6 | |||
| d635665c1b | |||
| 22467d05c8 | |||
| 7a699e16db | |||
| 341ba56bb9 | |||
| a320cc3e2b | |||
| 8b428357b2 | |||
| bb6d6b0951 | |||
| b94b8c6a4f | |||
| 43894afa18 | |||
| 28de31a8b9 | |||
| 974e70d7d1 | |||
| f914f1ad87 | |||
| 14dd5cb57b | |||
| 077ed287b7 | |||
| 9a41f2ff82 | |||
| 88f29e4180 | |||
| a8bd353ba6 | |||
| ecbaff503e | |||
| da4bf7f5c3 | |||
| 7d89d3546e | |||
| 1f3e5115c7 | |||
| 9de85175db |
41
.github/workflows/integration-tests.yml
vendored
Normal file
41
.github/workflows/integration-tests.yml
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
name: Integration Tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 * * *'
|
||||||
|
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
ci:
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
|
php: ['8.1', '8.2']
|
||||||
|
dependency-version: [prefer-lowest, prefer-stable]
|
||||||
|
|
||||||
|
name: PHP ${{ matrix.php }} - ${{ matrix.os }} - ${{ matrix.dependency-version }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Setup PHP
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: ${{ matrix.php }}
|
||||||
|
tools: composer:v2
|
||||||
|
coverage: none
|
||||||
|
|
||||||
|
- name: Setup Problem Matches
|
||||||
|
run: |
|
||||||
|
echo "::add-matcher::${{ runner.tool_cache }}/php.json"
|
||||||
|
echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
|
||||||
|
|
||||||
|
- name: Install PHP dependencies
|
||||||
|
run: composer update --${{ matrix.dependency-version }} --no-interaction --no-progress --ansi
|
||||||
|
|
||||||
|
- name: Integration Tests
|
||||||
|
run: composer test:integration
|
||||||
|
|
||||||
3
.github/workflows/tests.yml
vendored
3
.github/workflows/tests.yml
vendored
@ -43,6 +43,3 @@ jobs:
|
|||||||
- name: Unit Tests in Parallel
|
- name: Unit Tests in Parallel
|
||||||
run: composer test:parallel
|
run: composer test:parallel
|
||||||
if: startsWith(matrix.os, 'windows') != true
|
if: startsWith(matrix.os, 'windows') != true
|
||||||
|
|
||||||
- name: Integration Tests
|
|
||||||
run: composer test:integration
|
|
||||||
|
|||||||
30
CHANGELOG.md
30
CHANGELOG.md
@ -2,6 +2,36 @@
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
## [v2.2.3 (2023-03-24)](https://github.com/pestphp/pest/compare/v2.2.2...v2.2.3)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Unnecessary dataset on dataset arguments missmatch ([#736](https://github.com/pestphp/pest/pull/736))
|
||||||
|
- Parallel arguments on plugins order ([#703](https://github.com/pestphp/pest/pull/703))
|
||||||
|
- Arch plugin runtime exceptions on bad phpdocs ([2f2b51c](https://github.com/pestphp/pest/commit/2f2b51ce3d1b000be9d6add0e785fd0044931b3b))
|
||||||
|
|
||||||
|
## [v2.2.2 (2023-03-23)](https://github.com/pestphp/pest/compare/v2.2.1...v2.2.2)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Edge case in parallel executation test description ([3ce6408](https://github.com/pestphp/pest/commit/3ce640819541ca6022b250e000f336d87c3e7889))
|
||||||
|
|
||||||
|
## [v2.2.1 (2023-03-22)](https://github.com/pestphp/pest/compare/v2.2.0...v2.2.1)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Collision between tests names with underscores ([#724](https://github.com/pestphp/pest/pull/724))
|
||||||
|
|
||||||
|
### Chore
|
||||||
|
- Bumps PHPUnit to `^10.0.18` ([1408cff](https://github.com/pestphp/pest/commit/1408cffc028690057e44f00038f9390f776e6bfb))
|
||||||
|
|
||||||
|
## [v2.2.0 (2023-03-22)](https://github.com/pestphp/pest/compare/v2.1.0...v2.2.0)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Improved error messages on dataset arguments mismatch ([#698](https://github.com/pestphp/pest/pull/698))
|
||||||
|
- Allows the usage of `DateTimeInterface` on multiple expectations ([#716](https://github.com/pestphp/pest/pull/716))
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- `--dirty` option on Windows environments ([#721](https://github.com/pestphp/pest/pull/721))
|
||||||
|
- Parallel exit code when `phpunit.xml` is outdated ([14dd5cb](https://github.com/pestphp/pest/commit/14dd5cb57b9432300ac4e8095f069941cb43bdb5))
|
||||||
|
|
||||||
## [v2.1.0 (2023-03-21)](https://github.com/pestphp/pest/compare/v2.0.2...v2.1.0)
|
## [v2.1.0 (2023-03-21)](https://github.com/pestphp/pest/compare/v2.0.2...v2.1.0)
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@ -19,15 +19,15 @@
|
|||||||
"require": {
|
"require": {
|
||||||
"php": "^8.1.0",
|
"php": "^8.1.0",
|
||||||
"brianium/paratest": "^7.1.2",
|
"brianium/paratest": "^7.1.2",
|
||||||
"nunomaduro/collision": "^7.3.1",
|
"nunomaduro/collision": "^7.3.3",
|
||||||
"nunomaduro/termwind": "^1.15.1",
|
"nunomaduro/termwind": "^1.15.1",
|
||||||
"pestphp/pest-plugin": "^2.0.0",
|
"pestphp/pest-plugin": "^2.0.1",
|
||||||
"pestphp/pest-plugin-arch": "^2.0.1",
|
"pestphp/pest-plugin-arch": "^2.0.2",
|
||||||
"phpunit/phpunit": "^10.0.17"
|
"phpunit/phpunit": "^10.0.18"
|
||||||
},
|
},
|
||||||
"conflict": {
|
"conflict": {
|
||||||
"webmozart/assert": "<1.11.0",
|
"webmozart/assert": "<1.11.0",
|
||||||
"phpunit/phpunit": ">10.0.17"
|
"phpunit/phpunit": ">10.0.18"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
@ -71,7 +71,7 @@
|
|||||||
"test:unit": "php bin/pest --colors=always --exclude-group=integration --compact",
|
"test:unit": "php bin/pest --colors=always --exclude-group=integration --compact",
|
||||||
"test:inline": "php bin/pest --colors=always --configuration=phpunit.inline.xml",
|
"test:inline": "php bin/pest --colors=always --configuration=phpunit.inline.xml",
|
||||||
"test:parallel": "php bin/pest --colors=always --exclude-group=integration --parallel --processes=10",
|
"test:parallel": "php bin/pest --colors=always --exclude-group=integration --parallel --processes=10",
|
||||||
"test:integration": "php bin/pest --colors=always --group=integration -v",
|
"test:integration": "php bin/pest --colors=always --group=integration",
|
||||||
"update:snapshots": "REBUILD_SNAPSHOTS=true php bin/pest --colors=always",
|
"update:snapshots": "REBUILD_SNAPSHOTS=true php bin/pest --colors=always",
|
||||||
"test": [
|
"test": [
|
||||||
"@test:refacto",
|
"@test:refacto",
|
||||||
|
|||||||
@ -2,7 +2,7 @@ ARG PHP=8.1
|
|||||||
FROM php:${PHP}-cli-alpine
|
FROM php:${PHP}-cli-alpine
|
||||||
|
|
||||||
RUN apk update \
|
RUN apk update \
|
||||||
&& apk add zip libzip-dev icu-dev
|
&& apk add zip libzip-dev icu-dev git
|
||||||
|
|
||||||
RUN docker-php-ext-configure zip
|
RUN docker-php-ext-configure zip
|
||||||
RUN docker-php-ext-install zip
|
RUN docker-php-ext-install zip
|
||||||
|
|||||||
@ -5,11 +5,14 @@ declare(strict_types=1);
|
|||||||
namespace Pest\Concerns;
|
namespace Pest\Concerns;
|
||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
|
use Pest\Exceptions\DatasetArgsCountMismatch;
|
||||||
use Pest\Support\ChainableClosure;
|
use Pest\Support\ChainableClosure;
|
||||||
use Pest\Support\ExceptionTrace;
|
use Pest\Support\ExceptionTrace;
|
||||||
use Pest\Support\Reflection;
|
use Pest\Support\Reflection;
|
||||||
use Pest\TestSuite;
|
use Pest\TestSuite;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use ReflectionException;
|
||||||
|
use ReflectionFunction;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -212,7 +215,10 @@ trait Testable
|
|||||||
*/
|
*/
|
||||||
private function __runTest(Closure $closure, ...$args): mixed
|
private function __runTest(Closure $closure, ...$args): mixed
|
||||||
{
|
{
|
||||||
return $this->__callClosure($closure, $this->__resolveTestArguments($args));
|
$arguments = $this->__resolveTestArguments($args);
|
||||||
|
$this->__ensureDatasetArgumentNumberMatches($arguments);
|
||||||
|
|
||||||
|
return $this->__callClosure($closure, $arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -235,7 +241,7 @@ trait Testable
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_array($testParameterTypes[$argumentIndex], [\Closure::class, 'callable', 'mixed'])) {
|
if (in_array($testParameterTypes[$argumentIndex], [Closure::class, 'callable', 'mixed'])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,7 +255,7 @@ trait Testable
|
|||||||
return $arguments;
|
return $arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_array($testParameterTypes[0], [\Closure::class, 'callable'])) {
|
if (in_array($testParameterTypes[0], [Closure::class, 'callable'])) {
|
||||||
return $arguments;
|
return $arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,6 +270,30 @@ trait Testable
|
|||||||
return array_values($boundDatasetResult);
|
return array_values($boundDatasetResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures dataset items count matches underlying test case required parameters
|
||||||
|
*
|
||||||
|
* @throws ReflectionException
|
||||||
|
* @throws DatasetArgsCountMismatch
|
||||||
|
*/
|
||||||
|
private function __ensureDatasetArgumentNumberMatches(array $arguments): void
|
||||||
|
{
|
||||||
|
if ($arguments === []) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$underlyingTest = Reflection::getFunctionVariable($this->__test, 'closure');
|
||||||
|
$testReflection = new ReflectionFunction($underlyingTest);
|
||||||
|
$requiredParametersCount = $testReflection->getNumberOfRequiredParameters();
|
||||||
|
$suppliedParametersCount = count($arguments);
|
||||||
|
|
||||||
|
if ($suppliedParametersCount >= $requiredParametersCount) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new DatasetArgsCountMismatch($requiredParametersCount, $suppliedParametersCount);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -10,7 +10,7 @@ namespace Pest\Contracts\Plugins;
|
|||||||
interface HandlesArguments
|
interface HandlesArguments
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Adds arguments before of the Test Suite execution.
|
* Adds arguments before the Test Suite execution.
|
||||||
*
|
*
|
||||||
* @param array<int, string> $arguments
|
* @param array<int, string> $arguments
|
||||||
* @return array<int, string>
|
* @return array<int, string>
|
||||||
|
|||||||
15
src/Exceptions/DatasetArgsCountMismatch.php
Normal file
15
src/Exceptions/DatasetArgsCountMismatch.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Pest\Exceptions;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
final class DatasetArgsCountMismatch extends Exception
|
||||||
|
{
|
||||||
|
public function __construct(int $requiredCount, int $suppliedCount)
|
||||||
|
{
|
||||||
|
parent::__construct(sprintf('Test expects %d arguments but dataset only provides %d', $requiredCount, $suppliedCount));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -11,7 +11,9 @@ use Pest\Plugins\Actions\CallsBoot;
|
|||||||
use Pest\Plugins\Actions\CallsHandleArguments;
|
use Pest\Plugins\Actions\CallsHandleArguments;
|
||||||
use Pest\Plugins\Actions\CallsShutdown;
|
use Pest\Plugins\Actions\CallsShutdown;
|
||||||
use Pest\Support\Container;
|
use Pest\Support\Container;
|
||||||
|
use PHPUnit\TestRunner\TestResult\Facade;
|
||||||
use PHPUnit\TextUI\Application;
|
use PHPUnit\TextUI\Application;
|
||||||
|
use PHPUnit\TextUI\Configuration\Registry;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
@ -90,8 +92,11 @@ final class Kernel
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$configuration = Registry::get();
|
||||||
|
$result = Facade::result();
|
||||||
|
|
||||||
return CallsAddsOutput::execute(
|
return CallsAddsOutput::execute(
|
||||||
Result::exitCode(),
|
Result::exitCode($configuration, $result),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,7 @@ namespace Pest\Mixins;
|
|||||||
|
|
||||||
use BadMethodCallException;
|
use BadMethodCallException;
|
||||||
use Closure;
|
use Closure;
|
||||||
|
use DateTimeInterface;
|
||||||
use Error;
|
use Error;
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use Pest\Exceptions\InvalidExpectationValue;
|
use Pest\Exceptions\InvalidExpectationValue;
|
||||||
@ -124,7 +125,7 @@ final class Expectation
|
|||||||
*
|
*
|
||||||
* @return self<TValue>
|
* @return self<TValue>
|
||||||
*/
|
*/
|
||||||
public function toBeGreaterThan(int|float $expected, string $message = ''): self
|
public function toBeGreaterThan(int|float|DateTimeInterface $expected, string $message = ''): self
|
||||||
{
|
{
|
||||||
Assert::assertGreaterThan($expected, $this->value, $message);
|
Assert::assertGreaterThan($expected, $this->value, $message);
|
||||||
|
|
||||||
@ -136,7 +137,7 @@ final class Expectation
|
|||||||
*
|
*
|
||||||
* @return self<TValue>
|
* @return self<TValue>
|
||||||
*/
|
*/
|
||||||
public function toBeGreaterThanOrEqual(int|float $expected, string $message = ''): self
|
public function toBeGreaterThanOrEqual(int|float|DateTimeInterface $expected, string $message = ''): self
|
||||||
{
|
{
|
||||||
Assert::assertGreaterThanOrEqual($expected, $this->value, $message);
|
Assert::assertGreaterThanOrEqual($expected, $this->value, $message);
|
||||||
|
|
||||||
@ -148,7 +149,7 @@ final class Expectation
|
|||||||
*
|
*
|
||||||
* @return self<TValue>
|
* @return self<TValue>
|
||||||
*/
|
*/
|
||||||
public function toBeLessThan(int|float $expected, string $message = ''): self
|
public function toBeLessThan(int|float|DateTimeInterface $expected, string $message = ''): self
|
||||||
{
|
{
|
||||||
Assert::assertLessThan($expected, $this->value, $message);
|
Assert::assertLessThan($expected, $this->value, $message);
|
||||||
|
|
||||||
@ -160,7 +161,7 @@ final class Expectation
|
|||||||
*
|
*
|
||||||
* @return self<TValue>
|
* @return self<TValue>
|
||||||
*/
|
*/
|
||||||
public function toBeLessThanOrEqual(int|float $expected, string $message = ''): self
|
public function toBeLessThanOrEqual(int|float|DateTimeInterface $expected, string $message = ''): self
|
||||||
{
|
{
|
||||||
Assert::assertLessThanOrEqual($expected, $this->value, $message);
|
Assert::assertLessThanOrEqual($expected, $this->value, $message);
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ namespace Pest;
|
|||||||
|
|
||||||
function version(): string
|
function version(): string
|
||||||
{
|
{
|
||||||
return '2.1.0';
|
return '2.2.3';
|
||||||
}
|
}
|
||||||
|
|
||||||
function testDirectory(string $file = ''): string
|
function testDirectory(string $file = ''): string
|
||||||
|
|||||||
@ -102,6 +102,13 @@ final class Help implements HandlesArguments
|
|||||||
'desc' => 'Initialise a standard Pest configuration',
|
'desc' => 'Initialise a standard Pest configuration',
|
||||||
]], ...$content['Configuration']];
|
]], ...$content['Configuration']];
|
||||||
|
|
||||||
|
$content['Execution'] = [...[
|
||||||
|
[
|
||||||
|
'arg' => '--parallel',
|
||||||
|
'desc' => 'Run tests in parallel',
|
||||||
|
],
|
||||||
|
], ...$content['Execution']];
|
||||||
|
|
||||||
$content['Selection'] = array_merge([
|
$content['Selection'] = array_merge([
|
||||||
[
|
[
|
||||||
'arg' => '--bail',
|
'arg' => '--bail',
|
||||||
|
|||||||
@ -14,15 +14,16 @@ use Pest\Support\Arr;
|
|||||||
use Pest\Support\Container;
|
use Pest\Support\Container;
|
||||||
use Pest\TestSuite;
|
use Pest\TestSuite;
|
||||||
use function Pest\version;
|
use function Pest\version;
|
||||||
|
use Stringable;
|
||||||
use Symfony\Component\Console\Application;
|
use Symfony\Component\Console\Application;
|
||||||
use Symfony\Component\Console\Command\Command;
|
|
||||||
use Symfony\Component\Console\Input\ArgvInput;
|
use Symfony\Component\Console\Input\ArgvInput;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
|
||||||
|
|
||||||
final class Parallel implements HandlesArguments
|
final class Parallel implements HandlesArguments
|
||||||
{
|
{
|
||||||
use HandleArguments;
|
use HandleArguments;
|
||||||
|
|
||||||
|
private const GLOBAL_PREFIX = 'PEST_PARALLEL_GLOBAL_';
|
||||||
|
|
||||||
private const HANDLERS = [
|
private const HANDLERS = [
|
||||||
Parallel\Handlers\Parallel::class,
|
Parallel\Handlers\Parallel::class,
|
||||||
Parallel\Handlers\Pest::class,
|
Parallel\Handlers\Pest::class,
|
||||||
@ -59,6 +60,33 @@ final class Parallel implements HandlesArguments
|
|||||||
return ((int) $argvValue) === 1;
|
return ((int) $argvValue) === 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a global value that can be accessed by the parent process and all workers.
|
||||||
|
*/
|
||||||
|
public static function setGlobal(string $key, string|int|bool|Stringable $value): void
|
||||||
|
{
|
||||||
|
$data = ['value' => $value instanceof Stringable ? $value->__toString() : $value];
|
||||||
|
|
||||||
|
$_ENV[self::GLOBAL_PREFIX.$key] = json_encode($data, JSON_THROW_ON_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the given global value if one has been set.
|
||||||
|
*/
|
||||||
|
public static function getGlobal(string $key): string|int|bool|null
|
||||||
|
{
|
||||||
|
$placesToCheck = [$_SERVER, $_ENV];
|
||||||
|
|
||||||
|
foreach ($placesToCheck as $location) {
|
||||||
|
if (array_key_exists(self::GLOBAL_PREFIX.$key, $location)) {
|
||||||
|
// @phpstan-ignore-next-line
|
||||||
|
return json_decode((string) $location[self::GLOBAL_PREFIX.$key], true, 512, JSON_THROW_ON_ERROR)['value'] ?? null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
@ -86,12 +114,6 @@ final class Parallel implements HandlesArguments
|
|||||||
*/
|
*/
|
||||||
private function runTestSuiteInParallel(array $arguments): int
|
private function runTestSuiteInParallel(array $arguments): int
|
||||||
{
|
{
|
||||||
if (! class_exists(ParaTestCommand::class)) {
|
|
||||||
$this->askUserToInstallParatest();
|
|
||||||
|
|
||||||
return Command::FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
$handlers = array_filter(
|
$handlers = array_filter(
|
||||||
array_map(fn ($handler): object|string => Container::getInstance()->get($handler), self::HANDLERS),
|
array_map(fn ($handler): object|string => Container::getInstance()->get($handler), self::HANDLERS),
|
||||||
fn ($handler): bool => $handler instanceof HandlesArguments,
|
fn ($handler): bool => $handler instanceof HandlesArguments,
|
||||||
@ -128,20 +150,6 @@ final class Parallel implements HandlesArguments
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Outputs a message to the user asking them to install ParaTest as a dev dependency.
|
|
||||||
*/
|
|
||||||
private function askUserToInstallParatest(): void
|
|
||||||
{
|
|
||||||
/** @var OutputInterface $output */
|
|
||||||
$output = Container::getInstance()->get(OutputInterface::class);
|
|
||||||
|
|
||||||
$output->writeln([
|
|
||||||
'<fg=red>Pest Parallel requires ParaTest to run.</>',
|
|
||||||
'Please run <fg=yellow>composer require --dev brianium/paratest</>.',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds an instance of the Paratest command.
|
* Builds an instance of the Paratest command.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -20,13 +20,13 @@ use ParaTest\Options;
|
|||||||
use ParaTest\RunnerInterface;
|
use ParaTest\RunnerInterface;
|
||||||
use ParaTest\WrapperRunner\SuiteLoader;
|
use ParaTest\WrapperRunner\SuiteLoader;
|
||||||
use ParaTest\WrapperRunner\WrapperWorker;
|
use ParaTest\WrapperRunner\WrapperWorker;
|
||||||
|
use Pest\Result;
|
||||||
use Pest\TestSuite;
|
use Pest\TestSuite;
|
||||||
use PHPUnit\Event\Facade as EventFacade;
|
use PHPUnit\Event\Facade as EventFacade;
|
||||||
use PHPUnit\Runner\CodeCoverage;
|
use PHPUnit\Runner\CodeCoverage;
|
||||||
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;
|
||||||
use PHPUnit\TextUI\ShellExitCodeCalculator;
|
|
||||||
use PHPUnit\Util\ExcludeList;
|
use PHPUnit\Util\ExcludeList;
|
||||||
use function realpath;
|
use function realpath;
|
||||||
use SebastianBergmann\Timer\Timer;
|
use SebastianBergmann\Timer\Timer;
|
||||||
@ -330,14 +330,7 @@ final class WrapperRunner implements RunnerInterface
|
|||||||
$this->generateCodeCoverageReports();
|
$this->generateCodeCoverageReports();
|
||||||
$this->generateLogs();
|
$this->generateLogs();
|
||||||
|
|
||||||
$exitCode = (new ShellExitCodeCalculator())->calculate(
|
$exitCode = Result::exitCode($this->options->configuration, $testResultSum);
|
||||||
$this->options->configuration->failOnEmptyTestSuite(),
|
|
||||||
$this->options->configuration->failOnRisky(),
|
|
||||||
$this->options->configuration->failOnWarning(),
|
|
||||||
$this->options->configuration->failOnIncomplete(),
|
|
||||||
$this->options->configuration->failOnSkipped(),
|
|
||||||
$testResultSum,
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->clearFiles($this->testresultFiles);
|
$this->clearFiles($this->testresultFiles);
|
||||||
$this->clearFiles($this->coverageFiles);
|
$this->clearFiles($this->coverageFiles);
|
||||||
|
|||||||
@ -4,8 +4,8 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Pest;
|
namespace Pest;
|
||||||
|
|
||||||
use PHPUnit\TestRunner\TestResult\Facade;
|
use PHPUnit\TestRunner\TestResult\TestResult;
|
||||||
use PHPUnit\TextUI\Configuration\Registry;
|
use PHPUnit\TextUI\Configuration\Configuration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
@ -21,26 +21,24 @@ final class Result
|
|||||||
/**
|
/**
|
||||||
* If the exit code is different from 0.
|
* If the exit code is different from 0.
|
||||||
*/
|
*/
|
||||||
public static function failed(): bool
|
public static function failed(Configuration $configuration, TestResult $result): bool
|
||||||
{
|
{
|
||||||
return ! self::ok();
|
return ! self::ok($configuration, $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the exit code is exactly 0.
|
* If the exit code is exactly 0.
|
||||||
*/
|
*/
|
||||||
public static function ok(): bool
|
public static function ok(Configuration $configuration, TestResult $result): bool
|
||||||
{
|
{
|
||||||
return self::exitCode() === self::SUCCESS_EXIT;
|
return self::exitCode($configuration, $result) === self::SUCCESS_EXIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the test execution's exit code.
|
* Get the test execution's exit code.
|
||||||
*/
|
*/
|
||||||
public static function exitCode(): int
|
public static function exitCode(Configuration $configuration, TestResult $result): int
|
||||||
{
|
{
|
||||||
$result = Facade::result();
|
|
||||||
|
|
||||||
$returnCode = self::FAILURE_EXIT;
|
$returnCode = self::FAILURE_EXIT;
|
||||||
|
|
||||||
if ($result->wasSuccessfulIgnoringPhpunitWarnings()
|
if ($result->wasSuccessfulIgnoringPhpunitWarnings()
|
||||||
@ -48,8 +46,6 @@ final class Result
|
|||||||
$returnCode = self::SUCCESS_EXIT;
|
$returnCode = self::SUCCESS_EXIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
$configuration = Registry::get();
|
|
||||||
|
|
||||||
if ($configuration->failOnEmptyTestSuite() && $result->numberOfTests() === 0) {
|
if ($configuration->failOnEmptyTestSuite() && $result->numberOfTests() === 0) {
|
||||||
$returnCode = self::FAILURE_EXIT;
|
$returnCode = self::FAILURE_EXIT;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,7 +24,7 @@ final class StateGenerator
|
|||||||
|
|
||||||
foreach ($testResult->testErroredEvents() as $testResultEvent) {
|
foreach ($testResult->testErroredEvents() as $testResultEvent) {
|
||||||
if ($testResultEvent instanceof Errored) {
|
if ($testResultEvent instanceof Errored) {
|
||||||
$state->add(TestResult::fromTestCase(
|
$state->add(TestResult::fromPestParallelTestCase(
|
||||||
$testResultEvent->test(),
|
$testResultEvent->test(),
|
||||||
TestResult::FAIL,
|
TestResult::FAIL,
|
||||||
$testResultEvent->throwable()
|
$testResultEvent->throwable()
|
||||||
@ -35,7 +35,7 @@ final class StateGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($testResult->testFailedEvents() as $testResultEvent) {
|
foreach ($testResult->testFailedEvents() as $testResultEvent) {
|
||||||
$state->add(TestResult::fromTestCase(
|
$state->add(TestResult::fromPestParallelTestCase(
|
||||||
$testResultEvent->test(),
|
$testResultEvent->test(),
|
||||||
TestResult::FAIL,
|
TestResult::FAIL,
|
||||||
$testResultEvent->throwable()
|
$testResultEvent->throwable()
|
||||||
@ -43,7 +43,7 @@ final class StateGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($testResult->testMarkedIncompleteEvents() as $testResultEvent) {
|
foreach ($testResult->testMarkedIncompleteEvents() as $testResultEvent) {
|
||||||
$state->add(TestResult::fromTestCase(
|
$state->add(TestResult::fromPestParallelTestCase(
|
||||||
$testResultEvent->test(),
|
$testResultEvent->test(),
|
||||||
TestResult::INCOMPLETE,
|
TestResult::INCOMPLETE,
|
||||||
$testResultEvent->throwable()
|
$testResultEvent->throwable()
|
||||||
@ -52,7 +52,7 @@ final class StateGenerator
|
|||||||
|
|
||||||
foreach ($testResult->testConsideredRiskyEvents() as $riskyEvents) {
|
foreach ($testResult->testConsideredRiskyEvents() as $riskyEvents) {
|
||||||
foreach ($riskyEvents as $riskyEvent) {
|
foreach ($riskyEvents as $riskyEvent) {
|
||||||
$state->add(TestResult::fromTestCase(
|
$state->add(TestResult::fromPestParallelTestCase(
|
||||||
$riskyEvent->test(),
|
$riskyEvent->test(),
|
||||||
TestResult::RISKY,
|
TestResult::RISKY,
|
||||||
ThrowableBuilder::from(new TestOutcome($riskyEvent->message()))
|
ThrowableBuilder::from(new TestOutcome($riskyEvent->message()))
|
||||||
@ -62,12 +62,12 @@ final class StateGenerator
|
|||||||
|
|
||||||
foreach ($testResult->testSkippedEvents() as $testResultEvent) {
|
foreach ($testResult->testSkippedEvents() as $testResultEvent) {
|
||||||
if ($testResultEvent->message() === '__TODO__') {
|
if ($testResultEvent->message() === '__TODO__') {
|
||||||
$state->add(TestResult::fromTestCase($testResultEvent->test(), TestResult::TODO));
|
$state->add(TestResult::fromPestParallelTestCase($testResultEvent->test(), TestResult::TODO));
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$state->add(TestResult::fromTestCase(
|
$state->add(TestResult::fromPestParallelTestCase(
|
||||||
$testResultEvent->test(),
|
$testResultEvent->test(),
|
||||||
TestResult::SKIPPED,
|
TestResult::SKIPPED,
|
||||||
ThrowableBuilder::from(new SkippedWithMessageException($testResultEvent->message()))
|
ThrowableBuilder::from(new SkippedWithMessageException($testResultEvent->message()))
|
||||||
@ -77,7 +77,7 @@ final class StateGenerator
|
|||||||
foreach ($testResult->testTriggeredDeprecationEvents() as $testResultEvent) {
|
foreach ($testResult->testTriggeredDeprecationEvents() as $testResultEvent) {
|
||||||
$testResultEvent = $testResultEvent[0];
|
$testResultEvent = $testResultEvent[0];
|
||||||
|
|
||||||
$state->add(TestResult::fromTestCase(
|
$state->add(TestResult::fromPestParallelTestCase(
|
||||||
$testResultEvent->test(),
|
$testResultEvent->test(),
|
||||||
TestResult::DEPRECATED,
|
TestResult::DEPRECATED,
|
||||||
ThrowableBuilder::from(new TestOutcome($testResultEvent->message()))
|
ThrowableBuilder::from(new TestOutcome($testResultEvent->message()))
|
||||||
@ -87,7 +87,7 @@ final class StateGenerator
|
|||||||
foreach ($testResult->testTriggeredPhpDeprecationEvents() as $testResultEvent) {
|
foreach ($testResult->testTriggeredPhpDeprecationEvents() as $testResultEvent) {
|
||||||
$testResultEvent = $testResultEvent[0];
|
$testResultEvent = $testResultEvent[0];
|
||||||
|
|
||||||
$state->add(TestResult::fromTestCase(
|
$state->add(TestResult::fromPestParallelTestCase(
|
||||||
$testResultEvent->test(),
|
$testResultEvent->test(),
|
||||||
TestResult::DEPRECATED,
|
TestResult::DEPRECATED,
|
||||||
ThrowableBuilder::from(new TestOutcome($testResultEvent->message()))
|
ThrowableBuilder::from(new TestOutcome($testResultEvent->message()))
|
||||||
@ -97,7 +97,7 @@ final class StateGenerator
|
|||||||
foreach ($testResult->testTriggeredNoticeEvents() as $testResultEvent) {
|
foreach ($testResult->testTriggeredNoticeEvents() as $testResultEvent) {
|
||||||
$testResultEvent = $testResultEvent[0];
|
$testResultEvent = $testResultEvent[0];
|
||||||
|
|
||||||
$state->add(TestResult::fromTestCase(
|
$state->add(TestResult::fromPestParallelTestCase(
|
||||||
$testResultEvent->test(),
|
$testResultEvent->test(),
|
||||||
TestResult::NOTICE,
|
TestResult::NOTICE,
|
||||||
ThrowableBuilder::from(new TestOutcome($testResultEvent->message()))
|
ThrowableBuilder::from(new TestOutcome($testResultEvent->message()))
|
||||||
@ -107,7 +107,7 @@ final class StateGenerator
|
|||||||
foreach ($testResult->testTriggeredPhpNoticeEvents() as $testResultEvent) {
|
foreach ($testResult->testTriggeredPhpNoticeEvents() as $testResultEvent) {
|
||||||
$testResultEvent = $testResultEvent[0];
|
$testResultEvent = $testResultEvent[0];
|
||||||
|
|
||||||
$state->add(TestResult::fromTestCase(
|
$state->add(TestResult::fromPestParallelTestCase(
|
||||||
$testResultEvent->test(),
|
$testResultEvent->test(),
|
||||||
TestResult::NOTICE,
|
TestResult::NOTICE,
|
||||||
ThrowableBuilder::from(new TestOutcome($testResultEvent->message()))
|
ThrowableBuilder::from(new TestOutcome($testResultEvent->message()))
|
||||||
@ -117,7 +117,7 @@ final class StateGenerator
|
|||||||
foreach ($testResult->testTriggeredWarningEvents() as $testResultEvent) {
|
foreach ($testResult->testTriggeredWarningEvents() as $testResultEvent) {
|
||||||
$testResultEvent = $testResultEvent[0];
|
$testResultEvent = $testResultEvent[0];
|
||||||
|
|
||||||
$state->add(TestResult::fromTestCase(
|
$state->add(TestResult::fromPestParallelTestCase(
|
||||||
$testResultEvent->test(),
|
$testResultEvent->test(),
|
||||||
TestResult::WARN,
|
TestResult::WARN,
|
||||||
ThrowableBuilder::from(new TestOutcome($testResultEvent->message()))
|
ThrowableBuilder::from(new TestOutcome($testResultEvent->message()))
|
||||||
@ -127,7 +127,7 @@ final class StateGenerator
|
|||||||
foreach ($testResult->testTriggeredPhpWarningEvents() as $testResultEvent) {
|
foreach ($testResult->testTriggeredPhpWarningEvents() as $testResultEvent) {
|
||||||
$testResultEvent = $testResultEvent[0];
|
$testResultEvent = $testResultEvent[0];
|
||||||
|
|
||||||
$state->add(TestResult::fromTestCase(
|
$state->add(TestResult::fromPestParallelTestCase(
|
||||||
$testResultEvent->test(),
|
$testResultEvent->test(),
|
||||||
TestResult::WARN,
|
TestResult::WARN,
|
||||||
ThrowableBuilder::from(new TestOutcome($testResultEvent->message()))
|
ThrowableBuilder::from(new TestOutcome($testResultEvent->message()))
|
||||||
@ -136,7 +136,7 @@ final class StateGenerator
|
|||||||
|
|
||||||
// for each test that passed, we need to add it to the state
|
// for each test that passed, we need to add it to the state
|
||||||
for ($i = 0; $i < $passedTests; $i++) {
|
for ($i = 0; $i < $passedTests; $i++) {
|
||||||
$state->add(TestResult::fromTestCase(
|
$state->add(TestResult::fromPestParallelTestCase(
|
||||||
new TestMethod(
|
new TestMethod(
|
||||||
"$i", // @phpstan-ignore-line
|
"$i", // @phpstan-ignore-line
|
||||||
'', // @phpstan-ignore-line
|
'', // @phpstan-ignore-line
|
||||||
|
|||||||
@ -59,6 +59,8 @@ final class Str
|
|||||||
*/
|
*/
|
||||||
public static function evaluable(string $code): string
|
public static function evaluable(string $code): string
|
||||||
{
|
{
|
||||||
|
$code = str_replace('_', '__', $code);
|
||||||
|
|
||||||
$code = self::PREFIX.str_replace(' ', '_', $code);
|
$code = self::PREFIX.str_replace(' ', '_', $code);
|
||||||
|
|
||||||
// sticks to PHP8.2 function naming rules https://www.php.net/manual/en/functions.user-defined.php
|
// sticks to PHP8.2 function naming rules https://www.php.net/manual/en/functions.user-defined.php
|
||||||
|
|||||||
@ -32,6 +32,7 @@ final class GitDirtyTestCaseFilter implements TestCaseFilter
|
|||||||
assert(is_array($this->changedFiles));
|
assert(is_array($this->changedFiles));
|
||||||
|
|
||||||
$relativePath = str_replace($this->projectRoot, '', $testCaseFilename);
|
$relativePath = str_replace($this->projectRoot, '', $testCaseFilename);
|
||||||
|
$relativePath = str_replace(DIRECTORY_SEPARATOR, '/', $relativePath);
|
||||||
|
|
||||||
if (str_starts_with($relativePath, '/')) {
|
if (str_starts_with($relativePath, '/')) {
|
||||||
$relativePath = substr($relativePath, 1);
|
$relativePath = substr($relativePath, 1);
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
##teamcity[testSuiteStarted name='Tests/tests/Failure' locationHint='file://tests/.tests/Failure.php' flowId='1234']
|
##teamcity[testSuiteStarted name='Tests/tests/Failure' locationHint='file://tests/.tests/Failure.php' 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 src/Mixins/Expectation.php:342|nat src/Support/ExpectationPipeline.php:75|nat src/Support/ExpectationPipeline.php:79|nat src/Expectation.php:300|nat tests/.tests/Failure.php:6|nat src/Factories/TestCaseMethodFactory.php:100|nat src/Concerns/Testable.php:272|nat src/Support/ExceptionTrace.php:28|nat src/Concerns/Testable.php:272|nat src/Concerns/Testable.php:215|nat src/Kernel.php:84' 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 src/Mixins/Expectation.php:343|nat src/Support/ExpectationPipeline.php:75|nat src/Support/ExpectationPipeline.php:79|nat src/Expectation.php:300|nat tests/.tests/Failure.php:6|nat src/Factories/TestCaseMethodFactory.php:100|nat src/Concerns/Testable.php:302|nat src/Support/ExceptionTrace.php:28|nat src/Concerns/Testable.php:302|nat src/Concerns/Testable.php:221|nat src/Kernel.php:86' type='comparisonFailure' actual='true' expected='false' flowId='1234']
|
||||||
##teamcity[testFinished name='it can fail with comparison' duration='100000' flowId='1234']
|
##teamcity[testFinished name='it can fail with comparison' duration='100000' flowId='1234']
|
||||||
##teamcity[testStarted name='it can be ignored because of no assertions' locationHint='pest_qn://tests/.tests/Failure.php::it can be ignored because of no assertions' flowId='1234']
|
##teamcity[testStarted name='it can be ignored because of no assertions' locationHint='pest_qn://tests/.tests/Failure.php::it can be ignored because of no assertions' flowId='1234']
|
||||||
##teamcity[testIgnored name='it can be ignored because of no assertions' message='This test did not perform any assertions' details='' flowId='1234']
|
##teamcity[testIgnored name='it can be ignored because of no assertions' message='This test did not perform any assertions' details='' flowId='1234']
|
||||||
@ -9,7 +9,7 @@
|
|||||||
##teamcity[testIgnored name='it can be ignored because it is skipped' message='This test was ignored.' details='' flowId='1234']
|
##teamcity[testIgnored name='it can be ignored because it is skipped' message='This test was ignored.' details='' flowId='1234']
|
||||||
##teamcity[testFinished name='it can be ignored because it is skipped' duration='100000' flowId='1234']
|
##teamcity[testFinished name='it can be ignored because it is skipped' duration='100000' flowId='1234']
|
||||||
##teamcity[testStarted name='it can fail' locationHint='pest_qn://tests/.tests/Failure.php::it can fail' flowId='1234']
|
##teamcity[testStarted name='it can fail' locationHint='pest_qn://tests/.tests/Failure.php::it can fail' flowId='1234']
|
||||||
##teamcity[testFailed name='it can fail' message='oh noo' details='at tests/.tests/Failure.php:18|nat src/Factories/TestCaseMethodFactory.php:100|nat src/Concerns/Testable.php:272|nat src/Support/ExceptionTrace.php:28|nat src/Concerns/Testable.php:272|nat src/Concerns/Testable.php:215|nat src/Kernel.php:84' flowId='1234']
|
##teamcity[testFailed name='it can fail' message='oh noo' details='at tests/.tests/Failure.php:18|nat src/Factories/TestCaseMethodFactory.php:100|nat src/Concerns/Testable.php:302|nat src/Support/ExceptionTrace.php:28|nat src/Concerns/Testable.php:302|nat src/Concerns/Testable.php:221|nat src/Kernel.php:86' flowId='1234']
|
||||||
##teamcity[testFinished name='it can fail' duration='100000' flowId='1234']
|
##teamcity[testFinished name='it can fail' duration='100000' flowId='1234']
|
||||||
##teamcity[testStarted name='it is not done yet' locationHint='pest_qn://tests/.tests/Failure.php::it is not done yet' flowId='1234']
|
##teamcity[testStarted name='it is not done yet' locationHint='pest_qn://tests/.tests/Failure.php::it is not done yet' flowId='1234']
|
||||||
##teamcity[testIgnored name='it is not done yet' message='This test was ignored.' details='' flowId='1234']
|
##teamcity[testIgnored name='it is not done yet' message='This test was ignored.' details='' flowId='1234']
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
|
WARN Tests\Fixtures\CollisionTest
|
||||||
|
- error
|
||||||
|
- success
|
||||||
|
|
||||||
PASS Tests\Fixtures\DirectoryWithTests\ExampleTest
|
PASS Tests\Fixtures\DirectoryWithTests\ExampleTest
|
||||||
✓ it example 1
|
✓ it example 1
|
||||||
|
|
||||||
PASS Tests\Fixtures\ExampleTest
|
PASS Tests\Fixtures\ExampleTest
|
||||||
✓ it example 2
|
✓ it example 2
|
||||||
|
|
||||||
Tests: 2 passed (2 assertions)
|
Tests: 2 skipped, 2 passed (2 assertions)
|
||||||
|
|||||||
22
tests/.snapshots/collision-parallel.txt
Normal file
22
tests/.snapshots/collision-parallel.txt
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
⨯.
|
||||||
|
────────────────────────────────────────────────────────────────────────────
|
||||||
|
FAILED Tests\Fixtures\CollisionTest > error Exception
|
||||||
|
error
|
||||||
|
|
||||||
|
at tests/Fixtures/CollisionTest.php:4
|
||||||
|
1▕ <?php
|
||||||
|
2▕
|
||||||
|
3▕ test('error', function () {
|
||||||
|
➜ 4▕ throw new Exception('error');
|
||||||
|
5▕ })->skip(! isset($_SERVER['COLLISION_TEST']));
|
||||||
|
6▕
|
||||||
|
7▕ test('success', function () {
|
||||||
|
8▕ expect(true)->toBeTrue();
|
||||||
|
9▕ })->skip(! isset($_SERVER['COLLISION_TEST']));
|
||||||
|
|
||||||
|
1 tests/Fixtures/CollisionTest.php:4
|
||||||
|
2 src/Factories/TestCaseMethodFactory.php:100
|
||||||
|
|
||||||
|
|
||||||
|
Tests: 1 failed, 1 passed (1 assertions)
|
||||||
24
tests/.snapshots/collision.txt
Normal file
24
tests/.snapshots/collision.txt
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
FAIL Tests\Fixtures\CollisionTest
|
||||||
|
⨯ error
|
||||||
|
✓ success
|
||||||
|
────────────────────────────────────────────────────────────────────────────
|
||||||
|
FAILED Tests\Fixtures\CollisionTest > error Exception
|
||||||
|
error
|
||||||
|
|
||||||
|
at tests/Fixtures/CollisionTest.php:4
|
||||||
|
1▕ <?php
|
||||||
|
2▕
|
||||||
|
3▕ test('error', function () {
|
||||||
|
➜ 4▕ throw new Exception('error');
|
||||||
|
5▕ })->skip(! isset($_SERVER['COLLISION_TEST']));
|
||||||
|
6▕
|
||||||
|
7▕ test('success', function () {
|
||||||
|
8▕ expect(true)->toBeTrue();
|
||||||
|
9▕ })->skip(! isset($_SERVER['COLLISION_TEST']));
|
||||||
|
|
||||||
|
1 tests/Fixtures/CollisionTest.php:4
|
||||||
|
2 src/Factories/TestCaseMethodFactory.php:100
|
||||||
|
|
||||||
|
|
||||||
|
Tests: 1 failed, 1 passed (1 assertions)
|
||||||
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
Pest Testing Framework 2.1.0.
|
Pest Testing Framework 2.2.3.
|
||||||
|
|
||||||
USAGE: pest <file> [options]
|
USAGE: pest <file> [options]
|
||||||
|
|
||||||
@ -33,6 +33,7 @@
|
|||||||
--test-suffix [suffixes] Only search for test in files with specified suffix(es). Default: Test.php,.phpt
|
--test-suffix [suffixes] Only search for test in files with specified suffix(es). Default: Test.php,.phpt
|
||||||
|
|
||||||
EXECUTION OPTIONS:
|
EXECUTION OPTIONS:
|
||||||
|
--parallel ........................................... Run tests in parallel
|
||||||
--process-isolation ................ Run each test in a separate PHP process
|
--process-isolation ................ Run each test in a separate PHP process
|
||||||
--globals-backup ................. Backup and restore $GLOBALS for each test
|
--globals-backup ................. Backup and restore $GLOBALS for each test
|
||||||
--static-backup ......... Backup and restore static properties for each test
|
--static-backup ......... Backup and restore static properties for each test
|
||||||
|
|||||||
@ -334,12 +334,14 @@
|
|||||||
|
|
||||||
PASS Tests\Features\Expect\toBeGreatherThan
|
PASS Tests\Features\Expect\toBeGreatherThan
|
||||||
✓ passes
|
✓ passes
|
||||||
|
✓ passes with DateTime and DateTimeImmutable
|
||||||
✓ failures
|
✓ failures
|
||||||
✓ failures with custom message
|
✓ failures with custom message
|
||||||
✓ not failures
|
✓ not failures
|
||||||
|
|
||||||
PASS Tests\Features\Expect\toBeGreatherThanOrEqual
|
PASS Tests\Features\Expect\toBeGreatherThanOrEqual
|
||||||
✓ passes
|
✓ passes
|
||||||
|
✓ passes with DateTime and DateTimeImmutable
|
||||||
✓ failures
|
✓ failures
|
||||||
✓ failures with custom message
|
✓ failures with custom message
|
||||||
✓ not failures
|
✓ not failures
|
||||||
@ -382,12 +384,14 @@
|
|||||||
|
|
||||||
PASS Tests\Features\Expect\toBeLessThan
|
PASS Tests\Features\Expect\toBeLessThan
|
||||||
✓ passes
|
✓ passes
|
||||||
|
✓ passes with DateTime and DateTimeImmutable
|
||||||
✓ failures
|
✓ failures
|
||||||
✓ failures with custom message
|
✓ failures with custom message
|
||||||
✓ not failures
|
✓ not failures
|
||||||
|
|
||||||
PASS Tests\Features\Expect\toBeLessThanOrEqual
|
PASS Tests\Features\Expect\toBeLessThanOrEqual
|
||||||
✓ passes
|
✓ passes
|
||||||
|
✓ passes with DateTime and DateTimeImmutable
|
||||||
✓ failures
|
✓ failures
|
||||||
✓ failures with custom message
|
✓ failures with custom message
|
||||||
✓ not failures
|
✓ not failures
|
||||||
@ -775,6 +779,10 @@
|
|||||||
! warning → Undefined property: P\Tests\Features\Warnings::$fooqwdfwqdfqw
|
! warning → Undefined property: P\Tests\Features\Warnings::$fooqwdfwqdfqw
|
||||||
! user warning → This is a warning description
|
! user warning → This is a warning description
|
||||||
|
|
||||||
|
WARN Tests\Fixtures\CollisionTest
|
||||||
|
- error
|
||||||
|
- success
|
||||||
|
|
||||||
PASS Tests\Fixtures\DirectoryWithTests\ExampleTest
|
PASS Tests\Fixtures\DirectoryWithTests\ExampleTest
|
||||||
✓ it example 1
|
✓ it example 1
|
||||||
|
|
||||||
@ -901,7 +909,7 @@
|
|||||||
|
|
||||||
PASS Tests\Unit\Support\Str
|
PASS Tests\Unit\Support\Str
|
||||||
✓ it evaluates the code with ('version()', '__pest_evaluable_version__')
|
✓ it evaluates the code with ('version()', '__pest_evaluable_version__')
|
||||||
✓ it evaluates the code with ('version__ ', '__pest_evaluable_version___')
|
✓ it evaluates the code with ('version__ ', '__pest_evaluable_version_____')
|
||||||
✓ it evaluates the code with ('version\', '__pest_evaluable_version_')
|
✓ it evaluates the code with ('version\', '__pest_evaluable_version_')
|
||||||
|
|
||||||
PASS Tests\Unit\TestName
|
PASS Tests\Unit\TestName
|
||||||
@ -910,6 +918,8 @@
|
|||||||
✓ it may start with P with ('P\PPPackages\Foo', 'PPPackages\Foo')
|
✓ it may start with P with ('P\PPPackages\Foo', 'PPPackages\Foo')
|
||||||
✓ it may start with P with ('PPPackages\Foo', 'PPPackages\Foo') #1
|
✓ it may start with P with ('PPPackages\Foo', 'PPPackages\Foo') #1
|
||||||
✓ it may start with P with ('PPPackages\Foo', 'PPPackages\Foo') #2
|
✓ it may start with P with ('PPPackages\Foo', 'PPPackages\Foo') #2
|
||||||
|
✓ test description
|
||||||
|
✓ test_description
|
||||||
✓ ふ+が+
|
✓ ふ+が+
|
||||||
✓ ほげ
|
✓ ほげ
|
||||||
✓ 卜竹弓一十山
|
✓ 卜竹弓一十山
|
||||||
@ -965,6 +975,10 @@
|
|||||||
PASS Tests\Visual\BeforeEachTestName
|
PASS Tests\Visual\BeforeEachTestName
|
||||||
✓ latest description
|
✓ latest description
|
||||||
|
|
||||||
|
PASS Tests\Visual\Collision
|
||||||
|
✓ collision with ([''])
|
||||||
|
✓ collision with (['--parallel'])
|
||||||
|
|
||||||
PASS Tests\Visual\Help
|
PASS Tests\Visual\Help
|
||||||
✓ visual snapshot of help command output
|
✓ visual snapshot of help command output
|
||||||
|
|
||||||
@ -990,4 +1004,4 @@
|
|||||||
PASS Tests\Visual\Version
|
PASS Tests\Visual\Version
|
||||||
✓ visual snapshot of help command output
|
✓ visual snapshot of help command output
|
||||||
|
|
||||||
Tests: 2 deprecated, 3 warnings, 4 incomplete, 1 notice, 4 todos, 12 skipped, 695 passed (1680 assertions)
|
Tests: 2 deprecated, 3 warnings, 4 incomplete, 1 notice, 4 todos, 14 skipped, 703 passed (1702 assertions)
|
||||||
@ -1,3 +1,3 @@
|
|||||||
|
|
||||||
Pest Testing Framework 2.1.0.
|
Pest Testing Framework 2.2.3.
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,15 @@ test('passes', function () {
|
|||||||
expect(4)->toBeGreaterThan(3.9);
|
expect(4)->toBeGreaterThan(3.9);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('passes with DateTime and DateTimeImmutable', function () {
|
||||||
|
$now = new DateTime();
|
||||||
|
$past = (new DateTimeImmutable())->modify('-1 day');
|
||||||
|
|
||||||
|
expect($now)->toBeGreaterThan($past);
|
||||||
|
|
||||||
|
expect($past)->not->toBeGreaterThan($now);
|
||||||
|
});
|
||||||
|
|
||||||
test('failures', function () {
|
test('failures', function () {
|
||||||
expect(4)->toBeGreaterThan(4);
|
expect(4)->toBeGreaterThan(4);
|
||||||
})->throws(ExpectationFailedException::class);
|
})->throws(ExpectationFailedException::class);
|
||||||
|
|||||||
@ -7,6 +7,17 @@ test('passes', function () {
|
|||||||
expect(4)->toBeGreaterThanOrEqual(4);
|
expect(4)->toBeGreaterThanOrEqual(4);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('passes with DateTime and DateTimeImmutable', function () {
|
||||||
|
$now = new DateTime();
|
||||||
|
$past = (new DateTimeImmutable())->modify('-1 day');
|
||||||
|
|
||||||
|
expect($now)->toBeGreaterThanOrEqual($now);
|
||||||
|
|
||||||
|
expect($now)->toBeGreaterThanOrEqual($past);
|
||||||
|
|
||||||
|
expect($past)->not->toBeGreaterThanOrEqual($now);
|
||||||
|
});
|
||||||
|
|
||||||
test('failures', function () {
|
test('failures', function () {
|
||||||
expect(4)->toBeGreaterThanOrEqual(4.1);
|
expect(4)->toBeGreaterThanOrEqual(4.1);
|
||||||
})->throws(ExpectationFailedException::class);
|
})->throws(ExpectationFailedException::class);
|
||||||
|
|||||||
@ -7,6 +7,15 @@ test('passes', function () {
|
|||||||
expect(4)->toBeLessThan(5);
|
expect(4)->toBeLessThan(5);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('passes with DateTime and DateTimeImmutable', function () {
|
||||||
|
$now = new DateTime();
|
||||||
|
$past = (new DateTimeImmutable())->modify('-1 day');
|
||||||
|
|
||||||
|
expect($past)->toBeLessThan($now);
|
||||||
|
|
||||||
|
expect($now)->not->toBeLessThan($now);
|
||||||
|
});
|
||||||
|
|
||||||
test('failures', function () {
|
test('failures', function () {
|
||||||
expect(4)->toBeLessThan(4);
|
expect(4)->toBeLessThan(4);
|
||||||
})->throws(ExpectationFailedException::class);
|
})->throws(ExpectationFailedException::class);
|
||||||
|
|||||||
@ -7,6 +7,17 @@ test('passes', function () {
|
|||||||
expect(4)->toBeLessThanOrEqual(4);
|
expect(4)->toBeLessThanOrEqual(4);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('passes with DateTime and DateTimeImmutable', function () {
|
||||||
|
$now = new DateTime();
|
||||||
|
$past = (new DateTimeImmutable())->modify('-1 day');
|
||||||
|
|
||||||
|
expect($now)->toBeLessThanOrEqual($now);
|
||||||
|
|
||||||
|
expect($past)->toBeLessThanOrEqual($now);
|
||||||
|
|
||||||
|
expect($now)->not->toBeLessThanOrEqual($past);
|
||||||
|
});
|
||||||
|
|
||||||
test('failures', function () {
|
test('failures', function () {
|
||||||
expect(4)->toBeLessThanOrEqual(3.9);
|
expect(4)->toBeLessThanOrEqual(3.9);
|
||||||
})->throws(ExpectationFailedException::class);
|
})->throws(ExpectationFailedException::class);
|
||||||
|
|||||||
9
tests/Fixtures/CollisionTest.php
Normal file
9
tests/Fixtures/CollisionTest.php
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
test('error', function () {
|
||||||
|
throw new Exception('error');
|
||||||
|
})->skip(! isset($_SERVER['COLLISION_TEST']));
|
||||||
|
|
||||||
|
test('success', function () {
|
||||||
|
expect(true)->toBeTrue();
|
||||||
|
})->skip(! isset($_SERVER['COLLISION_TEST']));
|
||||||
@ -8,6 +8,6 @@ it('evaluates the code', function ($evaluatable, $expected) {
|
|||||||
expect($code)->toBe($expected);
|
expect($code)->toBe($expected);
|
||||||
})->with([
|
})->with([
|
||||||
['version()', '__pest_evaluable_version__'],
|
['version()', '__pest_evaluable_version__'],
|
||||||
['version__ ', '__pest_evaluable_version___'],
|
['version__ ', '__pest_evaluable_version_____'],
|
||||||
['version\\', '__pest_evaluable_version_'],
|
['version\\', '__pest_evaluable_version_'],
|
||||||
]);
|
]);
|
||||||
|
|||||||
@ -13,6 +13,8 @@ it('may start with P', function (string $real, string $toBePrinted) {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
$names = [
|
$names = [
|
||||||
|
'test description' => '__pest_evaluable_test_description',
|
||||||
|
'test_description' => '__pest_evaluable_test__description',
|
||||||
'ふ+が+' => '__pest_evaluable_ふ_が_',
|
'ふ+が+' => '__pest_evaluable_ふ_が_',
|
||||||
'ほげ' => '__pest_evaluable_ほげ',
|
'ほげ' => '__pest_evaluable_ほげ',
|
||||||
'卜竹弓一十山' => '__pest_evaluable_卜竹弓一十山',
|
'卜竹弓一十山' => '__pest_evaluable_卜竹弓一十山',
|
||||||
|
|||||||
42
tests/Visual/Collision.php
Normal file
42
tests/Visual/Collision.php
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
test('collision', function (array $arguments) {
|
||||||
|
$snapshot = __DIR__.'/../.snapshots/collision.txt';
|
||||||
|
|
||||||
|
if (in_array('--parallel', $arguments)) {
|
||||||
|
$snapshot = __DIR__.'/../.snapshots/collision-parallel.txt';
|
||||||
|
}
|
||||||
|
|
||||||
|
$output = function () use ($arguments) {
|
||||||
|
$process = (new Symfony\Component\Process\Process(
|
||||||
|
array_merge(['php', 'bin/pest', 'tests/Fixtures/CollisionTest.php'], $arguments),
|
||||||
|
null,
|
||||||
|
['COLLISION_PRINTER' => 'DefaultPrinter', 'COLLISION_IGNORE_DURATION' => 'true', 'COLLISION_TEST' => true]
|
||||||
|
));
|
||||||
|
|
||||||
|
$process->run();
|
||||||
|
|
||||||
|
return preg_replace('#\\x1b[[][^A-Za-z]*[A-Za-z]#', '', $process->getOutput());
|
||||||
|
};
|
||||||
|
|
||||||
|
if (getenv('REBUILD_SNAPSHOTS')) {
|
||||||
|
$outputContent = explode("\n", $output());
|
||||||
|
array_pop($outputContent);
|
||||||
|
array_pop($outputContent);
|
||||||
|
array_pop($outputContent);
|
||||||
|
|
||||||
|
if (in_array('--parallel', $arguments)) {
|
||||||
|
array_pop($outputContent);
|
||||||
|
array_pop($outputContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
file_put_contents($snapshot, implode("\n", $outputContent));
|
||||||
|
|
||||||
|
$this->markTestSkipped('Snapshot rebuilt.');
|
||||||
|
}
|
||||||
|
|
||||||
|
expect($output())->toContain(file_get_contents($snapshot));
|
||||||
|
})->with([
|
||||||
|
[['']],
|
||||||
|
[['--parallel']],
|
||||||
|
])->skip(PHP_OS_FAMILY === 'Windows');
|
||||||
@ -15,6 +15,6 @@ $run = function () {
|
|||||||
};
|
};
|
||||||
|
|
||||||
test('parallel', function () use ($run) {
|
test('parallel', function () use ($run) {
|
||||||
expect($run())->toContain('Tests: 2 deprecated, 3 warnings, 4 incomplete, 1 notice, 4 todos, 9 skipped, 686 passed (1668 assertions)')
|
expect($run())->toContain('Tests: 2 deprecated, 3 warnings, 4 incomplete, 1 notice, 4 todos, 11 skipped, 692 passed (1688 assertions)')
|
||||||
->toContain('Parallel: 3 processes');
|
->toContain('Parallel: 3 processes');
|
||||||
})->skip(PHP_OS_FAMILY === 'Windows');
|
})->skip(PHP_OS_FAMILY === 'Windows');
|
||||||
|
|||||||
Reference in New Issue
Block a user