Skip to content

Commit

Permalink
feat: query id inference pruning of purchased and oldest associations…
Browse files Browse the repository at this point in the history
… when limit is reached (#535)

Added the remaining logic to:
* store any queryID passed for future `purchase` conversion events when
`eventSubtype` is `addToCart`
* remove objectID/queryID association from store when `eventSubtype` is
`purchase`
* keep most recent 4,000 associations when store reaches 5,000
  • Loading branch information
JasonBerry authored Jul 9, 2024
1 parent fbbc5c8 commit 2e0ca49
Show file tree
Hide file tree
Showing 14 changed files with 736 additions and 98 deletions.
5 changes: 3 additions & 2 deletions lib/__tests__/_algoliaAgent.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import AlgoliaAnalytics from "../insights";
import type { RequestFnType } from "../utils/request";

jest.mock("../../package.json", () => ({ version: "1.0.1" }));

describe("algoliaAgent", () => {
let analyticsInstance: AlgoliaAnalytics;
let requestFn: jest.Mock<any, any>;
const requestFn: jest.MockedFunction<RequestFnType> = jest.fn();

beforeEach(() => {
requestFn = jest.fn();
requestFn.mockResolvedValue(true);
analyticsInstance = new AlgoliaAnalytics({ requestFn });
analyticsInstance.init({ apiKey: "test", appId: "test" });
});
Expand Down
5 changes: 3 additions & 2 deletions lib/__tests__/_sendEvent.node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { version } from "../../package.json";
import { getFunctionalInterface } from "../_getFunctionalInterface";
import AlgoliaAnalytics from "../insights";
import type { InsightsClient } from "../types";
import type { RequestFnType } from "../utils/request";

const defaultPayload = {
eventName: "my-event",
Expand All @@ -16,9 +17,9 @@ const defaultRequestUrl = `https://insights.algolia.io/1/events?X-Algolia-Applic

describe("_sendEvent in node env", () => {
let aa: InsightsClient;
let requestFn: jest.Mock<any, any>;
const requestFn: jest.MockedFunction<RequestFnType> = jest.fn();
beforeEach(() => {
requestFn = jest.fn();
requestFn.mockResolvedValue(true);
const instance = new AlgoliaAnalytics({ requestFn });
aa = getFunctionalInterface(instance);
aa("init", {
Expand Down
104 changes: 103 additions & 1 deletion lib/__tests__/_sendEvent.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import AlgoliaAnalytics from "../insights";
import { storeQueryForObject } from "../utils";
import { getQueryForObject, storeQueryForObject } from "../utils";
import { getRequesterForBrowser } from "../utils/getRequesterForBrowser";
import type { RequestFnType } from "../utils/request";

jest.mock("../../package.json", () => ({
version: "1.0.1"
Expand Down Expand Up @@ -156,6 +157,92 @@ describe("sendEvents", () => {
]
});
});
it("shouldn't infer query ids when additionalParams.inferQueryID is false", () => {
storeQueryForObject("my-index", "1", "clicked-query");
analyticsInstance.sendEvents(
[
{
eventType: "conversion",
eventName: "my-event",
index: "my-index",
objectIDs: ["1"]
}
],
{ inferQueryID: false }
);
analyticsInstance.sendEvents([
{
eventType: "conversion",
eventName: "my-event",
index: "my-index",
objectIDs: ["1"]
}
]);
expect(XMLHttpRequest.send).toHaveBeenCalledTimes(2);
const payload1 = JSON.parse(XMLHttpRequest.send.mock.calls[0][0]);
expect(payload1).toEqual({
events: [
{
eventType: "conversion",
eventName: "my-event",
index: "my-index",
objectIDs: ["1"],
userToken: expect.any(String)
}
]
});
const payload2 = JSON.parse(XMLHttpRequest.send.mock.calls[1][0]);
expect(payload2).toEqual({
events: [
{
eventType: "conversion",
eventName: "my-event",
index: "my-index",
objectIDs: ["1"],
userToken: expect.any(String)
}
]
});
});
it("should remove inferred query id from store when eventSubtype is 'purchase'", async () => {
const requestFn: jest.MockedFunction<RequestFnType> = jest
.fn()
.mockResolvedValue(true);
analyticsInstance = setupInstance({
requestFn
});
storeQueryForObject("my-index", "1", "clicked-query");
const send = analyticsInstance.sendEvents(
[
{
eventType: "conversion",
eventSubtype: "purchase",
eventName: "my-event",
index: "my-index",
objectIDs: ["1"]
}
],
{ inferQueryID: true }
);
expect(requestFn).toHaveBeenCalledTimes(1);
const [, payload] = requestFn.mock.calls[0];
expect(payload).toEqual({
events: [
{
eventType: "conversion",
eventSubtype: "purchase",
eventName: "my-event",
index: "my-index",
objectIDs: ["1"],
objectData: [{ queryID: "clicked-query" }],
userToken: expect.any(String),
objectIDsWithInferredQueryID: ["1"]
}
]
});
await send;
expect(getQueryForObject("my-index", "1")).toBeUndefined();
});
});

describe("with sendBeacon", () => {
Expand Down Expand Up @@ -284,6 +371,21 @@ describe("sendEvents", () => {
expect(result instanceof Promise).toBe(true);
expect(result).resolves.toBe("test");
});

it("shouldn't error when custom requestFn doesn't return a promise", () => {
fakeRequestFn.mockImplementationOnce(() => false);

const result = analyticsInstance.sendEvents([
{
eventType: "click",
eventName: "my-event",
index: "my-index",
objectIDs: ["1"]
}
]);

expect(result).toBe(false);
});
});

describe("init", () => {
Expand Down
41 changes: 41 additions & 0 deletions lib/__tests__/conversion.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import AlgoliaAnalytics from "../insights";
import { getQueryForObject } from "../utils";

const credentials = {
apiKey: "test",
Expand All @@ -20,6 +21,7 @@ beforeEach(() => {
});
analyticsInstance.sendEvents = jest.fn();
analyticsInstance.init(credentials);
localStorage.clear();
});

describe("convertedObjectIDsAfterSearch", () => {
Expand Down Expand Up @@ -97,6 +99,30 @@ describe("addedToCartObjectIDsAfterSearch", () => {
additionalParameters
);
});

it("should store the queryID", () => {
expect(getQueryForObject("index1", "12345")).toBeUndefined();
analyticsInstance.addedToCartObjectIDsAfterSearch(convertParams);
expect(getQueryForObject("index1", "12345")).toEqual([
"test",
expect.any(Number)
]);
});

it("should store the objectData.queryID if specified", () => {
expect(getQueryForObject("index1", "12345")).toBeUndefined();
analyticsInstance.addedToCartObjectIDsAfterSearch({
...convertParams,
objectData: convertParams.objectData.map((data) => ({
...data,
queryID: "objectData-query"
}))
});
expect(getQueryForObject("index1", "12345")).toEqual([
"objectData-query",
expect.any(Number)
]);
});
});

describe("purchasedObjectIDsAfterSearch", () => {
Expand Down Expand Up @@ -209,6 +235,21 @@ describe("addedToCartObjectIDs", () => {
additionalParameters
);
});

it("should store the objectData.queryID if specified", () => {
expect(getQueryForObject("index1", "12345")).toBeUndefined();
analyticsInstance.addedToCartObjectIDs({
...convertParams,
objectData: convertParams.objectData.map((data) => ({
...data,
queryID: "objectData-query"
}))
});
expect(getQueryForObject("index1", "12345")).toEqual([
"objectData-query",
expect.any(Number)
]);
});
});

describe("purchasedObjectIDs", () => {
Expand Down
Loading

0 comments on commit 2e0ca49

Please sign in to comment.