element-web/test/PosthogAnalytics-test.ts

216 lines
8 KiB
TypeScript
Raw Normal View History

import {
Anonymity,
getRedactedCurrentLocation,
IAnonymousEvent,
IPseudonymousEvent,
IRoomEvent,
PosthogAnalytics,
} from '../src/PosthogAnalytics';
2021-07-21 09:40:39 +03:00
import SdkConfig from '../src/SdkConfig';
class FakePosthog {
public capture;
public init;
2021-07-21 10:38:58 +03:00
public identify;
2021-07-28 11:37:08 +03:00
public reset;
public register;
2021-07-21 09:40:39 +03:00
constructor() {
this.capture = jest.fn();
this.init = jest.fn();
2021-07-21 10:38:58 +03:00
this.identify = jest.fn();
2021-07-28 11:37:08 +03:00
this.reset = jest.fn();
this.register = jest.fn();
2021-07-21 09:40:39 +03:00
}
}
2021-07-21 10:23:42 +03:00
export interface ITestEvent extends IAnonymousEvent {
2021-07-28 13:28:19 +03:00
key: "jest_test_event";
2021-07-21 09:40:39 +03:00
properties: {
2021-07-28 13:28:19 +03:00
foo: string;
};
2021-07-21 09:40:39 +03:00
}
2021-07-23 18:47:02 +03:00
export interface ITestPseudonymousEvent extends IPseudonymousEvent {
2021-07-28 13:28:19 +03:00
key: "jest_test_pseudo_event";
2021-07-23 18:47:02 +03:00
properties: {
2021-07-28 13:28:19 +03:00
foo: string;
};
2021-07-23 18:47:02 +03:00
}
2021-07-21 10:23:42 +03:00
export interface ITestRoomEvent extends IRoomEvent {
2021-07-28 13:28:19 +03:00
key: "jest_test_room_event";
2021-07-21 10:23:42 +03:00
properties: {
2021-07-28 13:28:19 +03:00
foo: string;
};
2021-07-21 10:23:42 +03:00
}
2021-07-21 09:40:39 +03:00
describe("PosthogAnalytics", () => {
let fakePosthog: FakePosthog;
const shaHashes = {
"42": "73475cb40a568e8da8a045ced110137e159f890ac4da883b6b17dc651b3a8049",
"some": "a6b46dd0d1ae5e86cbc8f37e75ceeb6760230c1ca4ffbcb0c97b96dd7d9c464b",
"pii": "bd75b3e080945674c0351f75e0db33d1e90986fa07b318ea7edf776f5eef38d4",
"foo": "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae",
};
2021-07-21 09:40:39 +03:00
beforeEach(() => {
fakePosthog = new FakePosthog();
2021-07-28 11:37:08 +03:00
2021-07-21 09:40:39 +03:00
window.crypto = {
subtle: {
digest: async (_, encodedMessage) => {
const message = new TextDecoder().decode(encodedMessage);
const hexHash = shaHashes[message];
const bytes = [];
for (let c = 0; c < hexHash.length; c += 2) {
bytes.push(parseInt(hexHash.substr(c, 2), 16));
}
return bytes;
},
},
2021-07-21 09:40:39 +03:00
};
});
afterEach(() => {
window.crypto = null;
});
describe("Initialisation", () => {
2021-07-28 11:37:08 +03:00
it("Should not be enabled without config being set", () => {
jest.spyOn(SdkConfig, "get").mockReturnValue({});
2021-07-28 11:37:08 +03:00
const analytics = new PosthogAnalytics(fakePosthog);
expect(analytics.isEnabled()).toBe(false);
});
2021-07-21 09:40:39 +03:00
2021-07-28 11:37:08 +03:00
it("Should be enabled if config is set", () => {
jest.spyOn(SdkConfig, "get").mockReturnValue({
posthog: {
projectApiKey: "foo",
apiHost: "bar",
},
});
2021-07-28 11:37:08 +03:00
const analytics = new PosthogAnalytics(fakePosthog);
analytics.setAnonymity(Anonymity.Pseudonymous);
expect(analytics.isEnabled()).toBe(true);
2021-07-21 09:40:39 +03:00
});
});
describe("Tracking", () => {
2021-07-28 11:37:08 +03:00
let analytics: PosthogAnalytics;
beforeEach(() => {
jest.spyOn(SdkConfig, "get").mockReturnValue({
posthog: {
projectApiKey: "foo",
apiHost: "bar",
},
});
2021-07-28 11:37:08 +03:00
analytics = new PosthogAnalytics(fakePosthog);
2021-07-21 09:40:39 +03:00
});
2021-07-23 18:47:02 +03:00
it("Should pass trackAnonymousEvent() to posthog", async () => {
2021-07-28 11:37:08 +03:00
analytics.setAnonymity(Anonymity.Pseudonymous);
await analytics.trackAnonymousEvent<ITestEvent>("jest_test_event", {
foo: "bar",
});
expect(fakePosthog.capture.mock.calls[0][0]).toBe("jest_test_event");
expect(fakePosthog.capture.mock.calls[0][1]["foo"]).toEqual("bar");
});
2021-07-21 10:23:42 +03:00
it("Should pass trackRoomEvent to posthog", async () => {
2021-07-28 11:37:08 +03:00
analytics.setAnonymity(Anonymity.Pseudonymous);
const roomId = "42";
await analytics.trackRoomEvent<IRoomEvent>("jest_test_event", roomId, {
foo: "bar",
});
expect(fakePosthog.capture.mock.calls[0][0]).toBe("jest_test_event");
expect(fakePosthog.capture.mock.calls[0][1]["foo"]).toEqual("bar");
expect(fakePosthog.capture.mock.calls[0][1]["hashedRoomId"])
.toEqual("73475cb40a568e8da8a045ced110137e159f890ac4da883b6b17dc651b3a8049");
2021-07-21 10:23:42 +03:00
});
2021-07-21 10:38:58 +03:00
2021-07-23 18:47:02 +03:00
it("Should pass trackPseudonymousEvent() to posthog", async () => {
2021-07-28 11:37:08 +03:00
analytics.setAnonymity(Anonymity.Pseudonymous);
2021-07-23 18:47:02 +03:00
await analytics.trackPseudonymousEvent<ITestEvent>("jest_test_pseudo_event", {
foo: "bar",
});
2021-07-23 18:47:02 +03:00
expect(fakePosthog.capture.mock.calls[0][0]).toBe("jest_test_pseudo_event");
expect(fakePosthog.capture.mock.calls[0][1]["foo"]).toEqual("bar");
});
it("Should not track pseudonymous messages if anonymous", async () => {
2021-07-28 11:37:08 +03:00
analytics.setAnonymity(Anonymity.Anonymous);
await analytics.trackPseudonymousEvent<ITestEvent>("jest_test_event", {
foo: "bar",
});
expect(fakePosthog.capture.mock.calls.length).toBe(0);
});
2021-07-21 15:48:10 +03:00
2021-07-23 18:47:02 +03:00
it("Should not track any events if disabled", async () => {
2021-07-28 11:37:08 +03:00
analytics.setAnonymity(Anonymity.Disabled);
2021-07-23 18:47:02 +03:00
await analytics.trackPseudonymousEvent<ITestEvent>("jest_test_event", {
foo: "bar",
});
await analytics.trackAnonymousEvent<ITestEvent>("jest_test_event", {
foo: "bar",
});
await analytics.trackRoomEvent<ITestRoomEvent>("room id", "foo", {
2021-07-23 18:47:02 +03:00
foo: "bar",
});
await analytics.trackPageView(200);
expect(fakePosthog.capture.mock.calls.length).toBe(0);
});
it("Should pseudonymise a location of a known screen", async () => {
const location = await getRedactedCurrentLocation(
"https://foo.bar", "#/register/some/pii", "/", Anonymity.Pseudonymous);
expect(location).toBe(
`https://foo.bar/#/register/\
2021-07-21 15:48:10 +03:00
a6b46dd0d1ae5e86cbc8f37e75ceeb6760230c1ca4ffbcb0c97b96dd7d9c464b/\
bd75b3e080945674c0351f75e0db33d1e90986fa07b318ea7edf776f5eef38d4`);
});
2021-07-21 15:48:10 +03:00
it("Should anonymise a location of a known screen", async () => {
const location = await getRedactedCurrentLocation(
"https://foo.bar", "#/register/some/pii", "/", Anonymity.Anonymous);
expect(location).toBe("https://foo.bar/#/register/<redacted>/<redacted>");
});
2021-07-21 15:48:10 +03:00
it("Should pseudonymise a location of an unknown screen", async () => {
const location = await getRedactedCurrentLocation(
"https://foo.bar", "#/not_a_screen_name/some/pii", "/", Anonymity.Pseudonymous);
expect(location).toBe(
`https://foo.bar/#/<redacted_screen_name>/\
2021-07-21 15:48:10 +03:00
a6b46dd0d1ae5e86cbc8f37e75ceeb6760230c1ca4ffbcb0c97b96dd7d9c464b/\
bd75b3e080945674c0351f75e0db33d1e90986fa07b318ea7edf776f5eef38d4`);
});
it("Should anonymise a location of an unknown screen", async () => {
const location = await getRedactedCurrentLocation(
"https://foo.bar", "#/not_a_screen_name/some/pii", "/", Anonymity.Anonymous);
expect(location).toBe("https://foo.bar/#/<redacted_screen_name>/<redacted>/<redacted>");
});
2021-07-21 15:48:10 +03:00
it("Should handle an empty hash", async () => {
2021-07-27 15:29:56 +03:00
const location = await getRedactedCurrentLocation(
"https://foo.bar", "", "/", Anonymity.Anonymous);
expect(location).toBe("https://foo.bar/");
});
it("Should identify the user to posthog if pseudonymous", async () => {
2021-07-28 11:37:08 +03:00
analytics.setAnonymity(Anonymity.Pseudonymous);
await analytics.identifyUser("foo");
expect(fakePosthog.identify.mock.calls[0][0])
.toBe("2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae");
});
it("Should not identify the user to posthog if anonymous", async () => {
2021-07-28 11:37:08 +03:00
analytics.setAnonymity(Anonymity.Anonymous);
await analytics.identifyUser("foo");
expect(fakePosthog.identify.mock.calls.length).toBe(0);
});
2021-07-21 10:38:58 +03:00
});
2021-07-21 09:40:39 +03:00
});