@jitsu/js 1.7.2 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,18 +12,22 @@ describe("Test Jitsu NodeJS client", () => {
12
12
 
13
13
  const startServer = async () => {
14
14
  requestLog = [];
15
+ let handler = (req, res) => {
16
+ res.setHeader("Content-Type", "text/javascript");
17
+ res.send({ ok: true });
18
+ requestLog.push({
19
+ type: req.params.type,
20
+ body: req.body,
21
+ });
22
+ };
15
23
  server = await createServer({
16
24
  port: 3088,
17
25
  https: false,
18
26
  handlers: {
19
- "/api/s/:type": (req, res) => {
20
- res.setHeader("Content-Type", "text/javascript");
21
- res.send({ ok: true });
22
- requestLog.push({
23
- type: req.params.type,
24
- body: req.body,
25
- });
26
- },
27
+ //we're using same handler for s2s and browser events since
28
+ //we don't check types anyway
29
+ "/api/s/:type": handler,
30
+ "/api/s/s2s/:type": handler,
27
31
  },
28
32
  });
29
33
  console.log("Running on " + server.baseUrl);
@@ -8,7 +8,7 @@
8
8
  <title>Tracking page</title>
9
9
  <script>
10
10
  window.testOnload = async j => {
11
- j.identify("user1", { email: "john.doe@gmail.com" });
11
+ j.identify("john-doe-id-1", { email: "john.doe@gmail.com" });
12
12
  j.track("pageLoaded", { trackParam: "trackValue" });
13
13
  };
14
14
  </script>
@@ -0,0 +1,20 @@
1
+ <!DOCTYPE html>
2
+
3
+ <html lang="en">
4
+ <head>
5
+ <meta charset="utf-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
7
+ <link rel="canonical" href="<%=trackingBase%>" />
8
+ <title>Tracking page</title>
9
+ <script type="text/javascript" src="<%=trackingBase%>/p.js" data-debug="true" defer></script>
10
+ <script>
11
+ (window.jitsuQ = window.jitsuQ || []).push(function (jitsu) {
12
+ jitsu.track("test-event");
13
+ });
14
+ </script>
15
+ </head>
16
+
17
+ <body>
18
+ <h1>Test</h1>
19
+ </body>
20
+ </html>
@@ -52,7 +52,10 @@ test.beforeAll(async () => {
52
52
  res.setHeader("Content-Type", "text/javascript");
53
53
  res.send(fs.readFileSync(path.join(__dirname, "../../dist/web/p.js.txt")).toString());
54
54
  },
55
- "/api/s/:type": (req, res) => {
55
+ "/api/s/:type": async (req, res) => {
56
+ //sleep for 30ms to simulate network latency. It helps catch bugs with async processing
57
+ await new Promise(resolve => setTimeout(resolve, 50));
58
+
56
59
  res.setHeader("Content-Type", "text/javascript");
57
60
  res.send({ ok: true });
58
61
  requestLog.push({
@@ -112,12 +115,14 @@ const generateTestEvents = async () => {
112
115
  const analytics = (window["analytics"] || window["jitsu"]) as AnalyticsInterface;
113
116
  console.log(`Generating test events. Implementation ${implName}: ${Object.keys(analytics)}`);
114
117
  await analytics.identify("userId2", { email: "john.doe2@gmail.com", caseName: "basic-identify" });
118
+ await analytics.page("test-page-right-after-identify", { caseName: "test-page-right-after-identify" });
115
119
  // jitsu must extract traits even from 'id' object
116
120
  await analytics.identify({ email: "john.doe3@gmail.com", caseName: "identify-without-user-id" });
117
121
  await analytics.group("group1", { name: "Group 1", caseName: "basic-group" });
118
122
  await analytics.page({ caseName: "page-without-name", context: { page: { title: "Synthetic Title" } } });
119
123
  await analytics.page("test-page", { caseName: "page-with-name" });
120
124
  await analytics.track("testEvent", { caseName: "track-with-name" });
125
+ await analytics.identify(9292649175 as any, { caseName: "identify-with-numeric-id-1" });
121
126
  console.log(`Test events for ${implName} has been generated`);
122
127
  };
123
128
 
@@ -162,21 +167,61 @@ test("segment-reference", async ({ browser }) => {
162
167
  {}
163
168
  );
164
169
  console.log("🍪 Segment Cookies", cookies);
165
-
170
+ let counter = 1;
166
171
  for (const type of Object.keys(requests)) {
167
172
  for (const { payload } of requests[type]) {
168
173
  const dir = path.join(__dirname, "artifacts", "segment-reference");
169
174
  fs.mkdirSync(dir, { recursive: true });
170
175
  const file = path.join(
171
176
  dir,
172
- `${payload.traits?.caseName || payload.properties?.caseName || payload.context?.caseName}.json`
177
+ `${counter++} - ${payload.traits?.caseName || payload.properties?.caseName || payload.context?.caseName}.json`
173
178
  );
174
179
  fs.writeFileSync(file, JSON.stringify(sortKeysRecursively(payload), null, 2));
175
180
  }
176
181
  }
177
182
  });
178
183
 
184
+ function describeEvent(type: string, body: any) {
185
+ const params = [
186
+ body.userId ? "userId=" + body.userId : undefined,
187
+ body.anonymousId ? "anonId=" + body.anonymousId : undefined,
188
+ body.traits ? ["traits=" + JSON.stringify(body.traits)] : [],
189
+ ]
190
+ .filter(x => !!x)
191
+ .join(", ");
192
+ return `${type}${type === "track" ? `(${body.event})` : ""}[${params}]`;
193
+ }
194
+ test("url-bug", async ({ browser }) => {
195
+ //tests a bug in getanalytics.io where the url without slash provided by
196
+ //<link rel="canonical" ../> causes incorrect page path
197
+ const browserContext = await browser.newContext();
198
+ const { page, uncaughtErrors } = await createLoggingPage(browserContext);
199
+ const [pageResult] = await Promise.all([page.goto(`${server.baseUrl}/url-bug.html`)]);
200
+
201
+ await page.waitForFunction(() => window["jitsu"] !== undefined, undefined, {
202
+ timeout: 1000,
203
+ polling: 100,
204
+ });
205
+ expect(pageResult.status()).toBe(200);
206
+ //wait for some time since the server has an artificial latency of 30ms
207
+ await new Promise(resolve => setTimeout(resolve, 1000));
208
+ expect(uncaughtErrors.length).toEqual(0);
209
+ expect(requestLog.length).toBe(2);
210
+ console.log(
211
+ `📝 Request log size of ${requestLog.length}`,
212
+ requestLog.map(x => describeEvent(x.type, x.body))
213
+ );
214
+ //a track contains a valid URL, probably because analytics can't grab the canonical URL yet
215
+ const trackEvent = requestLog.find(x => x.type === "page");
216
+ expect(trackEvent).toBeDefined();
217
+ const pagePath = trackEvent.body.context.page.path;
218
+ expect(pagePath).toBeDefined();
219
+ //it's "//localhost:3088" when the bug is present
220
+ expect(pagePath).toEqual("/");
221
+ });
222
+
179
223
  test("basic", async ({ browser }) => {
224
+ requestLog.length = 0;
180
225
  const browserContext = await browser.newContext();
181
226
 
182
227
  const { page: firstPage, uncaughtErrors: firstPageErrors } = await createLoggingPage(browserContext);
@@ -197,12 +242,18 @@ test("basic", async ({ browser }) => {
197
242
  {}
198
243
  );
199
244
  console.log("🍪 Jitsu Cookies", cookies);
245
+ //wait for some time since the server has an artificial latency of 30ms
246
+ await new Promise(resolve => setTimeout(resolve, 1000));
200
247
  expect(firstPageErrors.length).toEqual(0);
201
248
  const anonymousId = cookies["__eventn_id"];
202
249
  expect(anonymousId).toBeDefined();
203
- expect(cookies["__eventn_uid"]).toBe("user1");
250
+ expect(cookies["__eventn_uid"]).toBe("john-doe-id-1");
204
251
  expect(cookies["__eventn_id_usr"]).toBeDefined();
205
252
  expect(JSON.parse(decodeURIComponent(cookies["__eventn_id_usr"])).email).toEqual("john.doe@gmail.com");
253
+ console.log(
254
+ `📝 Request log size of ${requestLog.length}`,
255
+ requestLog.map(x => describeEvent(x.type, x.body))
256
+ );
206
257
  let identifies = requestLog.filter(x => x.type === "identify");
207
258
  let pages = requestLog.filter(x => x.type === "page");
208
259
  let tracks = requestLog.filter(x => x.type === "track");
@@ -218,18 +269,18 @@ test("basic", async ({ browser }) => {
218
269
  expect(track.properties.trackParam).toEqual("trackValue");
219
270
  expect(track.type).toEqual("track");
220
271
  expect(track.context.traits.email).toEqual("john.doe@gmail.com");
221
- expect(track.userId).toEqual("user1");
272
+ expect(track.userId).toEqual("john-doe-id-1");
222
273
  expect(track.event).toEqual("pageLoaded");
223
274
 
224
275
  console.log(chalk.bold("📝 Checking identify event"), JSON.stringify(identify, null, 3));
225
276
  expect(identify.traits.email).toEqual("john.doe@gmail.com");
226
- expect(identify.userId).toEqual("user1");
277
+ expect(identify.userId).toEqual("john-doe-id-1");
227
278
  expect(identify.anonymousId).toEqual(anonymousId);
228
279
 
229
280
  console.log(chalk.bold("📝 Checking page event"), JSON.stringify(page, null, 3));
230
281
  expect(page.anonymousId).toEqual(anonymousId);
231
282
  expect(page.context.traits.email).toEqual("john.doe@gmail.com");
232
- expect(page.userId).toEqual("user1");
283
+ expect(page.userId).toEqual("john-doe-id-1");
233
284
 
234
285
  expect(page.context.campaign.source).toEqual("source");
235
286
 
@@ -243,12 +294,13 @@ test("basic", async ({ browser }) => {
243
294
 
244
295
  await secondPage.evaluate(generateTestEvents);
245
296
  expect(secondPageErrors.length).toBe(0);
297
+ let counter = 1;
246
298
  requestLog.forEach(({ body: payload }) => {
247
299
  const dir = path.join(__dirname, "artifacts", "requests");
248
300
  fs.mkdirSync(dir, { recursive: true });
249
301
  const file = path.join(
250
302
  dir,
251
- `${payload.traits?.caseName || payload.properties?.caseName || payload.context?.caseName}.json`
303
+ `${counter++} - ${payload.traits?.caseName || payload.properties?.caseName || payload.context?.caseName}.json`
252
304
  );
253
305
  fs.writeFileSync(file, JSON.stringify(sortKeysRecursively(payload), null, 2));
254
306
  });
@@ -23,6 +23,11 @@ export type InternalPluginDescriptor = {
23
23
  name: string;
24
24
  };
25
25
  export type DeviceOptions = AnalyticsPluginDescriptor | InternalPluginDescriptor;
26
- declare const jitsuAnalyticsPlugin: (pluginConfig?: JitsuOptions) => AnalyticsPlugin;
26
+ export type JitsuPluginConfig = JitsuOptions & {
27
+ storageWrapper?: (persistentStorage: PersistentStorage) => PersistentStorage & {
28
+ reset: () => void;
29
+ };
30
+ };
31
+ declare const jitsuAnalyticsPlugin: (pluginConfig?: JitsuPluginConfig) => AnalyticsPlugin;
27
32
  export declare function randomId(hashString?: string | undefined): string;
28
33
  export default jitsuAnalyticsPlugin;