organizationMemberRow.spec.jsx 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. import {mountWithTheme} from 'sentry-test/enzyme';
  2. import OrganizationMemberRow from 'sentry/views/settings/organizationMembers/organizationMemberRow';
  3. describe('OrganizationMemberRow', function () {
  4. const member = {
  5. id: '1',
  6. email: '',
  7. name: '',
  8. role: 'member',
  9. roleName: 'Member',
  10. pending: false,
  11. flags: {
  12. 'sso:linked': false,
  13. },
  14. user: {
  15. id: '',
  16. has2fa: false,
  17. name: 'sentry@test.com',
  18. },
  19. };
  20. const currentUser = {
  21. id: '2',
  22. email: 'currentUser@email.com',
  23. };
  24. const defaultProps = {
  25. routes: [],
  26. orgId: 'org-slug',
  27. orgName: 'Organization Name',
  28. status: '',
  29. requireLink: false,
  30. memberCanLeave: false,
  31. canAddMembers: false,
  32. canRemoveMembers: false,
  33. member,
  34. currentUser,
  35. onSendInvite: () => {},
  36. onRemove: () => {},
  37. onLeave: () => {},
  38. };
  39. const resendButton = 'StyledButton[aria-label="Resend invite"]';
  40. const resendSsoButton = 'StyledButton[aria-label="Resend SSO link"]';
  41. const leaveButton = 'StyledButton[aria-label="Leave"]';
  42. const removeButton = 'StyledButton[aria-label="Remove"]';
  43. beforeEach(function () {});
  44. it('does not have 2fa warning if user has 2fa', function () {
  45. const wrapper = mountWithTheme(
  46. <OrganizationMemberRow
  47. {...defaultProps}
  48. member={{
  49. ...member,
  50. user: {
  51. ...member.user,
  52. has2fa: true,
  53. },
  54. }}
  55. />
  56. );
  57. expect(wrapper.find('IconCheckmark')).toHaveLength(1);
  58. expect(wrapper.find('IconFlag')).toHaveLength(0);
  59. });
  60. it('has 2fa warning if user does not have 2fa enabled', function () {
  61. const wrapper = mountWithTheme(
  62. <OrganizationMemberRow
  63. {...defaultProps}
  64. member={{
  65. ...member,
  66. user: {
  67. ...member.user,
  68. has2fa: false,
  69. },
  70. }}
  71. />
  72. );
  73. expect(wrapper.find('IconCheckmark')).toHaveLength(0);
  74. expect(wrapper.find('IconFlag')).toHaveLength(1);
  75. });
  76. describe('Pending user', function () {
  77. const props = {
  78. ...defaultProps,
  79. member: {
  80. ...member,
  81. pending: true,
  82. },
  83. };
  84. it('has "Invited" status, no "Resend Invite"', function () {
  85. const wrapper = mountWithTheme(
  86. <OrganizationMemberRow
  87. {...props}
  88. member={{
  89. ...member,
  90. pending: true,
  91. }}
  92. />
  93. );
  94. expect(wrapper.find('[data-test-id="member-role"]').text()).toBe('Invited Member');
  95. expect(wrapper.find(resendButton).prop('disabled')).toBe(true);
  96. });
  97. it('has "Resend Invite" button only if `canAddMembers` is true', function () {
  98. const wrapper = mountWithTheme(<OrganizationMemberRow {...props} canAddMembers />);
  99. expect(wrapper.find('[data-test-id="member-role"]').text()).toBe('Invited Member');
  100. expect(wrapper.find(resendButton).prop('disabled')).toBe(false);
  101. });
  102. it('has the right inviting states', function () {
  103. let wrapper = mountWithTheme(<OrganizationMemberRow {...props} canAddMembers />);
  104. expect(wrapper.find(resendButton).exists()).toBe(true);
  105. wrapper = mountWithTheme(
  106. <OrganizationMemberRow {...props} canAddMembers status="loading" />
  107. );
  108. // Should have loader
  109. expect(wrapper.find('LoadingIndicator')).toHaveLength(1);
  110. // No Resend Invite button
  111. expect(wrapper.find(resendButton).exists()).toBe(false);
  112. wrapper = mountWithTheme(
  113. <OrganizationMemberRow {...props} canAddMembers status="success" />
  114. );
  115. // Should have loader
  116. expect(wrapper.find('LoadingIndicator')).toHaveLength(0);
  117. // No Resend Invite button
  118. expect(wrapper.find(resendButton).exists()).toBe(false);
  119. expect(wrapper.find('[data-test-id="member-status"]').text()).toBe('Sent!');
  120. });
  121. });
  122. describe('Expired user', function () {
  123. it('has "Expired" status', function () {
  124. const wrapper = mountWithTheme(
  125. <OrganizationMemberRow
  126. {...defaultProps}
  127. canAddMembers
  128. member={{
  129. ...member,
  130. pending: true,
  131. expired: true,
  132. }}
  133. />
  134. );
  135. expect(wrapper.find('[data-test-id="member-role"]').text()).toBe('Expired Invite');
  136. expect(wrapper.find(resendButton).prop('disabled')).toBe(false);
  137. });
  138. });
  139. describe('Requires SSO Link', function () {
  140. const props = {
  141. ...defaultProps,
  142. flags: {
  143. 'sso:link': false,
  144. },
  145. requireLink: true,
  146. };
  147. it('shows "Invited" status if user has not registered and not linked', function () {
  148. const wrapper = mountWithTheme(
  149. <OrganizationMemberRow
  150. {...props}
  151. canAddMembers
  152. member={{
  153. ...member,
  154. pending: true,
  155. }}
  156. />
  157. );
  158. expect(wrapper.find('[data-test-id="member-role"]').text()).toBe('Invited Member');
  159. expect(wrapper.find(resendButton).prop('disabled')).toBe(false);
  160. });
  161. it('shows "missing SSO link" message if user is registered and needs link', function () {
  162. const wrapper = mountWithTheme(
  163. <OrganizationMemberRow
  164. {...props}
  165. member={{
  166. ...member,
  167. }}
  168. />
  169. );
  170. expect(wrapper.find('[data-test-id="member-role"]').text()).toBe('Member');
  171. expect(wrapper.find(resendSsoButton).prop('disabled')).toBe(true);
  172. });
  173. it('has "Resend SSO link" button only if `canAddMembers` is true and no link', function () {
  174. const wrapper = mountWithTheme(
  175. <OrganizationMemberRow
  176. {...props}
  177. canAddMembers
  178. member={{
  179. ...member,
  180. }}
  181. />
  182. );
  183. expect(wrapper.find(resendSsoButton).prop('disabled')).toBe(false);
  184. });
  185. it('has 2fa warning if user is linked does not have 2fa enabled', function () {
  186. const wrapper = mountWithTheme(
  187. <OrganizationMemberRow
  188. {...defaultProps}
  189. member={{
  190. ...member,
  191. flags: {
  192. 'sso:linked': true,
  193. },
  194. user: {
  195. ...member.user,
  196. has2fa: false,
  197. },
  198. }}
  199. />
  200. );
  201. expect(wrapper.find('IconCheckmark')).toHaveLength(0);
  202. expect(wrapper.find('IconFlag')).toHaveLength(1);
  203. });
  204. });
  205. describe('Is Current User', function () {
  206. const props = {
  207. ...defaultProps,
  208. member: {
  209. ...member,
  210. email: 'currentUser@email.com',
  211. },
  212. };
  213. it('has button to leave organization and no button to remove', function () {
  214. const wrapper = mountWithTheme(<OrganizationMemberRow {...props} memberCanLeave />);
  215. expect(wrapper.find(leaveButton).exists()).toBe(true);
  216. expect(wrapper.find(removeButton).exists()).toBe(false);
  217. });
  218. it('has disabled button to leave organization and no button to remove when member can not leave', function () {
  219. const wrapper = mountWithTheme(
  220. <OrganizationMemberRow {...props} memberCanLeave={false} />
  221. );
  222. expect(wrapper.find(leaveButton).prop('disabled')).toBe(true);
  223. expect(wrapper.find(removeButton).exists()).toBe(false);
  224. });
  225. });
  226. describe('Not Current User', function () {
  227. const props = {
  228. ...defaultProps,
  229. };
  230. it('does not have Leave button', function () {
  231. const wrapper = mountWithTheme(<OrganizationMemberRow {...props} memberCanLeave />);
  232. expect(wrapper.find(leaveButton).exists()).toBe(false);
  233. });
  234. it('has Remove disabled button when `canRemoveMembers` is false', function () {
  235. const wrapper = mountWithTheme(<OrganizationMemberRow {...props} />);
  236. expect(wrapper.find(removeButton).prop('disabled')).toBe(true);
  237. });
  238. it('has Remove button when `canRemoveMembers` is true', function () {
  239. const wrapper = mountWithTheme(
  240. <OrganizationMemberRow {...props} canRemoveMembers />
  241. );
  242. expect(wrapper.find(removeButton).prop('disabled')).toBe(false);
  243. });
  244. });
  245. });