integrationExternalMappingForm.spec.jsx 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. import {act, render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
  2. import IntegrationExternalMappingForm from 'sentry/components/integrationExternalMappingForm';
  3. describe('IntegrationExternalMappingForm', function () {
  4. const dataEndpoint = '/test/dataEndpoint/';
  5. const baseProps = {
  6. integration: TestStubs.GitHubIntegration(),
  7. dataEndpoint,
  8. getBaseFormEndpoint: jest.fn(_mapping => dataEndpoint),
  9. sentryNamesMapper: mappings => mappings,
  10. };
  11. const MOCK_USER_MAPPING = {
  12. id: '1',
  13. userId: '1',
  14. externalName: '@gwen',
  15. sentryName: 'gwen@mcu.org',
  16. };
  17. const MOCK_TEAM_MAPPING = {
  18. id: '1',
  19. teamId: '1',
  20. externalName: '@getsentry/animals',
  21. sentryName: '#zoo',
  22. };
  23. const DEFAULT_OPTIONS = [
  24. {id: '1', name: 'option1'},
  25. {id: '2', name: 'option2'},
  26. {id: '3', name: 'option3'},
  27. ];
  28. let getResponse, postResponse, putResponse;
  29. beforeEach(() => {
  30. jest.clearAllMocks();
  31. MockApiClient.clearMockResponses();
  32. getResponse = MockApiClient.addMockResponse({
  33. url: dataEndpoint,
  34. method: 'GET',
  35. body: DEFAULT_OPTIONS,
  36. });
  37. postResponse = MockApiClient.addMockResponse({
  38. url: dataEndpoint,
  39. method: 'POST',
  40. body: {},
  41. });
  42. putResponse = MockApiClient.addMockResponse({
  43. url: `${dataEndpoint}1/`,
  44. method: 'PUT',
  45. body: {},
  46. });
  47. });
  48. // No mapping provided (e.g. Create a new mapping)
  49. it('renders with no mapping provided as a form', function () {
  50. render(<IntegrationExternalMappingForm type="user" {...baseProps} />);
  51. expect(screen.getByPlaceholderText('@username')).toBeInTheDocument();
  52. expect(screen.getByText('Select Sentry User')).toBeInTheDocument();
  53. expect(screen.getByTestId('form-submit')).toBeInTheDocument();
  54. });
  55. it('renders with no mapping as an inline field', async function () {
  56. render(<IntegrationExternalMappingForm isInline type="user" {...baseProps} />);
  57. await act(tick);
  58. expect(screen.queryByPlaceholderText('@username')).not.toBeInTheDocument();
  59. expect(screen.getByText('Select Sentry User')).toBeInTheDocument();
  60. expect(screen.queryByTestId('form-submit')).not.toBeInTheDocument();
  61. });
  62. // Full mapping provided (e.g. Update an existing mapping)
  63. it('renders with a full mapping provided as a form', async function () {
  64. render(
  65. <IntegrationExternalMappingForm
  66. type="user"
  67. mapping={MOCK_USER_MAPPING}
  68. {...baseProps}
  69. />
  70. );
  71. await act(tick);
  72. expect(screen.getByDisplayValue(MOCK_USER_MAPPING.externalName)).toBeInTheDocument();
  73. expect(screen.getByText(`option${MOCK_USER_MAPPING.userId}`)).toBeInTheDocument();
  74. expect(screen.getByTestId('form-submit')).toBeInTheDocument();
  75. });
  76. it('renders with a full mapping provided as an inline field', async function () {
  77. render(
  78. <IntegrationExternalMappingForm
  79. isInline
  80. type="user"
  81. mapping={MOCK_USER_MAPPING}
  82. {...baseProps}
  83. />
  84. );
  85. await act(tick);
  86. expect(
  87. screen.queryByDisplayValue(MOCK_USER_MAPPING.externalName)
  88. ).not.toBeInTheDocument();
  89. expect(screen.getByText(`option${MOCK_USER_MAPPING.userId}`)).toBeInTheDocument();
  90. expect(screen.queryByTestId('form-submit')).not.toBeInTheDocument();
  91. });
  92. // Suggested mapping provided (e.g. Create new mapping from suggested external name)
  93. it('renders with a suggested mapping provided as a form', function () {
  94. render(
  95. <IntegrationExternalMappingForm
  96. type="team"
  97. mapping={{externalName: MOCK_TEAM_MAPPING.externalName}}
  98. {...baseProps}
  99. />
  100. );
  101. expect(screen.getByDisplayValue(MOCK_TEAM_MAPPING.externalName)).toBeInTheDocument();
  102. expect(screen.getByText('Select Sentry Team')).toBeInTheDocument();
  103. expect(screen.getByTestId('form-submit')).toBeInTheDocument();
  104. });
  105. it('renders with a suggested mapping provided as an inline field', function () {
  106. render(
  107. <IntegrationExternalMappingForm
  108. isInline
  109. type="team"
  110. mapping={{externalName: MOCK_TEAM_MAPPING.externalName}}
  111. {...baseProps}
  112. />
  113. );
  114. expect(
  115. screen.queryByDisplayValue(MOCK_TEAM_MAPPING.externalName)
  116. ).not.toBeInTheDocument();
  117. expect(screen.getByText('Select Sentry Team')).toBeInTheDocument();
  118. expect(screen.queryByTestId('form-submit')).not.toBeInTheDocument();
  119. });
  120. it('updates the model when submitting', async function () {
  121. render(
  122. <IntegrationExternalMappingForm
  123. type="user"
  124. mapping={{externalName: MOCK_USER_MAPPING.externalName}}
  125. {...baseProps}
  126. />
  127. );
  128. expect(baseProps.getBaseFormEndpoint).not.toHaveBeenCalled();
  129. expect(postResponse).not.toHaveBeenCalled();
  130. userEvent.type(screen.getByText('Select Sentry User'), 'option2');
  131. await act(tick);
  132. userEvent.click(screen.getAllByText('option2')[1]);
  133. userEvent.click(screen.getByTestId('form-submit'));
  134. expect(baseProps.getBaseFormEndpoint).toHaveBeenCalledWith({
  135. externalName: MOCK_USER_MAPPING.externalName,
  136. integrationId: baseProps.integration.id,
  137. provider: baseProps.integration.provider.name.toLowerCase(),
  138. // From option2 selection
  139. userId: '2',
  140. });
  141. expect(postResponse).toHaveBeenCalled();
  142. expect(putResponse).not.toHaveBeenCalled();
  143. });
  144. it('submits on blur when used as an inline field', async function () {
  145. render(
  146. <IntegrationExternalMappingForm
  147. isInline
  148. type="team"
  149. mapping={MOCK_TEAM_MAPPING}
  150. {...baseProps}
  151. />
  152. );
  153. await act(tick);
  154. expect(baseProps.getBaseFormEndpoint).not.toHaveBeenCalled();
  155. expect(putResponse).not.toHaveBeenCalled();
  156. userEvent.type(screen.getByRole('textbox'), 'option3');
  157. await act(tick);
  158. userEvent.click(screen.getAllByText('option3')[1]);
  159. expect(baseProps.getBaseFormEndpoint).toHaveBeenCalledWith({
  160. ...MOCK_TEAM_MAPPING,
  161. integrationId: baseProps.integration.id,
  162. provider: baseProps.integration.provider.name.toLowerCase(),
  163. // From option3 selection
  164. teamId: '3',
  165. });
  166. await act(tick);
  167. expect(putResponse).toHaveBeenCalled();
  168. expect(postResponse).not.toHaveBeenCalled();
  169. });
  170. it('allows defaultOptions to be provided', async function () {
  171. render(
  172. <IntegrationExternalMappingForm
  173. type="user"
  174. mapping={MOCK_USER_MAPPING}
  175. defaultOptions={DEFAULT_OPTIONS.map(({id, name}) => ({value: id, label: name}))}
  176. {...baseProps}
  177. />
  178. );
  179. const sentryNameField = screen.getByText(`option${MOCK_USER_MAPPING.userId}`);
  180. // Don't query for results on load
  181. expect(sentryNameField).toBeInTheDocument();
  182. await act(tick);
  183. expect(getResponse).not.toHaveBeenCalled();
  184. // Now that the user types, query for results
  185. userEvent.type(sentryNameField, 'option2');
  186. await act(tick);
  187. userEvent.click(screen.getAllByText('option2')[1]);
  188. expect(getResponse).toHaveBeenCalled();
  189. });
  190. });