|
2 | 2 | * @vitest-environment node |
3 | 3 | */ |
4 | 4 | import { beforeEach, describe, expect, it, vi } from 'vitest' |
5 | | -import type { FeatureFlagsConfig } from '@/lib/core/config/feature-flags' |
| 5 | +import type { |
| 6 | + FeatureFlagContext, |
| 7 | + FeatureFlagName, |
| 8 | + FeatureFlagsConfig, |
| 9 | +} from '@/lib/core/config/feature-flags' |
6 | 10 |
|
7 | 11 | const { mockFetch, mockIsPlatformAdmin, envRef, flagRef } = vi.hoisted(() => ({ |
8 | 12 | mockFetch: vi.fn(), |
@@ -42,6 +46,14 @@ function withAppConfig(doc: unknown) { |
42 | 46 | mockFetch.mockImplementation((_ids, parse) => Promise.resolve(parse(doc))) |
43 | 47 | } |
44 | 48 |
|
| 49 | +/** |
| 50 | + * `isFeatureEnabled` only accepts registered `FeatureFlagName`s. The registry is |
| 51 | + * empty in this PR, so tests reference flags through the AppConfig document and |
| 52 | + * cast their throwaway names through this helper. |
| 53 | + */ |
| 54 | +const enabled = (flag: string, ctx?: FeatureFlagContext) => |
| 55 | + isFeatureEnabled(flag as FeatureFlagName, ctx) |
| 56 | + |
45 | 57 | describe('getFeatureFlags', () => { |
46 | 58 | beforeEach(() => { |
47 | 59 | vi.clearAllMocks() |
@@ -94,62 +106,62 @@ describe('isFeatureEnabled', () => { |
94 | 106 |
|
95 | 107 | it('returns false for an unknown flag', async () => { |
96 | 108 | withAppConfig({ flags: {} }) |
97 | | - expect(await isFeatureEnabled('missing', { userId: 'u1' })).toBe(false) |
| 109 | + expect(await enabled('missing', { userId: 'u1' })).toBe(false) |
98 | 110 | }) |
99 | 111 |
|
100 | 112 | it('matches the global enabled clause', async () => { |
101 | 113 | withAppConfig({ flags: { f: { enabled: true } } }) |
102 | | - expect(await isFeatureEnabled('f')).toBe(true) |
| 114 | + expect(await enabled('f')).toBe(true) |
103 | 115 | }) |
104 | 116 |
|
105 | 117 | it('matches the userId allowlist', async () => { |
106 | 118 | withAppConfig({ flags: { f: { userIds: ['u1'] } } }) |
107 | | - expect(await isFeatureEnabled('f', { userId: 'u1' })).toBe(true) |
108 | | - expect(await isFeatureEnabled('f', { userId: 'u2' })).toBe(false) |
109 | | - expect(await isFeatureEnabled('f', {})).toBe(false) |
| 119 | + expect(await enabled('f', { userId: 'u1' })).toBe(true) |
| 120 | + expect(await enabled('f', { userId: 'u2' })).toBe(false) |
| 121 | + expect(await enabled('f', {})).toBe(false) |
110 | 122 | }) |
111 | 123 |
|
112 | 124 | it('matches the orgId allowlist', async () => { |
113 | 125 | withAppConfig({ flags: { f: { orgIds: ['o1'] } } }) |
114 | | - expect(await isFeatureEnabled('f', { orgId: 'o1' })).toBe(true) |
115 | | - expect(await isFeatureEnabled('f', { orgId: 'o2' })).toBe(false) |
| 126 | + expect(await enabled('f', { orgId: 'o1' })).toBe(true) |
| 127 | + expect(await enabled('f', { orgId: 'o2' })).toBe(false) |
116 | 128 | }) |
117 | 129 |
|
118 | 130 | describe('admin clause (lazy resolution)', () => { |
119 | 131 | it('resolves admin from userId when admins is the deciding clause', async () => { |
120 | 132 | withAppConfig({ flags: { f: { admins: true } } }) |
121 | 133 | mockIsPlatformAdmin.mockResolvedValue(true) |
122 | | - expect(await isFeatureEnabled('f', { userId: 'u1' })).toBe(true) |
| 134 | + expect(await enabled('f', { userId: 'u1' })).toBe(true) |
123 | 135 | expect(mockIsPlatformAdmin).toHaveBeenCalledWith('u1') |
124 | 136 |
|
125 | 137 | mockIsPlatformAdmin.mockResolvedValue(false) |
126 | | - expect(await isFeatureEnabled('f', { userId: 'u2' })).toBe(false) |
| 138 | + expect(await enabled('f', { userId: 'u2' })).toBe(false) |
127 | 139 | }) |
128 | 140 |
|
129 | 141 | it('uses the isAdmin override without querying', async () => { |
130 | 142 | withAppConfig({ flags: { f: { admins: true } } }) |
131 | | - expect(await isFeatureEnabled('f', { userId: 'u1', isAdmin: true })).toBe(true) |
| 143 | + expect(await enabled('f', { userId: 'u1', isAdmin: true })).toBe(true) |
132 | 144 | expect(mockIsPlatformAdmin).not.toHaveBeenCalled() |
133 | 145 | }) |
134 | 146 |
|
135 | 147 | it('resolves to false without querying when userId is absent', async () => { |
136 | 148 | withAppConfig({ flags: { f: { admins: true } } }) |
137 | | - expect(await isFeatureEnabled('f', { orgId: 'o1' })).toBe(false) |
| 149 | + expect(await enabled('f', { orgId: 'o1' })).toBe(false) |
138 | 150 | expect(mockIsPlatformAdmin).not.toHaveBeenCalled() |
139 | 151 | }) |
140 | 152 |
|
141 | 153 | it('does not query when an earlier clause already matched', async () => { |
142 | 154 | withAppConfig({ flags: { f: { enabled: true, admins: true } } }) |
143 | | - expect(await isFeatureEnabled('f', { userId: 'u1' })).toBe(true) |
| 155 | + expect(await enabled('f', { userId: 'u1' })).toBe(true) |
144 | 156 |
|
145 | 157 | withAppConfig({ flags: { g: { userIds: ['u1'], admins: true } } }) |
146 | | - expect(await isFeatureEnabled('g', { userId: 'u1' })).toBe(true) |
| 158 | + expect(await enabled('g', { userId: 'u1' })).toBe(true) |
147 | 159 | expect(mockIsPlatformAdmin).not.toHaveBeenCalled() |
148 | 160 | }) |
149 | 161 |
|
150 | 162 | it('does not query when the rule has no admins clause', async () => { |
151 | 163 | withAppConfig({ flags: { f: { userIds: ['u2'] } } }) |
152 | | - expect(await isFeatureEnabled('f', { userId: 'u1' })).toBe(false) |
| 164 | + expect(await enabled('f', { userId: 'u1' })).toBe(false) |
153 | 165 | expect(mockIsPlatformAdmin).not.toHaveBeenCalled() |
154 | 166 | }) |
155 | 167 | }) |
|
0 commit comments