integrationExternalMappingForm.spec.tsx 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. import {act, render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
  2. import IntegrationExternalMappingForm from './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', async function () {
  50. render(<IntegrationExternalMappingForm type="user" {...baseProps} />);
  51. await act(tick);
  52. expect(screen.getByPlaceholderText('@username')).toBeInTheDocument();
  53. expect(screen.getByText('Select Sentry User')).toBeInTheDocument();
  54. expect(screen.getByTestId('form-submit')).toBeInTheDocument();
  55. });
  56. it('renders with no mapping as an inline field', async function () {
  57. render(<IntegrationExternalMappingForm isInline type="user" {...baseProps} />);
  58. await act(tick);
  59. expect(screen.queryByPlaceholderText('@username')).not.toBeInTheDocument();
  60. expect(screen.getByText('Select Sentry User')).toBeInTheDocument();
  61. expect(screen.queryByTestId('form-submit')).not.toBeInTheDocument();
  62. });
  63. // Full mapping provided (e.g. Update an existing mapping)
  64. it('renders with a full mapping provided as a form', async function () {
  65. render(
  66. <IntegrationExternalMappingForm
  67. type="user"
  68. mapping={MOCK_USER_MAPPING}
  69. {...baseProps}
  70. />
  71. );
  72. await act(tick);
  73. expect(screen.getByDisplayValue(MOCK_USER_MAPPING.externalName)).toBeInTheDocument();
  74. expect(screen.getByText(`option${MOCK_USER_MAPPING.userId}`)).toBeInTheDocument();
  75. expect(screen.getByTestId('form-submit')).toBeInTheDocument();
  76. });
  77. it('renders with a full mapping provided as an inline field', async function () {
  78. render(
  79. <IntegrationExternalMappingForm
  80. isInline
  81. type="user"
  82. mapping={MOCK_USER_MAPPING}
  83. {...baseProps}
  84. />
  85. );
  86. await act(tick);
  87. expect(
  88. screen.queryByDisplayValue(MOCK_USER_MAPPING.externalName)
  89. ).not.toBeInTheDocument();
  90. expect(screen.getByText(`option${MOCK_USER_MAPPING.userId}`)).toBeInTheDocument();
  91. expect(screen.queryByTestId('form-submit')).not.toBeInTheDocument();
  92. });
  93. // Suggested mapping provided (e.g. Create new mapping from suggested external name)
  94. it('renders with a suggested mapping provided as a form', async function () {
  95. render(
  96. <IntegrationExternalMappingForm
  97. type="team"
  98. mapping={{externalName: MOCK_TEAM_MAPPING.externalName}}
  99. {...baseProps}
  100. />
  101. );
  102. await act(tick);
  103. expect(screen.getByDisplayValue(MOCK_TEAM_MAPPING.externalName)).toBeInTheDocument();
  104. expect(screen.getByText('Select Sentry Team')).toBeInTheDocument();
  105. expect(screen.getByTestId('form-submit')).toBeInTheDocument();
  106. });
  107. it('renders with a suggested mapping provided as an inline field', async function () {
  108. render(
  109. <IntegrationExternalMappingForm
  110. isInline
  111. type="team"
  112. mapping={{externalName: MOCK_TEAM_MAPPING.externalName}}
  113. {...baseProps}
  114. />
  115. );
  116. await act(tick);
  117. expect(
  118. screen.queryByDisplayValue(MOCK_TEAM_MAPPING.externalName)
  119. ).not.toBeInTheDocument();
  120. expect(screen.getByText('Select Sentry Team')).toBeInTheDocument();
  121. expect(screen.queryByTestId('form-submit')).not.toBeInTheDocument();
  122. });
  123. it('updates the model when submitting', async function () {
  124. render(
  125. <IntegrationExternalMappingForm
  126. type="user"
  127. mapping={{externalName: MOCK_USER_MAPPING.externalName}}
  128. {...baseProps}
  129. />
  130. );
  131. expect(baseProps.getBaseFormEndpoint).not.toHaveBeenCalled();
  132. expect(postResponse).not.toHaveBeenCalled();
  133. await userEvent.type(screen.getByText('Select Sentry User'), 'option2');
  134. await act(tick);
  135. await userEvent.click(screen.getAllByText('option2')[1]);
  136. await userEvent.click(screen.getByTestId('form-submit'));
  137. await act(tick);
  138. expect(baseProps.getBaseFormEndpoint).toHaveBeenCalledWith({
  139. externalName: MOCK_USER_MAPPING.externalName,
  140. integrationId: baseProps.integration.id,
  141. provider: baseProps.integration.provider.name.toLowerCase(),
  142. // From option2 selection
  143. userId: '2',
  144. });
  145. expect(postResponse).toHaveBeenCalled();
  146. expect(putResponse).not.toHaveBeenCalled();
  147. });
  148. it('submits on blur when used as an inline field', async function () {
  149. render(
  150. <IntegrationExternalMappingForm
  151. isInline
  152. type="team"
  153. mapping={MOCK_TEAM_MAPPING}
  154. {...baseProps}
  155. />
  156. );
  157. await act(tick);
  158. expect(baseProps.getBaseFormEndpoint).not.toHaveBeenCalled();
  159. expect(putResponse).not.toHaveBeenCalled();
  160. await userEvent.type(screen.getByRole('textbox'), 'option3');
  161. await act(tick);
  162. await userEvent.click(screen.getAllByText('option3')[1]);
  163. expect(baseProps.getBaseFormEndpoint).toHaveBeenCalledWith({
  164. ...MOCK_TEAM_MAPPING,
  165. integrationId: baseProps.integration.id,
  166. provider: baseProps.integration.provider.name.toLowerCase(),
  167. // From option3 selection
  168. teamId: '3',
  169. });
  170. await act(tick);
  171. expect(putResponse).toHaveBeenCalled();
  172. expect(postResponse).not.toHaveBeenCalled();
  173. });
  174. it('allows defaultOptions to be provided', async function () {
  175. render(
  176. <IntegrationExternalMappingForm
  177. type="user"
  178. mapping={MOCK_USER_MAPPING}
  179. defaultOptions={DEFAULT_OPTIONS.map(({id, name}) => ({value: id, label: name}))}
  180. {...baseProps}
  181. />
  182. );
  183. const sentryNameField = screen.getByText(`option${MOCK_USER_MAPPING.userId}`);
  184. // Don't query for results on load
  185. expect(sentryNameField).toBeInTheDocument();
  186. await act(tick);
  187. expect(getResponse).not.toHaveBeenCalled();
  188. // Now that the user types, query for results
  189. await userEvent.type(sentryNameField, 'option2');
  190. await act(tick);
  191. await userEvent.click(screen.getAllByText('option2')[1]);
  192. expect(getResponse).toHaveBeenCalled();
  193. });
  194. });