Repository: open-feature/js-sdk
Pull request #883 (2024-03-24 23:00:10)

fix: return metadata for the bound provider in hookContext
Clients were incorrectly populating the hook context provider metadata field with metadata from the default provider instead of the one bound to the client.


beeme1mr: Good catch! Could you please add some tests so that we can ensure we don't accidentally introduce a regression?
toddbaert: > Good catch! Could you please add some tests so that we can ensure we don't accidentally introduce a regression?

Agreed on this one, but if you have any trouble let me know and I'll happily add them myself; I know you're usually our "Python guy" so feel free to let me know if adding those tests is too tedious!
federicobond: Would something like this work? I wasn't sure where to put the mock provider definition.

Patch:
diff --git a/packages/client/src/client/open-feature-client.ts b/packages/client/src/client/open-feature-client.ts
index c9bf0857..500d3d61 100644
--- a/packages/client/src/client/open-feature-client.ts
+++ b/packages/client/src/client/open-feature-client.ts
@@ -201,7 +201,7 @@ export class OpenFeatureClient implements Client {
       defaultValue,
       flagValueType: flagType,
       clientMetadata: this.metadata,
-      providerMetadata: OpenFeature.providerMetadata,
+      providerMetadata: this._provider.metadata,
       context,
       logger: this._logger,
     };
diff --git a/packages/server/src/client/open-feature-client.ts b/packages/server/src/client/open-feature-client.ts
index 6c3f9d83..d697c167 100644
--- a/packages/server/src/client/open-feature-client.ts
+++ b/packages/server/src/client/open-feature-client.ts
@@ -254,7 +254,7 @@ export class OpenFeatureClient implements Client, ManageContext<OpenFeatureClien
       defaultValue,
       flagValueType: flagType,
       clientMetadata: this.metadata,
-      providerMetadata: OpenFeature.providerMetadata,
+      providerMetadata: this._provider.metadata,
       context: mergedContext,
       logger: this._logger,
     };


Test patch:
diff --git a/packages/client/test/hooks.spec.ts b/packages/client/test/hooks.spec.ts
index 72eeccf0..902eba1c 100644
--- a/packages/client/test/hooks.spec.ts
+++ b/packages/client/test/hooks.spec.ts
@@ -77,6 +77,39 @@ describe('Hooks', () => {
         ],
       });
     });
+    it('client metadata and provider metadata must match the client and provider used to resolve the flag', (done) => {
+      const provider: Provider = {
+        metadata: {
+          name: 'mock-my-domain-provider',
+        },
+        resolveBooleanEvaluation: jest.fn((): Promise<ResolutionDetails<boolean>> => {
+          return Promise.resolve({
+            value: BOOLEAN_VALUE,
+            variant: BOOLEAN_VARIANT,
+            reason: REASON,
+          });
+        }),
+      } as unknown as Provider;
+
+      OpenFeature.setProvider('my-domain', provider);
+      const client = OpenFeature.getClient('my-domain');
+
+      client.getBooleanValue(FLAG_KEY, false, {
+        hooks: [
+          {
+            before: (hookContext) => {
+              try {
+                expect(hookContext.providerMetadata).toEqual(provider.metadata);
+                expect(hookContext.clientMetadata).toEqual(client.metadata);
+                done();
+              } catch (err) {
+                done(err);
+              }
+            },
+          },
+        ],
+      });
+    });
   });
 
   describe('Requirement 4.1.3', () => {
diff --git a/packages/server/test/hooks.spec.ts b/packages/server/test/hooks.spec.ts
index 3dcb439d..cda0ec87 100644
--- a/packages/server/test/hooks.spec.ts
+++ b/packages/server/test/hooks.spec.ts
@@ -73,6 +73,39 @@ describe('Hooks', () => {
         ],
       });
     });
+    it('client metadata and provider metadata must match the client and provider used to resolve the flag', (done) => {
+      const provider: Provider = {
+        metadata: {
+          name: 'mock-my-domain-provider',
+        },
+        resolveBooleanEvaluation: jest.fn((): Promise<ResolutionDetails<boolean>> => {
+          return Promise.resolve({
+            value: BOOLEAN_VALUE,
+            variant: BOOLEAN_VARIANT,
+            reason: REASON,
+          });
+        }),
+      } as unknown as Provider;
+
+      OpenFeature.setProvider('my-domain', provider);
+      const client = OpenFeature.getClient('my-domain');
+
+      client.getBooleanValue(FLAG_KEY, false, undefined, {
+        hooks: [
+          {
+            before: (hookContext) => {
+              try {
+                expect(hookContext.providerMetadata).toEqual(provider.metadata);
+                expect(hookContext.clientMetadata).toEqual(client.metadata);
+                done();
+              } catch (err) {
+                done(err);
+              }
+            },
+          },
+        ],
+      });
+    });
   });
 
   describe('Requirement 4.1.3', () => {