diff --git a/arch-testing.md b/arch-testing.md index 75a3a33..98f9629 100644 --- a/arch-testing.md +++ b/arch-testing.md @@ -5,10 +5,41 @@ description: Architecture testing enables you to specify expectations that test # Architecture Testing -Architecture testing enables you to specify expectations that test whether your application adheres to a set of architectural rules, helping you maintain a clean and sustainable codebase. The expectations are determined by either Relative namespaces, fully qualified namespaces, or function names. +Architecture testing enables you to specify expectations that test whether your application adheres to a set of architectural rules, helping you maintain a clean and sustainable codebase. The expectations are determined by either relative namespaces, fully qualified namespaces, or function names. + +Here is an example of how you can define an architectural rule: + +```php +arch() + ->expect('App') + ->toUseStrictTypes() + ->not->toUse(['die', 'dd', 'dump']); + +arch() + ->expect('App\Models') + ->toBeClasses() + ->toExtend('Illuminate\Database\Eloquent\Model'); + ->toOnlyBeUsedIn('App\Repositories') + ->ignoring('App\Models\User'); + +arch() + ->expect('App\Http') + ->toOnlyBeUsedIn('App\Http'); + +arch()->preset()->php(); +arch()->preset()->security()->ignoring('md5'); +``` + +Now, let's dive into the various methods and modifiers available for architectural testing. In this section, you will learn: + +- [Expectations](#expectations): Allows to specify granular architectural rules. +- [Presets](#presets): Allows to use predefined sets of granular architectural rules. +- [Modifiers](#modifiers): To exclude or ignore certain types of files, classes, functions or lines of code. ## Expectations +Granular expectations allow you to define specific architectural rules for your application. Here are the available expectations: +
- [`toBeAbstract()`](#expect-toBeAbstract) @@ -27,8 +58,19 @@ Architecture testing enables you to specify expectations that test whether your - [`toExtendNothing()`](#expect-toExtendNothing) - [`toImplement()`](#expect-toImplement) - [`toImplementNothing()`](#expect-toImplementNothing) +- [`toHaveAllMethodsDocumented()`](#expect-toHaveAllMethodsDocumented) +- [`toHaveAllPropertiesDocumented()`](#expect-toHaveAllPropertiesDocumented) - [`toHaveAttribute()`](#expect-toHaveAttribute) +- [`toHaveFileSystemPermissions()`](#expect-toHaveFileSystemPermissions) +- [`toHaveLineCountLessThan`](#expect-toHaveLineCountLessThan) - [`toHaveMethod()`](#expect-toHaveMethod) +- [`toHaveMethods()`](#expect-toHaveMethod) +- [`toHavePrivateMethodsBesides()`](#expect-toHavePrivateMethodsBesides) +- [`toHavePrivateMethods()`](#expect-toHavePrivateMethods) +- [`toHaveProtectedMethodsBesides()`](#expect-toHaveProtectedMethodsBesides) +- [`toHaveProtectedMethods()`](#expect-toHaveProtectedMethods) +- [`toHavePublicMethodsBesides()`](#expect-toHavePublicMethodsBesides) +- [`toHavePublicMethods()`](#expect-toHavePublicMethods) - [`toHavePrefix()`](#expect-toHavePrefix) - [`toHaveSuffix()`](#expect-toHaveSuffix) - [`toHaveConstructor()`](#expect-toHaveConstructor) @@ -37,6 +79,8 @@ Architecture testing enables you to specify expectations that test whether your - [`toOnlyUse()`](#expect-toOnlyUse) - [`toOnlyBeUsedIn()`](#expect-toOnlyBeUsedIn) - [`toUse()`](#expect-toUse) +- [`toUseTrait()`](#expect-toUseTrait) +- [`toUseTraits()`](#expect-toUseTraits) - [`toUseNothing()`](#expect-toUseNothing) - [`toUseStrictTypes()`](#expect-toUseStrictTypes) @@ -244,6 +288,28 @@ arch('app') ->toImplementNothing(); ``` + +### `toHaveAllMethodsDocumented()` + +The `toHaveAllMethodsDocumented()` method may be used to ensure that all methods within a given namespace are documented. + +```php +arch('app') + ->expect('App') + ->toHaveAllMethodsDocumented(); +``` + + +### `toHaveAllPropertiesDocumented()` + +The `toHaveAllPropertiesDocumented()` method may be used to ensure that all properties within a given namespace are documented. + +```php +arch('app') + ->expect('App') + ->toHaveAllPropertiesDocumented(); +``` + ### `toHaveAttribute()` @@ -255,6 +321,28 @@ arch('app') ->toHaveAttribute('Symfony\Component\Console\Attribute\AsCommand'); ``` + +### `toHaveFileSystemPermissions()` + +The `toHaveFileSystemPermissions()` method may be used to ensure that all files within a given namespace have specific file system permissions. + +```php +arch('app') + ->expect('App') + ->not->toHaveFileSystemPermissions('0777'); +``` + + +### `toHaveLineCountLessThan()` + +The `toHaveLineCountLessThan()` method may be used to ensure that all files within a given namespace have a line count less than a specified value. + +```php +arch('app') + ->expect('App\Models') + ->toHaveLineCountLessThan(100); +``` + ### `toHaveMethod()` @@ -266,6 +354,82 @@ arch('app') ->toHaveMethod('index'); ``` + +### `toHaveMethods()` + +The `toHaveMethods()` method may be used to ensure that a certain class has specific methods. +```php +arch('app') + ->expect('App\Http\Controllers\HomeController') + ->toHaveMethods(['index', 'show']); +``` + + +### `toHavePrivateMethodsBesides()` + +The `toHavePrivateMethodsBesides()` method may be used to ensure that a certain class does not have any private methods besides the specified ones. + +```php +arch('app') + ->expect('App\Services\PaymentService') + ->not->toHavePrivateMethodsBesides(['doPayment']); +``` + + +### `toHavePrivateMethods()` + +The `toHavePrivateMethods()` method may be used to ensure that a certain class does not have any private methods. + +```php +arch('app') + ->expect('App\Services\PaymentService') + ->not->toHavePrivateMethods(); +``` + + +### `toHaveProtectedMethodsBesides()` + +The `toHaveProtectedMethodsBesides()` method may be used to ensure that a certain class does not have any protected methods besides the specified ones. + +```php +arch('app') + ->expect('App\Services\PaymentService') + ->not->toHaveProtectedMethodsBesides(['doPayment']); +``` + + +### `toHaveProtectedMethods()` + +The `toHaveProtectedMethods()` method may be used to ensure that a certain class does not have any protected methods. + +```php +arch('app') + ->expect('App\Services\PaymentService') + ->not->toHaveProtectedMethods(); +``` + + +### `toHavePublicMethodsBesides()` + +The `toHavePublicMethodsBesides()` method may be used to ensure that a certain class does not have any public methods besides the specified ones. + +```php +arch('app') + ->expect('App\Services\PaymentService') + ->not->toHavePublicMethodsBesides(['charge', 'refund']); +``` + + +### `toHavePublicMethods()` + +The `toHavePublicMethods()` method may be used to ensure that a certain class does not have any public methods. + +```php +arch('app') + ->expect('App\Services\PaymentService') + ->not->toHavePublicMethods(); +``` + ### `toHavePrefix()` @@ -358,6 +522,28 @@ arch('globals') ->not->toUse('Illuminate\Http'); ``` + +### `toUseTrait()` + +The `toUseTrait()` method may be used to ensure that all files within a given namespace use a specific trait. + +```php +arch('models') + ->expect('App\Models') + ->toUseTrait('Illuminate\Database\Eloquent\SoftDeletes'); +``` + + +### `toUseTraits()` + +The `toUseTraits()` method may be used to ensure that all files within a given namespace use specific traits. + +```php +arch('models') + ->expect('App\Models') + ->toUseTraits(['Illuminate\Database\Eloquent\SoftDeletes', 'App\Concerns\CustomTrait']); +``` + ### `toUseNothing()` @@ -380,67 +566,186 @@ arch('app') ->toUseStrictTypes(); ``` -### Modifiers +## Presets -Sometimes, you may want to apply the given expectation but excluding certain namespaces or type of files. For that, you may use the following modifiers: +Sometimes, writing arch expectations from scratch can be time-consuming, specifically when working on a new project, and you just want to ensure that the basic architectural rules are met. + +Presets are predefined sets of granular expectations that you can use to test your application's architecture.
-- [`classes()`](#modifier-classes) -- [`enums()`](#modifier-enums) -- [`ignoring()`](#modifier-ignoring) -- [`interfaces()`](#modifier-interfaces) -- [`traits()`](#modifier-traits) +- [`php`](#preset-php) +- [`security`](#preset-security) +- [`laravel`](#preset-laravel) +- [`strict`](#preset-strict) +- [`strict`](#preset-strict) +- [`custom`](#preset-custom)
- -### `classes()` + +### `php` -The `classes()` modifier allows you to restrict the expectation to only classes. +The `php` preset is a predefined set of expectations that can be used on any php project. It's not coupled with any framework or library. + +It avoids the usage of `die`, `var_dump`, and similar functions, and ensures you are not using deprecated PHP functions. ```php -arch('app') - ->expect('App') - ->classes() - ->toBeFinal(); +arch()->preset()->php(); ``` - -### `enums()` +You may find all the expectations included in the `php` preset below in our [source code](https://github.com/pestphp/pest/blob/3.x/src/ArchPresets/Php.php). -The `enums()` modifier allows you to restrict the expectation to only enums. + +### `security` + +The `security` preset is a predefined set of expectations that can be used on any php project. It's not coupled with any framework or library. + +It ensures you are not using code that could lead to security vulnerabilities, such as `eval`, `md5`, and similar functions. ```php -arch('app') - ->expect('App\Models') - ->enums() - ->toOnlyBeUsedIn('App\Models'); +arch()->preset()->security(); ``` +You may find all the expectations included in the `security` preset below in our [source code](https://github.com/pestphp/pest/blob/3.x/src/ArchPresets/Security.php). + + +### `laravel` + +The `laravel` preset is a predefined set of expectations that can be used on [Laravel](https://laravel.com) projects. + +It ensures you project's structure is following the well-known Laravel conventions, such as controllers only have `index`, `show`, `create`, `store`, `edit`, `update`, `destroy` as public methods and are always suffixed with `Controller` and so on. + +```php +arch()->preset()->laravel(); +``` + +You may find all the expectations included in the `laravel` preset below in our [source code](https://github.com/pestphp/pest/blob/3.x/src/ArchPresets/Laravel.php). + + +### `strict` + +The `strict` preset is a predefined set of expectations that can be used on any php project. It's not coupled with any framework or library. + +It ensures you are using strict types in all your files, that all your classes are final, and more. + +```php +arch()->preset()->strict(); +``` + +You may find all the expectations included in the `strict` preset below in our [source code](https://github.com/pestphp/pest/blob/3.x/src/ArchPresets/Strict.php). + + +### `relaxed` + +The `relaxed` preset is a predefined set of expectations that can be used on any php project. It's not coupled with any framework or library. + +It is the opposite of the `strict` preset, ensuring you are not using strict types in all your files, that all your classes are not final, and more. + +```php +arch()->preset()->relaxed(); +``` + +You may find all the expectations included in the `relaxed` preset below in our [source code](https://github.com/pestphp/pest/blob/3.x/src/ArchPresets/Relaxed.php). + + +### `custom` + +Typically you don't need to use the `custom` preset, as you can use the `arch()` method to write your granular expectations. However, if you want to create your own preset, you can use the `custom` preset. + +This may be useful if you have a set of expectations that you use frequently across multiple projects, or if you are plugin author and want to provide a set of expectations for your users. +```php +pest()->preset('ddd', function () { + return [ + expect('Infrastructure')->toOnlyBeUsedIn('Application'), + expect('Domain')->toOnlyBeUsedIn('Application'), + ]; +}); +``` + +With the `preset` method, you may have access to the application PSR-4 namespaces on the first argument of your closure's callback. + +```php +pest()->preset('silex', function (array $userNamespaces) { + dump($userNamespaces); // ['App\\'] +}); +``` + +## Modifiers + +Sometimes, you may want to apply the given expectation but excluding certain types of files, or ignoring certain classes, functions, or specific lines of code. For that, you may use the following methods: + +
+ +- [`ignoring()`](#modifier-ignoring) +- [`classes()`](#modifier-classes) +- [`enums()`](#modifier-enums) +- [`interfaces()`](#modifier-interfaces) +- [`traits()`](#modifier-traits) + +
+ ### `ignoring()` When defining your architecture rules, you can use the `ignoring()` method to exclude certain namespaces or classes that would otherwise be included in the rule definition. ```php -arch('facades') +arch() + ->preset() + ->php() + ->ignoring('die'); + +arch() ->expect('Illuminate\Support\Facades') ->not->toBeUsed() ->ignoring('App\Providers'); ``` +You may also ignore a specific line of code by using the `@pest-arch-ignore-line` or `@pest-arch-ignore-next-line` directives. + +```php +die('This line will be ignored'); // @pest-arch-ignore-line + +// @pest-arch-ignore-next-line +die('This line will be ignored'); +``` + In some cases, certain components may not be regarded as "dependencies" as they are part of the native PHP library. To customize the definition of "native" code and exclude it during testing, Pest allows you to specify what to ignore. For example, if you do not want to consider Laravel a "dependency", you can use the `arch()` method inside the `beforeEach()` function to disregard any code within the "Illuminate" namespace. This approach allows you to focus only on the actual dependencies of your application. ```php // tests/Pest.php -uses()->beforeEach(function () { +pest()->beforeEach(function () { $this->arch()->ignore([ 'Illuminate', ])->ignoreGlobalFunctions(); -})->in('Feature'); +}); +``` + + +### `classes()` + +The `classes()` modifier allows you to restrict the expectation to only classes. + +```php +arch('app') + ->expect('App') + ->classes() + ->toBeFinal(); +``` + + +### `enums()` + +The `enums()` modifier allows you to restrict the expectation to only enums. + +```php +arch('app') + ->expect('App\Models') + ->enums() + ->toOnlyBeUsedIn('App\Models'); ``` diff --git a/configuring-tests.md b/configuring-tests.md index 412ac2c..99fd53d 100644 --- a/configuring-tests.md +++ b/configuring-tests.md @@ -17,11 +17,11 @@ it('has home', function () { }); ``` -However, you may associate a specific folder or even your entire test suite with another base test case class, thus changing the value of `$this` within tests. To accomplish this, you can utilize the `uses()` and `in()` functions within your `Pest.php` configuration file. +However, you may associate a specific folder or even your entire test suite with another base test case class, thus changing the value of `$this` within tests. To accomplish this, you can utilize the `pest()` function and the `in()` method within your `Pest.php` configuration file. ```php // tests/Pest.php -uses(Tests\TestCase::class)->in('Feature'); +pest()->extend(Tests\TestCase::class)->in('Feature'); // tests/Feature/ExampleTest.php it('has home', function () { @@ -33,7 +33,7 @@ Additionally, Pest supports [glob patterns](https://www.php.net/manual/en/functi ```php // tests/Pest.php -uses(Tests\TestCase::class)->in('Feature/*Job*.php'); +pest()->extend(Tests\TestCase::class)->in('Feature/*Job*.php'); // This will apply the Tests\TestCase to all test files in the "Feature" directory that contains "Job" in their filename. ``` @@ -42,10 +42,10 @@ Another more complex example would be using a pattern to match multiple director ```php // tests/Pest.php -uses( - DuskTestCase::class, - DatabaseMigrations::class -)->in('../Modules/*/Tests/Browser'); +pest() + ->extend(DuskTestCase::class) + ->use(DatabaseMigrations::class) + ->in('../Modules/*/Tests/Browser'); // This will apply the DuskTestCase class and the DatabaseMigrations trait to all test files within any module's "Browser" directory. ``` @@ -65,7 +65,7 @@ class TestCase extends BaseTestCase } // tests/Pest.php -uses(TestCase::class)->in('Feature'); +pest()->extend(TestCase::class)->in('Feature'); // tests/Feature/ExampleTest.php it('has home', function () { @@ -73,7 +73,7 @@ it('has home', function () { }); ``` -A trait can be linked to a test or folder, much like classes. For instance, in Laravel, you can employ the `RefreshDatabase` trait to reset the database prior to each test. To include the trait in your test, pass the trait's name to the `uses()` function. +A trait can be linked to a test or folder, much like classes. For instance, in Laravel, you can employ the `RefreshDatabase` trait to reset the database prior to each test. To include the trait in your test, pass the trait's name to the `pest()->use()` method. ```php in('Feature'); +pest()->extend(TestCase::class)->use(RefreshDatabase::class)->in('Feature'); ``` -To associate a particular test with a specific test case class or trait, you can utilize the `uses()` function **within that specific test file**, omitting the use of the `in()` method. +To associate a particular test with a specific test case class or trait, you can utilize the `pest()->extend()` and `pest()->use()` methods **within that specific test file**, omitting the use of the `in()` method. ```php -uses(Tests\MySpecificTestCase::class); +pest()->extend(Tests\MySpecificTestCase::class); it('has home', function () { echo get_class($this); // \Tests\MySpecificTestCase diff --git a/creating-plugins.md b/creating-plugins.md index b5b4244..117c745 100644 --- a/creating-plugins.md +++ b/creating-plugins.md @@ -100,6 +100,27 @@ test('plugin example', function () { Custom expectations can be incorporated into your plugin's `Autoload.php` file. For information on how to build custom expectations, please refer to the comprehensive documentation on [Custom Expectations](/docs/custom-expectations). +## Adding Arch Presets + +If your plugin provides a custom Arch preset, you can define it within the `Autoload.php` file. + +```php +pest()->preset('ddd', function () { + return [ + expect('Infrastructure')->toOnlyBeUsedIn('Application'), + expect('Domain')->toOnlyBeUsedIn('Application'), + ]; +}); +``` + +Optionally, may have access to the application PSR-4 namespaces on the first argument of your closure's callback. + +```php +pest()->preset('silex', function (array $userNamespaces) { + dump($userNamespaces); // ['App\\'] +}); +``` + --- As you can see, crafting plugins on Pest can serve as a fantastic starting point for your open-source endeavors! In the next chapter, we will explore the concept of "Higher Order Testing": [Higher Order Testing](/docs/higher-order-testing) diff --git a/custom-helpers.md b/custom-helpers.md index 7ba908e..ae6e68d 100644 --- a/custom-helpers.md +++ b/custom-helpers.md @@ -74,7 +74,7 @@ class TestCase extends BaseTestCase } // tests/Pest.php -uses(TestCase::class)->in('Feature'); +pest()->extend(TestCase::class)->in('Feature'); // tests/Feature/PaymentsTest.php it('may buy a book', function () { diff --git a/documentation.md b/documentation.md index 123c525..ab60c3a 100644 --- a/documentation.md +++ b/documentation.md @@ -1,4 +1,5 @@ - ## Press + - [Pest v3 Now Available](/docs/pest3-now-available) - [Announcing Stressless](/docs/announcing-stressless) - [Pest's Spicy Summer Release](/docs/pest-spicy-summer-release) - [Announcing Pest 2.0](/docs/announcing-pest2) diff --git a/expectations.md b/expectations.md index e01da1f..d877632 100644 --- a/expectations.md +++ b/expectations.md @@ -55,8 +55,6 @@ With the Pest expectation API, you have access to an extensive collection of ind - [`toContainEqual()`](#expect-toContainEqual) - [`toContainOnlyInstancesOf()`](#expect-toContainOnlyInstancesOf) - [`toHaveCount()`](#expect-toHaveCount) -- [`toHaveMethod()`](#expect-toHaveMethod) -- [`toHaveMethods()`](#expect-toHaveMethods) - [`toHaveProperty()`](#expect-toHaveProperty) - [`toHaveProperties()`](#expect-toHaveProperties) - [`toMatchArray()`](#expect-toMatchArray) @@ -290,24 +288,6 @@ This expectation ensures that the `$count` provided matches the number of elemen expect(['Nuno', 'Luke', 'Alex', 'Dan'])->toHaveCount(4); ``` - -### `toHaveMethod(string $name)` - -This expectation ensures that `$value` has a method named `$name`. - -```php -expect($user)->toHaveMethod('getFullname'); -``` - - -### `toHaveMethods(iterable $names)` - -This expectation ensures that `$value` has all the methods contained in `$names`. - -```php -expect($user)->toHaveMethods(['getFullname', 'isAuthenticated']); -``` - ### `toHaveProperty(string $name, $value = null)` diff --git a/global-hooks.md b/global-hooks.md index cebf839..a2e3777 100644 --- a/global-hooks.md +++ b/global-hooks.md @@ -10,7 +10,7 @@ As previously discussed, hooks allow you to simplify your testing process and au For instance, if you need to perform some database operations before each test within the `Feature` folder, you may use the `beforeEach()` hook within your `Pest.php` configuration file. ```php -uses(TestCase::class)->beforeEach(function () { +pest()->extend(TestCase::class)->beforeEach(function () { // Interact with your database... })->group('integration')->in('Feature'); ``` @@ -18,15 +18,15 @@ uses(TestCase::class)->beforeEach(function () { In addition, you can define global hooks that will run before or after your entire test suite, regardless of the folder or group. ```php -uses()->beforeEach(function () { +pest()->beforeEach(function () { // Interact with your database... -})->in(__DIR__); // All folders, and all groups... +}); ``` In fact, any of the hooks mentioned in the [hooks](/docs/hooks) documentation can also be used in your `Pest.php` configuration file. ```php -uses(TestCase::class)->beforeAll(function () { +pest()->extend(TestCase::class)->beforeAll(function () { // Runs before each file... })->beforeEach(function () { // Runs before each test... diff --git a/grouping-tests.md b/grouping-tests.md index d64d7b9..a5fd5f3 100644 --- a/grouping-tests.md +++ b/grouping-tests.md @@ -10,7 +10,7 @@ You can assign tests folders to various groups using Pest's `group()` method. As For instance, consider the scenario where we assign the tests located in the `tests/Feature` folder to a group named "feature". ```php -uses(TestCase::class) +pest()->extend(TestCase::class) ->group('feature') ->in('Feature'); ``` @@ -37,10 +37,10 @@ it('has home', function () { })->group('feature', 'browser'); ``` -In some cases, you may want to assign a whole file to a group. To do so, you may combine the `uses()` and `group()` methods. +In some cases, you may want to assign a whole file to a group. To do so, you may use the `pest()->group()` method within the file. ```php -uses()->group('feature'); +pest()->group('feature'); it('has home', function () { // diff --git a/hooks.md b/hooks.md index 0d8a89d..dc183e1 100644 --- a/hooks.md +++ b/hooks.md @@ -84,6 +84,18 @@ afterEach(function () { }); ``` +Optionally, you can use the `after()` method to perform clean-up tasks after a specific test. This is useful when you need to clean up resources that are specific to a single test, rather than shared across all tests in the file. + +```php +it('may be created', function () { + $this->userRepository->create(); + + expect($user)->toBeInstanceOf(User::class); +})->after(function () { + $this->userRepository->reset(); +}); +``` + ## `beforeAll()` diff --git a/optimizing-tests.md b/optimizing-tests.md index 3464b93..ecbb5d1 100644 --- a/optimizing-tests.md +++ b/optimizing-tests.md @@ -65,7 +65,7 @@ You may even configure Pest to always use the compact printer so you don't have ```php // tests/Pest.php -uses()->compact(); +pest()->theme()->compact(); // ``` diff --git a/plugins.md b/plugins.md index b21ce31..ac5ae00 100644 --- a/plugins.md +++ b/plugins.md @@ -195,4 +195,4 @@ pest --watch=app,routes,tests --- -In this section, we have seen how plugins can enhance your Pest experience. Now, let's dive into architectural testing and how it can benefit your development process. By performing architectural testing, you can evaluate the overall design of your application and identify potential flaws before they become significant issues: [Arch Testing](/docs/arch-testing) +In this section, we have seen how plugins can enhance your Pest experience. Now, let's see how you can manage your team's tasks and responsibilities using Pest: [Team Management](/docs/team-management) diff --git a/skipping-tests.md b/skipping-tests.md index 1f96c6b..1aabbaa 100644 --- a/skipping-tests.md +++ b/skipping-tests.md @@ -77,28 +77,6 @@ beforeEach(function () { })->skip(); ``` -## Creating Todos - -While skipping tests can be a helpful way to exclude specific tests temporarily from your test suite, it can also lead to situations where skipped tests are forgotten or overlooked. To prevent this, Pest provide a way to create "todos", which are essentially placeholders for tests that need attention. - -To begin working with todos, simply invoke the `todo()` method. - -```php -it('has home')->todo(); -``` - -If you invoke the `todo()` method on a test, Pest's output will inform you that the test is a todo so you don't forget about it. - -
- -
- -You can easily view a list of pending todos contained in your test suite by including the `--todos` option when running Pest. - -```bash -./vendor/bin/pest --todos -``` - --- As your codebase expands, it's advisable to consider enhancing the speed of your test suite. To assist you with that, we offer comprehensive documentation on optimizing your test suite: [Optimizing Tests](/docs/optimizing-tests) diff --git a/support-policy.md b/support-policy.md index cec5cb4..7dd5e13 100644 --- a/support-policy.md +++ b/support-policy.md @@ -8,11 +8,11 @@ We strive to resolve all reported bugs or issues to the best of our abilities as Bug fixes will be available for outdated versions for a duration of two years following the latest version's release. The previous version will be regarded as outdated once a new version of Pest is released. -| Major Version | PHP Compatibility | Initial Release | Bug Fixes Until -| ---------------- | --- | --- | --- | -| Pest 3 | >= PHP 8.2 | February X, 2024 | To be determined -| Pest 2 | >= PHP 8.1 | March 20, 2023 | February X, 2026 -| Pest 1 | >= PHP 7.3 | January 7, 2021 | March 20, 2025 +| Major Version | PHP Compatibility | Initial Release | Bug Fixes Until +| ---------------- | --- |-------------------| --- | +| Pest 3 | >= PHP 8.2 | September 9, 2024 | To be determined +| Pest 2 | >= PHP 8.1 | March 20, 2023 | September 9, 2026 +| Pest 1 | >= PHP 7.3 | January 7, 2021 | March 20, 2025 Pest adheres to semantic versioning principles, where the version number `x.y.z` conveys the following information: - When issuing bug fixes, the `z` number is incremented (e.g., 3.10.2 to 3.10.3). diff --git a/team-management.md b/team-management.md new file mode 100644 index 0000000..607ff09 --- /dev/null +++ b/team-management.md @@ -0,0 +1,145 @@ +--- +title: Team Management +description: In this section, we will discuss the process of managing a small team of developers who directly in your Pest test suite. +--- + +# Team Management + +With Pest, you can manage tasks and todos with your team directly from the console. You can create, assign, and track tasks, as well as view the status of each task. + +## Setting Up Project + +To get started with team management in Pest, you need to specify the project's URL in your `pest.php` configuration file. This URL will be used to link todos to the corresponding project management system. + +```php +pest()->project()->github('my-organization/my-repository'); +``` + +If you are using a different version control system, you can use the `gitlab`, `bitbucket`, `jira`, or `custom` methods instead. + +## Creating Todos + +Typically, todos are linked to one or more tests that need to be passing. As such, tests can be used to track the progress of your todos / tasks. Pest provides a simple way to create todos by using the `todo()` method. + +```php +it('has a contact page', function () { + // +})->todo(); +``` + +When running your tests, Pest will inform you about any tests that are todos so you don't forget and see them in the test results. + +
+ +
+ +If you have one or more todos, you may want to view them separately from the rest of your test suite. You can do this by including the `--todos` option when running Pest. + +```bash +./vendor/bin/pest --todos +``` + +## Assigning Todos + +In some cases, you may want to assign a todo to a specific team member. Pest allows you to assign a todo to a specific team member by providing their name to the `assignee` argument of the `todo()` method. + +```php +it('has a contact page', function () { + // +})->todo(assignee: 'nunomaduro'); +``` + +You may assign multiple assignees by providing an array of names to the `assignee` argument. Also, you may filter todos by assignee by providing their name to the `--assignee` option when running Pest. + +```bash +./vendor/bin/pest --todos --assignee=nunomaduro +``` + +## Set Corresponding Issues + +Sometimes, todos are linked to issues in your project management system. Pest allows you to set the corresponding issue to a todo by providing the issue number to the `issue` argument of the `todo()` method. + +```php +it('has a contact page', function () { + // +})->todo(issue: 123); +``` + +Just like with assignees, you may set multiple issues by providing an array of issue numbers to the `issue` argument. Also, you may filter todos by issue by providing the issue number to the `--issue` option when running Pest. + +```bash +./vendor/bin/pest --todos --issue=123 +``` + +## Set Corresponding PRs + +Sometimes, todos are linked to pull requests in your version control system. Pest allows you to set the corresponding pull request to a todo by providing the pull request number to the `pr` argument of the `todo()` method. + +```php +it('has a contact page', function () { + // +})->todo(pr: 123); +``` + +Just like with assignees, you may set multiple pull requests by providing an array of pull request numbers to the `pr` argument. Also, you may filter todos by pull request by providing the pull request number to the `--pr` option when running Pest. + +```bash +./vendor/bin/pest --todos --pr=123 +``` + +## Writing Notes for Todos + +It is often helpful to provide additional context for a todo. Pest allows you to write notes for a todo by providing a string to the `note` argument of the `todo()` method. + +```php +it('has a contact page', function () { + // +})->todo(note: <<wip(assignee: 'nunomaduro', issue: 123); +``` + +## Marking Todos as Done + +Once a todo is completed, you can mark it as done by using the `done()` method. This method will remove the todo status from the test and mark it as a regular test while keeping all the context like assignees, issues, etc. + +```php +it('has a contact page', function () { + // +})->done(assignee: 'nunomaduro', issue: 123); +``` + +## Combining Todos with Assignees, Issues, and PRs + +You can combine todos with assignees, issues, and PRs to provide additional context and track the progress of your todos. This can be done using the `describe` group, and the `todo`, `assignee`, `issue`, and `pr` methods. + +```php +describe('contacts', function () { + it('has a contact page', function () { + // + }))->issue(123); // or ->pr(123) etc + + it('has a contact form', function () { + // + })->done(pr: 567); +})->wip(assignee: 'nunomaduro'); +``` + + +--- + +Now, let's dive into architectural testing and how it can benefit your development process. By performing architectural testing, you can evaluate the overall design of your application and identify potential flaws before they become significant issues: [Arch Testing](/docs/arch-testing) diff --git a/type-coverage.md b/type-coverage.md index a5c4a0c..1865b43 100644 --- a/type-coverage.md +++ b/type-coverage.md @@ -58,4 +58,4 @@ In addition, Pest supports reporting the type coverage to a specific file: --- -In this chapter, we have discussed Pest's Type Coverage plugin and how it can be used to measure the percentage of code that is covered by type declarations. In the following chapter, we explain how can you use Snapshots to test your code: [Snapshot Testing](/docs/snapshot-testing) +In this chapter, we have discussed Pest's Type Coverage plugin and how it can be used to measure the percentage of code that is covered by type declarations. In the following chapter, we explain how can you mutation testing to improve the quality of your tests: [Mutation Testing →](/docs/mutation-testing) diff --git a/upgrade-guide.md b/upgrade-guide.md index f63f8b8..e302c2e 100644 --- a/upgrade-guide.md +++ b/upgrade-guide.md @@ -1,8 +1,75 @@ --- title: Upgrade Guide -description: Upgrading To 2.x From 1.x +description: Upgrading To 3.x From 2.x --- +# Upgrading To 3.x From 2.x + +> **Estimated Upgrade Time**: 2 minutes + +We make an effort to document every potential breaking change, but some of these changes may exist in less frequently used sections of the framework. As a result, only a subset of these changes may impact your application. + +### Updating Dependencies + +> Likelihood Of Impact: High + +Pest 3 now requires PHP 8.2.0 or greater. To start migrating from Pest 1 to Pest 2, update the `pestphp/pest` dependency to `^2.0` in your application's `composer.json` file. + +```diff +- "pestphp/pest": "^2.0", ++ "pestphp/pest": "^3.0", +``` + +In addition, if you are using Laravel, please upgrade Collision to version 8. Note that, Laravel 11 is required. + +```diff +- "nunomaduro/collision": "^7.0", ++ "nunomaduro/collision": "^8.0", +``` + +All other Pest maintained plugins should be updated to version `^3.0` in your application's `composer.json` file. + +```diff +- "pestphp/pest-plugin-laravel": "^2.0", ++ "pestphp/pest-plugin-laravel": "^3.0", +``` + +### PHPUnit 11 Changes + +> Likelihood Of Impact: Medium + +Pest 3 is built on top of PHPUnit 11. This means that any notable changes made to PHPUnit 11 might have an impact on your test suite. To examine all the changes introduced in PHPUnit 11, please consult the [PHPUnit 11 changelog](https://github.com/sebastianbergmann/phpunit/blob/11.0.0/ChangeLog-11.0.md). + +### `toHaveMethod` and `toHaveMethods` Expectations + +> Likelihood Of Impact: Low + +The `toHaveMethod` and `toHaveMethods` expectations were replaced by the `toHaveMethod` and `toHaveMethods` architectural expectations. If you were using these expectations, you can no longer provide a object as architectural expectations expect an namespace or a class name. + +```diff +-expect($object)->toHaveMethod('method'); ++expect($object::class)->toHaveMethod('method'); +``` + +### `pest()` + +### Pest 2 Deprecations + +During Pest 2 release, some features were deprecated and will be removed in Pest 3. Here are the changes you should be aware of: + +#### `tap()` Method + +> Likelihood Of Impact: Low + +When performing high order testing, you might have utilized the `tap()` method to invoke assertions on an object that needs lazy evaluation during runtime. With Pest 2, the `tap()` method is deprecated, and on Pest 3 it was removed. Instead, you should use the `defer()` method. + +```diff +it('creates admins') +- ->tap(fn () => $this->artisan('user:create --admin')) ++ ->defer(fn () => $this->artisan('user:create --admin')) + ->assertDatabaseHas('users', ['id' => 1]); +``` + # Upgrading To 2.x From 1.x > **Estimated Upgrade Time**: 2 minutes diff --git a/why-pest.md b/why-pest.md index e3b7953..d938bc7 100644 --- a/why-pest.md +++ b/why-pest.md @@ -21,7 +21,6 @@ test('sum', function () { You can expect a smooth and efficient coding experience thanks to Pest's easy-to-use API inspired by Ruby's Rspec and Jest. In addition, the test reporting is well-organized, practical, and informative, with clear and concise error and stack trace displays for quick debugging. With Pest, you can obtain test reporting that is unmatched in its beauty, directly from the console! -
@@ -33,6 +32,8 @@ In addition to its exceptional test reporting, Pest also offers a range of other - Native [profiling tools](/docs/optimizing-tests#profiling) to optimize slow-running tests - Out-of-the-box [Architectural Testing](/docs/arch-testing) to test application rules - [Coverage](/docs/test-coverage) report directly on the terminal to track code coverage +- [Mutation Testing](#mutation-testing) to evaluate the quality of your test suite +- [Team Management](/docs/team-management) to manage tasks / todos with your team - Dozens of [optional plugins](/docs/plugins), such as Watch Mode and [Snapshot testing](https://github.com/spatie/pest-plugin-snapshots), to customize Pest to fit your needs. Whether you're engaged in a small personal project or a large-scale enterprise application, Pest has got you covered. So if you want to make the testing process enjoyable and efficient, give Pest a try. We're confident that you'll love it as much as we do.