UNPKG

mixpanel-react-native

Version:

Official React Native Tracking Library for Mixpanel Analytics

219 lines (175 loc) 7.96 kB
// Test UUID generation with polyfilled crypto.getRandomValues describe("MixpanelPersistent - UUID Generation", () => { const token = "test-token"; beforeEach(() => { jest.clearAllMocks(); }); it("should generate device ID using uuid.v4() with polyfill", async () => { let mixpanelPersistent; await jest.isolateModules(async () => { // Mock uuid to return a specific value jest.doMock("uuid", () => ({ v4: jest.fn(() => "polyfilled-uuid-1234"), })); // Now require the modules const { MixpanelPersistent } = require("mixpanel-react-native/javascript/mixpanel-persistent"); const uuid = require("uuid"); // Create instance MixpanelPersistent.instance = null; mixpanelPersistent = MixpanelPersistent.getInstance(null, token); // Load device ID (which triggers UUID generation) await mixpanelPersistent.loadDeviceId(token); // Verify uuid.v4 was called expect(uuid.v4).toHaveBeenCalled(); // Verify the device ID was set expect(mixpanelPersistent.getDeviceId(token)).toBe("polyfilled-uuid-1234"); }); }); it("should handle legacy device IDs without expo-crypto format", async () => { let mixpanelPersistent; await jest.isolateModules(async () => { // Create a mock storage with a legacy UUID const legacyUuid = "550e8400-e29b-41d4-a716-446655440000"; // Standard UUID v4 format const mockStorage = {}; jest.doMock("mixpanel-react-native/javascript/mixpanel-storage", () => { return { AsyncStorageAdapter: jest.fn().mockImplementation(() => ({ getItem: jest.fn((key) => { return Promise.resolve(mockStorage[key] || null); }), setItem: jest.fn((key, value) => { mockStorage[key] = value; return Promise.resolve(); }), removeItem: jest.fn((key) => { delete mockStorage[key]; return Promise.resolve(); }), })), }; }); // Pre-populate storage with legacy device ID const deviceIdKey = `MIXPANEL_${token}_device_id`; mockStorage[deviceIdKey] = legacyUuid; const { MixpanelPersistent } = require("mixpanel-react-native/javascript/mixpanel-persistent"); // Create instance MixpanelPersistent.instance = null; mixpanelPersistent = MixpanelPersistent.getInstance(null, token); // Load device ID from storage await mixpanelPersistent.loadDeviceId(token); // Verify the legacy device ID was loaded correctly expect(mixpanelPersistent.getDeviceId(token)).toBe(legacyUuid); // Verify it doesn't try to generate a new one const { randomUUID } = require("expo-crypto"); const uuid = require("uuid"); expect(randomUUID).not.toHaveBeenCalled(); expect(uuid.v4).not.toHaveBeenCalled(); }); }); it("should migrate from no device ID to expo-crypto format when available", async () => { let mixpanelPersistent; await jest.isolateModules(async () => { const mockStorage = {}; jest.doMock("mixpanel-react-native/javascript/mixpanel-storage", () => { return { AsyncStorageAdapter: jest.fn().mockImplementation(() => ({ getItem: jest.fn((key) => Promise.resolve(mockStorage[key] || null)), setItem: jest.fn((key, value) => { mockStorage[key] = value; return Promise.resolve(); }), removeItem: jest.fn((key) => { delete mockStorage[key]; return Promise.resolve(); }), })), }; }); // Mock expo-crypto to return a specific value jest.doMock("expo-crypto", () => ({ randomUUID: jest.fn(() => "expo-generated-uuid"), })); const { MixpanelPersistent } = require("mixpanel-react-native/javascript/mixpanel-persistent"); const { randomUUID } = require("expo-crypto"); // Create instance with no existing device ID MixpanelPersistent.instance = null; mixpanelPersistent = MixpanelPersistent.getInstance(null, token); // Load device ID (should generate new one) await mixpanelPersistent.loadDeviceId(token); // Verify expo-crypto was used for new device ID expect(randomUUID).toHaveBeenCalled(); expect(mixpanelPersistent.getDeviceId(token)).toBe("expo-generated-uuid"); // Verify it was persisted to storage const deviceIdKey = `MIXPANEL_${token}_device_id`; expect(mockStorage[deviceIdKey]).toBe("expo-generated-uuid"); }); }); it("should handle storage failures gracefully during identity persistence", async () => { let mixpanelPersistent; await jest.isolateModules(async () => { let shouldFail = false; jest.doMock("mixpanel-react-native/javascript/mixpanel-storage", () => { return { AsyncStorageAdapter: jest.fn().mockImplementation(() => ({ getItem: jest.fn(() => Promise.resolve(null)), setItem: jest.fn((key, value) => { if (shouldFail) { return Promise.reject(new Error("Storage write failed")); } return Promise.resolve(); }), removeItem: jest.fn(() => Promise.resolve()), })), }; }); // Mock expo-crypto jest.doMock("expo-crypto", () => ({ randomUUID: jest.fn(() => "test-uuid-12345"), })); const { MixpanelPersistent } = require("mixpanel-react-native/javascript/mixpanel-persistent"); // Create instance MixpanelPersistent.instance = null; mixpanelPersistent = MixpanelPersistent.getInstance(null, token); // First load should work (storage not failing yet) await mixpanelPersistent.loadDeviceId(token); expect(mixpanelPersistent.getDeviceId(token)).toBe("test-uuid-12345"); // Now make storage fail shouldFail = true; // Update identity and try to persist - should not throw mixpanelPersistent.updateDistinctId(token, "new-distinct-id"); mixpanelPersistent.updateUserId(token, "new-user-id"); // This should not throw even if storage fails await expect(mixpanelPersistent.persistIdentity(token)).resolves.not.toThrow(); // Identity should still be in memory even if storage failed expect(mixpanelPersistent.getDistinctId(token)).toBe("new-distinct-id"); expect(mixpanelPersistent.getUserId(token)).toBe("new-user-id"); expect(mixpanelPersistent.getDeviceId(token)).toBe("test-uuid-12345"); }); }); it("should continue working if storage read fails", async () => { let mixpanelPersistent; await jest.isolateModules(async () => { jest.doMock("mixpanel-react-native/javascript/mixpanel-storage", () => { return { AsyncStorageAdapter: jest.fn().mockImplementation(() => ({ getItem: jest.fn(() => Promise.reject(new Error("Storage read failed"))), setItem: jest.fn(() => Promise.resolve()), removeItem: jest.fn(() => Promise.resolve()), })), }; }); // Mock expo-crypto jest.doMock("expo-crypto", () => ({ randomUUID: jest.fn(() => "fallback-uuid"), })); const { MixpanelPersistent } = require("mixpanel-react-native/javascript/mixpanel-persistent"); // Create instance MixpanelPersistent.instance = null; mixpanelPersistent = MixpanelPersistent.getInstance(null, token); // Loading should not throw even if storage fails await expect(mixpanelPersistent.loadDeviceId(token)).resolves.not.toThrow(); // Should generate a new device ID since storage failed expect(mixpanelPersistent.getDeviceId(token)).toBe("fallback-uuid"); }); }); });