Bin
2025-12-17 2b99d77d73ba568beff0a549534017caaad8a6de
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import { registerAnalytics } from "./analytics";
 
describe("analytics", () => {
  const testUrl = "http://test.com/page";
  let originalRequestIdleCallback: any;
  let originalSendBeacon: any;
  let mockSendBeacon: jest.Mock;
 
  beforeEach(() => {
    // Mock window.requestIdleCallback
    originalRequestIdleCallback = window.requestIdleCallback;
    window.requestIdleCallback = (cb: any) => cb();
 
    // Mock navigator.sendBeacon
    originalSendBeacon = navigator.sendBeacon;
    mockSendBeacon = jest.fn(() => true);
    Object.defineProperty(navigator, "sendBeacon", {
      value: mockSendBeacon,
      configurable: true,
    });
 
    // Reset APP_SETTINGS before each test
    (window as any).APP_SETTINGS = {
      collect_analytics: true,
    };
 
    // Mock window.location - simple pattern works with JSDOM 22 (jest-environment-jsdom v29)
    Object.defineProperty(window, "location", {
      value: { href: testUrl },
      configurable: true,
      writable: true,
    });
  });
 
  afterEach(() => {
    // Restore original functions
    window.requestIdleCallback = originalRequestIdleCallback;
    Object.defineProperty(navigator, "sendBeacon", {
      value: originalSendBeacon,
      configurable: true,
    });
  });
 
  it("should register analytics function on window", () => {
    registerAnalytics();
    expect(window.__lsa).toBeDefined();
  });
 
  it("should not send analytics when collect_analytics is false", () => {
    registerAnalytics();
    (window as any).APP_SETTINGS.collect_analytics = false;
 
    window.__lsa("test.event", { data: "value" });
    expect(mockSendBeacon).not.toHaveBeenCalled();
  });
 
  it("should send analytics with correct payload using sendBeacon", () => {
    registerAnalytics();
 
    window.__lsa("test.event", { data: "value" });
 
    expect(mockSendBeacon).toHaveBeenCalledTimes(1);
    const [url, data] = mockSendBeacon.mock.calls[0];
 
    expect(url).toMatch(/^\/__lsa\/\?/);
    const params = new URLSearchParams(url.split("?")[1]);
    const payload = JSON.parse(params.get("__") || "");
 
    expect(payload).toEqual({
      data: "value",
      event: "test.event",
      url: testUrl,
    });
  });
 
  it("should fallback to Image when sendBeacon is not available", () => {
    // Remove sendBeacon
    Object.defineProperty(navigator, "sendBeacon", {
      value: undefined,
      configurable: true,
    });
 
    const mockImage = { src: "" };
    const originalImage = window.Image;
    (window as any).Image = jest.fn(() => mockImage);
 
    registerAnalytics();
    window.__lsa("test.event", { data: "value" });
 
    expect(window.Image).toHaveBeenCalled();
    expect(mockImage.src).toMatch(/^\/__lsa\/\?/);
 
    // Restore Image constructor
    (window as any).Image = originalImage;
  });
 
  it("should handle errors gracefully", () => {
    mockSendBeacon.mockImplementation(() => {
      throw new Error("Network error");
    });
 
    registerAnalytics();
 
    expect(() => {
      window.__lsa("test.event", { data: "value" });
    }).not.toThrow();
  });
 
  it("should work with minimal parameters", () => {
    registerAnalytics();
 
    window.__lsa("test.event");
 
    expect(mockSendBeacon).toHaveBeenCalledTimes(1);
    const [url] = mockSendBeacon.mock.calls[0];
    const params = new URLSearchParams(url.split("?")[1]);
    const payload = JSON.parse(params.get("__") || "");
 
    expect(payload).toEqual({
      event: "test.event",
      url: testUrl,
    });
  });
});