Skip to content

Commit 075b0ce

Browse files
committed
wip
1 parent aca2ca4 commit 075b0ce

File tree

1 file changed

+58
-44
lines changed

1 file changed

+58
-44
lines changed

pennant.md

Lines changed: 58 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
- [Updating Values](#updating-values)
2121
- [Bulk Updates](#bulk-updates)
2222
- [Purging Features](#purging-features)
23+
- [Testing](#testing)
2324
- [Events](#events)
2425
- [Testing](#testing)
2526

@@ -175,7 +176,7 @@ return Feature::for($user)->active('new-api')
175176
: $this->resolveLegacyApiResponse($request);
176177
```
177178

178-
> **Note**
179+
> **Note**
179180
> When using Pennant outside of an HTTP context, such as in an Artisan command or a queued job, you should typically [explicitly specify the feature's scope](#specifying-the-scope). Alternatively, you may define a [default scope](#default-scope) that accounts for both authenticated HTTP contexts and unauthenticated contexts.
180181
181182
<a name="checking-class-based-features"></a>
@@ -254,7 +255,7 @@ The `when` method may be used to fluently execute a given closure if a feature i
254255
fn () => $this->resolveLegacyApiResponse($request),
255256
);
256257
}
257-
258+
258259
// ...
259260
}
260261

@@ -297,11 +298,9 @@ Next, you may assign the middleware to a route and specify the features that are
297298
```php
298299
Route::get('/api/servers', function () {
299300
// ...
300-
})->middleware(['auth', 'features:new-api,servers-api']);
301+
})->middleware(['features:new-api,servers-api']);
301302
```
302303

303-
> **Note** As the `feature` middleware will check against the currently authenticated user, you should ensure that any authentication related middleware is applied _before_ the `feature` middleware.
304-
305304
<a name="customizing-the-response"></a>
306305
#### Customizing The Response
307306

@@ -381,25 +380,10 @@ if (Feature::for($user->team)->active('billing-v2')) {
381380
// ...
382381
```
383382

384-
The `for` method also accepts an array of scopes, which will check that the feature is active for all of the provided scopes:
385-
386-
```php
387-
Feature::define('improved-notifications', function (string $email) {
388-
return str_ends_with($email, '@example.com');
389-
});
390-
391-
Feature::for([
392-
393-
394-
])->active('improved-notifications');
395-
396-
// false
397-
```
398-
399383
<a name="default-scope"></a>
400384
### Default Scope
401385

402-
Sometimes, you may need to customize the default scope Pennant uses to check features. For example, maybe all of your features are checked against the currently authenticated user's team instead of the user. Instead of having to call `Feature::for($user->team)` every time you check a feature, you may instead specify the team as the default scope. Typically, this should be done in one of your application's service providers:
386+
It is also possible to customize the default scope Pennant uses to check features. For example, maybe all of your features are checked against the currently authenticated user's team instead of the user. Instead of having to call `Feature::for($user->team)` every time you check a feature, you may instead specify the team as the default scope. Typically, this should be done in one of your application's service providers:
403387

404388
```php
405389
<?php
@@ -524,17 +508,6 @@ Pennant's included Blade directive also makes it easy to conditionally render co
524508
@endfeature
525509
```
526510

527-
If you would like to retrieve multiple feature values at once for a single scope, you may use the `values` method:
528-
529-
```php
530-
Feature::values(['new-api', 'purchase-button']);
531-
532-
// [
533-
// 'new-api' => false,
534-
// 'purchase-button' => 'tart-orange',
535-
// ]
536-
```
537-
538511
> **Note** When using rich values, it is important to know that a feature is considered "active" when it has any value other than `false`.
539512
540513
<a name="eager-loading"></a>
@@ -657,22 +630,63 @@ php artisan pennant:purge new-api
657630
php artisan pennant:purge new-api purchase-button
658631
```
659632

633+
<a name="testing"></a>
634+
## Testing
635+
636+
When testing code that interacts with feature flags, the easiest way to control the feature flag's returned value in your tests is to simply re-define the feature. For example, imagine you have the following feature defined in one of your application's service provider:
637+
638+
```php
639+
use Illuminate\Support\Arr;
640+
use Laravel\Pennant\Feature;
641+
642+
Feature::define('purchase-button', fn () => Arr::random([
643+
'blue-sapphire',
644+
'seafoam-green',
645+
'tart-orange',
646+
]));
647+
```
648+
649+
To modify the feature's returned value in your tests, you may re-define the feature at the beginning of the test. The following test will always pass, even though the `Arr::random()` implementation is still present in the service provider:
650+
651+
```php
652+
use Laravel\Pennant\Feature;
653+
654+
public function test_it_can_control_feature_values()
655+
{
656+
Feature::define('purchase-button', 'seafoam-green');
657+
658+
$this->assertSame('seafoam-green', Feature::value('purchase-button'));
659+
}
660+
```
661+
662+
The same approach may be used for class based features:
663+
664+
```php
665+
use App\Features\NewApi;
666+
use Laravel\Pennant\Feature;
667+
668+
public function test_it_can_control_feature_values()
669+
{
670+
Feature::define(NewApi::class, true);
671+
672+
$this->assertTrue(Feature::value(NewApi::class));
673+
}
674+
```
675+
676+
If your feature is returning a `Lottery` instance, there are a handful of useful [testing helpers available](/docs/{{version}}/helpers#testing-lotteries).
677+
660678
<a name="events"></a>
661679
## Events
662680

663681
Pennant dispatches a variety of events that can be useful when tracking feature flags throughout your application.
664682

665-
### `Laravel\Pennant\Events\FeatureRetrieved`
666-
667-
This event is dispatched whenever a feature is retrieved and can be useful for creating and tracking metrics against a feature flag's usage throughout your application.
668-
669-
### `Laravel\Pennant\Events\FeatureResolved`
683+
### `Laravel\Pennant\Events\RetrievingKnownFeature`
670684

671-
This event is dispatched the first time a feature's value is resolved for a specific scope from it's definition or feature class resolver.
685+
This event is dispatched the first time a known feature is retrieved during a request for a specific scope. This event can be useful to create and track metrics against the feature flags that are being used throughout your application.
672686

673-
### `Laravel\Pennant\Events\UnknownFeatureResolved`
687+
### `Laravel\Pennant\Events\RetrievingUnknownFeature`
674688

675-
This event is dispatched the first time an unknown feature is resolved for a specific scope. This event can be useful if you have intended to remove a feature flag, but may have accidentally left some stray references to it throughout your application.
689+
This event is dispatched the first time an unknown feature is retrieved during a request for a specific scope. This event can be useful if you have intended to remove a feature flag, but may have accidentally left some stray references to it throughout your application.
676690

677691
For example, you may find it useful to listen for this event and `report` or throw an exception when it occurs:
678692

@@ -683,7 +697,7 @@ namespace App\Providers;
683697

684698
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
685699
use Illuminate\Support\Facades\Event;
686-
use Laravel\Pennant\Events\UnknownFeatureResolved;
700+
use Laravel\Pennant\Events\RetrievingUnknownFeature;
687701

688702
class EventServiceProvider extends ServiceProvider
689703
{
@@ -692,14 +706,14 @@ class EventServiceProvider extends ServiceProvider
692706
*/
693707
public function boot(): void
694708
{
695-
Event::listen(function (UnknownFeatureResolved $event) {
696-
report("Unknown feature resolved [{$event->feature}].");
709+
Event::listen(function (RetrievingUnknownFeature $event) {
710+
report("Resolving unknown feature [{$event->feature}].");
697711
});
698712
}
699713
}
700714
```
701715

702-
### `Laravel\Pennant\Events\DynamicallyRegisteringFeatureClass`
716+
### `Laravel\Pennant\Events\DynamicallyDefiningFeature`
703717

704718
This event is dispatched when a class based feature is being dynamically checked for the first time during a request.
705719

0 commit comments

Comments
 (0)