loaderScript.spec.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. import {ProjectKeysFixture} from 'sentry-fixture/projectKeys';
  2. import {initializeOrg} from 'sentry-test/initializeOrg';
  3. import {
  4. render,
  5. screen,
  6. userEvent,
  7. waitForElementToBeRemoved,
  8. } from 'sentry-test/reactTestingLibrary';
  9. import {t} from 'sentry/locale';
  10. import type {Organization} from 'sentry/types/organization';
  11. import type {Project, ProjectKey} from 'sentry/types/project';
  12. import LoaderScript from 'sentry/views/settings/project/loaderScript';
  13. function mockApi({
  14. organization,
  15. project,
  16. projectKeys,
  17. }: {
  18. organization: Organization;
  19. project: Project;
  20. projectKeys: ProjectKey[];
  21. }) {
  22. MockApiClient.clearMockResponses();
  23. MockApiClient.addMockResponse({
  24. url: `/projects/${organization.slug}/${project.slug}/keys/`,
  25. method: 'GET',
  26. body: projectKeys,
  27. });
  28. }
  29. describe('LoaderScript', function () {
  30. it('renders error', async function () {
  31. const {organization, project} = initializeOrg();
  32. MockApiClient.clearMockResponses();
  33. MockApiClient.addMockResponse({
  34. url: `/projects/${organization.slug}/${project.slug}/keys/`,
  35. method: 'GET',
  36. statusCode: 400,
  37. });
  38. render(<LoaderScript project={project} />);
  39. await waitForElementToBeRemoved(() => screen.queryByTestId('loading-indicator'));
  40. expect(screen.getByTestId('loading-error')).toHaveTextContent(
  41. 'Failed to load project keys.'
  42. );
  43. });
  44. it('renders empty', async function () {
  45. const {organization, project} = initializeOrg();
  46. mockApi({organization, project, projectKeys: []});
  47. render(<LoaderScript project={project} />);
  48. await waitForElementToBeRemoved(() => screen.queryByTestId('loading-indicator'));
  49. expect(
  50. screen.getByText('There are no keys active for this project.')
  51. ).toBeInTheDocument();
  52. });
  53. it('renders for single project', async function () {
  54. const {organization, project} = initializeOrg();
  55. const projectKey = ProjectKeysFixture()[0];
  56. const projectKeys = [projectKey];
  57. mockApi({organization, project, projectKeys});
  58. render(<LoaderScript project={project} />);
  59. await waitForElementToBeRemoved(() => screen.queryByTestId('loading-indicator'));
  60. // Loader Script is rendered
  61. expect(screen.getByText(`Client Key: ${projectKey.name}`)).toBeInTheDocument();
  62. const loaderScript = screen.getByRole('textbox', {
  63. name: 'Loader Script',
  64. }) as HTMLInputElement;
  65. const loaderScriptValue = loaderScript.value;
  66. expect(loaderScriptValue).toEqual(expect.stringContaining(projectKeys[0].dsn.cdn));
  67. });
  68. it('renders multiple keys', async function () {
  69. const {organization, project} = initializeOrg();
  70. const projectKeys = ProjectKeysFixture([
  71. {
  72. dsn: {
  73. secret:
  74. 'http://188ee45a58094d939428d8585aa6f662:a33bf9aba64c4bbdaf873bb9023b6d2c@dev.getsentry.net:8000/1',
  75. minidump:
  76. 'http://dev.getsentry.net:8000/api/1/minidump?sentry_key=188ee45a58094d939428d8585aa6f662',
  77. public: 'http://188ee45a58094d939428d8585aa6f662@dev.getsentry.net:8000/1',
  78. cdn: 'http://dev.getsentry.net:8000/js-sdk-loader/188ee45a58094d939428d8585aa6f662.min.js',
  79. csp: 'http://dev.getsentry.net:8000/api/1/csp-report/?sentry_key=188ee45a58094d939428d8585aa6f662',
  80. security:
  81. 'http://dev.getsentry.net:8000/api/1/security-report/?sentry_key=188ee45a58094d939428d8585aa6f662',
  82. unreal: '',
  83. crons: '',
  84. },
  85. public: '188ee45a58094d939428d8585aa6f662',
  86. secret: 'a33bf9aba64c4bbdaf873bb9023b6d2c',
  87. name: 'Key 2',
  88. rateLimit: null,
  89. projectId: 1,
  90. dateCreated: '2018-02-28T07:13:51.087Z',
  91. id: '188ee45a58094d939428d8585aa6f662',
  92. isActive: true,
  93. label: 'Key 2',
  94. browserSdkVersion: 'latest',
  95. browserSdk: {
  96. choices: [
  97. ['latest', 'latest'],
  98. ['7.x', '7.x'],
  99. ['6.x', '6.x'],
  100. ['5.x', '5.x'],
  101. ['4.x', '4.x'],
  102. ],
  103. },
  104. dynamicSdkLoaderOptions: {
  105. hasPerformance: false,
  106. hasReplay: false,
  107. hasDebug: false,
  108. },
  109. },
  110. ]);
  111. mockApi({organization, project, projectKeys});
  112. render(<LoaderScript project={project} />);
  113. await waitForElementToBeRemoved(() => screen.queryByTestId('loading-indicator'));
  114. expect(screen.getByText(`Client Key: ${projectKeys[0].name}`)).toBeInTheDocument();
  115. expect(screen.getByText(`Client Key: ${projectKeys[1].name}`)).toBeInTheDocument();
  116. const allLoaderScripts = screen.getAllByRole('textbox', {
  117. name: 'Loader Script',
  118. }) as HTMLInputElement[];
  119. expect(allLoaderScripts).toHaveLength(2);
  120. });
  121. it('allows to update key settings', async function () {
  122. const {organization, project} = initializeOrg();
  123. const baseKey = ProjectKeysFixture()[0];
  124. const projectKey = {
  125. ...baseKey,
  126. dynamicSdkLoaderOptions: {
  127. ...baseKey.dynamicSdkLoaderOptions,
  128. hasReplay: true,
  129. },
  130. };
  131. mockApi({organization, project, projectKeys: [projectKey]});
  132. const mockPut = MockApiClient.addMockResponse({
  133. url: `/projects/${organization.slug}/${project.slug}/keys/${projectKey.id}/`,
  134. method: 'PUT',
  135. body: {
  136. ...projectKey,
  137. dynamicSdkLoaderOptions: {
  138. ...projectKey.dynamicSdkLoaderOptions,
  139. hasPerformance: true,
  140. },
  141. },
  142. });
  143. render(<LoaderScript project={project} />);
  144. await waitForElementToBeRemoved(() => screen.queryByTestId('loading-indicator'));
  145. expect(screen.getByText(t('Enable Performance Monitoring'))).toBeInTheDocument();
  146. expect(screen.getByText(t('Enable Session Replay'))).toBeInTheDocument();
  147. expect(screen.getByText(t('Enable Debug Bundles & Logging'))).toBeInTheDocument();
  148. let performanceCheckbox = screen.getByRole('checkbox', {
  149. name: t('Enable Performance Monitoring'),
  150. });
  151. expect(performanceCheckbox).toBeEnabled();
  152. expect(performanceCheckbox).not.toBeChecked();
  153. const replayCheckbox = screen.getByRole('checkbox', {
  154. name: t('Enable Session Replay'),
  155. });
  156. expect(replayCheckbox).toBeEnabled();
  157. expect(replayCheckbox).toBeChecked();
  158. const debugCheckbox = screen.getByRole('checkbox', {
  159. name: t('Enable Debug Bundles & Logging'),
  160. });
  161. expect(debugCheckbox).toBeEnabled();
  162. expect(debugCheckbox).not.toBeChecked();
  163. // Toggle performance option
  164. await userEvent.click(
  165. screen.getByRole('checkbox', {
  166. name: t('Enable Performance Monitoring'),
  167. })
  168. );
  169. performanceCheckbox = await screen.findByRole('checkbox', {
  170. name: t('Enable Performance Monitoring'),
  171. checked: true,
  172. });
  173. expect(performanceCheckbox).toBeEnabled();
  174. expect(performanceCheckbox).toBeChecked();
  175. expect(mockPut).toHaveBeenCalledWith(
  176. `/projects/${organization.slug}/${project.slug}/keys/${projectKey.id}/`,
  177. expect.objectContaining({
  178. data: expect.objectContaining({
  179. dynamicSdkLoaderOptions: {
  180. ...projectKey.dynamicSdkLoaderOptions,
  181. hasPerformance: true,
  182. },
  183. }),
  184. })
  185. );
  186. });
  187. it('allows to update one of multiple keys', async function () {
  188. const {organization, project} = initializeOrg();
  189. const projectKeys = ProjectKeysFixture([
  190. {
  191. dsn: {
  192. secret:
  193. 'http://188ee45a58094d939428d8585aa6f662:a33bf9aba64c4bbdaf873bb9023b6d2c@dev.getsentry.net:8000/1',
  194. minidump:
  195. 'http://dev.getsentry.net:8000/api/1/minidump?sentry_key=188ee45a58094d939428d8585aa6f662',
  196. public: 'http://188ee45a58094d939428d8585aa6f662@dev.getsentry.net:8000/1',
  197. cdn: 'http://dev.getsentry.net:8000/js-sdk-loader/188ee45a58094d939428d8585aa6f662.min.js',
  198. csp: 'http://dev.getsentry.net:8000/api/1/csp-report/?sentry_key=188ee45a58094d939428d8585aa6f662',
  199. security:
  200. 'http://dev.getsentry.net:8000/api/1/security-report/?sentry_key=188ee45a58094d939428d8585aa6f662',
  201. unreal: '',
  202. crons: '',
  203. },
  204. public: '188ee45a58094d939428d8585aa6f662',
  205. secret: 'a33bf9aba64c4bbdaf873bb9023b6d2c',
  206. name: 'Key 2',
  207. rateLimit: null,
  208. projectId: 1,
  209. dateCreated: '2018-02-28T07:13:51.087Z',
  210. id: '188ee45a58094d939428d8585aa6f662',
  211. isActive: true,
  212. label: 'Key 2',
  213. browserSdkVersion: 'latest',
  214. browserSdk: {
  215. choices: [
  216. ['latest', 'latest'],
  217. ['7.x', '7.x'],
  218. ['6.x', '6.x'],
  219. ['5.x', '5.x'],
  220. ['4.x', '4.x'],
  221. ],
  222. },
  223. dynamicSdkLoaderOptions: {
  224. hasPerformance: false,
  225. hasReplay: false,
  226. hasDebug: false,
  227. },
  228. },
  229. ]);
  230. const projectKey = projectKeys[1];
  231. mockApi({organization, project, projectKeys});
  232. const mockPut = MockApiClient.addMockResponse({
  233. url: `/projects/${organization.slug}/${project.slug}/keys/${projectKey.id}/`,
  234. method: 'PUT',
  235. body: {
  236. ...projectKey,
  237. dynamicSdkLoaderOptions: {
  238. ...projectKey.dynamicSdkLoaderOptions,
  239. hasPerformance: true,
  240. },
  241. },
  242. });
  243. render(<LoaderScript project={project} />);
  244. await waitForElementToBeRemoved(() => screen.queryByTestId('loading-indicator'));
  245. expect(
  246. screen.getAllByRole('checkbox', {
  247. name: t('Enable Performance Monitoring'),
  248. checked: false,
  249. })
  250. ).toHaveLength(2);
  251. expect(
  252. screen.getAllByRole('checkbox', {
  253. name: t('Enable Session Replay'),
  254. checked: false,
  255. })
  256. ).toHaveLength(2);
  257. expect(
  258. screen.getAllByRole('checkbox', {
  259. name: t('Enable Debug Bundles & Logging'),
  260. checked: false,
  261. })
  262. ).toHaveLength(2);
  263. // Toggle performance option
  264. await userEvent.click(
  265. screen.getAllByRole('checkbox', {
  266. name: t('Enable Performance Monitoring'),
  267. })[1]
  268. );
  269. expect(
  270. await screen.findByRole('checkbox', {
  271. name: t('Enable Performance Monitoring'),
  272. checked: true,
  273. })
  274. ).toBeInTheDocument();
  275. expect(
  276. screen.getByRole('checkbox', {
  277. name: t('Enable Performance Monitoring'),
  278. checked: false,
  279. })
  280. ).toBeInTheDocument();
  281. expect(
  282. screen.getAllByRole('checkbox', {
  283. name: t('Enable Session Replay'),
  284. checked: false,
  285. })
  286. ).toHaveLength(2);
  287. expect(
  288. screen.getAllByRole('checkbox', {
  289. name: t('Enable Debug Bundles & Logging'),
  290. checked: false,
  291. })
  292. ).toHaveLength(2);
  293. expect(mockPut).toHaveBeenCalledWith(
  294. `/projects/${organization.slug}/${project.slug}/keys/${projectKey.id}/`,
  295. expect.objectContaining({
  296. data: expect.objectContaining({
  297. dynamicSdkLoaderOptions: {
  298. ...projectKey.dynamicSdkLoaderOptions,
  299. hasPerformance: true,
  300. },
  301. }),
  302. })
  303. );
  304. });
  305. });