manager.test.ts 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. import { it, expect, beforeEach, describe, vi } from 'vitest';
  2. import { debounce } from 'lodash';
  3. import { interfaces } from 'inversify';
  4. import {
  5. delay,
  6. WorkflowDocument,
  7. WorkflowHoverService,
  8. WorkflowSelectService,
  9. } from '@flowgram.ai/free-layout-core';
  10. import { FlowNodeRenderData } from '@flowgram.ai/document';
  11. import {
  12. EntityManager,
  13. PipelineRegistry,
  14. PipelineRenderer,
  15. PlaygroundConfigEntity,
  16. } from '@flowgram.ai/core';
  17. import { StackingContextManager } from '../src/manager';
  18. import { StackingComputeMode } from '../src/constant';
  19. import { createWorkflowContainer, workflowJSON } from './utils.mock';
  20. import { IStackingContextManager } from './type.mock';
  21. let container: interfaces.Container;
  22. let document: WorkflowDocument;
  23. let stackingContextManager: IStackingContextManager;
  24. beforeEach(async () => {
  25. container = createWorkflowContainer();
  26. container.bind(StackingContextManager).to(StackingContextManager);
  27. document = container.get<WorkflowDocument>(WorkflowDocument);
  28. stackingContextManager = container.get<StackingContextManager>(
  29. StackingContextManager
  30. ) as unknown as IStackingContextManager;
  31. await document.fromJSON(workflowJSON);
  32. });
  33. describe('StackingContextManager public methods', () => {
  34. it('should create instance', () => {
  35. const stackingContextManager = container.get<StackingContextManager>(StackingContextManager);
  36. expect(stackingContextManager.node).toMatchInlineSnapshot(`
  37. <div
  38. class="gedit-playground-layer gedit-flow-render-layer"
  39. />
  40. `);
  41. expect(stackingContextManager).not.toBeUndefined();
  42. });
  43. it('should execute init', () => {
  44. stackingContextManager.init();
  45. const pipelineRenderer = container.get<PipelineRenderer>(PipelineRenderer);
  46. expect(pipelineRenderer.node).toMatchInlineSnapshot(
  47. `
  48. <div
  49. class="gedit-playground-pipeline"
  50. >
  51. <div
  52. class="gedit-playground-layer gedit-flow-render-layer"
  53. />
  54. </div>
  55. `
  56. );
  57. expect(stackingContextManager.mode).toEqual(StackingComputeMode.Stacking);
  58. expect(stackingContextManager.disposers).toHaveLength(4);
  59. });
  60. it('should init with mode', () => {
  61. stackingContextManager.init(StackingComputeMode.Stacking);
  62. expect(stackingContextManager.mode).toEqual(StackingComputeMode.Stacking);
  63. });
  64. it('should execute ready', () => {
  65. stackingContextManager.compute = vi.fn();
  66. stackingContextManager.ready();
  67. expect(stackingContextManager.compute).toBeCalled();
  68. });
  69. it('should dispose', () => {
  70. expect(stackingContextManager.disposers).toHaveLength(0);
  71. stackingContextManager.init();
  72. expect(stackingContextManager.disposers).toHaveLength(4);
  73. const mockDispose = { dispose: vi.fn() };
  74. stackingContextManager.disposers.push(mockDispose);
  75. stackingContextManager.dispose();
  76. expect(mockDispose.dispose).toBeCalled();
  77. });
  78. });
  79. describe('StackingContextManager private methods', () => {
  80. it('should compute with debounce', async () => {
  81. const compute = vi.fn();
  82. vi.spyOn(stackingContextManager, 'compute').mockImplementation(debounce(compute, 10));
  83. stackingContextManager.compute();
  84. await delay(1);
  85. stackingContextManager.compute();
  86. await delay(1);
  87. stackingContextManager.compute();
  88. await delay(1);
  89. stackingContextManager.compute();
  90. expect(compute).toBeCalledTimes(0);
  91. await delay(20);
  92. expect(compute).toBeCalledTimes(1);
  93. });
  94. it('should get nodes and lines', async () => {
  95. const nodeIds = stackingContextManager.nodes.map((n) => n.id);
  96. const lineIds = stackingContextManager.lines.map((l) => l.id);
  97. expect(nodeIds).toEqual([
  98. 'root',
  99. 'start_0',
  100. 'condition_0',
  101. 'end_0',
  102. 'loop_0',
  103. 'break_0',
  104. 'variable_0',
  105. ]);
  106. expect(lineIds).toEqual([
  107. 'break_0_-variable_0_',
  108. 'start_0_-condition_0_',
  109. 'condition_0_if-end_0_',
  110. 'condition_0_else-end_0_',
  111. 'loop_0_-end_0_',
  112. 'start_0_-loop_0_',
  113. ]);
  114. });
  115. it('should generate context', async () => {
  116. const hoverService = container.get<WorkflowHoverService>(WorkflowHoverService);
  117. const selectService = container.get<WorkflowSelectService>(WorkflowSelectService);
  118. expect(stackingContextManager.context).toStrictEqual({
  119. hoveredEntity: undefined,
  120. hoveredEntityID: undefined,
  121. selectedEntities: [],
  122. selectedIDs: [],
  123. });
  124. hoverService.updateHoveredKey('start_0');
  125. const breakNode = document.getNode('break_0')!;
  126. const variableNode = document.getNode('variable_0')!;
  127. selectService.selection = [breakNode, variableNode];
  128. expect(stackingContextManager.context.hoveredEntityID).toEqual('start_0');
  129. expect(stackingContextManager.context.selectedIDs).toEqual(['break_0', 'variable_0']);
  130. });
  131. it('should callback compute when onZoom trigger', () => {
  132. const entityManager = container.get<EntityManager>(EntityManager);
  133. const pipelineRegistry = container.get<PipelineRegistry>(PipelineRegistry);
  134. const compute = vi.spyOn(stackingContextManager, 'compute').mockImplementation(() => {});
  135. const playgroundConfig =
  136. entityManager.getEntity<PlaygroundConfigEntity>(PlaygroundConfigEntity)!;
  137. pipelineRegistry.ready();
  138. stackingContextManager.mountListener();
  139. playgroundConfig.updateConfig({
  140. zoom: 1.5,
  141. });
  142. expect(stackingContextManager.node.style.transform).toBe('scale(1.5)');
  143. playgroundConfig.updateConfig({
  144. zoom: 2,
  145. });
  146. expect(stackingContextManager.node.style.transform).toBe('scale(2)');
  147. playgroundConfig.updateConfig({
  148. zoom: 1,
  149. });
  150. expect(stackingContextManager.node.style.transform).toBe('scale(1)');
  151. expect(compute).toBeCalledTimes(3);
  152. });
  153. it('should callback compute when onHover trigger', () => {
  154. const hoverService = container.get<WorkflowHoverService>(WorkflowHoverService);
  155. const compute = vi.spyOn(stackingContextManager, 'compute').mockImplementation(() => {});
  156. stackingContextManager.mountListener();
  157. hoverService.updateHoveredKey('start_0');
  158. hoverService.updateHoveredKey('end_0');
  159. expect(compute).toBeCalledTimes(2);
  160. });
  161. it('should callback compute when onEntityChange trigger', () => {
  162. const entityManager = container.get<EntityManager>(EntityManager);
  163. const compute = vi.spyOn(stackingContextManager, 'compute').mockImplementation(() => {});
  164. const node = document.getNode('start_0')!;
  165. stackingContextManager.mountListener();
  166. entityManager.fireEntityChanged(node);
  167. expect(compute).toBeCalledTimes(1);
  168. });
  169. it('should callback compute when onSelect trigger', () => {
  170. const selectService = container.get<WorkflowSelectService>(WorkflowSelectService);
  171. const compute = vi.spyOn(stackingContextManager, 'compute').mockImplementation(() => {});
  172. stackingContextManager.mountListener();
  173. const breakNode = document.getNode('break_0')!;
  174. const variableNode = document.getNode('variable_0')!;
  175. selectService.selectNode(breakNode);
  176. selectService.selectNode(variableNode);
  177. expect(compute).toBeCalledTimes(2);
  178. });
  179. it('should mount listeners', () => {
  180. const hoverService = container.get<WorkflowHoverService>(WorkflowHoverService);
  181. const selectService = container.get<WorkflowSelectService>(WorkflowSelectService);
  182. const compute = vi.spyOn(stackingContextManager, 'compute').mockImplementation(() => {});
  183. stackingContextManager.mountListener();
  184. // onHover
  185. hoverService.updateHoveredKey('start_0');
  186. hoverService.updateHoveredKey('end_0');
  187. expect(compute).toBeCalledTimes(2);
  188. compute.mockReset();
  189. // select callback
  190. const breakNode = document.getNode('break_0')!;
  191. const variableNode = document.getNode('variable_0')!;
  192. selectService.selectNode(breakNode);
  193. selectService.selectNode(variableNode);
  194. expect(compute).toBeCalledTimes(2);
  195. });
  196. it('should trigger compute in layers mode', async () => {
  197. stackingContextManager.init(StackingComputeMode.Layers);
  198. stackingContextManager.ready();
  199. await delay(200);
  200. const node = document.getNode('loop_0')!;
  201. const nodeRenderData = node.getData<FlowNodeRenderData>(FlowNodeRenderData);
  202. const element = nodeRenderData.node;
  203. expect(element.style.zIndex).toBe('9');
  204. });
  205. it('should trigger compute in stacking mode', async () => {
  206. stackingContextManager.init(StackingComputeMode.Stacking);
  207. stackingContextManager.ready();
  208. await delay(200);
  209. const node = document.getNode('loop_0')!;
  210. const nodeRenderData = node.getData<FlowNodeRenderData>(FlowNodeRenderData);
  211. const element = nodeRenderData.node;
  212. expect(element.style.zIndex).toBe('12');
  213. });
  214. });