posthog-node
Advanced tools
Comparing version 3.4.0 to 3.5.0
@@ -0,1 +1,6 @@ | ||
# 3.5.0 - 2024-01-09 | ||
1. When local evaluation is enabled, we automatically add flag information to all events sent to PostHog, whenever possible. This makes it easier to use these events in experiments. | ||
2. Fixes a bug where in some rare cases we may drop events when send_feature_flags is enabled on capture. | ||
# 3.4.0 - 2024-01-09 | ||
@@ -2,0 +7,0 @@ |
@@ -111,5 +111,5 @@ /// <reference types="node" /> | ||
private debugMode; | ||
private pendingPromises; | ||
private disableGeoip; | ||
private _optoutOverride; | ||
private pendingPromises; | ||
protected _events: SimpleEventEmitter; | ||
@@ -132,2 +132,3 @@ protected _flushTimer?: any; | ||
private buildPayload; | ||
protected addPendingPromise(promise: Promise<any>): void; | ||
/*** | ||
@@ -382,2 +383,3 @@ *** TRACKING | ||
shutdownAsync(): Promise<void>; | ||
private addLocalPersonAndGroupProperties; | ||
} | ||
@@ -384,0 +386,0 @@ |
@@ -15,5 +15,5 @@ import { PostHogFetchOptions, PostHogFetchResponse, PostHogAutocaptureElement, PostHogDecideResponse, PosthogCoreOptions, PostHogEventProperties, PostHogPersistedProperty, PosthogCaptureOptions, JsonType } from './types'; | ||
private debugMode; | ||
private pendingPromises; | ||
private disableGeoip; | ||
private _optoutOverride; | ||
private pendingPromises; | ||
protected _events: SimpleEventEmitter; | ||
@@ -36,2 +36,3 @@ protected _flushTimer?: any; | ||
private buildPayload; | ||
protected addPendingPromise(promise: Promise<any>): void; | ||
/*** | ||
@@ -38,0 +39,0 @@ *** TRACKING |
@@ -76,2 +76,3 @@ import { JsonType, PosthogCoreOptions, PostHogCoreStateless, PostHogFetchOptions, PostHogFetchResponse, PosthogFlagsAndPayloadsResponse, PostHogPersistedProperty } from '../../posthog-core/src'; | ||
shutdownAsync(): Promise<void>; | ||
private addLocalPersonAndGroupProperties; | ||
} |
{ | ||
"name": "posthog-node", | ||
"version": "3.4.0", | ||
"version": "3.5.0", | ||
"description": "PostHog Node.js integration", | ||
@@ -5,0 +5,0 @@ "repository": { |
@@ -124,3 +124,3 @@ import { createHash } from 'rusha' | ||
} else if (e instanceof Error) { | ||
console.error(`Error computing flag locally: ${key}: ${e}`) | ||
this.onError?.(new Error(`Error computing flag locally: ${key}: ${e}`)) | ||
} | ||
@@ -215,5 +215,7 @@ } | ||
if (!groupName) { | ||
console.warn( | ||
`[FEATURE FLAGS] Unknown group type index ${aggregation_group_type_index} for feature flag ${flag.key}` | ||
) | ||
if (this.debugMode) { | ||
console.warn( | ||
`[FEATURE FLAGS] Unknown group type index ${aggregation_group_type_index} for feature flag ${flag.key}` | ||
) | ||
} | ||
throw new InconclusiveMatchError('Flag has unknown group type index') | ||
@@ -223,3 +225,5 @@ } | ||
if (!(groupName in groups)) { | ||
console.warn(`[FEATURE FLAGS] Can't compute group feature flag: ${flag.key} without group names passed in`) | ||
if (this.debugMode) { | ||
console.warn(`[FEATURE FLAGS] Can't compute group feature flag: ${flag.key} without group names passed in`) | ||
} | ||
return false | ||
@@ -389,3 +393,3 @@ } | ||
if (!('flags' in responseJson)) { | ||
console.error(`Invalid response when getting feature flags: ${JSON.stringify(responseJson)}`) | ||
this.onError?.(new Error(`Invalid response when getting feature flags: ${JSON.stringify(responseJson)}`)) | ||
} | ||
@@ -392,0 +396,0 @@ |
@@ -108,22 +108,50 @@ import { version } from '../package.json' | ||
if (sendFeatureFlags) { | ||
super.getFeatureFlagsStateless(distinctId, groups, undefined, undefined, disableGeoip).then((flags) => { | ||
const featureVariantProperties: Record<string, string | boolean> = {} | ||
// :TRICKY: If we flush, or need to shut down, to not lose events we want this promise to resolve before we flush | ||
const capturePromise = Promise.resolve() | ||
.then(async () => { | ||
if (sendFeatureFlags) { | ||
// If we are sending feature flags, we need to make sure we have the latest flags | ||
return await super.getFeatureFlagsStateless(distinctId, groups, undefined, undefined, disableGeoip) | ||
} | ||
if ((this.featureFlagsPoller?.featureFlags?.length || 0) > 0) { | ||
// Otherwise we may as well check for the flags locally and include them if there | ||
const groupsWithStringValues: Record<string, string> = {} | ||
for (const [key, value] of Object.entries(groups || {})) { | ||
groupsWithStringValues[key] = String(value) | ||
} | ||
return await this.getAllFlags(distinctId, { | ||
groups: groupsWithStringValues, | ||
disableGeoip, | ||
onlyEvaluateLocally: true, | ||
}) | ||
} | ||
return {} | ||
}) | ||
.then((flags) => { | ||
// Derive the relevant flag properties to add | ||
const additionalProperties: Record<string, any> = {} | ||
if (flags) { | ||
for (const [feature, variant] of Object.entries(flags)) { | ||
if (variant !== false) { | ||
featureVariantProperties[`$feature/${feature}`] = variant | ||
} | ||
additionalProperties[`$feature/${feature}`] = variant | ||
} | ||
} | ||
const activeFlags = Object.keys(flags || {}).filter((flag) => flags?.[flag] !== false) | ||
const flagProperties = { | ||
$active_feature_flags: activeFlags || undefined, | ||
...featureVariantProperties, | ||
if (activeFlags.length > 0) { | ||
additionalProperties['$active_feature_flags'] = activeFlags | ||
} | ||
_capture({ ...properties, $groups: groups, ...flagProperties }) | ||
return additionalProperties | ||
}) | ||
} else { | ||
_capture({ ...properties, $groups: groups }) | ||
} | ||
.catch(() => { | ||
// Something went wrong getting the flag info - we should capture the event anyways | ||
return {} | ||
}) | ||
.then((additionalProperties) => { | ||
// No matter what - capture the event | ||
_capture({ ...additionalProperties, ...properties, $groups: groups }) | ||
}) | ||
this.addPendingPromise(capturePromise) | ||
} | ||
@@ -160,5 +188,15 @@ | ||
): Promise<string | boolean | undefined> { | ||
const { groups, personProperties, groupProperties, disableGeoip } = options || {} | ||
let { onlyEvaluateLocally, sendFeatureFlagEvents } = options || {} | ||
const { groups, disableGeoip } = options || {} | ||
let { onlyEvaluateLocally, sendFeatureFlagEvents, personProperties, groupProperties } = options || {} | ||
const adjustedProperties = this.addLocalPersonAndGroupProperties( | ||
distinctId, | ||
groups, | ||
personProperties, | ||
groupProperties | ||
) | ||
personProperties = adjustedProperties.allPersonProperties | ||
groupProperties = adjustedProperties.allGroupProperties | ||
// set defaults | ||
@@ -237,4 +275,15 @@ if (onlyEvaluateLocally == undefined) { | ||
): Promise<JsonType | undefined> { | ||
const { groups, personProperties, groupProperties, disableGeoip } = options || {} | ||
let { onlyEvaluateLocally, sendFeatureFlagEvents } = options || {} | ||
const { groups, disableGeoip } = options || {} | ||
let { onlyEvaluateLocally, sendFeatureFlagEvents, personProperties, groupProperties } = options || {} | ||
const adjustedProperties = this.addLocalPersonAndGroupProperties( | ||
distinctId, | ||
groups, | ||
personProperties, | ||
groupProperties | ||
) | ||
personProperties = adjustedProperties.allPersonProperties | ||
groupProperties = adjustedProperties.allGroupProperties | ||
let response = undefined | ||
@@ -330,5 +379,15 @@ | ||
): Promise<PosthogFlagsAndPayloadsResponse> { | ||
const { groups, personProperties, groupProperties, disableGeoip } = options || {} | ||
let { onlyEvaluateLocally } = options || {} | ||
const { groups, disableGeoip } = options || {} | ||
let { onlyEvaluateLocally, personProperties, groupProperties } = options || {} | ||
const adjustedProperties = this.addLocalPersonAndGroupProperties( | ||
distinctId, | ||
groups, | ||
personProperties, | ||
groupProperties | ||
) | ||
personProperties = adjustedProperties.allPersonProperties | ||
groupProperties = adjustedProperties.allGroupProperties | ||
// set defaults | ||
@@ -392,2 +451,23 @@ if (onlyEvaluateLocally == undefined) { | ||
} | ||
private addLocalPersonAndGroupProperties( | ||
distinctId: string, | ||
groups?: Record<string, string>, | ||
personProperties?: Record<string, string>, | ||
groupProperties?: Record<string, Record<string, string>> | ||
): { allPersonProperties: Record<string, string>; allGroupProperties: Record<string, Record<string, string>> } { | ||
const allPersonProperties = { $current_distinct_id: distinctId, ...(personProperties || {}) } | ||
const allGroupProperties: Record<string, Record<string, string>> = {} | ||
if (groups) { | ||
for (const groupName of Object.keys(groups)) { | ||
allGroupProperties[groupName] = { | ||
$group_key: groups[groupName], | ||
...(groupProperties?.[groupName] || {}), | ||
} | ||
} | ||
} | ||
return { allPersonProperties, allGroupProperties } | ||
} | ||
} |
@@ -6,2 +6,3 @@ // import { PostHog } from '../' | ||
import fetch from '../../src/fetch' | ||
import { waitForPromises } from 'posthog-core/test/test-utils/test-utils' | ||
@@ -112,2 +113,3 @@ jest.mock('../../package.json', () => ({ version: '1.2.3' })) | ||
await waitForPromises() | ||
jest.runOnlyPendingTimers() | ||
@@ -114,0 +116,0 @@ const batchEvents = getLastBatchEvents() |
@@ -54,3 +54,5 @@ // import { PostHog } from '../' | ||
await waitForPromises() | ||
jest.runOnlyPendingTimers() | ||
const batchEvents = getLastBatchEvents() | ||
@@ -80,2 +82,3 @@ expect(batchEvents).toEqual([ | ||
await waitForPromises() | ||
jest.runOnlyPendingTimers() | ||
@@ -103,2 +106,3 @@ expect(getLastBatchEvents()?.[0]).toEqual( | ||
await waitForPromises() | ||
jest.runOnlyPendingTimers() | ||
@@ -179,2 +183,3 @@ expect(getLastBatchEvents()?.[0]).toEqual( | ||
posthog.capture({ event: 'custom-time', distinctId: '123', timestamp: new Date('2021-02-03') }) | ||
await waitForPromises() | ||
jest.runOnlyPendingTimers() | ||
@@ -201,2 +206,3 @@ const batchEvents = getLastBatchEvents() | ||
await waitForPromises() | ||
jest.runOnlyPendingTimers() | ||
@@ -220,3 +226,5 @@ const batchEvents = getLastBatchEvents() | ||
await waitForPromises() | ||
jest.runOnlyPendingTimers() | ||
let batchEvents = getLastBatchEvents() | ||
@@ -238,2 +246,3 @@ expect(batchEvents?.[0].properties).toEqual({ | ||
await waitForPromises() | ||
jest.runOnlyPendingTimers() | ||
@@ -258,2 +267,3 @@ batchEvents = getLastBatchEvents() | ||
await waitForPromises() | ||
jest.runOnlyPendingTimers() | ||
@@ -297,2 +307,3 @@ batchEvents = getLastBatchEvents() | ||
posthog.debug(false) | ||
jest.useFakeTimers() | ||
}) | ||
@@ -333,2 +344,41 @@ | ||
}) | ||
it('should shutdown cleanly with pending capture flag promises', async () => { | ||
posthog = new PostHog('TEST_API_KEY', { | ||
host: 'http://example.com', | ||
fetchRetryCount: 0, | ||
flushAt: 4, | ||
}) | ||
const logSpy = jest.spyOn(console, 'log').mockImplementation(() => {}) | ||
jest.useRealTimers() | ||
posthog.debug(true) | ||
for (let i = 0; i < 10; i++) { | ||
posthog.capture({ event: 'test-event', distinctId: `${i}`, sendFeatureFlags: true }) | ||
} | ||
await posthog.shutdownAsync() | ||
// all capture calls happen during shutdown | ||
const batchEvents = getLastBatchEvents() | ||
expect(batchEvents?.length).toEqual(2) | ||
expect(batchEvents?.[batchEvents?.length - 1]).toMatchObject({ | ||
// last event in batch | ||
distinct_id: '9', | ||
event: 'test-event', | ||
library: 'posthog-node', | ||
library_version: '1.2.3', | ||
properties: { | ||
$lib: 'posthog-node', | ||
$lib_version: '1.2.3', | ||
$geoip_disable: true, | ||
}, | ||
timestamp: expect.any(String), | ||
type: 'capture', | ||
}) | ||
expect(10).toEqual(logSpy.mock.calls.filter((call) => call[1].includes('capture')).length) | ||
expect(3).toEqual(logSpy.mock.calls.filter((call) => call[1].includes('flush')).length) | ||
jest.useFakeTimers() | ||
logSpy.mockRestore() | ||
}) | ||
}) | ||
@@ -397,4 +447,75 @@ | ||
const multivariateFlag = { | ||
id: 1, | ||
name: 'Beta Feature', | ||
key: 'beta-feature-local', | ||
is_simple_flag: false, | ||
active: true, | ||
rollout_percentage: 100, | ||
filters: { | ||
groups: [ | ||
{ | ||
properties: [{ key: 'email', type: 'person', value: 'test@posthog.com', operator: 'exact' }], | ||
rollout_percentage: 100, | ||
}, | ||
{ | ||
rollout_percentage: 50, | ||
}, | ||
], | ||
multivariate: { | ||
variants: [ | ||
{ key: 'first-variant', name: 'First Variant', rollout_percentage: 50 }, | ||
{ key: 'second-variant', name: 'Second Variant', rollout_percentage: 25 }, | ||
{ key: 'third-variant', name: 'Third Variant', rollout_percentage: 25 }, | ||
], | ||
}, | ||
payloads: { 'first-variant': 'some-payload', 'third-variant': { a: 'json' } }, | ||
}, | ||
} | ||
const basicFlag = { | ||
id: 1, | ||
name: 'Beta Feature', | ||
key: 'person-flag', | ||
is_simple_flag: true, | ||
active: true, | ||
filters: { | ||
groups: [ | ||
{ | ||
properties: [ | ||
{ | ||
key: 'region', | ||
operator: 'exact', | ||
value: ['USA'], | ||
type: 'person', | ||
}, | ||
], | ||
rollout_percentage: 100, | ||
}, | ||
], | ||
payloads: { true: 300 }, | ||
}, | ||
} | ||
const falseFlag = { | ||
id: 1, | ||
name: 'Beta Feature', | ||
key: 'false-flag', | ||
is_simple_flag: true, | ||
active: true, | ||
filters: { | ||
groups: [ | ||
{ | ||
properties: [], | ||
rollout_percentage: 0, | ||
}, | ||
], | ||
payloads: { true: 300 }, | ||
}, | ||
} | ||
mockedFetch.mockImplementation( | ||
apiImplementation({ decideFlags: mockFeatureFlags, decideFlagPayloads: mockFeatureFlagPayloads }) | ||
apiImplementation({ | ||
decideFlags: mockFeatureFlags, | ||
decideFlagPayloads: mockFeatureFlagPayloads, | ||
localFlags: { flags: [multivariateFlag, basicFlag, falseFlag] }, | ||
}) | ||
) | ||
@@ -444,2 +565,5 @@ | ||
jest.runOnlyPendingTimers() | ||
await waitForPromises() | ||
expect(mockedFetch).toHaveBeenCalledWith( | ||
@@ -450,6 +574,2 @@ 'http://example.com/decide/?v=3', | ||
jest.runOnlyPendingTimers() | ||
await waitForPromises() | ||
expect(getLastBatchEvents()?.[0]).toEqual( | ||
@@ -480,2 +600,109 @@ expect.objectContaining({ | ||
it('captures feature flags with locally evaluated flags', async () => { | ||
mockedFetch.mockClear() | ||
mockedFetch.mockClear() | ||
expect(mockedFetch).toHaveBeenCalledTimes(0) | ||
posthog = new PostHog('TEST_API_KEY', { | ||
host: 'http://example.com', | ||
flushAt: 1, | ||
fetchRetryCount: 0, | ||
personalApiKey: 'TEST_PERSONAL_API_KEY', | ||
}) | ||
jest.runOnlyPendingTimers() | ||
await waitForPromises() | ||
posthog.capture({ | ||
distinctId: 'distinct_id', | ||
event: 'node test event', | ||
}) | ||
expect(mockedFetch).toHaveBeenCalledWith(...anyLocalEvalCall) | ||
// no decide call | ||
expect(mockedFetch).not.toHaveBeenCalledWith( | ||
'http://example.com/decide/?v=3', | ||
expect.objectContaining({ method: 'POST' }) | ||
) | ||
jest.runOnlyPendingTimers() | ||
await waitForPromises() | ||
expect(getLastBatchEvents()?.[0]).toEqual( | ||
expect.objectContaining({ | ||
distinct_id: 'distinct_id', | ||
event: 'node test event', | ||
properties: expect.objectContaining({ | ||
$active_feature_flags: ['beta-feature-local'], | ||
'$feature/beta-feature-local': 'third-variant', | ||
'$feature/false-flag': false, | ||
$lib: 'posthog-node', | ||
$lib_version: '1.2.3', | ||
$geoip_disable: true, | ||
}), | ||
}) | ||
) | ||
expect( | ||
Object.prototype.hasOwnProperty.call(getLastBatchEvents()?.[0].properties, '$feature/beta-feature-local') | ||
).toBe(true) | ||
expect(Object.prototype.hasOwnProperty.call(getLastBatchEvents()?.[0].properties, '$feature/beta-feature')).toBe( | ||
false | ||
) | ||
await posthog.shutdownAsync() | ||
}) | ||
it('doesnt add flag properties when locally evaluated flags are empty', async () => { | ||
mockedFetch.mockClear() | ||
expect(mockedFetch).toHaveBeenCalledTimes(0) | ||
mockedFetch.mockImplementation( | ||
apiImplementation({ decideFlags: { a: false, b: 'true' }, decideFlagPayloads: {}, localFlags: { flags: [] } }) | ||
) | ||
posthog = new PostHog('TEST_API_KEY', { | ||
host: 'http://example.com', | ||
flushAt: 1, | ||
fetchRetryCount: 0, | ||
personalApiKey: 'TEST_PERSONAL_API_KEY', | ||
}) | ||
posthog.capture({ | ||
distinctId: 'distinct_id', | ||
event: 'node test event', | ||
}) | ||
jest.runOnlyPendingTimers() | ||
await waitForPromises() | ||
expect(mockedFetch).toHaveBeenCalledWith(...anyLocalEvalCall) | ||
// no decide call | ||
expect(mockedFetch).not.toHaveBeenCalledWith( | ||
'http://example.com/decide/?v=3', | ||
expect.objectContaining({ method: 'POST' }) | ||
) | ||
jest.runOnlyPendingTimers() | ||
await waitForPromises() | ||
expect(getLastBatchEvents()?.[0]).toEqual( | ||
expect.objectContaining({ | ||
distinct_id: 'distinct_id', | ||
event: 'node test event', | ||
properties: expect.objectContaining({ | ||
$lib: 'posthog-node', | ||
$lib_version: '1.2.3', | ||
$geoip_disable: true, | ||
}), | ||
}) | ||
) | ||
expect( | ||
Object.prototype.hasOwnProperty.call(getLastBatchEvents()?.[0].properties, '$feature/beta-feature-local') | ||
).toBe(false) | ||
expect(Object.prototype.hasOwnProperty.call(getLastBatchEvents()?.[0].properties, '$feature/beta-feature')).toBe( | ||
false | ||
) | ||
}) | ||
it('captures feature flags with same geoip setting as capture', async () => { | ||
@@ -499,2 +726,5 @@ mockedFetch.mockClear() | ||
await waitForPromises() | ||
jest.runOnlyPendingTimers() | ||
expect(mockedFetch).toHaveBeenCalledWith( | ||
@@ -505,6 +735,2 @@ 'http://example.com/decide/?v=3', | ||
jest.runOnlyPendingTimers() | ||
await waitForPromises() | ||
expect(getLastBatchEvents()?.[0].properties).toEqual({ | ||
@@ -514,2 +740,3 @@ $active_feature_flags: ['feature-1', 'feature-2', 'feature-variant'], | ||
'$feature/feature-2': true, | ||
'$feature/disabled-flag': false, | ||
'$feature/feature-variant': 'variant', | ||
@@ -554,2 +781,3 @@ $lib: 'posthog-node', | ||
fetchRetryCount: 0, | ||
flushAt: 1, | ||
}) | ||
@@ -559,6 +787,7 @@ | ||
for (let i = 0; i < 1000; i++) { | ||
for (let i = 0; i < 100; i++) { | ||
const distinctId = `some-distinct-id${i}` | ||
await posthog.getFeatureFlag('beta-feature', distinctId) | ||
await waitForPromises() | ||
jest.runOnlyPendingTimers() | ||
@@ -588,2 +817,4 @@ | ||
it('$feature_flag_called is called appropriately when querying flags', async () => { | ||
mockedFetch.mockClear() | ||
const flags = { | ||
@@ -619,2 +850,4 @@ flags: [ | ||
jest.runOnlyPendingTimers() | ||
expect( | ||
@@ -625,3 +858,8 @@ await posthog.getFeatureFlag('beta-feature', 'some-distinct-id', { | ||
).toEqual(true) | ||
// TRICKY: There's now an extra step before events are queued, so need to wait for that to resolve | ||
jest.runOnlyPendingTimers() | ||
await waitForPromises() | ||
await posthog.flushAsync() | ||
expect(mockedFetch).toHaveBeenCalledWith('http://example.com/batch/', expect.any(Object)) | ||
@@ -653,2 +891,4 @@ | ||
jest.runOnlyPendingTimers() | ||
await waitForPromises() | ||
await posthog.flushAsync() | ||
@@ -666,2 +906,4 @@ expect(mockedFetch).not.toHaveBeenCalledWith('http://example.com/batch/', expect.any(Object)) | ||
jest.runOnlyPendingTimers() | ||
await waitForPromises() | ||
await posthog.flushAsync() | ||
expect(mockedFetch).toHaveBeenCalledWith('http://example.com/batch/', expect.any(Object)) | ||
@@ -694,2 +936,4 @@ | ||
jest.runOnlyPendingTimers() | ||
await waitForPromises() | ||
await posthog.flushAsync() | ||
expect(mockedFetch).not.toHaveBeenCalledWith('http://example.com/batch/', expect.any(Object)) | ||
@@ -705,2 +949,4 @@ | ||
jest.runOnlyPendingTimers() | ||
await waitForPromises() | ||
await posthog.flushAsync() | ||
// one to decide, one to batch | ||
@@ -734,2 +980,4 @@ expect(mockedFetch).toHaveBeenCalledWith(...anyDecideCall) | ||
jest.runOnlyPendingTimers() | ||
await waitForPromises() | ||
await posthog.flushAsync() | ||
// call decide, but not batch | ||
@@ -780,3 +1028,152 @@ expect(mockedFetch).toHaveBeenCalledWith(...anyDecideCall) | ||
}) | ||
it('should add default person & group properties for feature flags', async () => { | ||
await posthog.getFeatureFlag('random_key', 'some_id', { | ||
groups: { company: 'id:5', instance: 'app.posthog.com' }, | ||
personProperties: { x1: 'y1' }, | ||
groupProperties: { company: { x: 'y' } }, | ||
}) | ||
jest.runOnlyPendingTimers() | ||
expect(mockedFetch).toHaveBeenCalledWith( | ||
'http://example.com/decide/?v=3', | ||
expect.objectContaining({ | ||
body: JSON.stringify({ | ||
token: 'TEST_API_KEY', | ||
distinct_id: 'some_id', | ||
groups: { company: 'id:5', instance: 'app.posthog.com' }, | ||
person_properties: { | ||
$current_distinct_id: 'some_id', | ||
x1: 'y1', | ||
}, | ||
group_properties: { | ||
company: { $group_key: 'id:5', x: 'y' }, | ||
instance: { $group_key: 'app.posthog.com' }, | ||
}, | ||
geoip_disable: true, | ||
}), | ||
}) | ||
) | ||
mockedFetch.mockClear() | ||
await posthog.getFeatureFlag('random_key', 'some_id', { | ||
groups: { company: 'id:5', instance: 'app.posthog.com' }, | ||
personProperties: { $current_distinct_id: 'override' }, | ||
groupProperties: { company: { $group_key: 'group_override' } }, | ||
}) | ||
jest.runOnlyPendingTimers() | ||
expect(mockedFetch).toHaveBeenCalledWith( | ||
'http://example.com/decide/?v=3', | ||
expect.objectContaining({ | ||
body: JSON.stringify({ | ||
token: 'TEST_API_KEY', | ||
distinct_id: 'some_id', | ||
groups: { company: 'id:5', instance: 'app.posthog.com' }, | ||
person_properties: { | ||
$current_distinct_id: 'override', | ||
}, | ||
group_properties: { | ||
company: { $group_key: 'group_override' }, | ||
instance: { $group_key: 'app.posthog.com' }, | ||
}, | ||
geoip_disable: true, | ||
}), | ||
}) | ||
) | ||
mockedFetch.mockClear() | ||
// test nones | ||
await posthog.getAllFlagsAndPayloads('some_id', { | ||
groups: undefined, | ||
personProperties: undefined, | ||
groupProperties: undefined, | ||
}) | ||
jest.runOnlyPendingTimers() | ||
expect(mockedFetch).toHaveBeenCalledWith( | ||
'http://example.com/decide/?v=3', | ||
expect.objectContaining({ | ||
body: JSON.stringify({ | ||
token: 'TEST_API_KEY', | ||
distinct_id: 'some_id', | ||
groups: {}, | ||
person_properties: { | ||
$current_distinct_id: 'some_id', | ||
}, | ||
group_properties: {}, | ||
geoip_disable: true, | ||
}), | ||
}) | ||
) | ||
mockedFetch.mockClear() | ||
await posthog.getAllFlags('some_id', { | ||
groups: { company: 'id:5' }, | ||
personProperties: undefined, | ||
groupProperties: undefined, | ||
}) | ||
jest.runOnlyPendingTimers() | ||
expect(mockedFetch).toHaveBeenCalledWith( | ||
'http://example.com/decide/?v=3', | ||
expect.objectContaining({ | ||
body: JSON.stringify({ | ||
token: 'TEST_API_KEY', | ||
distinct_id: 'some_id', | ||
groups: { company: 'id:5' }, | ||
person_properties: { | ||
$current_distinct_id: 'some_id', | ||
}, | ||
group_properties: { company: { $group_key: 'id:5' } }, | ||
geoip_disable: true, | ||
}), | ||
}) | ||
) | ||
mockedFetch.mockClear() | ||
await posthog.getFeatureFlagPayload('random_key', 'some_id', undefined) | ||
jest.runOnlyPendingTimers() | ||
expect(mockedFetch).toHaveBeenCalledWith( | ||
'http://example.com/decide/?v=3', | ||
expect.objectContaining({ | ||
body: JSON.stringify({ | ||
token: 'TEST_API_KEY', | ||
distinct_id: 'some_id', | ||
groups: {}, | ||
person_properties: { | ||
$current_distinct_id: 'some_id', | ||
}, | ||
group_properties: {}, | ||
geoip_disable: true, | ||
}), | ||
}) | ||
) | ||
mockedFetch.mockClear() | ||
await posthog.isFeatureEnabled('random_key', 'some_id') | ||
jest.runOnlyPendingTimers() | ||
expect(mockedFetch).toHaveBeenCalledWith( | ||
'http://example.com/decide/?v=3', | ||
expect.objectContaining({ | ||
body: JSON.stringify({ | ||
token: 'TEST_API_KEY', | ||
distinct_id: 'some_id', | ||
groups: {}, | ||
person_properties: { | ||
$current_distinct_id: 'some_id', | ||
}, | ||
group_properties: {}, | ||
geoip_disable: true, | ||
}), | ||
}) | ||
) | ||
}) | ||
}) | ||
}) |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
983410
13750