Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: posthog feature flag #1955

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,20 @@ jest.mock('../../../src/utils/logger', () => {
afterAll(() => {
jest.restoreAllMocks();
});

let config = {
teamApiKey: 'YOUR_TEAM_API_KEY',
yourInstance: 'https://app.posthog.com',
autocapture: true,
capturePageView: true,
disableSessionRecording: false,
disableCookie: false,
propertyBlackList: ['name'],
personProfiles: 'always',
};

let posthogInstance;

beforeEach(() => {
// Reset the logger method mocks
errMock = jest.fn();
Expand All @@ -43,17 +56,6 @@ const destinationInfo = {
destinationId: 'sample-destination-id',
};

const config = {
teamApiKey: 'YOUR_TEAM_API_KEY',
yourInstance: 'https://app.posthog.com',
autocapture: true,
capturePageView: true,
disableSessionRecording: false,
disableCookie: false,
propertyBlackList: ['name'],
personProfiles: 'always'
};

const analytics = {
logLevel: 'INFO',
};
Expand Down Expand Up @@ -93,6 +95,67 @@ describe('Posthog Test', () => {

expect(isLoaded).toBe(true);
});

it('should include featureFlags in bootstrap when featureFlags is non-empty', () => {
const testConfig = {
...config,
flags: [
{ flag: 'flag-1', value: 'true' },
{ flag: 'flag-2', value: 'false' },
{ flag: 'flag-3', value: 'abcd' },
],
};
posthogInstance = new Posthog(testConfig, analytics, destinationInfo);
posthogInstance.init();
expect(posthogInstance.name).toBe('POSTHOG');
expect(posthogInstance.analytics).toBe(analytics);
expect(window.posthog._i[0][1].bootstrap).toStrictEqual({
featureFlags: { 'flag-1': true, 'flag-2': false, 'flag-3': 'abcd' },
});
});

it('should not include featureFlags in bootstrap when featureFlags is empty', () => {
const testConfig = {
...config,
flags: [],
};

posthogInstance = new Posthog(testConfig, analytics, destinationInfo);
posthogInstance.init();

expect(posthogInstance.name).toBe('POSTHOG');
expect(posthogInstance.analytics).toBe(analytics);

// Validate no featureFlags are included
expect(window.posthog._i[0][1].bootstrap).toStrictEqual(undefined);
});

it('should exclude invalid featureFlags values', () => {
const testConfig = {
...config,
flags: [
{ flag: 'flag-1', value: 'true' },
{ flag: 'flag-2', value: undefined },
{ flag: 'flag-3' },
{ value: 'val' },
{ flag: 'flag-5', value: 'control' },
],
};

posthogInstance = new Posthog(testConfig, analytics, destinationInfo);
posthogInstance.init();

expect(posthogInstance.name).toBe('POSTHOG');
expect(posthogInstance.analytics).toBe(analytics);

// Validate only valid flags are included
expect(window.posthog._i[0][1].bootstrap).toStrictEqual({
featureFlags: {
'flag-1': true,
'flag-5': 'control',
},
});
});
});
describe('processSuperProperties', () => {
it('should call posthog.register when superProperties is present', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
} from '@rudderstack/analytics-js-common/constants/integrations/Posthog/constants';
import Logger from '../../utils/logger';
import { isDefinedAndNotNull, removeTrailingSlashes } from '../../utils/utils';
import { getXhrHeaders, getPropertyBlackList, getDestinationOptions } from './utils';
import { getXhrHeaders, getPropertyBlackList, getDestinationOptions, getFlags } from './utils';
import { loadNativeSdk } from './nativeSdkLoader';

const logger = new Logger(DISPLAY_NAME);
Expand All @@ -22,14 +22,15 @@ class Posthog {
this.analytics = analytics;
this.teamApiKey = config.teamApiKey;
this.yourInstance = removeTrailingSlashes(config.yourInstance) || 'https://app.posthog.com';
this.flags = getFlags(config);
this.autocapture = config.autocapture || false;
this.capturePageView = config.capturePageView || false;
this.disableSessionRecording = config.disableSessionRecording || false;
this.disableCookie = config.disableCookie || false;
this.propertyBlackList = getPropertyBlackList(config);
this.xhrHeaders = getXhrHeaders(config);
this.enableLocalStoragePersistence = config.enableLocalStoragePersistence;
if(isDefinedAndNotNull(config.personProfiles)) {
if (isDefinedAndNotNull(config.personProfiles)) {
this.personProfiles = config.personProfiles;
}
({
Expand All @@ -55,7 +56,7 @@ class Posthog {
disable_cookie: this.disableCookie,
};

if(this.personProfiles) {
if (this.personProfiles) {
configObject.person_profiles = this.personProfiles;
}

Expand All @@ -69,6 +70,10 @@ class Posthog {
configObject.persistence = 'localStorage+cookie';
}

if (this.flags && Object.keys(this.flags).length > 0) {
configObject.bootstrap = { featureFlags: this.flags };
}

posthog.init(this.teamApiKey, configObject);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,34 @@ const getPropertyBlackList = config => {
return propertyBlackList;
};

export { getXhrHeaders, getPropertyBlackList, getDestinationOptions };
/**
* Returns bootstrap flags object
* @param {*} config
* @returns
*/
const getFlags = config => {
const flags = {};
if (config.flags && config.flags.length > 0) {
config.flags.forEach(bootstrapFlag => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
config.flags.forEach(bootstrapFlag => {
config.flags.forEach({flag, value} => {

if (
bootstrapFlag?.flag?.trim() &&
bootstrapFlag?.value?.trim()
) {
// parsing value to boolean if it's "true" or "false", otherwise keep as is
let parsedValue =
bootstrapFlag.value.toLowerCase() === "true"
? true
: bootstrapFlag.value.toLowerCase() === "false"
? false
: bootstrapFlag.value;

flags[bootstrapFlag.flag] = parsedValue;
}
});
}

return flags;
};

export { getXhrHeaders, getPropertyBlackList, getDestinationOptions, getFlags };