relocation.spec.tsx 23 KB

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