rawTrackAnalyticsEvent.spec.tsx 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. import {OrganizationFixture} from 'sentry-fixture/organization';
  2. import {SubscriptionFixture} from 'getsentry-test/fixtures/subscription';
  3. import ConfigStore from 'sentry/stores/configStore';
  4. import {uniqueId} from 'sentry/utils/guid';
  5. import sessionStorage from 'sentry/utils/sessionStorage';
  6. import rawTrackAnalyticsEvent from 'getsentry/utils/rawTrackAnalyticsEvent';
  7. import trackAmplitudeEvent from 'getsentry/utils/trackAmplitudeEvent';
  8. import trackMarketingEvent from 'getsentry/utils/trackMarketingEvent';
  9. import trackReloadEvent from 'getsentry/utils/trackReloadEvent';
  10. jest.mock('sentry/utils/guid');
  11. jest.mock('getsentry/utils/trackAmplitudeEvent');
  12. jest.mock('getsentry/utils/trackReloadEvent');
  13. jest.mock('getsentry/utils/trackMarketingEvent');
  14. describe('rawTrackAnalyticsEvent', function () {
  15. const user = ConfigStore.get('user');
  16. const organization = OrganizationFixture({orgRole: 'owner'});
  17. const subscription = SubscriptionFixture({organization, plan: 'am1_f'});
  18. const org_id = Number(organization.id);
  19. beforeEach(function () {
  20. (uniqueId as jest.MockedFunction<typeof uniqueId>).mockReturnValue('345');
  21. });
  22. afterEach(function () {
  23. (trackReloadEvent as jest.Mock).mockClear();
  24. (trackAmplitudeEvent as jest.Mock).mockClear();
  25. (trackMarketingEvent as jest.Mock).mockClear();
  26. (uniqueId as jest.Mock).mockClear();
  27. });
  28. it('tracks in reload but not amplitude with undefined organization', function () {
  29. rawTrackAnalyticsEvent({
  30. // @ts-expect-error: We're explicitly testing a case with organization=undefined
  31. organization: undefined,
  32. eventKey: 'test_event',
  33. eventName: 'Test Event',
  34. someProp: 'value',
  35. });
  36. expect(trackReloadEvent).toHaveBeenCalledWith(
  37. 'test_event',
  38. expect.objectContaining({
  39. someProp: 'value',
  40. org_id: undefined,
  41. user_id: parseInt(user.id, 10),
  42. })
  43. );
  44. expect(trackAmplitudeEvent).not.toHaveBeenCalled();
  45. });
  46. it('coerces organization_id and project_id and honor existing analytics sessions', function () {
  47. sessionStorage.setItem('ANALYTICS_SESSION', '789');
  48. rawTrackAnalyticsEvent({
  49. eventKey: 'test_event',
  50. eventName: 'Test Event',
  51. organization,
  52. someProp: 'value',
  53. project_id: '456',
  54. });
  55. expect(trackReloadEvent).toHaveBeenCalledWith(
  56. 'test_event',
  57. expect.objectContaining({
  58. someProp: 'value',
  59. project_id: 456,
  60. org_id,
  61. user_id: parseInt(user.id, 10),
  62. role: 'owner',
  63. analytics_session_id: '789',
  64. })
  65. );
  66. expect(trackAmplitudeEvent).toHaveBeenCalledWith(
  67. 'Test Event',
  68. org_id,
  69. expect.objectContaining({
  70. someProp: 'value',
  71. role: 'owner',
  72. project_id: 456,
  73. analytics_session_id: '789',
  74. url: 'http://localhost/',
  75. }),
  76. {time: undefined}
  77. );
  78. expect(uniqueId).not.toHaveBeenCalled();
  79. sessionStorage.removeItem('ANALYTICS_SESSION');
  80. expect(trackMarketingEvent).not.toHaveBeenCalled();
  81. });
  82. it('allows null organization and set analytics session if missing', function () {
  83. sessionStorage.removeItem('ANALYTICS_SESSION');
  84. rawTrackAnalyticsEvent({
  85. eventKey: 'test_event',
  86. eventName: 'Test Event',
  87. organization: null,
  88. someProp: 'value',
  89. });
  90. expect(trackReloadEvent).toHaveBeenCalledWith(
  91. 'test_event',
  92. expect.objectContaining({
  93. someProp: 'value',
  94. org_id: null,
  95. analytics_session_id: '345',
  96. })
  97. );
  98. expect(trackAmplitudeEvent).toHaveBeenCalledWith(
  99. 'Test Event',
  100. null,
  101. expect.objectContaining({someProp: 'value', analytics_session_id: '345'}),
  102. {time: undefined}
  103. );
  104. expect(uniqueId).toHaveBeenCalledWith();
  105. });
  106. it('allows string for organization', function () {
  107. rawTrackAnalyticsEvent({
  108. eventKey: 'test_event',
  109. eventName: 'Test Event',
  110. organization: org_id.toString(),
  111. someProp: 'value',
  112. });
  113. expect(trackReloadEvent).toHaveBeenCalledWith(
  114. 'test_event',
  115. expect.objectContaining({
  116. someProp: 'value',
  117. org_id,
  118. })
  119. );
  120. expect(trackAmplitudeEvent).toHaveBeenCalledWith(
  121. 'Test Event',
  122. org_id,
  123. expect.objectContaining({someProp: 'value'}),
  124. {time: undefined}
  125. );
  126. });
  127. it('if organization is a non number string then use undefined as value', function () {
  128. rawTrackAnalyticsEvent({
  129. eventKey: 'test_event',
  130. eventName: 'Test Event',
  131. organization: 'lol',
  132. someProp: 'value',
  133. });
  134. expect(trackReloadEvent).toHaveBeenCalledWith(
  135. 'test_event',
  136. expect.objectContaining({
  137. someProp: 'value',
  138. org_id: undefined,
  139. })
  140. );
  141. expect(trackAmplitudeEvent).not.toHaveBeenCalled();
  142. });
  143. it('pass custom referrer', function () {
  144. window.location.search = '?referrer=test';
  145. rawTrackAnalyticsEvent({
  146. eventKey: 'test_event',
  147. eventName: 'Test Event',
  148. organization,
  149. });
  150. expect(trackReloadEvent).toHaveBeenCalledWith(
  151. 'test_event',
  152. expect.objectContaining({custom_referrer: 'test'})
  153. );
  154. expect(trackAmplitudeEvent).toHaveBeenCalledWith(
  155. 'Test Event',
  156. org_id,
  157. expect.objectContaining({custom_referrer: 'test'}),
  158. {time: undefined}
  159. );
  160. window.location.search = '';
  161. });
  162. it('start analytics session', function () {
  163. rawTrackAnalyticsEvent(
  164. {
  165. eventKey: 'test_event',
  166. eventName: 'Test Event',
  167. organization: null,
  168. },
  169. {startSession: true}
  170. );
  171. expect(trackReloadEvent).toHaveBeenCalledWith(
  172. 'test_event',
  173. expect.objectContaining({analytics_session_id: '345'})
  174. );
  175. expect(trackAmplitudeEvent).toHaveBeenCalledWith(
  176. 'Test Event',
  177. null,
  178. expect.objectContaining({analytics_session_id: '345'}),
  179. {time: undefined}
  180. );
  181. expect(uniqueId).toHaveBeenCalledWith();
  182. });
  183. it('accepts subscription and sets plan', function () {
  184. rawTrackAnalyticsEvent({
  185. eventKey: 'test_event',
  186. eventName: 'Test Event',
  187. organization,
  188. subscription,
  189. });
  190. expect(trackReloadEvent).toHaveBeenCalledWith(
  191. 'test_event',
  192. expect.objectContaining({plan: 'am1_f'})
  193. );
  194. expect(trackAmplitudeEvent).toHaveBeenCalledWith(
  195. 'Test Event',
  196. org_id,
  197. expect.objectContaining({plan: 'am1_f'}),
  198. {time: undefined}
  199. );
  200. });
  201. it('applys mapValuesFn', function () {
  202. rawTrackAnalyticsEvent(
  203. {
  204. eventKey: 'test_event',
  205. eventName: 'Test Event',
  206. organization,
  207. },
  208. {
  209. mapValuesFn: data => ({...data, new_field: 'test'}),
  210. }
  211. );
  212. expect(trackReloadEvent).toHaveBeenCalledWith(
  213. 'test_event',
  214. expect.objectContaining({new_field: 'test'})
  215. );
  216. expect(trackAmplitudeEvent).toHaveBeenCalledWith(
  217. 'Test Event',
  218. org_id,
  219. expect.objectContaining({new_field: 'test'}),
  220. {time: undefined}
  221. );
  222. });
  223. it('send to marketing', function () {
  224. rawTrackAnalyticsEvent({
  225. eventKey: 'growth.onboarding_clicked_need_help',
  226. eventName: 'Growth: Onboarding Clicked Need Help',
  227. organization,
  228. subscription,
  229. });
  230. expect(trackReloadEvent).toHaveBeenCalledWith(
  231. 'growth.onboarding_clicked_need_help',
  232. expect.objectContaining({plan: 'am1_f'})
  233. );
  234. expect(trackAmplitudeEvent).toHaveBeenCalledWith(
  235. 'Growth: Onboarding Clicked Need Help',
  236. org_id,
  237. expect.objectContaining({plan: 'am1_f'}),
  238. {time: undefined}
  239. );
  240. expect(trackMarketingEvent).toHaveBeenCalledWith(
  241. 'Growth: Onboarding Clicked Need Help',
  242. {plan: 'am1_f'}
  243. );
  244. });
  245. it('sets previous_referrer', function () {
  246. sessionStorage.setItem('previous_referrer', 'something');
  247. rawTrackAnalyticsEvent({
  248. eventKey: 'test_event',
  249. eventName: 'Test Event',
  250. organization,
  251. });
  252. expect(trackAmplitudeEvent).toHaveBeenCalledWith(
  253. 'Test Event',
  254. org_id,
  255. expect.objectContaining({previous_referrer: 'something'}),
  256. {time: undefined}
  257. );
  258. sessionStorage.removeItem('previous_referrer');
  259. });
  260. it('pass in timestamp', function () {
  261. rawTrackAnalyticsEvent(
  262. {
  263. eventKey: 'test_event',
  264. eventName: 'Test Event',
  265. organization: org_id.toString(),
  266. someProp: 'value',
  267. },
  268. {time: 123}
  269. );
  270. expect(trackAmplitudeEvent).toHaveBeenCalledWith(
  271. 'Test Event',
  272. org_id,
  273. expect.objectContaining({someProp: 'value'}),
  274. {time: 123}
  275. );
  276. expect(trackReloadEvent).toHaveBeenCalledWith(
  277. 'test_event',
  278. expect.objectContaining({
  279. someProp: 'value',
  280. org_id,
  281. user_id: parseInt(user.id, 10),
  282. sent_at: '123',
  283. })
  284. );
  285. });
  286. });