flow-node-entity.spec.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /**
  2. * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
  3. * SPDX-License-Identifier: MIT
  4. */
  5. import { beforeEach, describe, expect, it } from 'vitest';
  6. import { TransformData } from '@flowgram.ai/core';
  7. import { FlowDocument } from '../src/flow-document';
  8. import { baseMockAddNode } from './flow.mock';
  9. import { createDocumentContainer } from './flow-document-container.mock';
  10. interface BlockData {
  11. children: string[];
  12. pre?: string;
  13. next?: string;
  14. depth: number;
  15. childrenSize: number;
  16. }
  17. const blockData: { [key: string]: BlockData } = {
  18. root: {
  19. children: ['start_0', 'dynamicSplit_0', 'end_0'],
  20. pre: undefined,
  21. next: undefined,
  22. depth: 0,
  23. childrenSize: 10,
  24. },
  25. start_0: {
  26. children: [],
  27. next: 'dynamicSplit_0',
  28. pre: undefined,
  29. depth: 1,
  30. childrenSize: 0,
  31. },
  32. dynamicSplit_0: {
  33. children: ['$blockIcon$dynamicSplit_0', '$inlineBlocks$dynamicSplit_0'],
  34. next: 'end_0',
  35. pre: 'start_0',
  36. depth: 1,
  37. childrenSize: 7,
  38. },
  39. $blockIcon$dynamicSplit_0: {
  40. children: [],
  41. next: '$inlineBlocks$dynamicSplit_0',
  42. pre: undefined,
  43. depth: 2,
  44. childrenSize: 0,
  45. },
  46. $inlineBlocks$dynamicSplit_0: {
  47. children: ['block_0', 'block_1'],
  48. pre: '$blockIcon$dynamicSplit_0',
  49. next: undefined,
  50. depth: 2,
  51. childrenSize: 5,
  52. },
  53. block_0: {
  54. children: ['$blockOrderIcon$block_0'],
  55. depth: 3,
  56. pre: undefined,
  57. next: 'block_1',
  58. childrenSize: 1,
  59. },
  60. $blockOrderIcon$block_0: {
  61. children: [],
  62. depth: 4,
  63. pre: undefined,
  64. next: undefined,
  65. childrenSize: 0,
  66. },
  67. block_1: {
  68. children: ['$blockOrderIcon$block_1', 'noop_0'],
  69. depth: 3,
  70. pre: 'block_0',
  71. next: undefined,
  72. childrenSize: 2,
  73. },
  74. $blockOrderIcon$block_1: {
  75. children: [],
  76. next: 'noop_0',
  77. depth: 4,
  78. pre: undefined,
  79. childrenSize: 0,
  80. },
  81. noop_0: {
  82. children: [],
  83. pre: '$blockOrderIcon$block_1',
  84. next: undefined,
  85. depth: 4,
  86. childrenSize: 0,
  87. },
  88. end_0: {
  89. children: [],
  90. pre: 'dynamicSplit_0',
  91. next: undefined,
  92. depth: 1,
  93. childrenSize: 0,
  94. },
  95. };
  96. describe('flow-node-entity', () => {
  97. let container = createDocumentContainer();
  98. let document: FlowDocument;
  99. beforeEach(() => {
  100. container = createDocumentContainer();
  101. container.get(FlowDocument).fromJSON(baseMockAddNode);
  102. document = container.get<FlowDocument>(FlowDocument);
  103. });
  104. it('get children', () => {
  105. const currentBlockData: { [key: string]: BlockData } = {};
  106. document.traverse((node, depth) => {
  107. currentBlockData[node.id] = {
  108. children: node.children.map((b) => b.id),
  109. depth,
  110. next: node.next?.id,
  111. pre: node.pre?.id,
  112. childrenSize: node.allChildren.length,
  113. };
  114. });
  115. expect(currentBlockData).toEqual(blockData);
  116. });
  117. it('flow node delete', () => {
  118. // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
  119. const node = document.getNode('$blockOrderIcon$block_1')!;
  120. node.dispose();
  121. expect(document.toString()).toEqual(`root
  122. |-- start_0
  123. |-- dynamicSplit_0
  124. |---- $blockIcon$dynamicSplit_0
  125. |---- $inlineBlocks$dynamicSplit_0
  126. |------ block_0
  127. |-------- $blockOrderIcon$block_0
  128. |------ block_1
  129. |-------- noop_0
  130. |-- end_0`);
  131. // transform 数据还在
  132. expect(node.getData(TransformData)).toBeDefined();
  133. });
  134. it('getExtInfo and updateExtInfo', () => {
  135. const node = document.getNode('start_0');
  136. let changedTimes = 0;
  137. node.onExtInfoChange((data) => {
  138. changedTimes++;
  139. });
  140. expect(node.toJSON().data).toEqual(undefined);
  141. expect(node.getExtInfo()).toEqual(undefined);
  142. node.updateExtInfo({ title: 'start' });
  143. expect(node.getExtInfo()).toEqual({ title: 'start' });
  144. expect(changedTimes).toEqual(1);
  145. node.updateExtInfo({ title: 'start' }); // same
  146. expect(changedTimes).toEqual(1);
  147. node.updateExtInfo({ content: 'content' });
  148. expect(node.getExtInfo()).toEqual({ title: 'start', content: 'content' });
  149. expect(changedTimes).toEqual(2);
  150. expect(node.toJSON()).toEqual({
  151. id: 'start_0',
  152. type: 'start',
  153. data: { title: 'start', content: 'content' }, // By default, extInfo will be present in data
  154. });
  155. node.updateExtInfo({ title: 'start2' }, true);
  156. expect(node.getExtInfo()).toEqual({ title: 'start2' });
  157. expect(changedTimes).toEqual(3);
  158. expect(node.toJSON().data).toEqual({ title: 'start2' });
  159. });
  160. });