teamProjects.spec.jsx 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. import {initializeOrg} from 'sentry-test/initializeOrg';
  2. import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
  3. import {Client} from 'sentry/api';
  4. import {TeamProjects as OrganizationTeamProjects} from 'sentry/views/settings/organizationTeams/teamProjects';
  5. describe('OrganizationTeamProjects', function () {
  6. let team;
  7. let getMock;
  8. let putMock;
  9. let postMock;
  10. let deleteMock;
  11. const project = TestStubs.Project({
  12. teams: [team],
  13. access: ['project:read', 'project:write', 'project:admin'],
  14. });
  15. const project2 = TestStubs.Project({
  16. id: '3',
  17. slug: 'project-slug-2',
  18. name: 'Project Name 2',
  19. access: ['project:read', 'project:write', 'project:admin'],
  20. });
  21. const {routerContext, organization} = initializeOrg({
  22. organization: TestStubs.Organization({slug: 'org-slug'}),
  23. projects: [project, project2],
  24. });
  25. beforeEach(function () {
  26. team = TestStubs.Team({slug: 'team-slug'});
  27. getMock = Client.addMockResponse({
  28. url: '/organizations/org-slug/projects/',
  29. body: [project, project2],
  30. });
  31. putMock = Client.addMockResponse({
  32. method: 'PUT',
  33. url: '/projects/org-slug/project-slug/',
  34. body: project,
  35. });
  36. postMock = Client.addMockResponse({
  37. method: 'POST',
  38. url: `/projects/org-slug/${project2.slug}/teams/${team.slug}/`,
  39. body: {...project2, teams: [team]},
  40. status: 201,
  41. });
  42. deleteMock = Client.addMockResponse({
  43. method: 'DELETE',
  44. url: `/projects/org-slug/${project2.slug}/teams/${team.slug}/`,
  45. body: {...project2, teams: []},
  46. status: 204,
  47. });
  48. });
  49. afterEach(function () {
  50. Client.clearMockResponses();
  51. });
  52. it('fetches linked and unlinked projects', function () {
  53. render(
  54. <OrganizationTeamProjects
  55. api={new MockApiClient()}
  56. organization={organization}
  57. team={team}
  58. params={{orgId: 'org-slug', teamId: team.slug}}
  59. location={{query: {}}}
  60. />,
  61. {context: routerContext}
  62. );
  63. expect(getMock).toHaveBeenCalledTimes(2);
  64. expect(getMock.mock.calls[0][1].query.query).toBe('team:team-slug');
  65. expect(getMock.mock.calls[1][1].query.query).toBe('!team:team-slug');
  66. });
  67. it('Should render', async function () {
  68. const {container} = render(
  69. <OrganizationTeamProjects
  70. api={new MockApiClient()}
  71. organization={organization}
  72. team={team}
  73. params={{orgId: 'org-slug', teamId: team.slug}}
  74. location={{query: {}}}
  75. />,
  76. {context: routerContext}
  77. );
  78. expect(await screen.findByText('project-slug')).toBeInTheDocument();
  79. expect(container).toSnapshot();
  80. });
  81. it('Should allow bookmarking', async function () {
  82. render(
  83. <OrganizationTeamProjects
  84. api={new MockApiClient()}
  85. organization={organization}
  86. team={team}
  87. params={{orgId: 'org-slug', teamId: team.slug}}
  88. location={{query: {}}}
  89. />,
  90. {context: routerContext}
  91. );
  92. const stars = await screen.findAllByRole('button', {name: 'Bookmark Project'});
  93. expect(stars).toHaveLength(2);
  94. await userEvent.click(stars[0]);
  95. expect(
  96. screen.getByRole('button', {name: 'Bookmark Project', pressed: true})
  97. ).toBeInTheDocument();
  98. expect(putMock).toHaveBeenCalledTimes(1);
  99. });
  100. it('Should allow adding and removing projects', async function () {
  101. render(
  102. <OrganizationTeamProjects
  103. api={new MockApiClient()}
  104. organization={organization}
  105. team={team}
  106. params={{orgId: 'org-slug', teamId: team.slug}}
  107. location={{query: {}}}
  108. />,
  109. {context: routerContext}
  110. );
  111. expect(getMock).toHaveBeenCalledTimes(2);
  112. await userEvent.click(await screen.findByText('Add Project'));
  113. // console.log(screen.debug());
  114. await userEvent.click(screen.getByRole('option', {name: 'project-slug-2'}));
  115. expect(postMock).toHaveBeenCalledTimes(1);
  116. // find second project's remove button
  117. const removeButtons = await screen.findAllByRole('button', {name: 'Remove'});
  118. await userEvent.click(removeButtons[1]);
  119. expect(deleteMock).toHaveBeenCalledTimes(1);
  120. });
  121. it('handles filtering unlinked projects', async function () {
  122. render(
  123. <OrganizationTeamProjects
  124. api={new MockApiClient()}
  125. organization={organization}
  126. team={team}
  127. params={{orgId: 'org-slug', teamId: team.slug}}
  128. location={{query: {}}}
  129. />,
  130. {context: routerContext}
  131. );
  132. expect(getMock).toHaveBeenCalledTimes(2);
  133. await userEvent.click(await screen.findByText('Add Project'));
  134. await userEvent.type(screen.getByRole('textbox'), 'a');
  135. expect(getMock).toHaveBeenCalledTimes(3);
  136. expect(getMock).toHaveBeenCalledWith(
  137. '/organizations/org-slug/projects/',
  138. expect.objectContaining({
  139. query: expect.objectContaining({
  140. query: '!team:team-slug a',
  141. }),
  142. })
  143. );
  144. });
  145. });