@@ -415,6 +415,126 @@ describe('FlagsProvider', () => {
415415 } ) ;
416416 } ) ;
417417
418+ describe ( 'Malformed API Response Resilience' , ( ) => {
419+ test ( 'handles API response missing items property' , async ( ) => {
420+ // GIVEN: API returns a response without an items property (e.g. unexpected iframe response)
421+ mockGetFlags . mockResolvedValue ( { } ) ;
422+
423+ // WHEN: Flags are loaded
424+ render (
425+ < TestWrapper >
426+ < FlagsProvider >
427+ < TestConsumer />
428+ </ FlagsProvider >
429+ </ TestWrapper > ,
430+ ) ;
431+
432+ // THEN: Falls back to empty array instead of crashing
433+ await waitFor ( ( ) => {
434+ expect ( screen . getByTestId ( 'loading' ) ) . toHaveTextContent ( 'false' ) ;
435+ } ) ;
436+ expect ( screen . getByTestId ( 'flags-count' ) ) . toHaveTextContent ( '0' ) ;
437+ } ) ;
438+
439+ test ( 'handles API response with undefined items' , async ( ) => {
440+ // GIVEN: API returns { items: undefined }
441+ mockGetFlags . mockResolvedValue ( { items : undefined } ) ;
442+
443+ // WHEN: Flags are loaded
444+ render (
445+ < TestWrapper >
446+ < FlagsProvider >
447+ < TestConsumer />
448+ </ FlagsProvider >
449+ </ TestWrapper > ,
450+ ) ;
451+
452+ // THEN: Falls back to empty array
453+ await waitFor ( ( ) => {
454+ expect ( screen . getByTestId ( 'loading' ) ) . toHaveTextContent ( 'false' ) ;
455+ } ) ;
456+ expect ( screen . getByTestId ( 'flags-count' ) ) . toHaveTextContent ( '0' ) ;
457+ } ) ;
458+
459+ test ( 'handles null API response' , async ( ) => {
460+ // GIVEN: API returns null (e.g. network issue or iframe communication failure)
461+ mockGetFlags . mockResolvedValue ( null ) ;
462+
463+ // WHEN: Flags are loaded
464+ render (
465+ < TestWrapper >
466+ < FlagsProvider >
467+ < TestConsumer />
468+ </ FlagsProvider >
469+ </ TestWrapper > ,
470+ ) ;
471+
472+ // THEN: Falls back to empty array
473+ await waitFor ( ( ) => {
474+ expect ( screen . getByTestId ( 'loading' ) ) . toHaveTextContent ( 'false' ) ;
475+ } ) ;
476+ expect ( screen . getByTestId ( 'flags-count' ) ) . toHaveTextContent ( '0' ) ;
477+ } ) ;
478+
479+ test ( 'handles undefined API response' , async ( ) => {
480+ // GIVEN: API returns undefined
481+ mockGetFlags . mockResolvedValue ( undefined ) ;
482+
483+ // WHEN: Flags are loaded
484+ render (
485+ < TestWrapper >
486+ < FlagsProvider >
487+ < TestConsumer />
488+ </ FlagsProvider >
489+ </ TestWrapper > ,
490+ ) ;
491+
492+ // THEN: Falls back to empty array
493+ await waitFor ( ( ) => {
494+ expect ( screen . getByTestId ( 'loading' ) ) . toHaveTextContent ( 'false' ) ;
495+ } ) ;
496+ expect ( screen . getByTestId ( 'flags-count' ) ) . toHaveTextContent ( '0' ) ;
497+ } ) ;
498+
499+ test ( 'recovers from malformed response when valid response follows' , async ( ) => {
500+ // GIVEN: First API call returns malformed response
501+ mockGetFlags . mockResolvedValue ( { } ) ;
502+
503+ const { rerender } = render (
504+ < TestWrapper >
505+ < FlagsProvider >
506+ < TestConsumer />
507+ </ FlagsProvider >
508+ </ TestWrapper > ,
509+ ) ;
510+
511+ await waitFor ( ( ) => {
512+ expect ( screen . getByTestId ( 'loading' ) ) . toHaveTextContent ( 'false' ) ;
513+ } ) ;
514+ expect ( screen . getByTestId ( 'flags-count' ) ) . toHaveTextContent ( '0' ) ;
515+
516+ // WHEN: Project changes and the next API call returns valid data
517+ ( useProjectContext as any ) . mockReturnValue ( { projectKey : 'new-project' } ) ;
518+ mockGetFlags . mockResolvedValue (
519+ createFlagsResponse ( [ { key : 'flag-1' , name : 'Flag 1' , kind : 'boolean' } as ApiFlag ] ) ,
520+ ) ;
521+
522+ rerender (
523+ < TestWrapper >
524+ < FlagsProvider >
525+ < TestConsumer />
526+ </ FlagsProvider >
527+ </ TestWrapper > ,
528+ ) ;
529+
530+ // THEN: Flags load correctly after recovery
531+ await waitFor ( ( ) => {
532+ expect ( screen . getByTestId ( 'flags-count' ) ) . toHaveTextContent ( '1' ) ;
533+ } ) ;
534+ expect ( screen . getByTestId ( 'flag-flag-1' ) ) . toHaveTextContent ( 'Flag 1' ) ;
535+ } ) ;
536+ } ) ;
537+
418538 describe ( 'Context Hook - useFlagsContext' , ( ) => {
419539 test ( 'throws error when used without FlagsProvider' , ( ) => {
420540 // GIVEN: Component uses context without provider
0 commit comments