teamProjects.spec.tsx 4.3 KB

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