diff --git a/packages/shared/sdk-client/__tests__/LDCLientImpl.inspections.test.ts b/packages/shared/sdk-client/__tests__/LDCLientImpl.inspections.test.ts index 13b5f1b780..ce56bdfa43 100644 --- a/packages/shared/sdk-client/__tests__/LDCLientImpl.inspections.test.ts +++ b/packages/shared/sdk-client/__tests__/LDCLientImpl.inspections.test.ts @@ -142,6 +142,60 @@ it('calls flag-detail-changed inspector for individial flag changes on patch', a }); }); +it('calls flag-detail-changed inspector when a flag is deleted', async () => { + const eventQueue = new AsyncQueue(); + const flagDetailChangedInspector: LDInspection = { + type: 'flag-detail-changed', + name: 'test flag detail changed inspector', + method: jest.fn(() => eventQueue.add({})), + }; + const platform = createBasicPlatform(); + const factory = makeTestDataManagerFactory('sdk-key', platform); + const client = new LDClientImpl( + 'sdk-key', + AutoEnvAttributes.Disabled, + platform, + { + sendEvents: false, + inspectors: [flagDetailChangedInspector], + logger: { + debug: jest.fn(), + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }, + }, + factory, + ); + let mockEventSource: MockEventSource; + + const putResponse = clone(mockResponseJson); + const putEvents = [{ data: JSON.stringify(putResponse) }]; + const deleteResponse = { + key: 'dev-test-flag', + version: putResponse['dev-test-flag'].version + 1, + }; + const deleteEvents = [{ data: JSON.stringify(deleteResponse) }]; + + platform.requests.createEventSource.mockImplementation( + (streamUri: string = '', options: any = {}) => { + mockEventSource = new MockEventSource(streamUri, options); + mockEventSource.simulateEvents('put', putEvents); + mockEventSource.simulateEvents('delete', deleteEvents); + return mockEventSource; + }, + ); + + await client.identify({ key: 'user-key' }, { waitForNetworkResults: true }); + + await eventQueue.take(); + expect(flagDetailChangedInspector.method).toHaveBeenCalledWith('dev-test-flag', { + reason: null, + value: undefined, + variationIndex: null, + }); +}); + it('calls flag-details-changed inspectors when all flag values change', async () => { const flagDetailsChangedInspector: LDInspection = { type: 'flag-details-changed', diff --git a/packages/shared/sdk-client/src/LDClientImpl.ts b/packages/shared/sdk-client/src/LDClientImpl.ts index ff6565b2bf..b61d0c5c49 100644 --- a/packages/shared/sdk-client/src/LDClientImpl.ts +++ b/packages/shared/sdk-client/src/LDClientImpl.ts @@ -509,6 +509,14 @@ export default class LDClientImpl implements LDClient { if (item?.flag && !item.flag.deleted) { const { reason, value, variation } = item.flag; details[flagKey] = createSuccessEvaluationDetail(value, variation, reason); + } else { + details[flagKey] = { + value: undefined, + // For backwards compatibility purposes reason and variationIndex are null instead of + // being undefined. + reason: null, + variationIndex: null, + }; } }); if (type === 'init') { diff --git a/packages/shared/sdk-client/src/api/LDInspection.ts b/packages/shared/sdk-client/src/api/LDInspection.ts index bf73dea37c..24d1c654de 100644 --- a/packages/shared/sdk-client/src/api/LDInspection.ts +++ b/packages/shared/sdk-client/src/api/LDInspection.ts @@ -71,6 +71,8 @@ export interface LDInspectionFlagDetailsChangedHandler { * * This interface should not be used by the application to access flags for the purpose of controlling application * flow. It is intended for monitoring, analytics, or debugging purposes. + * + * When a flag is deleted the `value` in the {@link LDEvaluationDetail} will be `undefined`. */ export interface LDInspectionFlagDetailChangedHandler { type: 'flag-detail-changed';