Skip to content
This repository has been archived by the owner on May 30, 2024. It is now read-only.

Commit

Permalink
prepare 5.14.0 release (#204)
Browse files Browse the repository at this point in the history
  • Loading branch information
LaunchDarklyCI authored Jan 29, 2021
1 parent a0f0f53 commit 84f71f4
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 0 deletions.
25 changes: 25 additions & 0 deletions event_factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ function EventFactory(withReasons) {
return false;
}

function userContextKind(user) {
return user.anonymous ? 'anonymousUser' : 'user';
}

ef.newEvalEvent = (flag, user, detail, defaultVal, prereqOfFlag) => {
const addExperimentData = isExperiment(flag, detail.reason);
const e = {
Expand All @@ -44,6 +48,9 @@ function EventFactory(withReasons) {
if (addExperimentData || withReasons) {
e.reason = detail.reason;
}
if (user && user.anonymous) {
e.contextKind = userContextKind(user);
}
return e;
};

Expand All @@ -67,6 +74,9 @@ function EventFactory(withReasons) {
if (withReasons) {
e.reason = detail.reason;
}
if (user && user.anonymous) {
e.contextKind = userContextKind(user);
}
return e;
};

Expand All @@ -82,6 +92,9 @@ function EventFactory(withReasons) {
if (withReasons) {
e.reason = detail.reason;
}
if (user && user.anonymous) {
e.contextKind = userContextKind(user);
}
return e;
};

Expand All @@ -102,12 +115,24 @@ function EventFactory(withReasons) {
if (data !== null && data !== undefined) {
e.data = data;
}
if (user && user.anonymous) {
e.contextKind = userContextKind(user);
}
if (metricValue !== null && metricValue !== undefined) {
e.metricValue = metricValue;
}
return e;
};

ef.newAliasEvent = (user, previousUser) => ({
kind: 'alias',
key: user.key,
contextKind: userContextKind(user),
previousKey: previousUser.key,
previousContextKind: userContextKind(previousUser),
creationDate: new Date().getTime(),
});

return ef;
}

Expand Down
15 changes: 15 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -981,6 +981,21 @@ declare module 'launchdarkly-node-server-sdk' {
* as part of the custom event for Data Export.
*/
track(key: string, user: LDUser, data?: any, metricValue?: number): void;

/**
* Associates two users for analytics purposes.
*
* This can be helpful in the situation where a person is represented by multiple
* LaunchDarkly users. This may happen, for example, when a person initially logs into
* an application-- the person might be represented by an anonymous user prior to logging
* in and a different user after logging in, as denoted by a different user key.
*
* @param user
* The newly identified user.
* @param previousUser
* The previously identified user.
*/
alias(user: LDUser, previousUser: LDUser): void;

/**
* Identifies a user to LaunchDarkly.
Expand Down
8 changes: 8 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,14 @@ const newClient = function(sdkKey, originalConfig) {

client.isOffline = () => config.offline;

client.alias = (user, previousUser) => {
if (!user || !previousUser) {
return;
}

eventProcessor.sendEvent(eventFactoryDefault.newAliasEvent(user, previousUser));
};

client.track = (eventName, user, data, metricValue) => {
if (!userExistsAndHasKey(user)) {
config.logger.warn(messages.missingUserKeyNoEvent());
Expand Down
3 changes: 3 additions & 0 deletions test-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ var allOptions: ld.LDOptions = {
wrapperVersion: 'y'
};
var userWithKeyOnly: ld.LDUser = { key: 'user' };
var anonymousUser: ld.LDUser = { key: 'anon-user', anonymous: true };
var user: ld.LDUser = {
key: 'user',
name: 'name',
Expand Down Expand Up @@ -69,6 +70,8 @@ client.track('key', user);
client.track('key', user, { ok: 1 });
client.track('key', user, null, 1.5);

client.alias(user, anonymousUser);

// evaluation methods with callbacks
client.variation('key', user, false, (value: ld.LDFlagValue) => { });
client.variation('key', user, 2, (value: ld.LDFlagValue) => { });
Expand Down
134 changes: 134 additions & 0 deletions test/LDClient-events-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ describe('LDClient - analytics events', () => {

var eventProcessor;
var defaultUser = { key: 'user' };
var anonymousUser = { key: 'anon-user', anonymous: true };
var userWithNoKey = { name: 'Keyless Joe' };
var userWithEmptyKey = { key: '' };

Expand Down Expand Up @@ -40,6 +41,35 @@ describe('LDClient - analytics events', () => {
});
});

it('generates event for existing feature when user is anonymous', async () => {
var flag = {
key: 'flagkey',
version: 1,
on: true,
targets: [],
fallthrough: { variation: 1 },
variations: ['a', 'b'],
trackEvents: true
};
var client = stubs.createClient({ eventProcessor: eventProcessor }, { flagkey: flag });
await client.waitForInitialization();
await client.variation(flag.key, anonymousUser, 'c');

expect(eventProcessor.events).toHaveLength(1);
var e = eventProcessor.events[0];
expect(e).toMatchObject({
kind: 'feature',
key: 'flagkey',
version: 1,
user: anonymousUser,
contextKind: 'anonymousUser',
variation: 1,
value: 'b',
default: 'c',
trackEvents: true
});
});

it('generates event for existing feature with reason', async () => {
var flag = {
key: 'flagkey',
Expand Down Expand Up @@ -215,6 +245,23 @@ describe('LDClient - analytics events', () => {
});
});

it('generates event for unknown feature when user is anonymous', async () => {
var client = stubs.createClient({ eventProcessor: eventProcessor }, {});
await client.waitForInitialization();
await client.variation('flagkey', anonymousUser, 'c');

expect(eventProcessor.events).toHaveLength(1);
var e = eventProcessor.events[0];
expect(e).toMatchObject({
kind: 'feature',
key: 'flagkey',
user: anonymousUser,
contextKind: 'anonymousUser',
value: 'c',
default: 'c'
});
});

it('generates event for existing feature when user key is missing', async () => {
var flag = {
key: 'flagkey',
Expand Down Expand Up @@ -376,6 +423,25 @@ describe('LDClient - analytics events', () => {
expect(logger.warn).not.toHaveBeenCalled();
});

it('generates an event for an anonymous user', async () => {
var data = { thing: 'stuff' };
var logger = stubs.stubLogger();
var client = stubs.createClient({ eventProcessor: eventProcessor, logger: logger }, {});
await client.waitForInitialization();

client.track('eventkey', anonymousUser, data);
expect(eventProcessor.events).toHaveLength(1);
var e = eventProcessor.events[0];
expect(e).toMatchObject({
kind: 'custom',
key: 'eventkey',
user: anonymousUser,
contextKind: 'anonymousUser',
data: data
});
expect(logger.warn).not.toHaveBeenCalled();
});

it('does not generate an event, and logs a warning, if user is missing', async () => {
var logger = stubs.stubLogger();
var client = stubs.createClient({ eventProcessor: eventProcessor, logger: logger }, {});
Expand Down Expand Up @@ -406,4 +472,72 @@ describe('LDClient - analytics events', () => {
expect(logger.warn).toHaveBeenCalledTimes(1);
});
});

describe('alias', () => {
it('generates an event for aliasing anonymous to known', async () => {
var client = stubs.createClient({ eventProcessor: eventProcessor }, {});
await client.waitForInitialization();

client.alias(defaultUser, anonymousUser);
expect(eventProcessor.events).toHaveLength(1);
var e = eventProcessor.events[0];
expect(e).toMatchObject({
kind: 'alias',
key: 'user',
previousKey: 'anon-user',
contextKind: 'user',
previousContextKind: 'anonymousUser'
});
});

it('generates an event for aliasing known to known', async () => {
var anotherUser = { key: 'another-user' };
var client = stubs.createClient({ eventProcessor: eventProcessor }, {});
await client.waitForInitialization();

client.alias(defaultUser, anotherUser);
expect(eventProcessor.events).toHaveLength(1);
var e = eventProcessor.events[0];
expect(e).toMatchObject({
kind: 'alias',
key: 'user',
previousKey: 'another-user',
contextKind: 'user',
previousContextKind: 'user'
});
});

it('generates an event for aliasing anonymous to anonymous', async () => {
var anotherAnonymousUser = { key: 'another-anon-user', anonymous: true };
var client = stubs.createClient({ eventProcessor: eventProcessor }, {});
await client.waitForInitialization();

client.alias(anonymousUser, anotherAnonymousUser);
expect(eventProcessor.events).toHaveLength(1);
var e = eventProcessor.events[0];
expect(e).toMatchObject({
kind: 'alias',
key: 'anon-user',
previousKey: 'another-anon-user',
contextKind: 'anonymousUser',
previousContextKind: 'anonymousUser'
});
});

it('generates an event for aliasing known to anonymous', async () => {
var client = stubs.createClient({ eventProcessor: eventProcessor }, {});
await client.waitForInitialization();

client.alias(anonymousUser, defaultUser);
expect(eventProcessor.events).toHaveLength(1);
var e = eventProcessor.events[0];
expect(e).toMatchObject({
kind: 'alias',
key: 'anon-user',
previousKey: 'user',
contextKind: 'anonymousUser',
previousContextKind: 'user'
});
});
});
});

0 comments on commit 84f71f4

Please sign in to comment.