Executions.spec.tsx 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /*
  2. Copyright (C) 2023 Cloudbase Solutions SRL
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. import React, { act } from "react";
  15. import { render } from "@testing-library/react";
  16. import {
  17. EXECUTION_MOCK,
  18. EXECUTION_TASKS_MOCK,
  19. } from "@tests/mocks/ExecutionsMock";
  20. import { INSTANCE_MOCK } from "@tests/mocks/InstancesMock";
  21. import TestUtils from "@tests/TestUtils";
  22. import Executions from "./";
  23. describe("Executions", () => {
  24. let defaultProps: Executions["props"];
  25. beforeEach(() => {
  26. defaultProps = {
  27. executions: [EXECUTION_MOCK],
  28. executionsTasks: [EXECUTION_TASKS_MOCK],
  29. loading: false,
  30. tasksLoading: false,
  31. instancesDetails: [INSTANCE_MOCK],
  32. onChange: jest.fn(),
  33. onCancelExecutionClick: jest.fn(),
  34. };
  35. });
  36. it("renders without crashing", () => {
  37. const { getByText } = render(<Executions {...defaultProps} />);
  38. expect(getByText(EXECUTION_TASKS_MOCK.tasks[0].id)).toBeTruthy();
  39. expect(getByText(EXECUTION_MOCK.id)).toBeTruthy();
  40. });
  41. it("sets selected execution on new props", () => {
  42. const { getByText, rerender } = render(<Executions {...defaultProps} />);
  43. rerender(
  44. <Executions
  45. {...defaultProps}
  46. executions={[
  47. EXECUTION_MOCK,
  48. { ...EXECUTION_MOCK, id: "new-id", status: "RUNNING" },
  49. ]}
  50. />
  51. );
  52. expect(getByText("new-id")).toBeTruthy();
  53. rerender(
  54. <Executions
  55. {...defaultProps}
  56. executions={[
  57. EXECUTION_MOCK,
  58. { ...EXECUTION_MOCK, id: "new-id", status: "COMPLETED" },
  59. { ...EXECUTION_MOCK, id: "new-id-2", status: "RUNNING" },
  60. ]}
  61. />
  62. );
  63. expect(getByText("new-id-2")).toBeTruthy();
  64. rerender(<Executions {...defaultProps} executions={[EXECUTION_MOCK]} />);
  65. expect(getByText(EXECUTION_MOCK.id)).toBeTruthy();
  66. });
  67. it("renders with no executions", () => {
  68. const { getByText, rerender } = render(<Executions {...defaultProps} />);
  69. expect(getByText(EXECUTION_MOCK.id)).toBeTruthy();
  70. rerender(<Executions {...defaultProps} executions={[]} />);
  71. expect(getByText("This transfer has not been executed yet.")).toBeTruthy();
  72. });
  73. it("doesn't dispatch onChange if no executions", () => {
  74. const { rerender } = render(
  75. <Executions {...defaultProps} executions={[]} />
  76. );
  77. rerender(<Executions {...defaultProps} executions={[]} />);
  78. expect(defaultProps.onChange).not.toHaveBeenCalled();
  79. });
  80. it("handles previous executions", async () => {
  81. const { rerender } = render(
  82. <Executions
  83. {...defaultProps}
  84. executions={[
  85. EXECUTION_MOCK,
  86. { ...EXECUTION_MOCK, id: "new-id", status: "RUNNING" },
  87. ]}
  88. />
  89. );
  90. const previousArrow = () =>
  91. TestUtils.selectAll(
  92. "Arrow__Wrapper",
  93. TestUtils.select("Timeline__Wrapper")!
  94. )[0];
  95. await act(async () => {
  96. previousArrow().click();
  97. });
  98. expect(defaultProps.onChange).toHaveBeenLastCalledWith(EXECUTION_MOCK.id);
  99. rerender(<Executions {...defaultProps} />);
  100. await act(async () => {
  101. previousArrow().click();
  102. });
  103. expect(defaultProps.onChange).toHaveBeenLastCalledWith(EXECUTION_MOCK.id);
  104. });
  105. it("doesn't handle previous executions in edge cases", () => {
  106. const executionsComponent = new Executions(defaultProps);
  107. executionsComponent.handlePreviousExecutionClick();
  108. expect(defaultProps.onChange).not.toHaveBeenCalled();
  109. });
  110. it("handles next executions", async () => {
  111. render(
  112. <Executions
  113. {...defaultProps}
  114. executions={[
  115. EXECUTION_MOCK,
  116. { ...EXECUTION_MOCK, id: "new-id", status: "RUNNING" },
  117. ]}
  118. />
  119. );
  120. const nextArrow = TestUtils.selectAll(
  121. "Arrow__Wrapper",
  122. TestUtils.select("Timeline__Wrapper")!
  123. )[1];
  124. await act(async () => {
  125. nextArrow.click();
  126. });
  127. expect(defaultProps.onChange).toHaveBeenLastCalledWith("new-id");
  128. const previousArrow = () =>
  129. TestUtils.selectAll(
  130. "Arrow__Wrapper",
  131. TestUtils.select("Timeline__Wrapper")!
  132. )[0];
  133. await act(async () => {
  134. previousArrow().click();
  135. });
  136. await act(async () => {
  137. nextArrow.click();
  138. });
  139. expect(defaultProps.onChange).toHaveBeenLastCalledWith("new-id");
  140. });
  141. it("doesn't handle next executions in edge cases", () => {
  142. const executionsComponent = new Executions(defaultProps);
  143. executionsComponent.handleNextExecutionClick();
  144. expect(defaultProps.onChange).not.toHaveBeenCalled();
  145. });
  146. it("handles timeline item click", async () => {
  147. render(
  148. <Executions
  149. {...defaultProps}
  150. executions={[
  151. EXECUTION_MOCK,
  152. { ...EXECUTION_MOCK, id: "new-id", status: "RUNNING" },
  153. ]}
  154. />
  155. );
  156. const timelineItem = TestUtils.select("Timeline__Item-");
  157. expect(timelineItem).toBeTruthy();
  158. await act(async () => {
  159. timelineItem!.click();
  160. });
  161. expect(defaultProps.onChange).toHaveBeenLastCalledWith(EXECUTION_MOCK.id);
  162. });
  163. it("handles cancel execution click", async () => {
  164. const newExecution = { ...EXECUTION_MOCK, id: "new-id", status: "RUNNING" };
  165. render(
  166. <Executions
  167. {...defaultProps}
  168. executions={[EXECUTION_MOCK, newExecution]}
  169. />
  170. );
  171. const cancelExecutionButton = Array.from(
  172. document.querySelectorAll("button")
  173. ).find(el => el.textContent === "Cancel Execution");
  174. expect(cancelExecutionButton).toBeTruthy();
  175. await act(async () => {
  176. cancelExecutionButton!.click();
  177. });
  178. expect(defaultProps.onCancelExecutionClick).toHaveBeenCalledWith(
  179. newExecution
  180. );
  181. });
  182. it("force cancels execution", async () => {
  183. const newExecution = {
  184. ...EXECUTION_MOCK,
  185. id: "new-id",
  186. status: "CANCELLING",
  187. };
  188. render(
  189. <Executions
  190. {...defaultProps}
  191. executions={[EXECUTION_MOCK, newExecution]}
  192. />
  193. );
  194. const cancelExecutionButton = Array.from(
  195. document.querySelectorAll("button")
  196. ).find(el => el.textContent === "Force Cancel Execution");
  197. expect(cancelExecutionButton).toBeTruthy();
  198. await act(async () => {
  199. cancelExecutionButton!.click();
  200. });
  201. expect(defaultProps.onCancelExecutionClick).toHaveBeenCalledWith(
  202. newExecution,
  203. true
  204. );
  205. });
  206. it("renders loading", () => {
  207. render(<Executions {...defaultProps} loading />);
  208. expect(TestUtils.select("Executions__LoadingWrapper")).toBeTruthy();
  209. });
  210. it("deletes execution", async () => {
  211. const deleteExecution = jest.fn();
  212. render(
  213. <Executions {...defaultProps} onDeleteExecutionClick={deleteExecution} />
  214. );
  215. const deleteExecutionButton = Array.from(
  216. document.querySelectorAll("button")
  217. ).find(el => el.textContent === "Delete Execution");
  218. expect(deleteExecutionButton).toBeTruthy();
  219. await act(async () => {
  220. deleteExecutionButton!.click();
  221. });
  222. expect(deleteExecution).toHaveBeenCalledWith(EXECUTION_MOCK);
  223. });
  224. });