relocation.spec.tsx 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. import {browserHistory} from 'react-router';
  2. import {initializeOrg} from 'sentry-test/initializeOrg';
  3. import {
  4. fireEvent,
  5. render,
  6. screen,
  7. userEvent,
  8. waitFor,
  9. } from 'sentry-test/reactTestingLibrary';
  10. import {addErrorMessage, addSuccessMessage} from 'sentry/actionCreators/indicator';
  11. import ConfigStore from 'sentry/stores/configStore';
  12. import Relocation from 'sentry/views/relocation/relocation';
  13. jest.mock('sentry/actionCreators/indicator');
  14. const fakePublicKey = `-----BEGIN PUBLIC KEY-----
  15. MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw5Or1zsGE1XJTL4q+1c4
  16. Ztu8+7SC/exrnEYlWH+LVLI8TVyuGwDTAXrgKHGwaMM5ZnjijP5i8+ph8lfLrybT
  17. l+2D81qPIqagEtNMDaHqUDm5Tq7I2qvxkJ5YuDLawRUPccKMwWlIDR2Gvfe3efce
  18. 870EicPsExz4uPOkNXGHJZ/FwCQrLo87MXFeqrqj+0Cf+qwCQSCW9qFWe5cj+zqt
  19. eeJa0qflcHHQzxK4/EKKpl/hkt4zi0aE/PuJgvJz2KB+X3+LzekTy90LzW3VhR4y
  20. IAxCAaGQJVsg9dhKOORjAf4XK9aXHvy/jUSyT43opj6AgNqXlKEQjb1NBA8qbJJS
  21. 8wIDAQAB
  22. -----END PUBLIC KEY-----`;
  23. const fakeRegionName = 'Narnia';
  24. const fakeRegionUrl = 'https://example.com';
  25. describe('Relocation', function () {
  26. let fetchExistingRelocation: jest.Mock;
  27. let fetchPublicKey: jest.Mock;
  28. beforeEach(function () {
  29. MockApiClient.asyncDelay = undefined;
  30. MockApiClient.clearMockResponses();
  31. fetchExistingRelocation = MockApiClient.addMockResponse({
  32. url: '/relocations/',
  33. body: [],
  34. });
  35. fetchPublicKey = MockApiClient.addMockResponse({
  36. url: '/publickeys/relocations/',
  37. body: {
  38. public_key: fakePublicKey,
  39. },
  40. });
  41. // The tests fail because we have a "component update was not wrapped in act" error. It should
  42. // be safe to ignore this error, but we should remove the mock once we move to react testing
  43. // library.
  44. //
  45. // eslint-disable-next-line no-console
  46. jest.spyOn(console, 'error').mockImplementation(jest.fn());
  47. });
  48. afterEach(function () {
  49. MockApiClient.clearMockResponses();
  50. MockApiClient.asyncDelay = undefined;
  51. });
  52. function renderPage(step) {
  53. const routeParams = {
  54. step,
  55. };
  56. const {routerProps, routerContext, organization} = initializeOrg({
  57. router: {
  58. params: routeParams,
  59. },
  60. });
  61. return render(<Relocation {...routerProps} />, {
  62. context: routerContext,
  63. organization,
  64. });
  65. }
  66. async function waitForRenderSuccess(step) {
  67. renderPage(step);
  68. await waitFor(() => expect(screen.getByTestId(step)).toBeInTheDocument());
  69. }
  70. async function waitForRenderError(step) {
  71. renderPage(step);
  72. await waitFor(() => expect(screen.getByTestId('loading-error')).toBeInTheDocument());
  73. }
  74. describe('Get Started', function () {
  75. it('renders', async function () {
  76. await waitForRenderSuccess('get-started');
  77. await waitFor(() => expect(fetchPublicKey).toHaveBeenCalled());
  78. expect(
  79. await screen.findByText('Basic information needed to get started')
  80. ).toBeInTheDocument();
  81. expect(
  82. await screen.findByText('Organization slugs being relocated')
  83. ).toBeInTheDocument();
  84. expect(await screen.findByText('Choose a datacenter location')).toBeInTheDocument();
  85. });
  86. it('redirects to `in-progress` page if user already has active relocation', async function () {
  87. MockApiClient.clearMockResponses();
  88. fetchExistingRelocation = MockApiClient.addMockResponse({
  89. url: '/relocations/',
  90. body: [
  91. {
  92. uuid: 'ccef828a-03d8-4dd0-918a-487ffecf8717',
  93. status: 'IN_PROGRESS',
  94. },
  95. ],
  96. });
  97. fetchPublicKey = MockApiClient.addMockResponse({
  98. url: '/publickeys/relocations/',
  99. body: {
  100. public_key: fakePublicKey,
  101. },
  102. });
  103. await waitForRenderSuccess('get-started');
  104. await waitFor(() => expect(fetchExistingRelocation).toHaveBeenCalled());
  105. await waitFor(() => expect(fetchPublicKey).toHaveBeenCalled());
  106. expect(browserHistory.push).toHaveBeenCalledWith('/relocation/in-progress/');
  107. });
  108. it('should prevent user from going to the next step if no org slugs or region are entered', async function () {
  109. await waitForRenderSuccess('get-started');
  110. await waitFor(() => expect(fetchPublicKey).toHaveBeenCalled());
  111. expect(await screen.getByRole('button', {name: 'Continue'})).toBeDisabled();
  112. });
  113. it('should be allowed to go to next step if org slug is entered, region is selected, and promo code is entered', async function () {
  114. await waitForRenderSuccess('get-started');
  115. await waitFor(() => expect(fetchPublicKey).toHaveBeenCalled());
  116. fetchPublicKey = MockApiClient.addMockResponse({
  117. url: '/promocodes-external/free-hugs',
  118. method: 'GET',
  119. statusCode: 200,
  120. });
  121. ConfigStore.set('regions', [{name: fakeRegionName, url: fakeRegionUrl}]);
  122. ConfigStore.set('relocationConfig', {selectableRegions: [fakeRegionName]});
  123. const orgSlugsInput = await screen.getByLabelText('org-slugs');
  124. const continueButton = await screen.getByRole('button', {name: 'Continue'});
  125. await userEvent.type(orgSlugsInput, 'test-org');
  126. await userEvent.type(await screen.getByLabelText('region'), 'Narnia');
  127. await userEvent.click(await screen.getByRole('menuitemradio'));
  128. expect(continueButton).toBeEnabled();
  129. await userEvent.click(screen.getByText('Got a promo code?', {exact: false}));
  130. const promoCodeInput = await screen.getByLabelText('promocode');
  131. await userEvent.type(promoCodeInput, 'free-hugs');
  132. await userEvent.click(continueButton);
  133. expect(addErrorMessage).not.toHaveBeenCalledWith();
  134. sessionStorage.clear();
  135. });
  136. it('should not be allowed to go to next step if org slug is entered, region is selected, and promo code is invalid', async function () {
  137. await waitForRenderSuccess('get-started');
  138. await waitFor(() => expect(fetchPublicKey).toHaveBeenCalled());
  139. fetchPublicKey = MockApiClient.addMockResponse({
  140. url: '/promocodes-external/free-hugs',
  141. method: 'GET',
  142. statusCode: 403,
  143. });
  144. ConfigStore.set('regions', [{name: fakeRegionName, url: fakeRegionUrl}]);
  145. ConfigStore.set('relocationConfig', {selectableRegions: [fakeRegionName]});
  146. const orgSlugsInput = await screen.getByLabelText('org-slugs');
  147. const continueButton = await screen.getByRole('button', {name: 'Continue'});
  148. await userEvent.type(orgSlugsInput, 'test-org');
  149. await userEvent.type(await screen.getByLabelText('region'), 'Narnia');
  150. await userEvent.click(await screen.getByRole('menuitemradio'));
  151. expect(continueButton).toBeEnabled();
  152. await userEvent.click(screen.getByText('Got a promo code?', {exact: false}));
  153. const promoCodeInput = await screen.getByLabelText('promocode');
  154. await userEvent.type(promoCodeInput, 'free-hugs');
  155. await userEvent.click(continueButton);
  156. expect(addErrorMessage).toHaveBeenCalledWith(
  157. 'That promotional code has already been claimed, does not have enough remaining uses, is no longer valid, or never existed.'
  158. );
  159. });
  160. it('should show loading indicator and error message if existing relocation retrieval failed', async function () {
  161. MockApiClient.clearMockResponses();
  162. fetchExistingRelocation = MockApiClient.addMockResponse({
  163. url: '/relocations/',
  164. statusCode: 400,
  165. });
  166. fetchPublicKey = MockApiClient.addMockResponse({
  167. url: '/publickeys/relocations/',
  168. body: {
  169. public_key: fakePublicKey,
  170. },
  171. });
  172. await waitForRenderError('get-started');
  173. await waitFor(() => expect(fetchExistingRelocation).toHaveBeenCalled());
  174. expect(fetchPublicKey).toHaveBeenCalledTimes(1);
  175. expect(
  176. await screen.queryByRole('button', {name: 'Continue'})
  177. ).not.toBeInTheDocument();
  178. expect(await screen.queryByLabelText('org-slugs')).not.toBeInTheDocument();
  179. expect(await screen.getByRole('button', {name: 'Retry'})).toBeInTheDocument();
  180. MockApiClient.addMockResponse({
  181. url: '/relocations/',
  182. body: [],
  183. });
  184. await userEvent.click(screen.getByRole('button', {name: 'Retry'}));
  185. await waitFor(() => expect(fetchPublicKey).toHaveBeenCalled());
  186. await waitFor(() => expect(screen.getByTestId('get-started')).toBeInTheDocument());
  187. expect(fetchExistingRelocation).toHaveBeenCalledTimes(1);
  188. expect(await screen.queryByLabelText('org-slugs')).toBeInTheDocument();
  189. expect(await screen.queryByRole('button', {name: 'Continue'})).toBeInTheDocument();
  190. });
  191. });
  192. describe('Public Key', function () {
  193. it('should show instructions if key retrieval was successful', async function () {
  194. await waitForRenderSuccess('public-key');
  195. await waitFor(() => expect(fetchPublicKey).toHaveBeenCalled());
  196. expect(
  197. await screen.findByText("Save Sentry's public key to your machine")
  198. ).toBeInTheDocument();
  199. expect(await screen.getByText('key.pub')).toBeInTheDocument();
  200. expect(await screen.getByRole('button', {name: 'Continue'})).toBeInTheDocument();
  201. });
  202. it('should show loading indicator if key retrieval still in progress', function () {
  203. MockApiClient.asyncDelay = 1;
  204. renderPage('public-key');
  205. expect(screen.queryByRole('button', {name: 'Continue'})).not.toBeInTheDocument();
  206. expect(screen.queryByText('key.pub')).not.toBeInTheDocument();
  207. });
  208. it('should show loading indicator and error message if key retrieval failed', async function () {
  209. MockApiClient.clearMockResponses();
  210. fetchExistingRelocation = MockApiClient.addMockResponse({
  211. url: '/relocations/',
  212. body: [],
  213. });
  214. fetchPublicKey = MockApiClient.addMockResponse({
  215. url: '/publickeys/relocations/',
  216. statusCode: 400,
  217. });
  218. await waitForRenderError('public-key');
  219. await waitFor(() => expect(fetchPublicKey).toHaveBeenCalled());
  220. expect(fetchExistingRelocation).toHaveBeenCalledTimes(1);
  221. expect(
  222. await screen.queryByRole('button', {name: 'Continue'})
  223. ).not.toBeInTheDocument();
  224. expect(await screen.queryByText('key.pub')).not.toBeInTheDocument();
  225. expect(await screen.getByRole('button', {name: 'Retry'})).toBeInTheDocument();
  226. MockApiClient.addMockResponse({
  227. url: '/publickeys/relocations/',
  228. body: {
  229. public_key: fakePublicKey,
  230. },
  231. });
  232. await userEvent.click(screen.getByRole('button', {name: 'Retry'}));
  233. await waitFor(() => expect(fetchPublicKey).toHaveBeenCalled());
  234. await waitFor(() => expect(screen.getByTestId('public-key')).toBeInTheDocument());
  235. expect(fetchExistingRelocation).toHaveBeenCalledTimes(1);
  236. expect(await screen.queryByText('key.pub')).toBeInTheDocument();
  237. expect(await screen.queryByRole('button', {name: 'Continue'})).toBeInTheDocument();
  238. });
  239. });
  240. describe('Encrypt Backup', function () {
  241. it('renders', async function () {
  242. await waitForRenderSuccess('encrypt-backup');
  243. await waitFor(() => expect(fetchPublicKey).toHaveBeenCalled());
  244. expect(
  245. await screen.findByText(
  246. 'Create an encrypted backup of your current self-hosted instance'
  247. )
  248. ).toBeInTheDocument();
  249. });
  250. });
  251. describe('Upload Backup', function () {
  252. it('renders', async function () {
  253. await waitForRenderSuccess('upload-backup');
  254. expect(
  255. await screen.findByText('Upload Tarball to begin the relocation process')
  256. ).toBeInTheDocument();
  257. });
  258. it('accepts a file upload', async function () {
  259. await waitForRenderSuccess('upload-backup');
  260. const relocationFile = new File(['hello'], 'hello.tar', {type: 'file'});
  261. const input = screen.getByLabelText('file-upload');
  262. await userEvent.upload(input, relocationFile);
  263. expect(await screen.findByText('hello.tar')).toBeInTheDocument();
  264. expect(await screen.findByText('Start Relocation')).toBeInTheDocument();
  265. });
  266. it('accepts a file upload through drag and drop', async function () {
  267. await waitForRenderSuccess('upload-backup');
  268. const relocationFile = new File(['hello'], 'hello.tar', {type: 'file'});
  269. const dropzone = screen.getByLabelText('dropzone');
  270. fireEvent.drop(dropzone, {dataTransfer: {files: [relocationFile]}});
  271. expect(await screen.findByText('hello.tar')).toBeInTheDocument();
  272. expect(await screen.findByText('Start Relocation')).toBeInTheDocument();
  273. });
  274. it('correctly removes file and prompts for file upload', async function () {
  275. await waitForRenderSuccess('upload-backup');
  276. const relocationFile = new File(['hello'], 'hello.tar', {type: 'file'});
  277. const input = screen.getByLabelText('file-upload');
  278. await userEvent.upload(input, relocationFile);
  279. await userEvent.click(screen.getByText('Remove file'));
  280. expect(screen.queryByText('hello.tar')).not.toBeInTheDocument();
  281. expect(
  282. await screen.findByText('Upload Tarball to begin the relocation process')
  283. ).toBeInTheDocument();
  284. });
  285. it('fails to starts relocation job if some form data is missing', async function () {
  286. const mockapi = MockApiClient.addMockResponse({
  287. url: `/relocations/`,
  288. method: 'POST',
  289. });
  290. await waitForRenderSuccess('upload-backup');
  291. const relocationFile = new File(['hello'], 'hello.tar', {type: 'file'});
  292. const input = screen.getByLabelText('file-upload');
  293. await userEvent.upload(input, relocationFile);
  294. await userEvent.click(await screen.findByText('Start Relocation'));
  295. await waitFor(() => expect(mockapi).not.toHaveBeenCalled());
  296. expect(addErrorMessage).toHaveBeenCalledWith(
  297. 'An error has occurred while trying to start relocation job. Please contact support for further assistance.'
  298. );
  299. });
  300. it('starts relocation job if form data is available from previous steps', async function () {
  301. const mockapi = MockApiClient.addMockResponse({
  302. url: `/relocations/`,
  303. method: 'POST',
  304. responseJSON: [
  305. {
  306. uuid: 'ccef828a-03d8-4dd0-918a-487ffecf8717',
  307. status: 'IN_PROGRESS',
  308. },
  309. ],
  310. });
  311. await waitForRenderSuccess('get-started');
  312. ConfigStore.set('regions', [{name: fakeRegionName, url: fakeRegionUrl}]);
  313. ConfigStore.set('relocationConfig', {selectableRegions: [fakeRegionName]});
  314. const orgSlugsInput = await screen.getByLabelText('org-slugs');
  315. const continueButton = await screen.getByRole('button', {name: 'Continue'});
  316. await userEvent.type(orgSlugsInput, 'test-org');
  317. await userEvent.type(screen.getByLabelText('region'), 'Narnia');
  318. await userEvent.click(screen.getByRole('menuitemradio'));
  319. await userEvent.click(continueButton);
  320. await waitForRenderSuccess('upload-backup');
  321. const relocationFile = new File(['hello'], 'hello.tar', {type: 'file'});
  322. const input = screen.getByLabelText('file-upload');
  323. await userEvent.upload(input, relocationFile);
  324. await userEvent.click(await screen.findByText('Start Relocation'));
  325. await waitFor(() =>
  326. expect(mockapi).toHaveBeenCalledWith(
  327. '/relocations/',
  328. expect.objectContaining({host: fakeRegionUrl, method: 'POST'})
  329. )
  330. );
  331. expect(addSuccessMessage).toHaveBeenCalledWith(
  332. "Your relocation has started - we'll email you with updates as soon as we have 'em!"
  333. );
  334. await waitForRenderSuccess('in-progress');
  335. });
  336. it('throws error if user already has an in-progress relocation job', async function () {
  337. const mockapi = MockApiClient.addMockResponse({
  338. url: `/relocations/`,
  339. method: 'POST',
  340. statusCode: 409,
  341. });
  342. await waitForRenderSuccess('get-started');
  343. ConfigStore.set('regions', [{name: fakeRegionName, url: fakeRegionUrl}]);
  344. ConfigStore.set('relocationConfig', {selectableRegions: [fakeRegionName]});
  345. const orgSlugsInput = screen.getByLabelText('org-slugs');
  346. const continueButton = screen.getByRole('button', {name: 'Continue'});
  347. await userEvent.type(orgSlugsInput, 'test-org');
  348. await userEvent.type(screen.getByLabelText('region'), 'Narnia');
  349. await userEvent.click(screen.getByRole('menuitemradio'));
  350. await userEvent.click(continueButton);
  351. await waitForRenderSuccess('upload-backup');
  352. const relocationFile = new File(['hello'], 'hello.tar', {type: 'file'});
  353. const input = screen.getByLabelText('file-upload');
  354. await userEvent.upload(input, relocationFile);
  355. await userEvent.click(await screen.findByText('Start Relocation'));
  356. await waitFor(() => expect(mockapi).toHaveBeenCalled());
  357. expect(addErrorMessage).toHaveBeenCalledWith(
  358. 'You already have an in-progress relocation job.'
  359. );
  360. });
  361. it('throws error if daily limit of relocations has been reached', async function () {
  362. const mockapi = MockApiClient.addMockResponse({
  363. url: `/relocations/`,
  364. method: 'POST',
  365. statusCode: 429,
  366. });
  367. await waitForRenderSuccess('get-started');
  368. ConfigStore.set('regions', [{name: fakeRegionName, url: fakeRegionUrl}]);
  369. ConfigStore.set('relocationConfig', {selectableRegions: [fakeRegionName]});
  370. const orgSlugsInput = screen.getByLabelText('org-slugs');
  371. const continueButton = screen.getByRole('button', {name: 'Continue'});
  372. await userEvent.type(orgSlugsInput, 'test-org');
  373. await userEvent.type(screen.getByLabelText('region'), 'Narnia');
  374. await userEvent.click(screen.getByRole('menuitemradio'));
  375. await userEvent.click(continueButton);
  376. await waitForRenderSuccess('upload-backup');
  377. const relocationFile = new File(['hello'], 'hello.tar', {type: 'file'});
  378. const input = screen.getByLabelText('file-upload');
  379. await userEvent.upload(input, relocationFile);
  380. await userEvent.click(await screen.findByText('Start Relocation'));
  381. await waitFor(() => expect(mockapi).toHaveBeenCalled());
  382. expect(addErrorMessage).toHaveBeenCalledWith(
  383. 'We have reached the daily limit of relocations - please try again tomorrow, or contact support.'
  384. );
  385. });
  386. it('throws error if user session has expired', async function () {
  387. const mockapi = MockApiClient.addMockResponse({
  388. url: `/relocations/`,
  389. method: 'POST',
  390. statusCode: 401,
  391. });
  392. ConfigStore.set('regions', [{name: fakeRegionName, url: fakeRegionUrl}]);
  393. ConfigStore.set('relocationConfig', {selectableRegions: [fakeRegionName]});
  394. await waitForRenderSuccess('get-started');
  395. const orgSlugsInput = screen.getByLabelText('org-slugs');
  396. const continueButton = screen.getByRole('button', {name: 'Continue'});
  397. await userEvent.type(orgSlugsInput, 'test-org');
  398. await userEvent.type(screen.getByLabelText('region'), 'Narnia');
  399. await userEvent.click(screen.getByRole('menuitemradio'));
  400. await userEvent.click(continueButton);
  401. await waitForRenderSuccess('upload-backup');
  402. const relocationFile = new File(['hello'], 'hello.tar', {type: 'file'});
  403. const input = screen.getByLabelText('file-upload');
  404. await userEvent.upload(input, relocationFile);
  405. await userEvent.click(await screen.findByText('Start Relocation'));
  406. await waitFor(() => expect(mockapi).toHaveBeenCalled());
  407. expect(addErrorMessage).toHaveBeenCalledWith('Your session has expired.');
  408. });
  409. it('throws error for 500 error', async function () {
  410. const mockapi = MockApiClient.addMockResponse({
  411. url: `/relocations/`,
  412. method: 'POST',
  413. statusCode: 500,
  414. });
  415. ConfigStore.set('regions', [{name: fakeRegionName, url: fakeRegionUrl}]);
  416. ConfigStore.set('relocationConfig', {selectableRegions: [fakeRegionName]});
  417. await waitForRenderSuccess('get-started');
  418. const orgSlugsInput = screen.getByLabelText('org-slugs');
  419. const continueButton = screen.getByRole('button', {name: 'Continue'});
  420. await userEvent.type(orgSlugsInput, 'test-org');
  421. await userEvent.type(screen.getByLabelText('region'), 'Narnia');
  422. await userEvent.click(screen.getByRole('menuitemradio'));
  423. await userEvent.click(continueButton);
  424. await waitForRenderSuccess('upload-backup');
  425. const relocationFile = new File(['hello'], 'hello.tar', {type: 'file'});
  426. const input = screen.getByLabelText('file-upload');
  427. await userEvent.upload(input, relocationFile);
  428. await userEvent.click(await screen.findByText('Start Relocation'));
  429. await waitFor(() => expect(mockapi).toHaveBeenCalled());
  430. expect(addErrorMessage).toHaveBeenCalledWith(
  431. 'An error has occurred while trying to start relocation job. Please contact support for further assistance.'
  432. );
  433. });
  434. });
  435. describe('In Progress', function () {
  436. it('renders', async function () {
  437. MockApiClient.clearMockResponses();
  438. fetchExistingRelocation = MockApiClient.addMockResponse({
  439. url: '/relocations/',
  440. body: [
  441. {
  442. uuid: 'ccef828a-03d8-4dd0-918a-487ffecf8717',
  443. status: 'IN_PROGRESS',
  444. },
  445. ],
  446. });
  447. fetchPublicKey = MockApiClient.addMockResponse({
  448. url: '/publickeys/relocations/',
  449. body: {
  450. public_key: fakePublicKey,
  451. },
  452. });
  453. await waitForRenderSuccess('in-progress');
  454. expect(
  455. await screen.findByText('Your relocation is under way!')
  456. ).toBeInTheDocument();
  457. });
  458. it('redirects to `get-started` page if there is no existing relocation', async function () {
  459. await waitForRenderSuccess('in-progress');
  460. await waitFor(() => expect(fetchExistingRelocation).toHaveBeenCalled());
  461. await waitFor(() => expect(fetchPublicKey).toHaveBeenCalled());
  462. expect(browserHistory.push).toHaveBeenCalledWith('/relocation/get-started/');
  463. });
  464. it('redirects to `get-started` page if there is no active relocation', async function () {
  465. MockApiClient.clearMockResponses();
  466. fetchExistingRelocation = MockApiClient.addMockResponse({
  467. url: '/relocations/',
  468. body: [
  469. {
  470. uuid: 'ccef828a-03d8-4dd0-918a-487ffecf8717',
  471. status: 'SUCCESS',
  472. },
  473. ],
  474. });
  475. fetchPublicKey = MockApiClient.addMockResponse({
  476. url: '/publickeys/relocations/',
  477. body: {
  478. public_key: fakePublicKey,
  479. },
  480. });
  481. await waitForRenderSuccess('in-progress');
  482. await waitFor(() => expect(fetchExistingRelocation).toHaveBeenCalled());
  483. await waitFor(() => expect(fetchPublicKey).toHaveBeenCalled());
  484. expect(browserHistory.push).toHaveBeenCalledWith('/relocation/get-started/');
  485. });
  486. });
  487. });