@@ -22,11 +22,12 @@ class MockProvider implements Provider {
22
22
readonly runsOn = 'client' ;
23
23
private hasInitialize : boolean ;
24
24
private hasContextChanged : boolean ;
25
+ private asyncContextChangedHandler : boolean ;
25
26
private failOnInit : boolean ;
26
27
private failOnContextChange : boolean ;
27
28
private asyncDelay ?: number ;
28
29
private enableEvents : boolean ;
29
- onContextChange ?: ( ) => Promise < void > ;
30
+ onContextChange ?: ( ) => Promise < void > | void ;
30
31
initialize ?: ( ) => Promise < void > ;
31
32
32
33
constructor ( options ?: {
@@ -35,6 +36,7 @@ class MockProvider implements Provider {
35
36
enableEvents ?: boolean ;
36
37
failOnInit ?: boolean ;
37
38
hasContextChanged ?: boolean ;
39
+ asyncContextChangedHandler ?: boolean ;
38
40
failOnContextChange ?: boolean ;
39
41
name ?: string ;
40
42
} ) {
@@ -45,6 +47,7 @@ class MockProvider implements Provider {
45
47
this . enableEvents = options ?. enableEvents ?? true ;
46
48
this . failOnInit = options ?. failOnInit ?? false ;
47
49
this . failOnContextChange = options ?. failOnContextChange ?? false ;
50
+ this . asyncContextChangedHandler = options ?. asyncContextChangedHandler ?? true ;
48
51
if ( this . hasContextChanged ) {
49
52
this . onContextChange = this . changeHandler ;
50
53
}
@@ -80,15 +83,19 @@ class MockProvider implements Provider {
80
83
}
81
84
82
85
private changeHandler ( ) {
83
- return new Promise < void > ( ( resolve , reject ) =>
84
- setTimeout ( ( ) => {
85
- if ( this . failOnContextChange ) {
86
- reject ( new Error ( ERR_MESSAGE ) ) ;
87
- } else {
88
- resolve ( ) ;
89
- }
90
- } , this . asyncDelay ) ,
91
- ) ;
86
+ if ( this . asyncContextChangedHandler ) {
87
+ return new Promise < void > ( ( resolve , reject ) =>
88
+ setTimeout ( ( ) => {
89
+ if ( this . failOnContextChange ) {
90
+ reject ( new Error ( ERR_MESSAGE ) ) ;
91
+ } else {
92
+ resolve ( ) ;
93
+ }
94
+ } , this . asyncDelay ) ,
95
+ ) ;
96
+ } else if ( this . failOnContextChange ) {
97
+ throw new Error ( ERR_MESSAGE ) ;
98
+ }
92
99
}
93
100
}
94
101
@@ -598,6 +605,25 @@ describe('Events', () => {
598
605
599
606
expect ( handler ) . toHaveBeenCalledTimes ( 2 ) ;
600
607
} ) ;
608
+
609
+ it ( 'Reconciling events are not emitted for synchronous onContextChange operations' , async ( ) => {
610
+ const provider = new MockProvider ( {
611
+ hasInitialize : false ,
612
+ hasContextChanged : true ,
613
+ asyncContextChangedHandler : false ,
614
+ } ) ;
615
+
616
+ const reconcileHandler = jest . fn ( ( ) => { } ) ;
617
+ const changedEventHandler = jest . fn ( ( ) => { } ) ;
618
+
619
+ await OpenFeature . setProviderAndWait ( domain , provider ) ;
620
+ OpenFeature . addHandler ( ProviderEvents . Reconciling , reconcileHandler ) ;
621
+ OpenFeature . addHandler ( ProviderEvents . ContextChanged , changedEventHandler ) ;
622
+ await OpenFeature . setContext ( domain , { } ) ;
623
+
624
+ expect ( reconcileHandler ) . not . toHaveBeenCalled ( ) ;
625
+ expect ( changedEventHandler ) . toHaveBeenCalledTimes ( 1 ) ;
626
+ } ) ;
601
627
} ) ;
602
628
603
629
describe ( 'provider has no context changed handler' , ( ) => {
@@ -615,7 +641,7 @@ describe('Events', () => {
615
641
} ) ;
616
642
} ) ;
617
643
} ) ;
618
-
644
+
619
645
describe ( 'client' , ( ) => {
620
646
describe ( 'provider has context changed handler' , ( ) => {
621
647
it ( 'Stale and ContextChanged are emitted' , async ( ) => {
@@ -810,12 +836,9 @@ describe('Events', () => {
810
836
} ;
811
837
812
838
client . addHandler ( ProviderEvents . ContextChanged , handler ) ;
813
-
839
+
814
840
// update context change twice
815
- await Promise . all ( [
816
- OpenFeature . setContext ( domain , { } ) ,
817
- OpenFeature . setContext ( domain , { } ) ,
818
- ] ) ;
841
+ await Promise . all ( [ OpenFeature . setContext ( domain , { } ) , OpenFeature . setContext ( domain , { } ) ] ) ;
819
842
820
843
// should only have run once
821
844
expect ( runs ) . toEqual ( 1 ) ;
0 commit comments