|
1 | | -import { Analytics } from '@utils/analytics'; |
| 1 | +import { Analytics, groupsFromUser } from '@utils/analytics'; |
2 | 2 | import { PostHog } from 'posthog-node'; |
3 | 3 | import { v4 as uuidv4 } from 'uuid'; |
4 | 4 | import { ANALYTICS_TEAM_TAG } from '@lib/constants'; |
| 5 | +import type { ApiUser } from '@lib/api'; |
5 | 6 |
|
6 | 7 | jest.mock('posthog-node'); |
7 | 8 | jest.mock('uuid'); |
@@ -154,6 +155,120 @@ describe('Analytics', () => { |
154 | 155 | }); |
155 | 156 | }); |
156 | 157 |
|
| 158 | + describe('groups (before_send injection)', () => { |
| 159 | + type TestEvent = Record<string, unknown> & { |
| 160 | + groups?: Record<string, string>; |
| 161 | + }; |
| 162 | + type BeforeSendFn = (event: TestEvent | null) => TestEvent | null; |
| 163 | + |
| 164 | + const getBeforeSend = (): BeforeSendFn => |
| 165 | + (MockedPostHog.mock.calls[0][1] as { before_send: BeforeSendFn }) |
| 166 | + .before_send; |
| 167 | + |
| 168 | + it('does not attach groups before setGroups is called', () => { |
| 169 | + const beforeSend = getBeforeSend(); |
| 170 | + const event = { event: 'x', distinctId: 'd', properties: {} }; |
| 171 | + |
| 172 | + expect(beforeSend(event)).toBe(event); |
| 173 | + expect(event).not.toHaveProperty('groups'); |
| 174 | + }); |
| 175 | + |
| 176 | + it('injects the active group map into every event', () => { |
| 177 | + analytics.setGroups({ |
| 178 | + instance: 'https://us.posthog.com', |
| 179 | + organization: 'org-1', |
| 180 | + project: 'team-uuid', |
| 181 | + }); |
| 182 | + const beforeSend = getBeforeSend(); |
| 183 | + |
| 184 | + const result = beforeSend({ |
| 185 | + event: 'x', |
| 186 | + distinctId: 'd', |
| 187 | + properties: {}, |
| 188 | + }); |
| 189 | + |
| 190 | + expect(result?.groups).toEqual({ |
| 191 | + instance: 'https://us.posthog.com', |
| 192 | + organization: 'org-1', |
| 193 | + project: 'team-uuid', |
| 194 | + }); |
| 195 | + }); |
| 196 | + |
| 197 | + it('lets per-event groups override the active map', () => { |
| 198 | + analytics.setGroups({ instance: 'https://us.posthog.com', project: 'a' }); |
| 199 | + const beforeSend = getBeforeSend(); |
| 200 | + |
| 201 | + const result = beforeSend({ |
| 202 | + event: 'x', |
| 203 | + distinctId: 'd', |
| 204 | + properties: {}, |
| 205 | + groups: { project: 'override' }, |
| 206 | + }); |
| 207 | + |
| 208 | + expect(result?.groups).toEqual({ |
| 209 | + instance: 'https://us.posthog.com', |
| 210 | + project: 'override', |
| 211 | + }); |
| 212 | + }); |
| 213 | + |
| 214 | + it('passes null events through untouched', () => { |
| 215 | + analytics.setGroups({ instance: 'https://us.posthog.com' }); |
| 216 | + const beforeSend = getBeforeSend(); |
| 217 | + |
| 218 | + expect(beforeSend(null)).toBeNull(); |
| 219 | + }); |
| 220 | + }); |
| 221 | + |
| 222 | + describe('groupsFromUser', () => { |
| 223 | + const userWith = (overrides: Partial<ApiUser>): ApiUser => |
| 224 | + ({ |
| 225 | + distinct_id: 'd', |
| 226 | + organization: { id: 'org-1' }, |
| 227 | + team: { id: 1, uuid: 'team-uuid', organization: 'org-1' }, |
| 228 | + organizations: [], |
| 229 | + ...overrides, |
| 230 | + } as unknown as ApiUser); |
| 231 | + |
| 232 | + it('always includes the host as the instance group', () => { |
| 233 | + expect(groupsFromUser(null, 'https://us.posthog.com')).toEqual({ |
| 234 | + instance: 'https://us.posthog.com', |
| 235 | + }); |
| 236 | + }); |
| 237 | + |
| 238 | + it('maps org id, customer id, and team uuid (not numeric project id)', () => { |
| 239 | + const user = userWith({ |
| 240 | + organization: { |
| 241 | + id: 'org-uuid', |
| 242 | + customer_id: 'cus_123', |
| 243 | + } as ApiUser['organization'], |
| 244 | + team: { |
| 245 | + id: 42, |
| 246 | + uuid: 'team-uuid', |
| 247 | + organization: 'org-uuid', |
| 248 | + } as ApiUser['team'], |
| 249 | + }); |
| 250 | + |
| 251 | + expect(groupsFromUser(user, 'https://eu.posthog.com')).toEqual({ |
| 252 | + instance: 'https://eu.posthog.com', |
| 253 | + organization: 'org-uuid', |
| 254 | + customer: 'cus_123', |
| 255 | + project: 'team-uuid', |
| 256 | + }); |
| 257 | + }); |
| 258 | + |
| 259 | + it('omits optional keys that are absent', () => { |
| 260 | + const user = userWith({ |
| 261 | + organization: { id: 'org-uuid' } as ApiUser['organization'], |
| 262 | + team: { id: 42, organization: 'org-uuid' } as ApiUser['team'], |
| 263 | + }); |
| 264 | + |
| 265 | + expect(groupsFromUser(user, 'https://us.posthog.com')).toEqual({ |
| 266 | + instance: 'https://us.posthog.com', |
| 267 | + organization: 'org-uuid', |
| 268 | + }); |
| 269 | + }); |
| 270 | + }); |
| 271 | + |
157 | 272 | describe('integration with other methods', () => { |
158 | 273 | it('should work correctly with setTag and captureException', () => { |
159 | 274 | const error = new Error('Test error'); |
|
0 commit comments