From 23d14aade82d25132714fd3be108cd91c9c15f49 Mon Sep 17 00:00:00 2001 From: Michael Beemer Date: Tue, 12 Dec 2023 11:38:43 -0500 Subject: [PATCH] feat: add named provider metadata accessor (#715) ## This PR - adds an accessor for named provider metadata ### Related Issues Fixes #714 ### Notes The default metadata is returned if the name doesn't match a registered provider. This is another example where provider namespace would work well. It doesn't make sense to call this "named client" since we are only interested in the client. --------- Signed-off-by: Michael Beemer Co-authored-by: Todd Baert --- packages/client/test/open-feature.spec.ts | 22 +++++++++++++++++++--- packages/server/test/open-feature.spec.ts | 22 +++++++++++++++++++--- packages/shared/src/open-feature.ts | 14 ++++++++++++-- 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/packages/client/test/open-feature.spec.ts b/packages/client/test/open-feature.spec.ts index 24cf03e4c..e19d3e071 100644 --- a/packages/client/test/open-feature.spec.ts +++ b/packages/client/test/open-feature.spec.ts @@ -39,13 +39,13 @@ describe('OpenFeature', () => { describe('Requirement 1.1.2.1', () => { it('should throw because the provider is not intended for the client', () => { const provider = mockProvider({ runsOn: 'server' }); - expect(() => OpenFeature.setProvider(provider)).toThrowError( - "Provider 'mock-events-success' is intended for use on the server." + expect(() => OpenFeature.setProvider(provider)).toThrow( + "Provider 'mock-events-success' is intended for use on the server.", ); }); it('should succeed because the provider is intended for the client', () => { const provider = mockProvider({ runsOn: 'client' }); - expect(() => OpenFeature.setProvider(provider)).not.toThrowError(); + expect(() => OpenFeature.setProvider(provider)).not.toThrow(); }); }); @@ -132,6 +132,22 @@ describe('OpenFeature', () => { OpenFeature.setProvider('client2', { ...provider1 }); expect(provider1.onClose).toHaveBeenCalledTimes(1); }); + + it('should return the default provider metadata when passing an unregistered client name', async () => { + const mockProvider = { metadata: { name: 'test' } } as unknown as Provider; + OpenFeature.setProvider(mockProvider); + const metadata = OpenFeature.getProviderMetadata('unused'); + expect(metadata.name === mockProvider.metadata.name).toBeTruthy(); + }); + + it('should return the named provider metadata when passing a registered client name', async () => { + const mockProvider = { metadata: { name: 'mock' } } as unknown as Provider; + const mockNamedProvider = { metadata: { name: 'named-mock' } } as unknown as Provider; + OpenFeature.setProvider(mockProvider); + OpenFeature.setProvider('mocked', mockNamedProvider); + const metadata = OpenFeature.getProviderMetadata('mocked'); + expect(metadata.name === mockNamedProvider.metadata.name).toBeTruthy(); + }); }); describe('Requirement 1.1.4', () => { diff --git a/packages/server/test/open-feature.spec.ts b/packages/server/test/open-feature.spec.ts index 05dbb8e7f..624142114 100644 --- a/packages/server/test/open-feature.spec.ts +++ b/packages/server/test/open-feature.spec.ts @@ -39,13 +39,13 @@ describe('OpenFeature', () => { describe('Requirement 1.1.2.1', () => { it('should throw because the provider is not intended for the server', () => { const provider = mockProvider({ runsOn: 'client' }); - expect(() => OpenFeature.setProvider(provider)).toThrowError( - "Provider 'mock-events-success' is intended for use on the client." + expect(() => OpenFeature.setProvider(provider)).toThrow( + "Provider 'mock-events-success' is intended for use on the client.", ); }); it('should succeed because the provider is intended for the server', () => { const provider = mockProvider({ runsOn: 'server' }); - expect(() => OpenFeature.setProvider(provider)).not.toThrowError(); + expect(() => OpenFeature.setProvider(provider)).not.toThrow(); }); }); @@ -132,6 +132,22 @@ describe('OpenFeature', () => { OpenFeature.setProvider('client2', { ...provider1 }); expect(provider1.onClose).toHaveBeenCalledTimes(1); }); + + it('should return the default provider metadata when passing an unregistered client name', async () => { + const mockProvider = { metadata: { name: 'test' } } as unknown as Provider; + OpenFeature.setProvider(mockProvider); + const metadata = OpenFeature.getProviderMetadata('unused'); + expect(metadata.name === mockProvider.metadata.name).toBeTruthy(); + }); + + it('should return the named provider metadata when passing a registered client name', async () => { + const mockProvider = { metadata: { name: 'mock' } } as unknown as Provider; + const mockNamedProvider = { metadata: { name: 'named-mock' } } as unknown as Provider; + OpenFeature.setProvider(mockProvider); + OpenFeature.setProvider('mocked', mockNamedProvider); + const metadata = OpenFeature.getProviderMetadata('mocked'); + expect(metadata.name === mockNamedProvider.metadata.name).toBeTruthy(); + }); }); describe('Requirement 1.1.4', () => { diff --git a/packages/shared/src/open-feature.ts b/packages/shared/src/open-feature.ts index f2d2b3e51..313e31fae 100644 --- a/packages/shared/src/open-feature.ts +++ b/packages/shared/src/open-feature.ts @@ -50,11 +50,21 @@ export abstract class OpenFeatureCommonAPI