Repository: open-feature/js-sdk
Pull request #480 (2023-07-05 17:36:41)

fix: events on anon provider/client
* fix an issue where events would fail to run on the default provider anonymous client if the provider was changed


Patch:
diff --git a/packages/shared/src/open-feature.ts b/packages/shared/src/open-feature.ts
index 00edbfe2..199320f1 100644
--- a/packages/shared/src/open-feature.ts
+++ b/packages/shared/src/open-feature.ts
@@ -191,7 +191,12 @@ export abstract class OpenFeatureCommonAPI<P extends CommonProvider = CommonProv
     const namedProviders = [...this._clientProviders.keys()];
     const eventEmitterNames = [...this._clientEvents.keys()].filter(isDefined);
     const unboundEmitterNames = eventEmitterNames.filter((name) => !namedProviders.includes(name));
-    return unboundEmitterNames.map((name) => this._clientEvents.get(name)).filter(isDefined);
+    return [
+      // all unbound, named emitters
+      ...unboundEmitterNames.map((name) => this._clientEvents.get(name)),
+      // the default emitter
+      this._clientEvents.get(undefined)
+    ].filter(isDefined);
   }
 
   private transferListeners(


Test patch:
diff --git a/packages/client/test/events.spec.ts b/packages/client/test/events.spec.ts
index c737c985..e8d38a33 100644
--- a/packages/client/test/events.spec.ts
+++ b/packages/client/test/events.spec.ts
@@ -197,7 +197,44 @@ describe('Events', () => {
       OpenFeature.setProvider(clientId, provider);
     });
 
-    it('anonymous provider with named client should run', (done) => {
+    it('anonymous provider with anonymous client should run non-init events', (done) => {
+      const defaultProvider = new MockProvider({
+        failOnInit: false,
+        initialStatus: ProviderStatus.NOT_READY,
+        name: 'default',
+      });
+
+      // get a anon client
+      const anonClient = OpenFeature.getClient();
+      anonClient.addHandler(ProviderEvents.ConfigurationChanged, () => {
+        done();
+      });
+
+      // set the default provider
+      OpenFeature.setProvider(defaultProvider);
+
+      // fire events
+      defaultProvider.events?.emit(ProviderEvents.ConfigurationChanged);
+    });
+
+    it('anonymous provider with anonymous client should run init events', (done) => {
+      const defaultProvider = new MockProvider({
+        failOnInit: false,
+        initialStatus: ProviderStatus.NOT_READY,
+        name: 'default',
+      });
+
+      // get a anon client
+      const anonClient = OpenFeature.getClient();
+      anonClient.addHandler(ProviderEvents.Ready, () => {
+        done();
+      });
+
+      // set the default provider
+      OpenFeature.setProvider(defaultProvider);
+    });
+
+    it('anonymous provider with named client should run non-init events', (done) => {
       const defaultProvider = new MockProvider({
         failOnInit: false,
         initialStatus: ProviderStatus.NOT_READY,
diff --git a/packages/server/test/events.spec.ts b/packages/server/test/events.spec.ts
index 90a5c7b7..055ba1be 100644
--- a/packages/server/test/events.spec.ts
+++ b/packages/server/test/events.spec.ts
@@ -200,7 +200,44 @@ describe('Events', () => {
       OpenFeature.setProvider(clientId, provider);
     });
 
-    it('anonymous provider with named client should run', (done) => {
+    it('anonymous provider with anonymous client should run non-init events', (done) => {
+      const defaultProvider = new MockProvider({
+        failOnInit: false,
+        initialStatus: ProviderStatus.NOT_READY,
+        name: 'default',
+      });
+
+      // get a anon client
+      const anonClient = OpenFeature.getClient();
+      anonClient.addHandler(ProviderEvents.ConfigurationChanged, () => {
+        done();
+      });
+
+      // set the default provider
+      OpenFeature.setProvider(defaultProvider);
+
+      // fire events
+      defaultProvider.events?.emit(ProviderEvents.ConfigurationChanged);
+    });
+
+    it('anonymous provider with anonymous client should run init events', (done) => {
+      const defaultProvider = new MockProvider({
+        failOnInit: false,
+        initialStatus: ProviderStatus.NOT_READY,
+        name: 'default',
+      });
+
+      // get a anon client
+      const anonClient = OpenFeature.getClient();
+      anonClient.addHandler(ProviderEvents.Ready, () => {
+        done();
+      });
+
+      // set the default provider
+      OpenFeature.setProvider(defaultProvider);
+    });
+
+    it('anonymous provider with named client should run non-init events', (done) => {
       const defaultProvider = new MockProvider({
         failOnInit: false,
         initialStatus: ProviderStatus.NOT_READY,