File size: 2,763 Bytes
fd2c364
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import { beforeEach, describe, expect, it, vi } from "vitest";

type MockPostHog = {
  init: ReturnType<typeof vi.fn>;
  capture: ReturnType<typeof vi.fn>;
  captureException: ReturnType<typeof vi.fn>;
  opt_in_capturing: ReturnType<typeof vi.fn>;
  opt_out_capturing: ReturnType<typeof vi.fn>;
  has_opted_out_capturing: ReturnType<typeof vi.fn>;
  identify: ReturnType<typeof vi.fn>;
  get_property: ReturnType<typeof vi.fn>;
  reset: ReturnType<typeof vi.fn>;
};

async function loadTelemetryWithLegacyUser() {
  let identifiedUserId: string | undefined = "legacy-cloud-user";
  const mockPosthog: MockPostHog = {
    init: vi.fn(),
    capture: vi.fn(),
    captureException: vi.fn(),
    opt_in_capturing: vi.fn(),
    opt_out_capturing: vi.fn(),
    has_opted_out_capturing: vi.fn(() => false),
    identify: vi.fn((userId: string) => {
      identifiedUserId = userId;
    }),
    get_property: vi.fn((property: string) =>
      property === "$user_id" ? identifiedUserId : undefined,
    ),
    reset: vi.fn(() => {
      identifiedUserId = undefined;
    }),
  };
  mockPosthog.init.mockReturnValue(mockPosthog);

  vi.doMock("posthog-js", () => ({
    default: mockPosthog,
  }));

  const telemetry = await import("#/services/telemetry");
  return { telemetry, mockPosthog };
}

describe("Telemetry bootstrap identity migration", () => {
  beforeEach(() => {
    vi.resetModules();
    vi.clearAllMocks();
    localStorage.clear();
    sessionStorage.clear();
    delete (window as unknown as Record<string, unknown>)
      .__AGENT_CANVAS_LOCK_TO_CLOUD__;
  });

  it("preserves an identified user while Cloud identity is unresolved", async () => {
    const { telemetry, mockPosthog } = await loadTelemetryWithLegacyUser();

    await telemetry.setTelemetryConsent("granted");

    expect(mockPosthog.reset).not.toHaveBeenCalled();
    expect(mockPosthog.opt_in_capturing).toHaveBeenCalled();
    expect(mockPosthog.identify).not.toHaveBeenCalled();
  });

  it("preserves OAuth bootstrap identity instead of resetting legacy users", async () => {
    const { telemetry, mockPosthog } = await loadTelemetryWithLegacyUser();

    telemetry.configurePostHogBootstrap({
      distinctID: "bootstrapped-browser-id",
      sessionID: "bootstrapped-session-id",
    });
    await telemetry.setTelemetryConsent("granted");

    expect(mockPosthog.reset).not.toHaveBeenCalled();
    expect(mockPosthog.init).toHaveBeenCalledWith(
      expect.any(String),
      expect.objectContaining({
        bootstrap: {
          distinctID: "bootstrapped-browser-id",
          sessionID: "bootstrapped-session-id",
        },
        person_profiles: "always",
      }),
      "agent-canvas",
    );
    expect(mockPosthog.identify).not.toHaveBeenCalled();
  });
});