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: add support of custom page event name in mixpanel #1622

Merged
merged 17 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
11 changes: 3 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
"crypto-js": "4.2.0",
"deep-object-diff": "1.1.9",
"get-value": "3.0.1",
"handlebars": "^4.7.8",
Gauravudia marked this conversation as resolved.
Show resolved Hide resolved
"is": "3.3.0",
"lodash.get": "4.4.2",
"lodash.isempty": "4.4.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import {
mapTraits,
filterSetOnceTraits,
unset,
formatTraits
formatTraits,
generatePageOrScreenCustomEventName,
} from '../../../src/integrations/Mixpanel/util';

describe('parseConfigArray', () => {
Expand Down Expand Up @@ -217,12 +218,9 @@ describe('mapTraits', () => {
});
});


describe('filterSetOnceTraits', () => {

// Should return an object with setTraits, setOnce, email, and username keys when given valid outgoingTraits and setOnceProperties inputs
it('should return an object with setTraits, setOnce, email, and username keys', () => {

const outgoingTraits = {
email: '[email protected]',
firstName: 'John',
Expand All @@ -233,10 +231,8 @@ describe('filterSetOnceTraits', () => {
};
const setOnceProperties = ['email', 'username'];


const result = filterSetOnceTraits(outgoingTraits, setOnceProperties);


expect(result).toHaveProperty('setTraits');
expect(result).toHaveProperty('setOnce');
expect(result).toHaveProperty('email');
Expand All @@ -245,7 +241,6 @@ describe('filterSetOnceTraits', () => {

// Should correctly extract and remove setOnceProperties from the outgoingTraits object
it('should correctly extract and remove setOnceProperties', () => {

const outgoingTraits = {
email: '[email protected]',
firstName: 'John',
Expand All @@ -256,10 +251,8 @@ describe('filterSetOnceTraits', () => {
};
const setOnceProperties = ['email', 'username'];


const result = filterSetOnceTraits(outgoingTraits, setOnceProperties);


expect(result.setTraits).not.toHaveProperty('email');
expect(result.setTraits).not.toHaveProperty('username');
expect(result.setOnce).toHaveProperty('email', '[email protected]');
Expand All @@ -268,7 +261,6 @@ describe('filterSetOnceTraits', () => {

// Should correctly handle cases where setOnceProperties are not present in the outgoingTraits object
it('should correctly handle cases where setOnceProperties are not present', () => {

const outgoingTraits = {
firstName: 'John',
lastName: 'Doe',
Expand All @@ -277,11 +269,9 @@ describe('filterSetOnceTraits', () => {
};
const setOnceProperties = ['email', 'username'];


const result = filterSetOnceTraits(outgoingTraits, setOnceProperties);
console.log(result);


expect(result).toHaveProperty('setTraits');
expect(result).toHaveProperty('setOnce');
expect(result).toHaveProperty('email');
Expand All @@ -290,21 +280,17 @@ describe('filterSetOnceTraits', () => {

// Should correctly handle cases where the outgoingTraits object is empty
it('should return an object with empty setTraits and setOnce properties when given an empty outgoingTraits object', () => {

const outgoingTraits = {};
const setOnceProperties = ['email', 'username'];


const result = filterSetOnceTraits(outgoingTraits, setOnceProperties);


expect(result.setTraits).toEqual({});
expect(result.setOnce).toEqual({});
});

// Should correctly handle cases where setOnceProperties are present in the outgoingTraits object but have non-string values
it('should exclude non-string setOnceProperties from the setOnce property in the result object', () => {

const outgoingTraits = {
email: '[email protected]',
firstName: 'John',
Expand All @@ -317,10 +303,8 @@ describe('filterSetOnceTraits', () => {
};
const setOnceProperties = ['email', 'username', 'age', 'gender'];


const result = filterSetOnceTraits(outgoingTraits, setOnceProperties);


expect(result.setOnce).toEqual({
age: 25,
gender: 'male',
Expand All @@ -338,7 +322,6 @@ describe('filterSetOnceTraits', () => {

// Should not modify the original outgoingTraits object
it('should not modify the original outgoingTraits object', () => {

const outgoingTraits = {
email: '[email protected]',
firstName: 'John',
Expand All @@ -349,10 +332,8 @@ describe('filterSetOnceTraits', () => {
};
const setOnceProperties = ['email', 'username'];


filterSetOnceTraits(outgoingTraits, setOnceProperties);


expect(outgoingTraits).toEqual({
email: '[email protected]',
firstName: 'John',
Expand All @@ -365,7 +346,6 @@ describe('filterSetOnceTraits', () => {

// Should correctly handle cases where setOnceProperties contain nested properties
it('should correctly handle cases where setOnceProperties contain nested properties', () => {

const outgoingTraits = {
email: '[email protected]',
firstName: 'John',
Expand All @@ -381,10 +361,8 @@ describe('filterSetOnceTraits', () => {
};
const setOnceProperties = ['address.street', 'address.city'];


const result = filterSetOnceTraits(outgoingTraits, setOnceProperties);


expect(result.setTraits).toEqual({
email: '[email protected]',
firstName: 'John',
Expand All @@ -406,7 +384,6 @@ describe('filterSetOnceTraits', () => {
});

describe('unset', () => {

// Can unset a property at the top level of an object
it('should unset a property at the top level of an object', () => {
const obj = { name: 'John', age: 30 };
Expand Down Expand Up @@ -442,9 +419,7 @@ describe('unset', () => {
});
});


describe('formatTraits', () => {

// Extracts defined traits from message and sets them as outgoing traits
it('should extract defined traits from message and set them as outgoing traits', () => {
// Arrange
Expand All @@ -457,10 +432,9 @@ describe('formatTraits', () => {
phone: '1234567890',
name: 'John Doe',
customField1: 'value1',
customField2: 'value2'
}
}

customField2: 'value2',
},
},
};
const setOnceProperties = ['firstName'];

Expand All @@ -474,12 +448,44 @@ describe('formatTraits', () => {
email: '[email protected]',
name: 'John Doe',
customField1: 'value1',
customField2: 'value2'
customField2: 'value2',
});
expect(result.setOnce).toEqual({
firstName: 'John'
firstName: 'John',
});
});
});

describe('generatePageOrScreenCustomEventName', () => {
it('should generate a custom event name when userDefinedEventTemplate contains handlebars and message object is provided', () => {
saikumarrs marked this conversation as resolved.
Show resolved Hide resolved
const message = { name: 'Home' };
const userDefinedEventTemplate = 'Viewed a {{ name }} page';
const expected = 'Viewed a Home page';
const result = generatePageOrScreenCustomEventName(message, userDefinedEventTemplate);
expect(result).toBe(expected);
});

it('should generate a empty event name when userDefinedEventTemplate is undefined/null/empty', () => {
const message = { name: 'Home' };
const userDefinedEventTemplate = undefined;
const expected = '';
const result = generatePageOrScreenCustomEventName(message, userDefinedEventTemplate);
expect(result).toBe(expected);
});

it('should return the userDefinedEventTemplate when it does not contain handlebars', () => {
const message = { name: 'Home' };
const userDefinedEventTemplate = 'Viewed a Home page';
const expected = 'Viewed a Home page';
const result = generatePageOrScreenCustomEventName(message, userDefinedEventTemplate);
expect(result).toBe(expected);
});

it('should return a event name when message object is not provided', () => {
const message = undefined;
const userDefinedEventTemplate = 'Viewed a {{ path }} page';
const expected = 'Viewed a page';
const result = generatePageOrScreenCustomEventName(message, userDefinedEventTemplate);
expect(result).toBe(expected);
});
});
Gauravudia marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
parseConfigArray,
inverseObjectArrays,
getConsolidatedPageCalls,
generatePageOrScreenCustomEventName,
} from './util';
import { loadNativeSdk } from './nativeSdkLoader';

Expand Down Expand Up @@ -63,6 +64,8 @@
destinationId: this.destinationId,
} = destinationInfo ?? {});
this.ignoreDnt = config.ignoreDnt || false;
this.useUserDefinedPageEventName = config.useUserDefinedPageEventName || false;
this.userDefinedPageEventTemplate = config.userDefinedPageEventTemplate;
}

init() {
Expand Down Expand Up @@ -181,7 +184,24 @@
* @param {*} rudderElement
*/
page(rudderElement) {
const { name, properties } = rudderElement.message;
const { properties } = rudderElement.message;

Check warning on line 187 in packages/analytics-js-integrations/src/integrations/Mixpanel/browser.js

View check run for this annotation

Codecov / codecov/patch

packages/analytics-js-integrations/src/integrations/Mixpanel/browser.js#L187

Added line #L187 was not covered by tests

if (this.useUserDefinedPageEventName) {
if (!this.userDefinedPageEventTemplate) {
logger.error(

Check warning on line 191 in packages/analytics-js-integrations/src/integrations/Mixpanel/browser.js

View check run for this annotation

Codecov / codecov/patch

packages/analytics-js-integrations/src/integrations/Mixpanel/browser.js#L191

Added line #L191 was not covered by tests
'Event template is missing. Please provide a valid event template in `Page/Screen Event Name Template` setting',
);
return;

Check warning on line 194 in packages/analytics-js-integrations/src/integrations/Mixpanel/browser.js

View check run for this annotation

Codecov / codecov/patch

packages/analytics-js-integrations/src/integrations/Mixpanel/browser.js#L194

Added line #L194 was not covered by tests
}
const eventName = generatePageOrScreenCustomEventName(

Check warning on line 196 in packages/analytics-js-integrations/src/integrations/Mixpanel/browser.js

View check run for this annotation

Codecov / codecov/patch

packages/analytics-js-integrations/src/integrations/Mixpanel/browser.js#L196

Added line #L196 was not covered by tests
rudderElement.message,
this.userDefinedPageEventTemplate,
);
window.mixpanel.track(eventName, properties);
saikumarrs marked this conversation as resolved.
Show resolved Hide resolved
return;

Check warning on line 201 in packages/analytics-js-integrations/src/integrations/Mixpanel/browser.js

View check run for this annotation

Codecov / codecov/patch

packages/analytics-js-integrations/src/integrations/Mixpanel/browser.js#L200-L201

Added lines #L200 - L201 were not covered by tests
}
Gauravudia marked this conversation as resolved.
Show resolved Hide resolved

const { name } = rudderElement.message;

Check warning on line 204 in packages/analytics-js-integrations/src/integrations/Mixpanel/browser.js

View check run for this annotation

Codecov / codecov/patch

packages/analytics-js-integrations/src/integrations/Mixpanel/browser.js#L204

Added line #L204 was not covered by tests
const { category } = properties;
// consolidated Page Calls
if (this.consolidatedPageCalls) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
/* eslint-disable no-prototype-builtins */
import get from 'get-value';
import { DISPLAY_NAME } from '@rudderstack/analytics-js-common/constants/integrations/Mixpanel/constants';
import Handlebars from 'handlebars';
import Logger from '../../utils/logger';
import { getDefinedTraits, extractCustomFields } from '../../utils/utils';

Expand Down Expand Up @@ -38,7 +39,7 @@ const traitAliases = {

/**
* Removes a property from an object based on a given property path.
*
*
* @param {object} obj - The object from which the property needs to be removed.
* @param {string} propertyPath - The path of the property to be removed, using dot notation.
* @returns {undefined} - This function does not return anything.
Expand All @@ -54,7 +55,7 @@ const traitAliases = {
* }
* }
* };
*
*
* unset(obj, 'person.address.city');
* Output: { person: { name: 'John', age: 30, address: { state: 'NY' } } }
*/
Expand Down Expand Up @@ -82,7 +83,7 @@ function filterSetOnceTraits(outgoingTraits, setOnceProperties) {

// Step 1: find the k-v pairs of setOnceProperties in traits and contextTraits

setOnceProperties.forEach((propertyPath) => {
setOnceProperties.forEach(propertyPath => {
const pathSegments = propertyPath.split('.');
const propName = pathSegments[pathSegments.length - 1];

Expand Down Expand Up @@ -239,6 +240,18 @@ const getConsolidatedPageCalls = config =>
? config.consolidatedPageCalls
: true;

/**
* Generates a custom event name for a page or screen.
*
* @param {Object} message - The message object
* @param {string} userDefinedEventTemplate - The user-defined event template to be used for generating the event name.
* @returns {string} The generated custom event name.
*/
const generatePageOrScreenCustomEventName = (message, userDefinedEventTemplate) => {
const eventTemplate = Handlebars.compile(userDefinedEventTemplate || '');
return eventTemplate(message);
};
Gauravudia marked this conversation as resolved.
Show resolved Hide resolved

export {
mapTraits,
unionArrays,
Expand All @@ -249,5 +262,6 @@ export {
inverseObjectArrays,
getConsolidatedPageCalls,
filterSetOnceTraits,
unset
unset,
generatePageOrScreenCustomEventName,
};
Loading