Skip to content

Commit 17491ee

Browse files
committed
add sync features command and tests
1 parent a0e14ed commit 17491ee

File tree

3 files changed

+150
-2
lines changed

3 files changed

+150
-2
lines changed

config/feature-flags.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@
22

33
return [
44

5+
/*
6+
|--------------------------------------------------------------------------
7+
| Features
8+
|--------------------------------------------------------------------------
9+
|
10+
| Declare features that are managed by the app with the Feature
11+
| Flag package. The format is ['name' => FeatureState::on()].
12+
*/
13+
14+
'features' => [],
15+
516
/*
617
|--------------------------------------------------------------------------
718
| Cache
@@ -20,8 +31,8 @@
2031
| Models
2132
|--------------------------------------------------------------------------
2233
|
23-
| If you need to customise any models used then you can swap them out by
24-
| replacing the default models defined here.
34+
| If you need to customise any models used then you can swap
35+
| them out by replacing the default models defined here.
2536
*/
2637

2738
'feature_model' => \Codinglabs\FeatureFlags\Models\Feature::class,

src/Actions/SyncFeaturesAction.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace Codinglabs\FeatureFlags\Actions;
4+
5+
use Codinglabs\FeatureFlags\Models\Feature;
6+
7+
class SyncFeaturesAction
8+
{
9+
public function __invoke(): void
10+
{
11+
$features = collect(config('feature-flags.features'))
12+
->map(fn ($state, $name) => [
13+
'name' => $name,
14+
'state' => $state
15+
]);
16+
17+
$featureModels = Feature::all();
18+
19+
$featureModels->whereNotIn('name', $features->pluck('name'))
20+
->each(fn (Feature $feature) => $feature->delete());
21+
22+
$features->whereNotIn('name', $featureModels->pluck('name'))
23+
->each(fn (array $feature) => Feature::create($feature));
24+
}
25+
}

tests/SyncFeaturesActionTest.php

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<?php
2+
3+
use Codinglabs\FeatureFlags\Models\Feature;
4+
use Codinglabs\FeatureFlags\Enums\FeatureState;
5+
use Codinglabs\FeatureFlags\Facades\FeatureFlag;
6+
use Codinglabs\FeatureFlags\Actions\SyncFeaturesAction;
7+
8+
beforeEach(function () {
9+
config([
10+
'feature-flags.cache_store' => 'array',
11+
'feature-flags.cache_prefix' => 'testing',
12+
]);
13+
14+
cache()->store('array')->clear();
15+
});
16+
17+
afterEach(function () {
18+
FeatureFlag::reset();
19+
});
20+
21+
it('adds features that have no been synced', function () {
22+
config([
23+
'feature-flags.features' => [
24+
'some-feature' => FeatureState::on(),
25+
'some-other-feature' => FeatureState::off(),
26+
'some-dynamic-feature' => FeatureState::dynamic(),
27+
],
28+
]);
29+
30+
(new SyncFeaturesAction)->__invoke();
31+
32+
$this->assertDatabaseCount('features', 3);
33+
34+
$this->assertDatabaseHas('features', [
35+
'name' => 'some-feature',
36+
'state' => FeatureState::on(),
37+
]);
38+
39+
$this->assertDatabaseHas('features', [
40+
'name' => 'some-other-feature',
41+
'state' => FeatureState::off(),
42+
]);
43+
44+
$this->assertDatabaseHas('features', [
45+
'name' => 'some-dynamic-feature',
46+
'state' => FeatureState::dynamic(),
47+
]);
48+
});
49+
50+
it('skips features that have already been synced even if the state has changed', function () {
51+
Feature::factory()->create([
52+
'name' => 'some-feature',
53+
'state' => FeatureState::off()
54+
]);
55+
56+
Feature::factory()->create([
57+
'name' => 'some-other-feature',
58+
'state' => FeatureState::on()
59+
]);
60+
61+
config([
62+
'feature-flags.features' => [
63+
'some-feature' => FeatureState::on(),
64+
'some-other-feature' => FeatureState::on(),
65+
],
66+
]);
67+
68+
(new SyncFeaturesAction)->__invoke();
69+
70+
$this->assertDatabaseCount('features', 2);
71+
72+
$this->assertDatabaseHas('features', [
73+
'name' => 'some-feature',
74+
'state' => FeatureState::off(),
75+
]);
76+
77+
$this->assertDatabaseHas('features', [
78+
'name' => 'some-other-feature',
79+
'state' => FeatureState::on(),
80+
]);
81+
});
82+
83+
it('removes features that have been removed', function () {
84+
Feature::factory()->create([
85+
'name' => 'some-feature',
86+
'state' => FeatureState::off()
87+
]);
88+
89+
Feature::factory()->create([
90+
'name' => 'some-other-feature',
91+
'state' => FeatureState::on()
92+
]);
93+
94+
config([
95+
'feature-flags.features' => [
96+
'some-feature' => FeatureState::off(),
97+
],
98+
]);
99+
100+
(new SyncFeaturesAction)->__invoke();
101+
102+
$this->assertDatabaseCount('features', 1);
103+
104+
$this->assertDatabaseHas('features', [
105+
'name' => 'some-feature',
106+
'state' => FeatureState::off(),
107+
]);
108+
109+
$this->assertDatabaseMissing('features', [
110+
'name' => 'some-other-feature',
111+
]);
112+
});

0 commit comments

Comments
 (0)