teamProjects.spec.tsx 4.1 KB

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