@@ -2,7 +2,12 @@ import type { TestingModule } from '@nestjs/testing';
22import { Test } from '@nestjs/testing' ;
33import type { INestApplication } from '@nestjs/common' ;
44import supertest from 'supertest' ;
5- import { OpenFeatureController , OpenFeatureControllerContextScopedController , OpenFeatureTestService } from './test-app' ;
5+ import {
6+ OpenFeatureController ,
7+ OpenFeatureContextScopedController ,
8+ OpenFeatureRequireFlagsEnabledController ,
9+ OpenFeatureTestService ,
10+ } from './test-app' ;
611import { exampleContextFactory , getOpenFeatureDefaultTestModule } from './fixtures' ;
712import { OpenFeatureModule } from '../src' ;
813import { defaultProvider , providers } from './fixtures' ;
@@ -14,11 +19,9 @@ describe('OpenFeature SDK', () => {
1419
1520 beforeAll ( async ( ) => {
1621 moduleRef = await Test . createTestingModule ( {
17- imports : [
18- getOpenFeatureDefaultTestModule ( )
19- ] ,
22+ imports : [ getOpenFeatureDefaultTestModule ( ) ] ,
2023 providers : [ OpenFeatureTestService ] ,
21- controllers : [ OpenFeatureController ] ,
24+ controllers : [ OpenFeatureController , OpenFeatureRequireFlagsEnabledController ] ,
2225 } ) . compile ( ) ;
2326 app = moduleRef . createNestApplication ( ) ;
2427 app = await app . init ( ) ;
@@ -112,7 +115,7 @@ describe('OpenFeature SDK', () => {
112115 } ) ;
113116
114117 describe ( 'evaluation context service should' , ( ) => {
115- it ( 'inject the evaluation context from contex factory' , async function ( ) {
118+ it ( 'inject the evaluation context from contex factory' , async function ( ) {
116119 const evaluationSpy = jest . spyOn ( defaultProvider , 'resolveBooleanEvaluation' ) ;
117120 await supertest ( app . getHttpServer ( ) )
118121 . get ( '/dynamic-context-in-service' )
@@ -122,26 +125,77 @@ describe('OpenFeature SDK', () => {
122125 expect ( evaluationSpy ) . toHaveBeenCalledWith ( 'testBooleanFlag' , false , { targetingKey : 'dynamic-user' } , { } ) ;
123126 } ) ;
124127 } ) ;
128+
129+ describe ( 'require flags enabled decorator' , ( ) => {
130+ describe ( 'OpenFeatureController' , ( ) => {
131+ it ( 'should sucessfully return the response if the flag is enabled' , async ( ) => {
132+ await supertest ( app . getHttpServer ( ) ) . get ( '/flags-enabled' ) . expect ( 200 ) . expect ( 'Get Boolean Flag Success!' ) ;
133+ } ) ;
134+
135+ it ( 'should throw an exception if the flag is disabled' , async ( ) => {
136+ jest . spyOn ( defaultProvider , 'resolveBooleanEvaluation' ) . mockResolvedValueOnce ( {
137+ value : false ,
138+ reason : 'DISABLED' ,
139+ } ) ;
140+ await supertest ( app . getHttpServer ( ) ) . get ( '/flags-enabled' ) . expect ( 404 ) ;
141+ } ) ;
142+
143+ it ( 'should throw a custom exception if the flag is disabled' , async ( ) => {
144+ jest . spyOn ( defaultProvider , 'resolveBooleanEvaluation' ) . mockResolvedValueOnce ( {
145+ value : false ,
146+ reason : 'DISABLED' ,
147+ } ) ;
148+ await supertest ( app . getHttpServer ( ) ) . get ( '/flags-enabled-custom-exception' ) . expect ( 403 ) ;
149+ } ) ;
150+
151+ it ( 'should throw a custom exception if the flag is disabled with context' , async ( ) => {
152+ await supertest ( app . getHttpServer ( ) )
153+ . get ( '/flags-enabled-custom-exception-with-context' )
154+ . set ( 'x-user-id' , '123' )
155+ . expect ( 403 ) ;
156+ } ) ;
157+ } ) ;
158+
159+ describe ( 'OpenFeatureControllerRequireFlagsEnabled' , ( ) => {
160+ it ( 'should allow access to the RequireFlagsEnabled controller with global context interceptor' , async ( ) => {
161+ await supertest ( app . getHttpServer ( ) )
162+ . get ( '/require-flags-enabled' )
163+ . set ( 'x-user-id' , '123' )
164+ . expect ( 200 )
165+ . expect ( 'Hello, world!' ) ;
166+ } ) ;
167+
168+ it ( 'should throw a 403 - Forbidden exception if user does not match targeting requirements' , async ( ) => {
169+ await supertest ( app . getHttpServer ( ) ) . get ( '/require-flags-enabled' ) . set ( 'x-user-id' , 'not-123' ) . expect ( 403 ) ;
170+ } ) ;
171+
172+ it ( 'should throw a 403 - Forbidden exception if one of the flags is disabled' , async ( ) => {
173+ jest . spyOn ( defaultProvider , 'resolveBooleanEvaluation' ) . mockResolvedValueOnce ( {
174+ value : false ,
175+ reason : 'DISABLED' ,
176+ } ) ;
177+ await supertest ( app . getHttpServer ( ) ) . get ( '/require-flags-enabled' ) . set ( 'x-user-id' , '123' ) . expect ( 403 ) ;
178+ } ) ;
179+ } ) ;
180+ } ) ;
125181 } ) ;
126182
127183 describe ( 'Without global context interceptor' , ( ) => {
128-
129184 let moduleRef : TestingModule ;
130185 let app : INestApplication ;
131186
132187 beforeAll ( async ( ) => {
133-
134188 moduleRef = await Test . createTestingModule ( {
135189 imports : [
136190 OpenFeatureModule . forRoot ( {
137191 contextFactory : exampleContextFactory ,
138192 defaultProvider,
139193 providers,
140- useGlobalInterceptor : false
194+ useGlobalInterceptor : false ,
141195 } ) ,
142196 ] ,
143197 providers : [ OpenFeatureTestService ] ,
144- controllers : [ OpenFeatureController , OpenFeatureControllerContextScopedController ] ,
198+ controllers : [ OpenFeatureController , OpenFeatureContextScopedController ] ,
145199 } ) . compile ( ) ;
146200 app = moduleRef . createNestApplication ( ) ;
147201 app = await app . init ( ) ;
@@ -158,7 +212,7 @@ describe('OpenFeature SDK', () => {
158212 } ) ;
159213
160214 describe ( 'evaluation context service should' , ( ) => {
161- it ( 'inject empty context if no context interceptor is configured' , async function ( ) {
215+ it ( 'inject empty context if no context interceptor is configured' , async function ( ) {
162216 const evaluationSpy = jest . spyOn ( defaultProvider , 'resolveBooleanEvaluation' ) ;
163217 await supertest ( app . getHttpServer ( ) )
164218 . get ( '/dynamic-context-in-service' )
@@ -172,9 +226,26 @@ describe('OpenFeature SDK', () => {
172226 describe ( 'With Controller bound Context interceptor' , ( ) => {
173227 it ( 'should not use context if global context interceptor is not configured' , async ( ) => {
174228 const evaluationSpy = jest . spyOn ( defaultProvider , 'resolveBooleanEvaluation' ) ;
175- await supertest ( app . getHttpServer ( ) ) . get ( '/controller-context' ) . set ( 'x-user-id' , '123' ) . expect ( 200 ) . expect ( 'true' ) ;
229+ await supertest ( app . getHttpServer ( ) )
230+ . get ( '/controller-context' )
231+ . set ( 'x-user-id' , '123' )
232+ . expect ( 200 )
233+ . expect ( 'true' ) ;
176234 expect ( evaluationSpy ) . toHaveBeenCalledWith ( 'testBooleanFlag' , false , { targetingKey : '123' } , { } ) ;
177235 } ) ;
178236 } ) ;
237+
238+ describe ( 'require flags enabled decorator' , ( ) => {
239+ it ( 'should return a 404 - Not Found exception if the flag is disabled' , async ( ) => {
240+ jest . spyOn ( providers . domainScopedClient , 'resolveBooleanEvaluation' ) . mockResolvedValueOnce ( {
241+ value : false ,
242+ reason : 'DISABLED' ,
243+ } ) ;
244+ await supertest ( app . getHttpServer ( ) )
245+ . get ( '/controller-context/flags-enabled' )
246+ . set ( 'x-user-id' , '123' )
247+ . expect ( 404 ) ;
248+ } ) ;
249+ } ) ;
179250 } ) ;
180251} ) ;
0 commit comments