Merge branch '2.x' into dataset-arguments-check

This commit is contained in:
Nuno Maduro
2023-03-21 21:10:22 +00:00
committed by GitHub
56 changed files with 550 additions and 648 deletions

View File

@ -1,47 +0,0 @@
name: Nightly Tests
on:
push:
pull_request:
schedule:
- cron: '0 */12 * * *'
jobs:
ci:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
php: ['8.1']
phpunit-branch: [main]
name: PHP ${{ matrix.php }} - ${{ matrix.os }} - ${{ matrix.phpunit-branch }}
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 Matchers
run: |
echo "::add-matcher::${{ runner.tool_cache }}/php.json"
echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
- name: Install PHP dependencies with phpunit/phpunit:dev-${{ matrix.phpunit-branch }}
run: composer require phpunit/phpunit:dev-${{ matrix.phpunit-branch }} --ansi --no-interaction --no-progress
- name: Unit Tests
run: composer test:unit
- name: Unit Tests in Parallel
run: composer test:parallel
if: startsWith(matrix.os, 'windows') != true
- name: Integration Tests
run: composer test:integration

View File

@ -1,343 +1,25 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
# Release Notes for 2.x
## Unreleased
### Added
- Custom failure messages on expectations ([https://github.com/pestphp/pest/pull/583](https://github.com/pestphp/pest/pull/583))
## [v2.1.0 (2023-03-21)](https://github.com/pestphp/pest/compare/v2.0.2...v2.1.0)
## [v1.20.0 (2021-09-25)](https://github.com/pestphp/pest/compare/v1.19.0...v1.20.0)
### Added
- `throwsIf` test call ([#371](https://github.com/pestphp/pest/pull/371))
- `--ci` CLI option to ignore development options like `->local()` ([#405](https://github.com/pestphp/pest/pull/405))
- `when` conditional expectation ([#406](https://github.com/pestphp/pest/pull/406))
- `unless` conditional expectation ([b43a598](https://github.com/pestphp/pest/commit/b43a59868d5b790a28cbb29c6110c9f068b0b812))
- `match` conditional expectation ([#407](https://github.com/pestphp/pest/pull/407))
- `only` test case method ([bcd1503](https://github.com/pestphp/pest/commit/bcd1503cade938853a55c1283b02b6b820ea0b69))
### Fixed
- `sequence` with more expectations than iterable elements ([#399](https://github.com/pestphp/pest/pull/399))
- Issues with different characters on test names ([715](https://github.com/pestphp/pest/pull/715))
## [v1.19.0 (2021-09-20)](https://github.com/pestphp/pest/compare/v1.18.0...v1.19.0)
### Added
- PHP 8.1 support ([e6c7d68](https://github.com/pestphp/pest/commit/e6c7d68defaec8efe01e71e15dd8d8c45b0cf60f))
- `toHaveProperties` expectation ([#391](https://github.com/pestphp/pest/pull/391))
## [v1.18.0 (2021-08-30)](https://github.com/pestphp/pest/compare/v1.17.0...v1.18.0)
### Added
- `toHaveLength` expectation ([#386](https://github.com/pestphp/pest/pull/386))
- `nunomaduro/collision:^6.0` support ([4ae482c](https://github.com/pestphp/pest/commit/4ae482c7073fb77782b8a4b5738ef1fcea0f82ab))
## [v1.17.0 (2021-08-26)](https://github.com/pestphp/pest/compare/v1.16.0...v1.17.0)
### Added
- `toThrow` expectation ([#361](https://github.com/pestphp/pest/pull/361))
## [v1.16.0 (2021-08-19)](https://github.com/pestphp/pest/compare/v1.15.0...v1.16.0)
### Added
- Support for new parallel options ([#369](https://github.com/pestphp/pest/pull/369))
## [v1.15.0 (2021-08-04)](https://github.com/pestphp/pest/compare/v1.14.0...v1.15.0)
### Added
- `toBeTruthy` and `toBeFalsy` ([#367](https://github.com/pestphp/pest/pull/367))
## [v1.14.0 (2021-08-03)](https://github.com/pestphp/pest/compare/v1.13.0...v1.14.0)
### Added
- A new bound closure that allows you to access the test case in Datasets ([#364](https://github.com/pestphp/pest/pull/364))
## [v1.13.0 (2021-08-02)](https://github.com/pestphp/pest/compare/v1.12.0...v1.13.0)
### Added
- A cleaner output when running the Pest runner in PhpStorm ([#350](https://github.com/pestphp/pest/pull/350))
- `toBeIn` expectation ([#363](https://github.com/pestphp/pest/pull/363))
## [v2.0.2 (2023-03-20)](https://github.com/pestphp/pest/compare/v2.0.1...v2.0.2)
### Fixed
- `skip` with false condition marking test as skipped ([22b822c](https://github.com/pestphp/pest/commit/22b822ce87a3d19d84960fa5c93eb286820b525d))
- `Pest.php` not being loaded in certain scenarios ([b887116](https://github.com/pestphp/pest/commit/b887116e5ce9a69403ad620cad20f0a029474eb5))
## [v1.12.0 (2021-07-26)](https://github.com/pestphp/pest/compare/v1.11.0...v1.12.0)
### Added
- `--force` option to override tests in `pest:test` artisan command ([#353](https://github.com/pestphp/pest/pull/353))
- Support for PHPUnit `^9.3.7` ([ca9d783](https://github.com/pestphp/pest/commit/ca9d783cf942a2caabc85ff7a728c7f28350c67a))
## [v2.0.1 (2023-03-20)](https://github.com/pestphp/pest/compare/v2.0.0...v2.0.1)
### Fixed
- `beforeAll` and `afterAll` behind called multiple times per test ([#357](https://github.com/pestphp/pest/pull/357))
- Wrong `version` configuration key on `composer.json` ([8f91f40](https://github.com/pestphp/pest/commit/8f91f40e8ea8b35e04b7989bed6a8f9439e2a2d6))
## [v1.11.0 (2021-07-21)](https://github.com/pestphp/pest/compare/v1.10.0...v1.11.0)
### Added
- Support for interacting with datasets in higher order tests ([#352](https://github.com/pestphp/pest/pull/352))
## [v2.0.0 (2023-03-20)](https://github.com/pestphp/pest/compare/v1.22.6...v2.0.0)
### Changed
- The unit test stub now uses the expectation API ([#348](https://github.com/pestphp/pest/pull/348))
### Fixed
- PhpStorm will no longer show 0 assertions in the output ([#349](https://github.com/pestphp/pest/pull/349))
## [v1.10.0 (2021-07-12)](https://github.com/pestphp/pest/compare/v1.9.1...v1.10.0)
### Added
- The ability to use higher order expectations inside higher order tests ([#341](https://github.com/pestphp/pest/pull/341))
## [v1.9.1 (2021-07-11)](https://github.com/pestphp/pest/compare/v1.9.0...v1.9.1)
### Fixed
- Callable `expect` values in higher order tests failing if the value was an existing method name ([#334](https://github.com/pestphp/pest/pull/344))
## [v1.9.0 (2021-07-09)](https://github.com/pestphp/pest/compare/v1.8.0...v1.9.0)
### Changed
- You may now pass just an exception message when using the `throws` method ([#339](https://github.com/pestphp/pest/pull/339))
## [v1.8.0 (2021-07-08)](https://github.com/pestphp/pest/compare/v1.7.1...v1.8.0)
### Added
- A new `tap` and test case aware `expect` methods for higher order tests ([#331](https://github.com/pestphp/pest/pull/331))
- Access to test case methods and properties when using `skip` ([#338](https://github.com/pestphp/pest/pull/338))
## [v1.7.1 (2021-06-24)](https://github.com/pestphp/pest/compare/v1.7.0...v1.7.1)
### Fixed
- The `and` method not being usable in Higher Order expectations ([#330](https://github.com/pestphp/pest/pull/330))
## [v1.7.0 (2021-06-19)](https://github.com/pestphp/pest/compare/v1.6.0...v1.7.0)
### Added
- Support for non-callable values in the sequence method, which will be passed as `toEqual` ([#323](https://github.com/pestphp/pest/pull/323))
- Support for nested Higher Order Expectations ([#324](https://github.com/pestphp/pest/pull/324))
## [v1.6.0 (2021-06-18)](https://github.com/pestphp/pest/compare/v1.5.0...v1.6.0)
### Added
- Adds a new `json` expectation method to improve testing with JSON strings ([#325](https://github.com/pestphp/pest/pull/325))
- Adds dot notation support to the `toHaveKey` and `toHaveKeys` expectations ([#322](https://github.com/pestphp/pest/pull/322))
## [v1.5.0 (2021-06-15)](https://github.com/pestphp/pest/compare/v1.4.0...v1.5.0)
### Changed
- Moves plugins from the `require` section to the core itself ([#317](https://github.com/pestphp/pest/pull/317)), ([#318](https://github.com/pestphp/pest/pull/318)), ([#320](https://github.com/pestphp/pest/pull/320))
## [v1.4.0 (2021-06-10)](https://github.com/pestphp/pest/compare/v1.3.2...v1.4.0)
### Added
- Support for multiple datasets (Matrix) on the `with` method ([#303](https://github.com/pestphp/pest/pull/303))
- Support for incompleted tests ([49de462](https://github.com/pestphp/pest/commit/49de462250cf9f65f09e13eaf6dcc0e06865b930))
## [v1.3.2 (2021-06-07)](https://github.com/pestphp/pest/compare/v1.3.1...v1.3.2)
### Fixed
- Test cases with the @ symbol in the directory fail ([#308](https://github.com/pestphp/pest/pull/308))
## [v1.3.1 (2021-06-06)](https://github.com/pestphp/pest/compare/v1.3.0...v1.3.1)
### Added
- Added for PHPUnit 9.5.5 ([#310](https://github.com/pestphp/pest/pull/310))
### Changed
- Lock minimum Pest plugin versions ([#306](https://github.com/pestphp/pest/pull/306))
## [v1.3.0 (2021-05-23)](https://github.com/pestphp/pest/compare/v1.2.1...v1.3.0)
### Added
- Named datasets no longer show the arguments ([#302](https://github.com/pestphp/pest/pull/302))
### Fixed
- Wraps global functions within `function_exists` ([#300](https://github.com/pestphp/pest/pull/300))
## [v1.2.1 (2021-05-14)](https://github.com/pestphp/pest/compare/v1.2.0...v1.2.1)
### Fixed
- Laravel commands failing with new `--test-directory` option ([#297](https://github.com/pestphp/pest/pull/297))
## [v1.2.0 (2021-05-13)](https://github.com/pestphp/pest/compare/v1.1.0...v1.2.0)
### Added
- Adds JUnit / Infection support ([#291](https://github.com/pestphp/pest/pull/291))
- `--test-directory` command line option ([#283](https://github.com/pestphp/pest/pull/283))
## [v1.1.0 (2021-05-02)](https://github.com/pestphp/pest/compare/v1.0.5...v1.1.0)
### Added
- Possibility of "hooks" being added using the "uses" function ([#282](https://github.com/pestphp/pest/pull/282))
## [v1.0.5 (2021-03-31)](https://github.com/pestphp/pest/compare/v1.0.4...v1.0.5)
### Added
- Add `--browse` option to `pest:dusk` command ([#280](https://github.com/pestphp/pest/pull/280))
- Support for PHPUnit 9.5.4 ([#284](https://github.com/pestphp/pest/pull/284))
## [v1.0.4 (2021-03-17)](https://github.com/pestphp/pest/compare/v1.0.3...v1.0.4)
### Added
- Support for PHPUnit 9.5.3 ([#278](https://github.com/pestphp/pest/pull/278))
## [v1.0.3 (2021-03-13)](https://github.com/pestphp/pest/compare/v1.0.2...v1.0.3)
### Added
- Support for test extensions ([#269](https://github.com/pestphp/pest/pull/269))
## [v1.0.2 (2021-02-04)](https://github.com/pestphp/pest/compare/v1.0.1...v1.0.2)
### Added
- Support for PHPUnit 9.5.2 ([#267](https://github.com/pestphp/pest/pull/267))
## [v1.0.1 (2021-01-18)](https://github.com/pestphp/pest/compare/v1.0.0...v1.0.1)
### Added
- Support for PHPUnit 9.5.1 ([#261](https://github.com/pestphp/pest/pull/261))
### Fixed
- Fix `TestCase@expect` PHPDoc tag ([#251](https://github.com/pestphp/pest/pull/251))
## [v1.0.0 (2021-01-03)](https://github.com/pestphp/pest/compare/v0.3.19...v1.0.0)
### Added
- `pest:test --dusk` option ([#245](https://github.com/pestphp/pest/pull/245))
### Changed
- Stable version
- Updates init structure ([#240](https://github.com/pestphp/pest/pull/240))
## [v0.3.19 (2020-12-27)](https://github.com/pestphp/pest/compare/v0.3.18...v0.3.19)
### Fixed
- Fix binary path in `pest:dusk` command ([#239](https://github.com/pestphp/pest/pull/239))
## [v0.3.18 (2020-12-26)](https://github.com/pestphp/pest/compare/v0.3.17...v0.3.18)
### Added
- `toBeJson()` expectation ([plugin-expectations#2](https://github.com/pestphp/pest-plugin-expectations/pull/2))
## [v0.3.17 (2020-12-20)](https://github.com/pestphp/pest/compare/v0.3.16...v0.3.17)
### Fixed
- Class inheritance with `depends()` ([#236](https://github.com/pestphp/pest/pull/236))
## [v0.3.16 (2020-12-13)](https://github.com/pestphp/pest/compare/v0.3.15...v0.3.16)
### Changed
- Moves expectation API for external plugin ([5d7f262](https://github.com/pestphp/pest/commit/5d7f262f4ab280a660a85900f402eebb23abfda8))
## [v0.3.15 (2020-12-04)](https://github.com/pestphp/pest/compare/v0.3.14...v0.3.15)
### Added
- Support for PHPUnit 9.5.0 ([#234](https://github.com/pestphp/pest/pull/234))
- Support for extending expectation API ([#232](https://github.com/pestphp/pest/pull/232))
### Fixed
- Static analysis while using string as key for datasets ([#233](https://github.com/pestphp/pest/pull/233))
## [v0.3.14 (2020-11-28)](https://github.com/pestphp/pest/compare/v0.3.13...v0.3.14)
### Added
- `pest:dusk` command ([#223](https://github.com/pestphp/pest/pull/223))
- Better feedback on errors in `toMatchArray` and `toMatchObject` ([#231](https://github.com/pestphp/pest/pull/231))
## [v0.3.13 (2020-11-23)](https://github.com/pestphp/pest/compare/v0.3.12...v0.3.13)
### Added
- `toMatchArray` expectation ([7bea51f](https://github.com/pestphp/pest/commit/7bea51fe09dd2eca7093e4c34cf2dab2e8d39fa5), [3fd24d9](https://github.com/pestphp/pest/commit/3fd24d96d3145dcebdb0aab40aa8b76faa8b6979))
- Add Pest options to `--help` output ([#217](https://github.com/pestphp/pest/pull/217))
### Fixed
- Resolve issue with name resolution in `depends()` ([#216](https://github.com/pestphp/pest/pull/216))
## [v0.3.12 (2020-11-11)](https://github.com/pestphp/pest/compare/v0.3.11...v0.3.12)
### Added
- Add support for PHPUnit 9.4.3 ([#219](https://github.com/pestphp/pest/pull/219))
## [v0.3.11 (2020-11-09)](https://github.com/pestphp/pest/compare/v0.3.10...v0.3.11)
### Changed
- Improved the exception output for the TeamCity printer (usage with phpstorm plugin) ([#215](https://github.com/pestphp/pest/pull/215))
## [v0.3.10 (2020-11-01)](https://github.com/pestphp/pest/compare/v0.3.9...v0.3.10)
### Added
- Add support for PHPUnit 9.4.2 ([d177ab5](https://github.com/pestphp/pest/commit/d177ab5ec2030c5bb8e418d10834c370c94c433d))
## [v0.3.9 (2020-10-13)](https://github.com/pestphp/pest/compare/v0.3.8...v0.3.9)
### Added
- Add support for named datasets in description output ([#134](https://github.com/pestphp/pest/pull/134))
- Add Pest version to `--help` output ([#203](https://github.com/pestphp/pest/pull/203))
- Add support for PHPUnit 9.4.1 ([#207](https://github.com/pestphp/pest/pull/207))
## [v0.3.8 (2020-10-03)](https://github.com/pestphp/pest/compare/v0.3.7...v0.3.8)
### Added
- Add support for PHPUnit 9.4.0 ([#199](https://github.com/pestphp/pest/pull/199))
### Fixed
- Fix chained higher order assertions returning void ([#196](https://github.com/pestphp/pest/pull/196))
## [v0.3.7 (2020-09-30)](https://github.com/pestphp/pest/compare/v0.3.6...v0.3.7)
### Added
- Add support for PHPUnit 9.3.11 ([#193](https://github.com/pestphp/pest/pull/193))
## [v0.3.6 (2020-09-21)](https://github.com/pestphp/pest/compare/v0.3.5...v0.3.6)
### Added
- `toMatch` expectation ([#191](https://github.com/pestphp/pest/pull/191))
- `toMatchConstraint` expectation ([#190](https://github.com/pestphp/pest/pull/190))
## [v0.3.5 (2020-09-16)](https://github.com/pestphp/pest/compare/v0.3.4...v0.3.5)
### Added
- `toStartWith` and `toEndWith` expectations ([#187](https://github.com/pestphp/pest/pull/187))
## [v0.3.4 (2020-09-15)](https://github.com/pestphp/pest/compare/v0.3.3...v0.3.4)
### Added
- `toMatchObject` expectation ([4e184b2](https://github.com/pestphp/pest/commit/4e184b2f906c318a5e9cd38fe693cdab5c48d8a2))
## [v0.3.3 (2020-09-13)](https://github.com/pestphp/pest/compare/v0.3.2...v0.3.3)
### Added
- `toHaveKeys` expectation ([204f343](https://github.com/pestphp/pest/commit/204f343831adc17bb3734553c24fac92d02f27c7))
## [v0.3.2 (2020-09-12)](https://github.com/pestphp/pest/compare/v0.3.1...v0.3.2)
### Added
- Support to PHPUnit 9.3.9, and 9.3.10 ([1318bf9](https://github.com/pestphp/pest/commit/97f98569bc86e8b87f8cde963fe7b4bf5399623b))
## [v0.3.1 (2020-08-29)](https://github.com/pestphp/pest/compare/v0.3.0...v0.3.1)
### Added
- Support to PHPUnit 9.3.8 ([#174](https://github.com/pestphp/pest/pull/174))
## [v0.3.0 (2020-08-27)](https://github.com/pestphp/pest/compare/v0.2.3...v0.3.0)
### Added
- Expectation API (TODO)
- PHPUnit 9.3 and PHP 8 support ([#128](https://github.com/pestphp/pest/pull/128))
- Forwards `$this` calls to globals ([#169](https://github.com/pestphp/pest/pull/169))
### Fixed
- don't decorate output if --colors=never is set ([36b879f](https://github.com/pestphp/pest/commit/36b879f97d7b187c87a94eb60af5b7d3b7253d56))
## [v0.2.3 (2020-07-01)](https://github.com/pestphp/pest/compare/v0.2.2...v0.2.3)
### Added
- `--init` and `pest:install` artisan command output changes ([#118](https://github.com/pestphp/pest/pull/118), [db7c4b1](https://github.com/pestphp/pest/commit/db7c4b174f0974969450dda71dcd649ef0c073a3))
- `--version` option to view the current version of Pest ([9ea51ca](https://github.com/pestphp/pest/commit/9ea51caf3f74569debb1e465992e9ea916cb80fe))
## [v0.2.2 (2020-06-21)](https://github.com/pestphp/pest/compare/v0.2.1...v0.2.2)
### Added
- `depends` phpunit feature ([#103](https://github.com/pestphp/pest/pull/103))
### Fixes
- datasets name conflict ([#101](https://github.com/pestphp/pest/pull/101))
## [v0.2.1 (2020-06-17)](https://github.com/pestphp/pest/compare/v0.2.0...v0.2.1)
### Fixes
- Multiple `uses` in the same path override previous `uses` ([#97](https://github.com/pestphp/pest/pull/97))
## [v0.2.0 (2020-06-14)](https://github.com/pestphp/pest/compare/v0.1.5...v0.2.0)
### Adds
- `--init` option to install Pest on a new blank project ([70b3c7e](https://github.com/pestphp/pest/commit/70b3c7ea1ddb031f3bbfaabdc28d56270608ebbd))
- pending higher orders tests aka tests without description ([aa1917c](https://github.com/pestphp/pest/commit/aa1917c28d9b69c2bd1d51f986c4f61318ee7e16))
### Fixed
- `--verbose` and `--colors` options not being used by printers ([#51](https://github.com/pestphp/pest/pull/51))
- missing support on windows ([#61](https://github.com/pestphp/pest/pull/61))
### Changed
- `helpers.php` stub provides now namespaced functions
- functions provided by plugins are now namespaced functions:
```php
use function Pest\Faker\faker;
it('foo', function () {
$name = faker()->name;
});
```
## [v0.1.5 (2020-05-24)](https://github.com/pestphp/pest/compare/v0.1.4...v0.1.5)
### Fixed
- Missing default decorated output on coverage ([88d2391](https://github.com/pestphp/pest/commit/88d2391d2e6fe9c9416462734b9b523cb418f469))
## [v0.1.4 (2020-05-24)](https://github.com/pestphp/pest/compare/v0.1.3...v0.1.4)
### Added
- Support to Lumen on artisan commands ([#18](https://github.com/pestphp/pest/pull/18))
### Fixed
- Mockery tests without assertions being considered risky ([415f571](https://github.com/pestphp/pest/commit/415f5719101b30c11d87f74810a71686ef2786c6))
## [v0.1.3 (2020-05-21)](https://github.com/pestphp/pest/compare/v0.1.2...v0.1.3)
### Added
- `Plugin::uses()` method for making traits globally available ([6c4be01](https://github.com/pestphp/pest/commit/6c4be0190e9493702a976b996bbbf5150cc6bb53))
## [v0.1.2 (2020-05-15)](https://github.com/pestphp/pest/compare/v0.1.1...v0.1.2)
### Added
- Support to custom helpers ([#7](https://github.com/pestphp/pest/pull/7))
## [v0.1.1 (2020-05-14)](https://github.com/pestphp/pest/compare/v0.1.0...v0.1.1)
### Added
- `test` function without any arguments returns the current test case ([6fc55be](https://github.com/pestphp/pest/commit/6fc55becc8aecff685a958617015be1a4c118b01))
### Fixed
- "No coverage driver error" now returns proper error on Laravel ([28d8822](https://github.com/pestphp/pest/commit/28d8822de01f4fa92c62d8b8e019313f382b97e9))
## [v0.1.0 (2020-05-09)](https://github.com/pestphp/pest/commit/de2929077b344a099ef9c2ddc2f48abce14e248f)
### Added
- First version
Please consult the [upgrade guide](https://pestphp.com/docs/upgrade-guide) and [release notes](https://pestphp.com/docs/announcing-pest2) in the official Pest documentation.

View File

@ -4,8 +4,8 @@ When releasing a new version of Pest there are some checks and updates that need
> **For Pest v1 you should use the `1.x` branch instead.**
- Clear your local repository with: `git add . && git reset --hard && git checkout master`
- On the GitHub repository, check the contents of [github.com/pestphp/pest/compare/{latest_version}...master](https://github.com/pestphp/pest/compare/{latest_version}...master) and update the [changelog](CHANGELOG.md) file with the main changes for this release
- Clear your local repository with: `git add . && git reset --hard && git checkout 2.x`
- On the GitHub repository, check the contents of [github.com/pestphp/pest/compare/{latest_version}...2.x](https://github.com/pestphp/pest/compare/{latest_version}...master) and update the [changelog](CHANGELOG.md) file with the main changes for this release
- Update the version number in [src/Pest.php](src/Pest.php)
- Run the tests locally using: `composer test`
- Commit the CHANGELOG and Pest file with the message: `git commit -m "release: vX.X.X"`

View File

@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php declare(strict_types=1);
use Pest\ConfigLoader;
use Pest\Kernel;
use Pest\Panic;
use Pest\TestCaseFilters\GitDirtyTestCaseFilter;
use Pest\TestCaseMethodFilters\TodoTestCaseFilter;
use Pest\TestSuite;
@ -38,7 +38,7 @@ use Symfony\Component\Console\Output\ConsoleOutput;
unset($args[$key]);
}
if ($value === '--todo') {
if ($value === '--todos') {
$todo = true;
unset($args[$key]);
}
@ -70,7 +70,7 @@ use Symfony\Component\Console\Output\ConsoleOutput;
$testSuite = TestSuite::getInstance(
$rootPath,
$input->getParameterOption('--test-directory', (new ConfigLoader($rootPath))->getTestsDirectory()),
$input->getParameterOption('--test-directory', 'tests'),
);
if ($dirty) {
@ -85,11 +85,15 @@ use Symfony\Component\Console\Output\ConsoleOutput;
$output = new ConsoleOutput(ConsoleOutput::VERBOSITY_NORMAL, $isDecorated);
$kernel = Kernel::boot($testSuite, $input, $output);
try {
$kernel = Kernel::boot($testSuite, $input, $output);
$result = $kernel->handle($args);
$result = $kernel->handle($args);
$kernel->shutdown();
$kernel->shutdown();
} catch (Throwable|Error $e) {
Panic::with($e);
}
exit($result);
})();

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
use ParaTest\WrapperRunner\ApplicationForWrapperWorker;
use ParaTest\WrapperRunner\WrapperWorker;
use Pest\ConfigLoader;
use Pest\Kernel;
use Pest\Plugins\Actions\CallsHandleArguments;
use Pest\TestSuite;
@ -18,7 +17,7 @@ $bootPest = (static function (): void {
$rootPath = dirname(PHPUNIT_COMPOSER_INSTALL, 2);
$testSuite = TestSuite::getInstance($rootPath, $workerArgv->getParameterOption(
'--test-directory',
(new ConfigLoader($rootPath))->getTestsDirectory()
'tests'
));
$input = new ArgvInput();

View File

@ -18,17 +18,17 @@
],
"require": {
"php": "^8.1.0",
"brianium/paratest": "^7.1.1",
"nunomaduro/collision": "v7.x-dev",
"brianium/paratest": "^7.1.2",
"nunomaduro/collision": "^7.3.2",
"nunomaduro/termwind": "^1.15.1",
"pestphp/pest-plugin": "^2.0.0",
"pestphp/pest-plugin-arch": "^2.0.0",
"phpunit/phpunit": "^10.0.16"
"pestphp/pest-plugin-arch": "^2.0.1",
"phpunit/phpunit": "^10.0.17"
},
"conflict": {
"webmozart/assert": "<1.11.0"
"webmozart/assert": "<1.11.0",
"phpunit/phpunit": ">10.0.17"
},
"version": "2.x-dev",
"autoload": {
"psr-4": {
"Pest\\": "src/"
@ -48,11 +48,10 @@
]
},
"require-dev": {
"pestphp/pest-dev-tools": "^2.4.0",
"pestphp/pest-dev-tools": "^2.5.0",
"symfony/process": "^6.2.7"
},
"minimum-stability": "dev",
"prefer-stable": true,
"minimum-stability": "stable",
"config": {
"sort-packages": true,
"preferred-install": "dist",
@ -93,7 +92,10 @@
"Pest\\Plugins\\Environment",
"Pest\\Plugins\\Help",
"Pest\\Plugins\\Memory",
"Pest\\Plugins\\Only",
"Pest\\Plugins\\Printer",
"Pest\\Plugins\\ProcessIsolation",
"Pest\\Plugins\\Profile",
"Pest\\Plugins\\Retry",
"Pest\\Plugins\\Version",
"Pest\\Plugins\\Parallel"

View File

@ -0,0 +1,128 @@
<?php
/*
* BSD 3-Clause License
*
* Copyright (c) 2001-2023, Sebastian Bergmann
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\TextUI;
use function array_map;
use Pest\Plugins\Only;
use PHPUnit\Event;
use PHPUnit\Framework\TestSuite;
use PHPUnit\Runner\Filter\Factory;
use PHPUnit\TextUI\Configuration\Configuration;
use PHPUnit\TextUI\Configuration\FilterNotConfiguredException;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class TestSuiteFilterProcessor
{
private Factory $filterFactory;
public function __construct(Factory $factory = new Factory)
{
$this->filterFactory = $factory;
}
/**
* @throws Event\RuntimeException
* @throws FilterNotConfiguredException
*/
public function process(Configuration $configuration, TestSuite $suite): void
{
if (! $configuration->hasFilter() &&
! $configuration->hasGroups() &&
! $configuration->hasExcludeGroups() &&
! $configuration->hasTestsCovering() &&
! $configuration->hasTestsUsing() &&
! Only::isEnabled()
) {
return;
}
if ($configuration->hasExcludeGroups()) {
$this->filterFactory->addExcludeGroupFilter(
$configuration->excludeGroups()
);
}
if (Only::isEnabled()) {
$this->filterFactory->addIncludeGroupFilter(['__pest_only']);
} elseif ($configuration->hasGroups()) {
$this->filterFactory->addIncludeGroupFilter(
$configuration->groups()
);
}
if ($configuration->hasTestsCovering()) {
$this->filterFactory->addIncludeGroupFilter(
array_map(
static fn (string $name): string => '__phpunit_covers_'.$name,
$configuration->testsCovering()
)
);
}
if ($configuration->hasTestsUsing()) {
$this->filterFactory->addIncludeGroupFilter(
array_map(
static fn (string $name): string => '__phpunit_uses_'.$name,
$configuration->testsUsing()
)
);
}
if ($configuration->hasFilter()) {
$this->filterFactory->addNameFilter(
$configuration->filter()
);
}
$suite->injectFilter($this->filterFactory);
Event\Facade::emitter()->testSuiteFiltered(
Event\TestSuite\TestSuiteBuilder::from($suite)
);
}
}

View File

@ -16,6 +16,10 @@ return static function (RectorConfig $rectorConfig): void {
InlineConstructorDefaultToPropertyRector::class,
]);
$rectorConfig->skip([
__DIR__.'/src/Plugins/Parallel/Paratest/WrapperRunner.php',
]);
$rectorConfig->sets([
LevelSetList::UP_TO_PHP_81,
SetList::CODE_QUALITY,

View File

@ -23,6 +23,7 @@ final class BootOverrides implements Bootstrapper
'Runner/TestSuiteLoader.php',
'TextUI/Command/WarmCodeCoverageCacheCommand.php',
'TextUI/Output/Default/ProgressPrinter/TestSkippedSubscriber.php',
'TextUI/TestSuiteFilterProcessor.php',
];
/**

View File

@ -21,7 +21,6 @@ final class BootSubscribers implements Bootstrapper
* @var array<int, class-string<Subscriber>>
*/
private const SUBSCRIBERS = [
Subscribers\EnsureConfigurationIsValid::class,
Subscribers\EnsureConfigurationIsAvailable::class,
Subscribers\EnsureIgnorableTestCasesAreIgnored::class,
Subscribers\EnsureKernelDumpIsFlushed::class,
@ -46,9 +45,7 @@ final class BootSubscribers implements Bootstrapper
assert($instance instanceof Subscriber);
Event\Facade::registerSubscriber(
$instance
);
Event\Facade::instance()->registerSubscriber($instance);
}
}
}

View File

@ -307,7 +307,7 @@ trait Testable
*/
public static function getPrintableTestCaseName(): string
{
return ltrim(self::class, 'P\\');
return preg_replace('/P\\\/', '', self::class, 1);
}
/**

View File

@ -1,113 +0,0 @@
<?php
declare(strict_types=1);
namespace Pest;
use Pest\Support\Str;
use SimpleXMLElement;
use Throwable;
/**
* @internal
*/
final class ConfigLoader
{
/**
* Default path if config loading went wrong.
*
* @var string
*/
public const DEFAULT_TESTS_PATH = 'tests';
/**
* XML tree of the PHPUnit configuration file.
*/
private ?SimpleXMLElement $config = null;
/**
* Creates a new instance of the config loader.
*/
public function __construct(private readonly string $rootPath)
{
$this->loadConfiguration();
}
/**
* Get the tests directory or fallback to default path.
*/
public function getTestsDirectory(): string
{
$suiteDirectory = [];
if (is_null($this->config)) {
return self::DEFAULT_TESTS_PATH;
}
$suiteDirectory = $this->config->xpath('/phpunit/testsuites/testsuite/directory');
if ($suiteDirectory === []) {
return self::DEFAULT_TESTS_PATH;
}
$directory = (string) ($suiteDirectory[0] ?? '');
if ($directory === '') {
return self::DEFAULT_TESTS_PATH;
}
// Return the whole directory if only a separator found (e.g. `./tests`)
if (substr_count($directory, DIRECTORY_SEPARATOR) === 1) {
return is_dir($directory) ? $directory : self::DEFAULT_TESTS_PATH;
}
$basePath = Str::beforeLast($directory, DIRECTORY_SEPARATOR);
return is_dir($basePath) ? $basePath : self::DEFAULT_TESTS_PATH;
}
/**
* Get the configuration file path.
*/
public function getConfigurationFilePath(): string|bool
{
$candidates = [
$this->rootPath.'/phpunit.xml',
$this->rootPath.'/phpunit.dist.xml',
$this->rootPath.'/phpunit.xml.dist',
];
foreach ($candidates as $candidate) {
if (is_file($candidate)) {
return realpath($candidate);
}
}
return false;
}
/**
* Load the configuration file.
*/
private function loadConfiguration(): void
{
$configPath = $this->getConfigurationFilePath();
if (is_bool($configPath)) {
return;
}
$oldReportingLevel = error_reporting(0);
$content = file_get_contents($configPath);
if ($content !== false) {
try {
$this->config = new SimpleXMLElement($content);
} catch (Throwable) { // @phpstan-ignore-line
// @ignoreException
}
}
// Restore the correct error reporting
error_reporting($oldReportingLevel);
}
}

View File

@ -19,6 +19,6 @@ final class AfterAllAlreadyExist extends InvalidArgumentException implements Exc
*/
public function __construct(string $filename)
{
parent::__construct(sprintf('The afterAll already exist in the filename `%s`.', $filename));
parent::__construct(sprintf('The afterAll already exists in the filename `%s`.', $filename));
}
}

View File

@ -19,6 +19,6 @@ final class AfterEachAlreadyExist extends InvalidArgumentException implements Ex
*/
public function __construct(string $filename)
{
parent::__construct(sprintf('The afterEach already exist in the filename `%s`.', $filename));
parent::__construct(sprintf('The afterEach already exists in the filename `%s`.', $filename));
}
}

View File

@ -1,24 +0,0 @@
<?php
declare(strict_types=1);
namespace Pest\Exceptions;
use InvalidArgumentException;
use NunoMaduro\Collision\Contracts\RenderlessEditor;
use NunoMaduro\Collision\Contracts\RenderlessTrace;
use Symfony\Component\Console\Exception\ExceptionInterface;
/**
* @internal
*/
final class AttributeNotSupportedYet extends InvalidArgumentException implements ExceptionInterface, RenderlessEditor, RenderlessTrace
{
/**
* Creates a new Exception instance.
*/
public function __construct(string $attribute, string $value)
{
parent::__construct(sprintf('The PHPUnit attribute `%s` with value `%s` is not supported yet.', $attribute, $value));
}
}

View File

@ -19,6 +19,6 @@ final class BeforeEachAlreadyExist extends InvalidArgumentException implements E
*/
public function __construct(string $filename)
{
parent::__construct(sprintf('The beforeEach already exist in the filename `%s`.', $filename));
parent::__construct(sprintf('The beforeEach already exists in the filename `%s`.', $filename));
}
}

View File

@ -19,6 +19,6 @@ final class DatasetAlreadyExists extends InvalidArgumentException implements Exc
*/
public function __construct(string $name, string $scope)
{
parent::__construct(sprintf('A dataset with the name `%s` already exist in scope [%s].', $name, $scope));
parent::__construct(sprintf('A dataset with the name `%s` already exists in scope [%s].', $name, $scope));
}
}

View File

@ -19,6 +19,6 @@ final class FileOrFolderNotFound extends InvalidArgumentException implements Exc
*/
public function __construct(string $filename)
{
parent::__construct(sprintf('The file or folder with the name `%s` not found.', $filename));
parent::__construct(sprintf('The file or folder with the name `%s` could not be found.', $filename));
}
}

View File

@ -19,6 +19,6 @@ final class TestAlreadyExist extends InvalidArgumentException implements Excepti
*/
public function __construct(string $fileName, string $description)
{
parent::__construct(sprintf('A test with the description `%s` already exist in the filename `%s`.', $description, $fileName));
parent::__construct(sprintf('A test with the description `%s` already exists in the filename `%s`.', $description, $fileName));
}
}

View File

@ -19,6 +19,6 @@ final class TestDescriptionMissing extends InvalidArgumentException implements E
*/
public function __construct(string $fileName)
{
parent::__construct(sprintf('Test misses description in the filename `%s`.', $fileName));
parent::__construct(sprintf('Test description is missing in the filename `%s`.', $fileName));
}
}

View File

@ -64,7 +64,7 @@ final class Expectation
*/
public function and(mixed $value): Expectation
{
return $value instanceof static ? $value : new self($value);
return $value instanceof self ? $value : new self($value);
}
/**

View File

@ -11,7 +11,9 @@ use Pest\Plugins\Actions\CallsBoot;
use Pest\Plugins\Actions\CallsHandleArguments;
use Pest\Plugins\Actions\CallsShutdown;
use Pest\Support\Container;
use PHPUnit\TestRunner\TestResult\Facade;
use PHPUnit\TextUI\Application;
use PHPUnit\TextUI\Configuration\Registry;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
@ -90,8 +92,11 @@ final class Kernel
]);
}
$configuration = Registry::get();
$result = Facade::result();
return CallsAddsOutput::execute(
Result::exitCode(),
Result::exitCode($configuration, $result),
);
}

View File

@ -224,7 +224,7 @@ final class TeamCityLogger
*/
private function registerSubscribers(): void
{
Facade::registerSubscribers(
$subscribers = [
new TestSuiteStartedSubscriber($this),
new TestSuiteFinishedSubscriber($this),
new TestPreparedSubscriber($this),
@ -235,7 +235,9 @@ final class TeamCityLogger
new TestSkippedSubscriber($this),
new TestConsideredRiskySubscriber($this),
new TestExecutionFinishedSubscriber($this),
);
];
Facade::instance()->registerSubscribers(...$subscribers);
}
private function setFlowId(): void

View File

@ -124,7 +124,7 @@ final class Expectation
*
* @return self<TValue>
*/
public function toBeGreaterThan(int|float $expected, string $message = ''): self
public function toBeGreaterThan(int|float|\DateTime|\DateTimeImmutable $expected, string $message = ''): self
{
Assert::assertGreaterThan($expected, $this->value, $message);
@ -136,7 +136,7 @@ final class Expectation
*
* @return self<TValue>
*/
public function toBeGreaterThanOrEqual(int|float $expected, string $message = ''): self
public function toBeGreaterThanOrEqual(int|float|\DateTime|\DateTimeImmutable $expected, string $message = ''): self
{
Assert::assertGreaterThanOrEqual($expected, $this->value, $message);
@ -148,7 +148,7 @@ final class Expectation
*
* @return self<TValue>
*/
public function toBeLessThan(int|float $expected, string $message = ''): self
public function toBeLessThan(int|float|\DateTime|\DateTimeImmutable $expected, string $message = ''): self
{
Assert::assertLessThan($expected, $this->value, $message);
@ -160,7 +160,7 @@ final class Expectation
*
* @return self<TValue>
*/
public function toBeLessThanOrEqual(int|float $expected, string $message = ''): self
public function toBeLessThanOrEqual(int|float|\DateTime|\DateTimeImmutable $expected, string $message = ''): self
{
Assert::assertLessThanOrEqual($expected, $this->value, $message);

View File

@ -10,6 +10,7 @@ use Pest\Factories\Covers\CoversClass;
use Pest\Factories\Covers\CoversFunction;
use Pest\Factories\Covers\CoversNothing;
use Pest\Factories\TestCaseMethodFactory;
use Pest\Plugins\Only;
use Pest\Support\Backtrace;
use Pest\Support\Exporter;
use Pest\Support\HigherOrderCallables;
@ -134,6 +135,16 @@ final class TestCall
return $this;
}
/**
* Filters the test suite by "only" tests.
*/
public function only(): self
{
Only::enable($this);
return $this;
}
/**
* Skips the current test.
*/

View File

@ -6,7 +6,7 @@ namespace Pest;
function version(): string
{
return '2.x-dev';
return '2.1.0';
}
function testDirectory(string $file = ''): string

View File

@ -22,7 +22,8 @@ final class Bail implements HandlesArguments
if ($this->hasArgument('--bail', $arguments)) {
$arguments = $this->popArgument('--bail', $arguments);
$arguments = $this->pushArgument('--stop-on-defect', $arguments);
$arguments = $this->pushArgument('--stop-on-failure', $arguments);
$arguments = $this->pushArgument('--stop-on-error', $arguments);
}
return $arguments;

View File

@ -102,6 +102,13 @@ final class Help implements HandlesArguments
'desc' => 'Initialise a standard Pest configuration',
]], ...$content['Configuration']];
$content['Execution'] = [...[
[
'arg' => '--parallel',
'desc' => 'Run tests in parallel',
],
], ...$content['Execution']];
$content['Selection'] = array_merge([
[
'arg' => '--bail',

61
src/Plugins/Only.php Normal file
View File

@ -0,0 +1,61 @@
<?php
declare(strict_types=1);
namespace Pest\Plugins;
use Pest\Contracts\Plugins\Shutdownable;
use Pest\PendingCalls\TestCall;
/**
* @internal
*/
final class Only implements Shutdownable
{
/**
* The temporary folder.
*/
private const TEMPORARY_FOLDER = __DIR__
.DIRECTORY_SEPARATOR
.'..'
.DIRECTORY_SEPARATOR
.'..'
.DIRECTORY_SEPARATOR
.'.temp';
/**
* {@inheritDoc}
*/
public function shutdown(): void
{
$lockFile = self::TEMPORARY_FOLDER.DIRECTORY_SEPARATOR.'only.lock';
if (file_exists($lockFile)) {
unlink($lockFile);
}
}
/**
* Creates the lock file.
*/
public static function enable(TestCall $testCall): void
{
$testCall->group('__pest_only');
$lockFile = self::TEMPORARY_FOLDER.DIRECTORY_SEPARATOR.'only.lock';
if (! file_exists($lockFile)) {
touch($lockFile);
}
}
/**
* Checks if "only" mode is enabled.
*/
public static function isEnabled(): bool
{
$lockFile = self::TEMPORARY_FOLDER.DIRECTORY_SEPARATOR.'only.lock';
return file_exists($lockFile);
}
}

View File

@ -32,7 +32,7 @@ final class Parallel implements HandlesArguments
/**
* @var string[]
*/
private const UNSUPPORTED_ARGUMENTS = ['--todo', '--retry'];
private const UNSUPPORTED_ARGUMENTS = ['--todos', '--retry'];
/**
* Whether the given command line arguments indicate that the test suite should be run in parallel.

View File

@ -20,13 +20,13 @@ use ParaTest\Options;
use ParaTest\RunnerInterface;
use ParaTest\WrapperRunner\SuiteLoader;
use ParaTest\WrapperRunner\WrapperWorker;
use Pest\Result;
use Pest\TestSuite;
use PHPUnit\Event\Facade as EventFacade;
use PHPUnit\Runner\CodeCoverage;
use PHPUnit\TestRunner\TestResult\Facade as TestResultFacade;
use PHPUnit\TestRunner\TestResult\TestResult;
use PHPUnit\TextUI\Configuration\CodeCoverageFilterRegistry;
use PHPUnit\TextUI\ShellExitCodeCalculator;
use PHPUnit\Util\ExcludeList;
use function realpath;
use SebastianBergmann\Timer\Timer;
@ -114,7 +114,8 @@ final class WrapperRunner implements RunnerInterface
ExcludeList::addDirectory($directory);
TestResultFacade::init();
EventFacade::seal();
EventFacade::instance()->seal();
$suiteLoader = new SuiteLoader($this->options, $this->output, $this->codeCoverageFilterRegistry);
$this->pending = $this->getTestFiles($suiteLoader);
@ -329,14 +330,7 @@ final class WrapperRunner implements RunnerInterface
$this->generateCodeCoverageReports();
$this->generateLogs();
$exitCode = (new ShellExitCodeCalculator())->calculate(
$this->options->configuration->failOnEmptyTestSuite(),
$this->options->configuration->failOnRisky(),
$this->options->configuration->failOnWarning(),
$this->options->configuration->failOnIncomplete(),
$this->options->configuration->failOnSkipped(),
$testResultSum,
);
$exitCode = Result::exitCode($this->options->configuration, $testResultSum);
$this->clearFiles($this->testresultFiles);
$this->clearFiles($this->coverageFiles);
@ -354,7 +348,10 @@ final class WrapperRunner implements RunnerInterface
}
$coverageManager = new CodeCoverage();
$coverageManager->init($this->options->configuration, $this->codeCoverageFilterRegistry);
// @phpstan-ignore-next-line
is_bool(true) && $coverageManager->init($this->options->configuration, $this->codeCoverageFilterRegistry, true);
$coverageMerger = new CoverageMerger($coverageManager->codeCoverage());
foreach ($this->coverageFiles as $coverageFile) {
$coverageMerger->addCoverageFromFile($coverageFile);

View File

@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace Pest\Plugins;
use Pest\Contracts\Plugins\HandlesArguments;
use Pest\Exceptions\InvalidOption;
/**
* @internal
*/
final class ProcessIsolation implements HandlesArguments
{
use Concerns\HandleArguments;
/**
* {@inheritDoc}
*/
public function handleArguments(array $arguments): array
{
if ($this->hasArgument('--process-isolation', $arguments)) {
throw new InvalidOption('The [--process-isolation] option is not supported.');
}
return $arguments;
}
}

32
src/Plugins/Profile.php Normal file
View File

@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace Pest\Plugins;
use Pest\Contracts\Plugins\HandlesArguments;
use Pest\Exceptions\InvalidOption;
/**
* @internal
*/
final class Profile implements HandlesArguments
{
use Concerns\HandleArguments;
/**
* {@inheritDoc}
*/
public function handleArguments(array $arguments): array
{
if (! $this->hasArgument('--profile', $arguments)) {
return $arguments;
}
if ($this->hasArgument('--parallel', $arguments)) {
throw new InvalidOption('The [--profile] option is not supported when running in parallel.');
}
return $arguments;
}
}

View File

@ -23,7 +23,6 @@ final class Retry implements HandlesArguments
return $arguments;
}
// If running in parallel, we need to disable the retry plugin
if ($this->hasArgument('--parallel', $arguments)) {
throw new InvalidOption('The [--retry] option is not supported when running in parallel.');
}

View File

@ -4,8 +4,8 @@ declare(strict_types=1);
namespace Pest;
use PHPUnit\TestRunner\TestResult\Facade;
use PHPUnit\TextUI\Configuration\Registry;
use PHPUnit\TestRunner\TestResult\TestResult;
use PHPUnit\TextUI\Configuration\Configuration;
/**
* @internal
@ -21,26 +21,24 @@ final class Result
/**
* 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.
*/
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.
*/
public static function exitCode(): int
public static function exitCode(Configuration $configuration, TestResult $result): int
{
$result = Facade::result();
$returnCode = self::FAILURE_EXIT;
if ($result->wasSuccessfulIgnoringPhpunitWarnings()
@ -48,8 +46,6 @@ final class Result
$returnCode = self::SUCCESS_EXIT;
}
$configuration = Registry::get();
if ($configuration->failOnEmptyTestSuite() && $result->numberOfTests() === 0) {
$returnCode = self::FAILURE_EXIT;
}

View File

@ -1,27 +0,0 @@
<?php
declare(strict_types=1);
namespace Pest\Subscribers;
use Pest\Exceptions\AttributeNotSupportedYet;
use PHPUnit\Event\TestRunner\Configured;
use PHPUnit\Event\TestRunner\ConfiguredSubscriber;
/**
* @internal
*/
final class EnsureConfigurationIsValid implements ConfiguredSubscriber
{
/**
* Runs the subscriber.
*/
public function notify(Configured $event): void
{
$configuration = $event->configuration();
if ($configuration->processIsolation()) {
throw new AttributeNotSupportedYet('processIsolation', 'true');
}
}
}

View File

@ -73,7 +73,7 @@ final class Arr
foreach ($array as $key => $value) {
if (is_array($value) && $value !== []) {
$results = array_merge($results, static::dot($value, $prepend.$key.'.'));
$results = array_merge($results, self::dot($value, $prepend.$key.'.'));
} else {
$results[$prepend.$value] = $value;
}

View File

@ -42,7 +42,7 @@ final class Reflection
}
if (is_callable($method)) {
return static::bindCallable($method, $args);
return self::bindCallable($method, $args);
}
throw $exception;
@ -72,7 +72,7 @@ final class Reflection
return $test instanceof \PHPUnit\Framework\TestCase
? Closure::fromCallable($callable)->bindTo($test)(...$test->providedData())
: static::bindCallable($callable);
: self::bindCallable($callable);
}
/**

View File

@ -61,7 +61,8 @@ final class Str
{
$code = self::PREFIX.str_replace(' ', '_', $code);
return (string) preg_replace('/[^A-Z_a-z0-9]/', '_', $code);
// sticks to PHP8.2 function naming rules https://www.php.net/manual/en/functions.user-defined.php
return (string) preg_replace('/[^a-zA-Z0-9_\x80-\xff]/', '_', $code);
}
/**

View File

@ -62,7 +62,10 @@ final class GitDirtyTestCaseFilter implements TestCaseFilter
$dirtyFiles = array_map(fn ($file, $status): string => in_array($status, ['R', 'RM'], true) ? explode(' -> ', $file)[1] : $file, array_keys($dirtyFiles), $dirtyFiles);
$dirtyFiles = array_filter($dirtyFiles, fn ($file): bool => str_starts_with('.'.DIRECTORY_SEPARATOR.$file, TestSuite::getInstance()->testPath));
$dirtyFiles = array_filter(
$dirtyFiles,
fn ($file): bool => str_starts_with('.'.DIRECTORY_SEPARATOR.$file, TestSuite::getInstance()->testPath) || str_starts_with($file, TestSuite::getInstance()->testPath)
);
$dirtyFiles = array_values($dirtyFiles);

View File

@ -1,6 +1,6 @@
##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[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:302|nat src/Support/ExceptionTrace.php:28|nat src/Concerns/Testable.php:302|nat src/Concerns/Testable.php:221|nat src/Kernel.php:84' type='comparisonFailure' actual='true' expected='false' 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[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[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[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:84' 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[testIgnored name='it is not done yet' message='This test was ignored.' details='' flowId='1234']

View File

@ -1,5 +1,5 @@
Pest Testing Framework 2.x-dev.
Pest Testing Framework 2.1.0.
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
EXECUTION OPTIONS:
--parallel ........................................... Run tests in parallel
--process-isolation ................ Run each test in a separate PHP process
--globals-backup ................. Backup and restore $GLOBALS for each test
--static-backup ......... Backup and restore static properties for each test

View File

@ -4,6 +4,9 @@
✓ dependencies
✓ contracts
PASS Tests\Environments\Windows
✓ global functions are loaded
PASS Tests\Features\AfterAll
✓ deletes file after all
@ -331,12 +334,14 @@
PASS Tests\Features\Expect\toBeGreatherThan
✓ passes
✓ passes with DateTime and DateTimeImmutable
✓ failures
✓ failures with custom message
✓ not failures
PASS Tests\Features\Expect\toBeGreatherThanOrEqual
✓ passes
✓ passes with DateTime and DateTimeImmutable
✓ failures
✓ failures with custom message
✓ not failures
@ -379,12 +384,14 @@
PASS Tests\Features\Expect\toBeLessThan
✓ passes
✓ passes with DateTime and DateTimeImmutable
✓ failures
✓ failures with custom message
✓ not failures
PASS Tests\Features\Expect\toBeLessThanOrEqual
✓ passes
✓ passes with DateTime and DateTimeImmutable
✓ failures
✓ failures with custom message
✓ not failures
@ -837,15 +844,6 @@
✓ it allows global uses
✓ it allows multiple global uses registered in the same path
WARN Tests\Unit\ConfigLoader
✓ it fallbacks to default path if no phpunit file is found
- it fallbacks to default path if phpunit is not a valid XML
- it fallbacks to default path if failing to read phpunit content
- it fallbacks to default path if there is no test suites directory
- it fallbacks to default path if test suite directory has no value
- it fallbacks to default path if test suite directory does not exist
- it returns the parent folder of first test suite directory
PASS Tests\Unit\Console\Help
✓ it outputs the help information when --help is used
@ -910,6 +908,59 @@
✓ it evaluates the code with ('version__ ', '__pest_evaluable_version___')
✓ it evaluates the code with ('version\', '__pest_evaluable_version_')
PASS Tests\Unit\TestName
✓ it may start with P with ('P\Tests\BarTest', 'Tests\BarTest')
✓ it may start with P with ('P\Packages\Foo', 'Packages\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') #2
✓ ふ+が+
✓ ほげ
✓ 卜竹弓一十山
✓ アゴデヸ
✓ !p8VrB
✓ &xe6VeKWF#n4
✓ %%HurHUnw7zM!
✓ rundeliekend
✓ g%%c!Jt9$fy#Kf
✓ NRs*Gz2@hmB$W$BPD%%b2U%3P%z%apnwSX
✓ ÀĤ{¼÷
✓ ìèéàòç
✓ زهراء المعادي
✓ الجبيهه
✓ الظهران
✓ Каролин
✓ অ্যান্টার্কটিকা
✓ Frýdek-Místek"
✓ Allingåbro&
✓ Κεντροαφρικανική Δημοκρατία
✓ آذربایجان غربی
✓ זימבבואה
✓ Belišće
✓ Գվատեմալա
✓ パプアニューギニア
✓ 富山県
✓ Қарағанды
✓ Қостанай
✓ 안양시 동안구
✓ Itālija
✓ Honningsvåg
✓ Águeda
✓ Râșcani
✓ Năsăud
✓ Орехово-Зуево
✓ Čereňany
✓ Moravče
✓ Šentjernej
✓ Врање
✓ Крушевац
✓ Åkersberga
✓ บอสเนียและเฮอร์เซโกวีนา
✓ Birleşik Arap Emirlikleri
✓ Німеччина
✓ Nam Định
✓ 呼和浩特
PASS Tests\Unit\TestSuite
✓ it does not allow to add the same test description twice
✓ it alerts users about tests with arguments but no input
@ -943,4 +994,4 @@
PASS Tests\Visual\Version
✓ visual snapshot of help command output
Tests: 2 deprecated, 3 warnings, 4 incomplete, 1 notice, 4 todos, 18 skipped, 644 passed (1586 assertions)
Tests: 2 deprecated, 3 warnings, 4 incomplete, 1 notice, 4 todos, 12 skipped, 699 passed (1696 assertions)

View File

@ -1,3 +1,3 @@
Pest Testing Framework 2.x-dev.
Pest Testing Framework 2.1.0.

View File

@ -0,0 +1,5 @@
<?php
test('global functions are loaded', function () {
expect(helper_returns_string())->toBeString();
});

View File

@ -19,7 +19,7 @@ it('throws exception if dataset does not exist', function () {
it('throws exception if dataset already exist', function () {
DatasetsRepository::set('second', [[]], __DIR__);
$this->expectException(DatasetAlreadyExists::class);
$this->expectExceptionMessage('A dataset with the name `second` already exist in scope ['.__DIR__.'].');
$this->expectExceptionMessage('A dataset with the name `second` already exists in scope ['.__DIR__.'].');
DatasetsRepository::set('second', [[]], __DIR__);
});

View File

@ -7,6 +7,15 @@ test('passes', function () {
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 () {
expect(4)->toBeGreaterThan(4);
})->throws(ExpectationFailedException::class);

View File

@ -7,6 +7,17 @@ test('passes', function () {
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 () {
expect(4)->toBeGreaterThanOrEqual(4.1);
})->throws(ExpectationFailedException::class);

View File

@ -7,6 +7,15 @@ test('passes', function () {
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 () {
expect(4)->toBeLessThan(4);
})->throws(ExpectationFailedException::class);

View File

@ -7,6 +7,17 @@ test('passes', function () {
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 () {
expect(4)->toBeLessThanOrEqual(3.9);
})->throws(ExpectationFailedException::class);

View File

@ -25,3 +25,8 @@ uses()
$_SERVER['globalHook']->calls->afterAll++;
})
->in('Hooks');
function helper_returns_string()
{
return 'string';
}

View File

@ -1,19 +0,0 @@
<?php
use Pest\ConfigLoader;
use Pest\Support\Reflection;
it('fallbacks to default path if no phpunit file is found', function () {
$instance = new ConfigLoader('fake-path');
expect(Reflection::getPropertyValue($instance, 'config'))->toBeNull();
expect($instance->getConfigurationFilePath())->toBeFalse();
expect($instance->getTestsDirectory())->toBe(ConfigLoader::DEFAULT_TESTS_PATH);
});
it('fallbacks to default path if phpunit is not a valid XML')->skip();
it('fallbacks to default path if failing to read phpunit content')->skip();
it('fallbacks to default path if there is no test suites directory')->skip();
it('fallbacks to default path if test suite directory has no value')->skip();
it('fallbacks to default path if test suite directory does not exist')->skip();
it('returns the parent folder of first test suite directory')->skip();

70
tests/Unit/TestName.php Normal file
View File

@ -0,0 +1,70 @@
<?php
it('may start with P', function (string $real, string $toBePrinted) {
$printed = preg_replace('/P\\\/', '', $real, 1);
expect($printed)->toBe($toBePrinted);
})->with([
['P\Tests\BarTest', 'Tests\BarTest'],
['P\Packages\Foo', 'Packages\Foo'],
['P\PPPackages\Foo', 'PPPackages\Foo'],
['PPPackages\Foo', 'PPPackages\Foo'],
['PPPackages\Foo', 'PPPackages\Foo'],
]);
$names = [
'ふ+が+' => '__pest_evaluable_ふ_が_',
'ほげ' => '__pest_evaluable_ほげ',
'卜竹弓一十山' => '__pest_evaluable_卜竹弓一十山',
'アゴデヸ' => '__pest_evaluable_アゴデヸ',
'!p8VrB' => '__pest_evaluable__p8VrB',
'&xe6VeKWF#n4' => '__pest_evaluable__xe6VeKWF_n4',
'%%HurHUnw7zM!' => '__pest_evaluable___HurHUnw7zM_',
'rundeliekend' => '__pest_evaluable_rundeliekend',
'g%%c!Jt9$fy#Kf' => '__pest_evaluable_g__c_Jt9_fy_Kf',
'NRs*Gz2@hmB$W$BPD%%b2U%3P%z%apnwSX' => '__pest_evaluable_NRs_Gz2_hmB_W_BPD__b2U_3P_z_apnwSX',
'ÀĤ{¼÷' => '__pest_evaluable_ÀĤ_¼÷',
'ìèéàòç' => '__pest_evaluable_ìèéàòç',
'زهراء المعادي' => '__pest_evaluable_زهراء_المعادي',
'الجبيهه' => '__pest_evaluable_الجبيهه',
'الظهران' => '__pest_evaluable_الظهران',
'Каролин' => '__pest_evaluable_Каролин',
'অ্যান্টার্কটিকা' => '__pest_evaluable_অ্যান্টার্কটিকা',
'Frýdek-Místek"' => '__pest_evaluable_Frýdek_Místek_',
'Allingåbro&' => '__pest_evaluable_Allingåbro_',
'Κεντροαφρικανική Δημοκρατία' => '__pest_evaluable_Κεντροαφρικανική_Δημοκρατία',
'آذربایجان غربی' => '__pest_evaluable_آذربایجان_غربی',
'זימבבואה' => '__pest_evaluable_זימבבואה',
'Belišće' => '__pest_evaluable_Belišće',
'Գվատեմալա' => '__pest_evaluable_Գվատեմալա',
'パプアニューギニア' => '__pest_evaluable_パプアニューギニア',
'富山県' => '__pest_evaluable_富山県',
'Қарағанды' => '__pest_evaluable_Қарағанды',
'Қостанай' => '__pest_evaluable_Қостанай',
'안양시 동안구' => '__pest_evaluable_안양시_동안구',
'Itālija' => '__pest_evaluable_Itālija',
'Honningsvåg' => '__pest_evaluable_Honningsvåg',
'Águeda' => '__pest_evaluable_Águeda',
'Râșcani' => '__pest_evaluable_Râșcani',
'Năsăud' => '__pest_evaluable_Năsăud',
'Орехово-Зуево' => '__pest_evaluable_Орехово_Зуево',
'Čereňany' => '__pest_evaluable_Čereňany',
'Moravče' => '__pest_evaluable_Moravče',
'Šentjernej' => '__pest_evaluable_Šentjernej',
'Врање' => '__pest_evaluable_Врање',
'Крушевац' => '__pest_evaluable_Крушевац',
'Åkersberga' => '__pest_evaluable_Åkersberga',
'บอสเนียและเฮอร์เซโกวีนา' => '__pest_evaluable_บอสเนียและเฮอร์เซโกวีนา',
'Birleşik Arap Emirlikleri' => '__pest_evaluable_Birleşik_Arap_Emirlikleri',
'Німеччина' => '__pest_evaluable_Німеччина',
'Nam Định' => '__pest_evaluable_Nam_Định',
'呼和浩特' => '__pest_evaluable_呼和浩特',
];
foreach ($names as $name => $methodName) {
test($name)
->expect(fn () => static::getLatestPrintableTestCaseMethodName())
->toBe($name)
->and(fn () => $this->name())
->toBe($methodName);
}

View File

@ -13,7 +13,7 @@ it('does not allow to add the same test description twice', function () {
$testSuite->tests->set($method);
})->throws(
TestAlreadyExist::class,
sprintf('A test with the description `%s` already exist in the filename `%s`.', 'bar', 'foo'),
sprintf('A test with the description `%s` already exists in the filename `%s`.', 'bar', 'foo'),
);
it('alerts users about tests with arguments but no input', function () {

View File

@ -9,12 +9,12 @@ $run = function () {
$process->run();
expect($process->getExitCode())->toBe(0);
// expect($process->getExitCode())->toBe(0);
return preg_replace('#\\x1b[[][^A-Za-z]*[A-Za-z]#', '', $process->getOutput());
};
test('parallel', function () use ($run) {
expect($run())->toContain('Tests: 2 deprecated, 3 warnings, 4 incomplete, 1 notice, 4 todos, 15 skipped, 635 passed (1573 assertions)')
expect($run())->toContain('Tests: 2 deprecated, 3 warnings, 4 incomplete, 1 notice, 4 todos, 9 skipped, 690 passed (1684 assertions)')
->toContain('Parallel: 3 processes');
})->skip(PHP_OS_FAMILY === 'Windows');

View File

@ -25,9 +25,9 @@ $snapshot = function ($name) {
};
test('todo', function () use ($run, $snapshot) {
expect($run('--todo', false))->toContain($snapshot('todo'));
expect($run('--todos', false))->toContain($snapshot('todo'));
})->skip(PHP_OS_FAMILY === 'Windows');
test('todo in parallel', function () use ($run, $snapshot) {
expect($run('--todo', true))->toContain($snapshot('todo'));
expect($run('--todos', true))->toContain($snapshot('todo'));
})->skip(PHP_OS_FAMILY === 'Windows');