teamProjects.spec.jsx 4.6 KB

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