teamProjects.spec.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import {Organization} from 'sentry-fixture/organization';
  2. import {initializeOrg} from 'sentry-test/initializeOrg';
  3. import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
  4. import OrganizationTeamProjects from 'sentry/views/settings/organizationTeams/teamProjects';
  5. describe('OrganizationTeamProjects', function () {
  6. let getMock!: jest.Mock;
  7. let putMock!: jest.Mock;
  8. let postMock!: jest.Mock;
  9. let deleteMock!: jest.Mock;
  10. const team = TestStubs.Team({slug: 'team-slug'});
  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, routerProps, organization} = initializeOrg({
  22. organization: Organization({slug: 'org-slug'}),
  23. projects: [project, project2],
  24. router: {params: {teamId: team.slug}},
  25. });
  26. beforeEach(function () {
  27. getMock = MockApiClient.addMockResponse({
  28. url: '/organizations/org-slug/projects/',
  29. body: [project, project2],
  30. });
  31. putMock = MockApiClient.addMockResponse({
  32. method: 'PUT',
  33. url: '/projects/org-slug/project-slug/',
  34. body: project,
  35. });
  36. postMock = MockApiClient.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 = MockApiClient.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. MockApiClient.clearMockResponses();
  51. });
  52. it('should fetch linked and unlinked projects', async function () {
  53. render(<OrganizationTeamProjects {...routerProps} team={team} />, {
  54. context: routerContext,
  55. organization,
  56. });
  57. expect(await screen.findByText('project-slug')).toBeInTheDocument();
  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 allow bookmarking', async function () {
  63. render(<OrganizationTeamProjects {...routerProps} team={team} />, {
  64. context: routerContext,
  65. organization,
  66. });
  67. const stars = await screen.findAllByRole('button', {name: 'Bookmark Project'});
  68. expect(stars).toHaveLength(2);
  69. await userEvent.click(stars[0]);
  70. expect(
  71. screen.getByRole('button', {name: 'Bookmark Project', pressed: true})
  72. ).toBeInTheDocument();
  73. expect(putMock).toHaveBeenCalledTimes(1);
  74. expect(putMock).toHaveBeenCalledWith(
  75. expect.any(String),
  76. expect.objectContaining({
  77. data: {isBookmarked: true},
  78. })
  79. );
  80. });
  81. it('should allow adding and removing projects', async function () {
  82. render(<OrganizationTeamProjects {...routerProps} team={team} />, {
  83. context: routerContext,
  84. organization,
  85. });
  86. expect(getMock).toHaveBeenCalledTimes(2);
  87. await userEvent.click(await screen.findByText('Add Project'));
  88. await userEvent.click(screen.getByRole('option', {name: 'project-slug-2'}));
  89. expect(postMock).toHaveBeenCalledTimes(1);
  90. // find second project's remove button
  91. const removeButtons = await screen.findAllByRole('button', {name: 'Remove'});
  92. await userEvent.click(removeButtons[1]);
  93. expect(deleteMock).toHaveBeenCalledTimes(1);
  94. });
  95. it('handles filtering unlinked projects', async function () {
  96. render(<OrganizationTeamProjects {...routerProps} team={team} />, {
  97. context: routerContext,
  98. organization,
  99. });
  100. expect(getMock).toHaveBeenCalledTimes(2);
  101. await userEvent.click(await screen.findByText('Add Project'));
  102. await userEvent.type(screen.getByRole('textbox'), 'a');
  103. expect(getMock).toHaveBeenCalledTimes(3);
  104. expect(getMock).toHaveBeenCalledWith(
  105. '/organizations/org-slug/projects/',
  106. expect.objectContaining({
  107. query: expect.objectContaining({
  108. query: '!team:team-slug a',
  109. }),
  110. })
  111. );
  112. });
  113. });