Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
@@ -0,0 +1,151 @@
import Wingify from '../../../src/integrations/Wingify/browser';
import { integrations } from '../../../src/integrations/index';

const destinationInfo = {
areTransformationsConnected: false,
destinationId: 'sample-destination-id',
};

const mockWingify = new Wingify(
{
accountId: '654331',
settingsTolerance: 2000,
libraryTolerance: 2500,
isSPA: 1,
useExistingJquery: false,
sendExperimentTrack: false,
sendExperimentIdentify: false,
},
{ loglevel: 'debug', loadOnlyIntegrations: { Wingify: { loadIntegration: true } } },
destinationInfo,
);

describe('Wingify registry', () => {
test('should be registered in integrations map', () => {
expect(integrations.WINGIFY).toBeDefined();
expect(typeof integrations.WINGIFY).toBe('function');
});
});

describe('Wingify init tests', () => {
let wingify;

test('Testing init call of Wingify', () => {
wingify = new Wingify(
{
accountId: '654331',
settingsTolerance: 2000,
libraryTolerance: 2500,
isSPA: 1,
useExistingJquery: false,
sendExperimentTrack: false,
sendExperimentIdentify: false,
},
{ loglevel: 'debug', loadOnlyIntegrations: { Wingify: { loadIntegration: true } } },
destinationInfo,
);
wingify.init();
const script = window.document.querySelector(
'script[src="https://edge.wingify.net/tag/654331.js"]',
);
expect(script).toBeDefined();
Comment thread
zeeshan-vwo marked this conversation as resolved.
Outdated
});
});

describe('Wingify Track Event', () => {
beforeEach(() => {
jest.restoreAllMocks();
jest.spyOn(mockWingify, 'init').mockImplementation(() => {
window.WINGIFY = {
push: jest.fn(),
event: jest.fn(),
};
return Promise.resolve(window.WINGIFY);
});
});

test('Track call without parameters', async () => {
mockWingify.init();
mockWingify.track({
message: {
context: {},
event: 'buttonClicked',
},
});
expect(window.WINGIFY.event).toHaveBeenCalled();
expect(window.WINGIFY.event).toHaveBeenCalledWith(
'rudder.buttonClicked',
{},
{
ogName: 'buttonClicked',
source: 'rudderstack',
},
);
});

test('Track call with parameters', async () => {
mockWingify.init();
mockWingify.track({
message: {
context: {},
event: 'checkoutCompleted',
properties: {
category: 'Food',
currency: 'INR',
total: 123,
},
},
});
expect(window.WINGIFY.event).toHaveBeenCalled();
expect(window.WINGIFY.event).toHaveBeenCalledWith(
'rudder.checkoutCompleted',
{
category: 'Food',
currency: 'INR',
total: 123,
},
{
ogName: 'checkoutCompleted',
source: 'rudderstack',
},
);
});
});

describe('Wingify Identify Event', () => {
beforeEach(() => {
jest.restoreAllMocks();
jest.spyOn(mockWingify, 'init').mockImplementation(() => {
window.WINGIFY = {
push: jest.fn(),
visitor: jest.fn(),
};
return Promise.resolve(window.WINGIFY);
});
});

test('Vistor call with attributes', async () => {
Comment thread
zeeshan-vwo marked this conversation as resolved.
Outdated
Comment thread
zeeshan-vwo marked this conversation as resolved.
Outdated
mockWingify.init();
mockWingify.identify({
message: {
userId: 'rudder01',
context: {
traits: {
email: 'abc@ruddertack.com',
Comment thread
zeeshan-vwo marked this conversation as resolved.
Outdated
isRudderEvents: true,
},
},
},
});
expect(window.WINGIFY.visitor).toHaveBeenCalled();
expect(window.WINGIFY.visitor).toHaveBeenCalledWith(
{
'rudder.email': 'abc@ruddertack.com',
'rudder.isRudderEvents': true,
},
{
source: 'rudderstack',
},
);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { sanitizeName, sanitizeAttributes } from '../../../src/integrations/Wingify/utils';

describe('Wingify utilities tests', () => {
describe('Sanitize Names', () => {
it('should trim and add the rudder prefix to the event name', () => {
const name1 = 'abcd';
const name2 = ' abcd ';

const expectedName = 'rudder.abcd';

const result1 = sanitizeName(name1);
const result2 = sanitizeName(name2);

expect(result1).toEqual(expectedName);
expect(result2).toEqual(expectedName);
});
});

describe('Sanitize Attributes', () => {
it('should sanitize all the keys of the traits object', () => {
const attributes = {
companySize: 100,
companyName: 'RudderStack',
};

const expectedAttributes = {
'rudder.companySize': 100,
'rudder.companyName': 'RudderStack',
};

const result = sanitizeAttributes(attributes);

expect(result).toEqual(expectedAttributes);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ export const VERO_NAME = 'VERO';
export const VERO_DISPLAY_NAME = 'Vero';
export const VWO_NAME = 'VWO';
export const VWO_DISPLAY_NAME = 'VWO';
export const WINGIFY_NAME = 'WINGIFY';
export const WINGIFY_DISPLAY_NAME = 'Wingify';
export const WOOPRA_NAME = 'WOOPRA';
export const WOOPRA_DISPLAY_NAME = 'WOOPRA';
export const XPIXEL_NAME = 'XPIXEL';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/* eslint-disable @typescript-eslint/naming-convention */
/* eslint-disable no-undef */
/* eslint-disable no-underscore-dangle */
/* eslint-disable class-methods-use-this */
/* eslint-disable camelcase */
import { NAME, DISPLAY_NAME } from './constants';
import Logger from '../../utils/logger';
import { getDestinationOptions, sanitizeName, sanitizeAttributes } from './utils';
import { loadNativeSdk } from './nativeSdkLoader';

const logger = new Logger(DISPLAY_NAME);

class Wingify {
constructor(config, analytics, destinationInfo) {
if (analytics.logLevel) {
logger.setLogLevel(analytics.logLevel);
}
this.analytics = analytics;
this.accountId = config.accountId;
this.settingsTolerance = config.settingsTolerance;
this.isSPA = config.isSPA;
this.libraryTolerance = config.libraryTolerance;
this.useExistingJquery = config.useExistingJquery;
this.sendExperimentTrack = config.sendExperimentTrack;
this.sendExperimentIdentify = config.sendExperimentIdentify;
this.name = NAME;
({
shouldApplyDeviceModeTransformation: this.shouldApplyDeviceModeTransformation,
propagateEventsUntransformedOnError: this.propagateEventsUntransformedOnError,
destinationId: this.destinationId,
} = destinationInfo ?? {});
}

init() {
const wingifyIntgConfig = getDestinationOptions(this.analytics.loadOnlyIntegrations);
if (wingifyIntgConfig?.loadIntegration) {
const account_id = this.accountId;
const settings_tolerance = this.settingsTolerance;
loadNativeSdk(account_id, settings_tolerance);
} else {
logger.info('loadIntegration flag is disabled');
}

window.WINGIFY = window.WINGIFY || [];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could we update this integration to use the documented window.Wingify global? Current Wingify examples initialize window.Wingify, so calls queued on window.WINGIFY will not reach SmartCode unless Wingify confirms an alias. Please add a contract test against window.Wingify instead of an uppercase local shim.

window.WINGIFY.event =
window.WINGIFY.event ||
function (...args) {
window.WINGIFY.push(['event', ...args]);
};

window.WINGIFY.visitor =
window.WINGIFY.visitor ||
function (...args) {
window.WINGIFY.push(['visitor', ...args]);
};

if (this.sendExperimentTrack || this.sendExperimentIdentify) {
this.experimentViewed();
}
}

isLoaded() {
return !!window._wingify_code;
}

isReady() {
return this.isLoaded();
}

experimentViewed() {
window.WINGIFY = window.WINGIFY || [];
window.WINGIFY.push([
'onVariationApplied',
data => {
if (!data) {
return;
}
const expId = data[1];
const variationId = data[2];
logger.info(
'experiment id:',
expId,
'Variation Name:',
_wingify_exp[expId].comb_n[variationId],
);
if (
typeof _wingify_exp[expId].comb_n[variationId] !== 'undefined' &&
['VISUAL_AB', 'VISUAL', 'SPLIT_URL', 'SURVEY'].indexOf(_wingify_exp[expId].type) > -1
) {
Comment thread
zeeshan-vwo marked this conversation as resolved.
Outdated
Comment thread
zeeshan-vwo marked this conversation as resolved.
try {
if (this.sendExperimentTrack) {
this.analytics.track('Experiment Viewed', {
experimentId: expId,
variationName: _wingify_exp[expId].comb_n[variationId],
CampaignName: _wingify_exp[expId].name,
VariationId: variationId,
});
}
} catch (error) {
logger.error('experimentViewed', error);
}
try {
if (this.sendExperimentIdentify) {
this.analytics.identify({
[`Experiment: ${expId}`]: _wingify_exp[expId].comb_n[variationId],
});
}
} catch (error) {
logger.error('experimentViewed', error);
}
}
},
]);
}

identify(rudderElement) {
const { message } = rudderElement;
const { traits } = message.context || message;
const payload = traits || {};
const formattedAttributes = sanitizeAttributes(payload);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

window.WINGIFY.visitor(formattedAttributes, { source: 'rudderstack' });
}

track(rudderElement) {
const eventName = rudderElement.message.event;
if (!eventName) {
logger.error('[WINGIFY] track:: event name is required');
return;
}
Comment thread
zeeshan-vwo marked this conversation as resolved.
Outdated
const properties = rudderElement.message?.properties || {};
window.WINGIFY = window.WINGIFY || [];
if (eventName === 'Order Completed') {
const total = rudderElement.message.properties
? rudderElement.message.properties.total || rudderElement.message.properties.revenue
: 0;
window.WINGIFY = window.WINGIFY || [];
window.WINGIFY.push(['track.revenueConversion', total]);
}
const sanitizedEventName = sanitizeName(eventName);
Comment thread
zeeshan-vwo marked this conversation as resolved.
logger.debug(`[WINGIFY] eventName: ${sanitizedEventName}`);
window.WINGIFY.event(sanitizedEventName, properties, { source: 'rudderstack', ogName: eventName });
}
}

export default Wingify;
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { WINGIFY_NAME as NAME, WINGIFY_DISPLAY_NAME as DISPLAY_NAME } from '../../constants/Destinations';

const DIR_NAME = 'Wingify';

const CNameMapping = {
[NAME]: NAME,
Wingify: NAME,
wingify: NAME,
WINGIFY: NAME,
};

export { NAME, CNameMapping, DISPLAY_NAME, DIR_NAME };
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as Wingify } from './browser';
Comment thread
zeeshan-vwo marked this conversation as resolved.
Loading