loaderScript.spec.tsx 11 KB

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