teamMembers.spec.jsx 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. import React from 'react';
  2. import {Client} from 'app/api';
  3. import {initializeOrg} from 'sentry-test/initializeOrg';
  4. import {mountWithTheme} from 'sentry-test/enzyme';
  5. import {openInviteMembersModal} from 'app/actionCreators/modal';
  6. import TeamMembers from 'app/views/settings/organizationTeams/teamMembers';
  7. jest.mock('app/actionCreators/modal', () => ({
  8. openInviteMembersModal: jest.fn(),
  9. }));
  10. describe('TeamMembers', function() {
  11. const {organization, routerContext} = initializeOrg();
  12. const team = TestStubs.Team();
  13. const members = TestStubs.Members();
  14. beforeEach(function() {
  15. Client.clearMockResponses();
  16. Client.addMockResponse({
  17. url: `/organizations/${organization.slug}/members/`,
  18. method: 'GET',
  19. body: members,
  20. });
  21. Client.addMockResponse({
  22. url: `/teams/${organization.slug}/${team.slug}/members/`,
  23. method: 'GET',
  24. body: members,
  25. });
  26. });
  27. it('renders', async function() {
  28. const wrapper = mountWithTheme(
  29. <TeamMembers
  30. params={{orgId: organization.slug, teamId: team.slug}}
  31. organization={organization}
  32. />,
  33. routerContext
  34. );
  35. await tick();
  36. wrapper.update();
  37. });
  38. it('can invite member from team dropdown with access', async function() {
  39. const org = TestStubs.Organization({access: ['team:admin'], openMembership: false});
  40. const wrapper = mountWithTheme(
  41. <TeamMembers params={{orgId: org.slug, teamId: team.slug}} organization={org} />,
  42. routerContext
  43. );
  44. await tick();
  45. wrapper.update();
  46. wrapper.find('DropdownButton[data-test-id="add-member"]').simulate('click');
  47. wrapper
  48. .find('StyledCreateMemberLink[data-test-id="invite-member"]')
  49. .simulate('click');
  50. expect(openInviteMembersModal).toHaveBeenCalled();
  51. });
  52. it('can invite member from team dropdown with access and `Open Membership` enabled', async function() {
  53. const org = TestStubs.Organization({access: ['team:admin'], openMembership: true});
  54. const wrapper = mountWithTheme(
  55. <TeamMembers params={{orgId: org.slug, teamId: team.slug}} organization={org} />,
  56. routerContext
  57. );
  58. await tick();
  59. wrapper.update();
  60. wrapper.find('DropdownButton[data-test-id="add-member"]').simulate('click');
  61. wrapper
  62. .find('StyledCreateMemberLink[data-test-id="invite-member"]')
  63. .simulate('click');
  64. expect(openInviteMembersModal).toHaveBeenCalled();
  65. });
  66. it('can invite member from team dropdown without access and `Open Membership` enabled', async function() {
  67. const org = TestStubs.Organization({access: [], openMembership: true});
  68. const wrapper = mountWithTheme(
  69. <TeamMembers params={{orgId: org.slug, teamId: team.slug}} organization={org} />,
  70. routerContext
  71. );
  72. await tick();
  73. wrapper.update();
  74. wrapper.find('DropdownButton[data-test-id="add-member"]').simulate('click');
  75. wrapper
  76. .find('StyledCreateMemberLink[data-test-id="invite-member"]')
  77. .simulate('click');
  78. expect(openInviteMembersModal).toHaveBeenCalled();
  79. });
  80. it('cannot invite member from team dropdown without access and `Open Membership` disabled', async function() {
  81. const org = TestStubs.Organization({access: [], openMembership: false});
  82. const wrapper = mountWithTheme(
  83. <TeamMembers params={{orgId: org.slug, teamId: team.slug}} organization={org} />,
  84. routerContext
  85. );
  86. await tick();
  87. wrapper.update();
  88. expect(
  89. wrapper.find('DropdownButton[data-test-id="add-member"]').prop('disabled')
  90. ).toBe(true);
  91. });
  92. it('can remove member from team', async function() {
  93. const endpoint = `/organizations/${organization.slug}/members/${
  94. members[0].id
  95. }/teams/${team.slug}/`;
  96. const mock = Client.addMockResponse({
  97. url: endpoint,
  98. method: 'DELETE',
  99. statusCode: 200,
  100. });
  101. const wrapper = mountWithTheme(
  102. <TeamMembers
  103. params={{orgId: organization.slug, teamId: team.slug}}
  104. organization={organization}
  105. />,
  106. routerContext
  107. );
  108. await tick();
  109. wrapper.update();
  110. expect(mock).not.toHaveBeenCalled();
  111. wrapper
  112. .find('Button')
  113. .at(1)
  114. .simulate('click');
  115. expect(mock).toHaveBeenCalledWith(
  116. endpoint,
  117. expect.objectContaining({
  118. method: 'DELETE',
  119. })
  120. );
  121. });
  122. it('can only remove self from team', async function() {
  123. const me = TestStubs.Member({
  124. id: '123',
  125. email: 'foo@example.com',
  126. });
  127. Client.addMockResponse({
  128. url: `/teams/${organization.slug}/${team.slug}/members/`,
  129. method: 'GET',
  130. body: [...members, me],
  131. });
  132. const endpoint = `/organizations/${organization.slug}/members/${me.id}/teams/${
  133. team.slug
  134. }/`;
  135. const mock = Client.addMockResponse({
  136. url: endpoint,
  137. method: 'DELETE',
  138. statusCode: 200,
  139. });
  140. const organizationMember = TestStubs.Organization({
  141. access: [],
  142. });
  143. const wrapper = mountWithTheme(
  144. <TeamMembers
  145. params={{orgId: organization.slug, teamId: team.slug}}
  146. organization={organizationMember}
  147. />,
  148. routerContext
  149. );
  150. await tick();
  151. wrapper.update();
  152. expect(mock).not.toHaveBeenCalled();
  153. expect(wrapper.find('IdBadge')).toHaveLength(members.length + 1);
  154. // Can only remove self
  155. expect(wrapper.find('button[aria-label="Remove"]')).toHaveLength(1);
  156. wrapper.find('button[aria-label="Remove"]').simulate('click');
  157. expect(mock).toHaveBeenCalledWith(
  158. endpoint,
  159. expect.objectContaining({
  160. method: 'DELETE',
  161. })
  162. );
  163. });
  164. });