@qy_better_lib/hooks 0.1.9 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DOCUMENTATION.md +704 -0
- package/USAGE.md +444 -0
- package/__tests__/use-chart/index.test.ts +287 -0
- package/__tests__/use-emit/index.test.ts +248 -0
- package/__tests__/use-fullscreen/index.test.ts +162 -0
- package/__tests__/use-image/index.test.ts +230 -0
- package/__tests__/use-layout-flow/index.test.ts +382 -0
- package/__tests__/use-mqtt/index.test.ts +392 -0
- package/__tests__/use-print/index.test.ts +378 -0
- package/__tests__/use-watermark/index.test.ts +277 -0
- package/__tests__/use-websocket/index.test.ts +402 -0
- package/dist/hooks.min.js +76 -0
- package/lib/_virtual/dayjs.min.js +2 -0
- package/lib/_virtual/dayjs.min2.js +4 -0
- package/lib/index.d.ts +5 -2
- package/lib/index.js +20 -31
- package/lib/node_modules/dayjs/dayjs.min.js +286 -0
- package/lib/packages/hooks/node_modules/@qy_better_lib/core/lib/directives/click_outside.js +19 -0
- package/lib/packages/hooks/node_modules/@qy_better_lib/core/lib/utils/dom.js +25 -0
- package/lib/packages/hooks/node_modules/@qy_better_lib/core/lib/utils/echarts.js +166 -0
- package/lib/packages/hooks/node_modules/@qy_better_lib/core/lib/utils/file.js +55 -0
- package/lib/packages/hooks/node_modules/@qy_better_lib/core/lib/utils/is.js +8 -0
- package/lib/packages/hooks/node_modules/@qy_better_lib/core/lib/utils/object.js +83 -0
- package/lib/packages/hooks/node_modules/@qy_better_lib/core/lib/utils/random.js +11 -0
- package/lib/use-chart/config.d.ts +2 -3
- package/lib/use-chart/config.js +80 -0
- package/lib/use-chart/index.d.ts +5 -13
- package/lib/use-chart/index.js +199 -0
- package/lib/use-chart/type.d.ts +92 -4
- package/lib/use-emit/extend.d.ts +2 -1
- package/lib/use-emit/extend.js +34 -15
- package/lib/use-emit/index.d.ts +2 -13
- package/lib/use-emit/index.js +22 -17
- package/lib/use-emit/type.d.ts +16 -0
- package/lib/use-fullscreen/index.d.ts +23 -0
- package/lib/use-fullscreen/index.js +53 -0
- package/lib/use-image/index.d.ts +18 -52
- package/lib/use-image/index.js +189 -67
- package/lib/use-image/type.d.ts +8 -10
- package/lib/use-image/type.js +7 -6
- package/lib/use-layout-flow/index.d.ts +14 -40
- package/lib/use-layout-flow/index.js +286 -0
- package/lib/use-layout-flow/type.d.ts +46 -0
- package/lib/use-mqtt/index.d.ts +9 -18
- package/lib/use-mqtt/index.js +179 -0
- package/lib/use-mqtt/type.d.ts +78 -0
- package/lib/use-print/index.d.ts +5 -9
- package/lib/use-print/index.js +274 -40
- package/lib/use-print/type.d.ts +58 -0
- package/lib/use-watermark/index.d.ts +7 -0
- package/lib/use-watermark/index.js +134 -0
- package/lib/use-watermark/type.d.ts +55 -0
- package/lib/use-websocket/index.d.ts +6 -13
- package/lib/use-websocket/index.js +192 -39
- package/lib/use-websocket/type.d.ts +54 -0
- package/package.json +9 -3
- package/dist/@qy_better_lib/hooks.min.js +0 -15
- package/lib/use-chart/utils.d.ts +0 -7
- package/lib/use-file/index.d.ts +0 -14
- package/lib/use-file/index.js +0 -26
- package/lib/use-image/canvastoDataURL.d.ts +0 -11
- package/lib/use-image/canvastoDataURL.js +0 -7
- package/lib/use-image/canvastoFile.d.ts +0 -11
- package/lib/use-image/canvastoFile.js +0 -9
- package/lib/use-image/dataURLtoFile.d.ts +0 -10
- package/lib/use-image/dataURLtoFile.js +0 -16
- package/lib/use-image/dataURLtoImage.d.ts +0 -7
- package/lib/use-image/dataURLtoImage.js +0 -9
- package/lib/use-image/downloadFile.d.ts +0 -7
- package/lib/use-image/downloadFile.js +0 -9
- package/lib/use-image/filetoDataURL.d.ts +0 -7
- package/lib/use-image/filetoDataURL.js +0 -9
- package/lib/use-image/imagetoCanvas.d.ts +0 -26
- package/lib/use-image/imagetoCanvas.js +0 -41
- package/lib/use-image/urltoBlob.d.ts +0 -8
- package/lib/use-image/urltoBlob.js +0 -6
- package/lib/use-image/urltoImage.d.ts +0 -7
- package/lib/use-image/urltoImage.js +0 -13
- package/lib/use-utils/index.d.ts +0 -1
- package/lib/use-utils/use-fullscreen.d.ts +0 -9
- package/lib/use-waterMark/index.d.ts +0 -17
- package/lib/use-waterMark/index.js +0 -29
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { use_image } from '../../src/use-image';
|
|
3
|
+
import { EImageType } from '../../src/use-image/type';
|
|
4
|
+
|
|
5
|
+
// 模拟@qy_better_lib/core中的工具函数
|
|
6
|
+
vi.mock('@qy_better_lib/core', () => {
|
|
7
|
+
// 在vi.mock内部定义MockFile类
|
|
8
|
+
class MockFile extends Blob {
|
|
9
|
+
name: string;
|
|
10
|
+
size: number;
|
|
11
|
+
type: string;
|
|
12
|
+
|
|
13
|
+
constructor(name: string, size: number, type: string) {
|
|
14
|
+
super([], { type });
|
|
15
|
+
this.name = name;
|
|
16
|
+
this.size = size;
|
|
17
|
+
this.type = type;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
__esModule: true,
|
|
23
|
+
to_base64: vi.fn().mockResolvedValue('data:image/jpeg;base64,test'),
|
|
24
|
+
download_file: vi.fn(),
|
|
25
|
+
compress_image: vi.fn().mockResolvedValue(new MockFile('compressed.jpg', 512, 'image/jpeg')),
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// 模拟File对象
|
|
30
|
+
class MockFile extends Blob {
|
|
31
|
+
name: string;
|
|
32
|
+
size: number;
|
|
33
|
+
type: string;
|
|
34
|
+
|
|
35
|
+
constructor(name: string, size: number, type: string) {
|
|
36
|
+
super([], { type });
|
|
37
|
+
this.name = name;
|
|
38
|
+
this.size = size;
|
|
39
|
+
this.type = type;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 模拟Image对象
|
|
44
|
+
class MockImage {
|
|
45
|
+
private _src: string = '';
|
|
46
|
+
onload: ((this: HTMLImageElement, ev: Event) => any) | null = null;
|
|
47
|
+
onerror: ((this: HTMLImageElement, ev: ErrorEvent) => any) | null = null;
|
|
48
|
+
width: number = 100;
|
|
49
|
+
height: number = 100;
|
|
50
|
+
|
|
51
|
+
constructor() {
|
|
52
|
+
// 模拟Image构造函数
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 模拟设置src时自动触发onload
|
|
56
|
+
set src(url: string) {
|
|
57
|
+
this._src = url;
|
|
58
|
+
// 延迟一点时间触发onload,模拟真实的图片加载
|
|
59
|
+
setTimeout(() => {
|
|
60
|
+
if (this.onload) {
|
|
61
|
+
this.onload.call(this as any, new Event('load'));
|
|
62
|
+
}
|
|
63
|
+
}, 0);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
get src() {
|
|
67
|
+
return this._src;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// 模拟加载成功
|
|
71
|
+
simulateLoad() {
|
|
72
|
+
if (this.onload) {
|
|
73
|
+
this.onload.call(this as any, new Event('load'));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// 模拟加载失败
|
|
78
|
+
simulateError() {
|
|
79
|
+
if (this.onerror) {
|
|
80
|
+
this.onerror.call(this as any, new ErrorEvent('error', { error: new Error('Image load failed') }));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// 模拟Image构造函数
|
|
86
|
+
vi.stubGlobal('Image', MockImage);
|
|
87
|
+
|
|
88
|
+
// 模拟fetch
|
|
89
|
+
const mockFetch: any = vi.fn().mockResolvedValue({
|
|
90
|
+
ok: true,
|
|
91
|
+
blob: vi.fn().mockResolvedValue(new Blob(['test'], { type: 'image/jpeg' })),
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// 模拟document
|
|
95
|
+
const mockDocument: any = {
|
|
96
|
+
createElement: vi.fn().mockReturnValue({
|
|
97
|
+
getContext: vi.fn().mockReturnValue({
|
|
98
|
+
scale: vi.fn(),
|
|
99
|
+
drawImage: vi.fn(),
|
|
100
|
+
clearRect: vi.fn(),
|
|
101
|
+
fillText: vi.fn(),
|
|
102
|
+
fillStyle: '',
|
|
103
|
+
font: '',
|
|
104
|
+
textAlign: '',
|
|
105
|
+
textBaseline: '',
|
|
106
|
+
rotate: vi.fn(),
|
|
107
|
+
}),
|
|
108
|
+
toDataURL: vi.fn().mockReturnValue('data:image/jpeg;base64,test'),
|
|
109
|
+
width: 100,
|
|
110
|
+
height: 100,
|
|
111
|
+
}),
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
// 模拟全局对象
|
|
115
|
+
beforeEach(() => {
|
|
116
|
+
vi.clearAllMocks();
|
|
117
|
+
global.Image = MockImage as any;
|
|
118
|
+
global.fetch = mockFetch;
|
|
119
|
+
global.document = mockDocument as Document;
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
afterEach(() => {
|
|
123
|
+
vi.resetModules();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
describe('use_image', () => {
|
|
127
|
+
it('should initialize with all methods', () => {
|
|
128
|
+
const imageMethods = use_image();
|
|
129
|
+
|
|
130
|
+
expect(typeof imageMethods.compress).toBe('function');
|
|
131
|
+
expect(typeof imageMethods.compress_accurately).toBe('function');
|
|
132
|
+
expect(typeof imageMethods.compress_image).toBe('function');
|
|
133
|
+
expect(typeof imageMethods.canvas_to_data_url).toBe('function');
|
|
134
|
+
expect(typeof imageMethods.canvas_to_file).toBe('function');
|
|
135
|
+
expect(typeof imageMethods.data_url_to_file).toBe('function');
|
|
136
|
+
expect(typeof imageMethods.data_url_to_image).toBe('function');
|
|
137
|
+
expect(typeof imageMethods.file_to_data_url).toBe('function');
|
|
138
|
+
expect(typeof imageMethods.image_to_canvas).toBe('function');
|
|
139
|
+
expect(typeof imageMethods.url_to_blob).toBe('function');
|
|
140
|
+
expect(typeof imageMethods.url_to_image).toBe('function');
|
|
141
|
+
expect(typeof imageMethods.download_file).toBe('function');
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('should compress image successfully', async () => {
|
|
145
|
+
const { compress } = use_image();
|
|
146
|
+
|
|
147
|
+
const mockFile = new MockFile('test.jpg', 1024, 'image/jpeg');
|
|
148
|
+
const result = await compress(mockFile, { quality: 0.8 });
|
|
149
|
+
|
|
150
|
+
expect(result).toBeInstanceOf(Blob);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('should compress image accurately', async () => {
|
|
154
|
+
const { compress_accurately } = use_image();
|
|
155
|
+
|
|
156
|
+
const mockFile = new MockFile('test.jpg', 1024, 'image/jpeg');
|
|
157
|
+
const result = await compress_accurately(mockFile, { size: 0.5 });
|
|
158
|
+
|
|
159
|
+
expect(result).toBeInstanceOf(Blob);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('should use core compress image', async () => {
|
|
163
|
+
const { compress_image } = use_image();
|
|
164
|
+
|
|
165
|
+
const mockFile = new MockFile('test.jpg', 1024, 'image/jpeg');
|
|
166
|
+
const result = await compress_image(mockFile);
|
|
167
|
+
|
|
168
|
+
// 不检查是否是MockFile的实例,而是检查返回值是否具有正确的属性
|
|
169
|
+
expect(result).toBeInstanceOf(Blob);
|
|
170
|
+
expect(result.type).toBe('image/jpeg');
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it('should convert file to data url', async () => {
|
|
174
|
+
const { file_to_data_url } = use_image();
|
|
175
|
+
|
|
176
|
+
const mockFile = new MockFile('test.jpg', 1024, 'image/jpeg');
|
|
177
|
+
const result = await file_to_data_url(mockFile);
|
|
178
|
+
|
|
179
|
+
expect(typeof result).toBe('string');
|
|
180
|
+
expect(result.startsWith('data:image')).toBe(true);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('should convert url to blob', async () => {
|
|
184
|
+
const { url_to_blob } = use_image();
|
|
185
|
+
|
|
186
|
+
const result = await url_to_blob('https://example.com/test.jpg');
|
|
187
|
+
|
|
188
|
+
expect(result).toBeInstanceOf(Blob);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('should convert url to image', async () => {
|
|
192
|
+
const { url_to_image } = use_image();
|
|
193
|
+
|
|
194
|
+
const result = await url_to_image('https://example.com/test.jpg');
|
|
195
|
+
|
|
196
|
+
expect(result).toBeInstanceOf(MockImage);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('should download file', () => {
|
|
200
|
+
const { download_file } = use_image();
|
|
201
|
+
|
|
202
|
+
const mockBlob = new Blob(['test'], { type: 'image/jpeg' });
|
|
203
|
+
download_file(mockBlob, 'test.jpg');
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it('should handle invalid image type', async () => {
|
|
207
|
+
const { compress } = use_image();
|
|
208
|
+
|
|
209
|
+
const mockFile = new MockFile('test.jpg', 1024, 'image/jpeg');
|
|
210
|
+
const result = await compress(mockFile, { type: 'invalid-type' as any });
|
|
211
|
+
|
|
212
|
+
expect(result).toBeInstanceOf(Blob);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('should return original file if compression fails', async () => {
|
|
216
|
+
const { compress } = use_image();
|
|
217
|
+
|
|
218
|
+
const mockFile = new MockFile('test.jpg', 1024, 'image/jpeg');
|
|
219
|
+
// 模拟压缩后文件更大
|
|
220
|
+
const mockCompressedFile = new MockFile('compressed.jpg', 2048, 'image/jpeg');
|
|
221
|
+
|
|
222
|
+
// 模拟canvas.toDataURL返回更大的文件
|
|
223
|
+
const canvas = mockDocument.createElement('canvas');
|
|
224
|
+
canvas.toDataURL = vi.fn().mockReturnValue('data:image/jpeg;base64,' + 'a'.repeat(3000));
|
|
225
|
+
|
|
226
|
+
const result = await compress(mockFile, { quality: 0.8 });
|
|
227
|
+
|
|
228
|
+
expect(result).toBeInstanceOf(Blob);
|
|
229
|
+
});
|
|
230
|
+
});
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { use_layout_flow } from '../../src/use-layout-flow';
|
|
3
|
+
|
|
4
|
+
// 模拟@antv/x6库
|
|
5
|
+
const mockGraph: any = {
|
|
6
|
+
getNodes: vi.fn().mockReturnValue([]),
|
|
7
|
+
getEdges: vi.fn().mockReturnValue([]),
|
|
8
|
+
resetCells: vi.fn(),
|
|
9
|
+
createNode: vi.fn().mockReturnValue({ id: 'test-node' }),
|
|
10
|
+
createEdge: vi.fn().mockReturnValue({ id: 'test-edge' }),
|
|
11
|
+
on: vi.fn(),
|
|
12
|
+
clearCells: vi.fn(),
|
|
13
|
+
zoomToFit: vi.fn(),
|
|
14
|
+
centerContent: vi.fn(),
|
|
15
|
+
getCellById: vi.fn().mockReturnValue(null),
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// 模拟Graph构造函数
|
|
19
|
+
class MockGraphClass {
|
|
20
|
+
constructor(options: any) {
|
|
21
|
+
return mockGraph;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const mockGraphClass: any = vi.fn(MockGraphClass);
|
|
26
|
+
|
|
27
|
+
// 模拟dagre库
|
|
28
|
+
const mockDagreGraph: any = {
|
|
29
|
+
setGraph: vi.fn(),
|
|
30
|
+
setDefaultEdgeLabel: vi.fn(),
|
|
31
|
+
setNode: vi.fn(),
|
|
32
|
+
setEdge: vi.fn(),
|
|
33
|
+
nodes: vi.fn().mockReturnValue([]),
|
|
34
|
+
node: vi.fn().mockReturnValue({ x: 0, y: 0 }),
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const mockDagre: any = {
|
|
38
|
+
graphlib: {
|
|
39
|
+
Graph: vi.fn().mockImplementation(() => mockDagreGraph),
|
|
40
|
+
},
|
|
41
|
+
layout: vi.fn(),
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// 模拟动态导入
|
|
45
|
+
vi.mock('@antv/x6', () => {
|
|
46
|
+
return {
|
|
47
|
+
__esModule: true,
|
|
48
|
+
Graph: mockGraphClass,
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
vi.mock('dagre', () => {
|
|
53
|
+
return {
|
|
54
|
+
__esModule: true,
|
|
55
|
+
default: mockDagre,
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// 确保mockGraph的getNodes和getEdges方法返回有效的数组
|
|
60
|
+
mockGraph.getNodes = vi.fn().mockReturnValue([{ id: 'node1' }]);
|
|
61
|
+
mockGraph.getEdges = vi.fn().mockReturnValue([{
|
|
62
|
+
getSource: vi.fn().mockReturnValue({ cell: 'node1' }),
|
|
63
|
+
getTarget: vi.fn().mockReturnValue({ cell: 'node2' }),
|
|
64
|
+
getSourceNode: vi.fn().mockReturnValue({ getBBox: vi.fn().mockReturnValue({ x: 0, y: 0, width: 100, height: 60, center: { x: 50, y: 30 } }) }),
|
|
65
|
+
getTargetNode: vi.fn().mockReturnValue({ getBBox: vi.fn().mockReturnValue({ x: 200, y: 0, width: 100, height: 60, center: { x: 250, y: 30 } }) }),
|
|
66
|
+
setVertices: vi.fn(),
|
|
67
|
+
}]);
|
|
68
|
+
|
|
69
|
+
// 模拟deep_assign函数
|
|
70
|
+
vi.mock('@qy_better_lib/core', () => {
|
|
71
|
+
return {
|
|
72
|
+
__esModule: true,
|
|
73
|
+
deep_assign: vi.fn().mockImplementation((...args) => Object.assign({}, ...args)),
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// 模拟容器元素
|
|
78
|
+
const mockContainer: any = {
|
|
79
|
+
id: 'test-container',
|
|
80
|
+
clientWidth: 800,
|
|
81
|
+
clientHeight: 600,
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
beforeEach(() => {
|
|
85
|
+
vi.clearAllMocks();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
afterEach(() => {
|
|
89
|
+
vi.resetModules();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
describe('use_layout_flow', () => {
|
|
93
|
+
it('should initialize and return all methods', () => {
|
|
94
|
+
const layoutFlow = use_layout_flow({});
|
|
95
|
+
|
|
96
|
+
expect(typeof layoutFlow.init).toBe('function');
|
|
97
|
+
expect(typeof layoutFlow.add_graph_elements).toBe('function');
|
|
98
|
+
expect(typeof layoutFlow.layout).toBe('function');
|
|
99
|
+
expect(typeof layoutFlow.center_content).toBe('function');
|
|
100
|
+
expect(typeof layoutFlow.create_nodes).toBe('function');
|
|
101
|
+
expect(typeof layoutFlow.create_edges).toBe('function');
|
|
102
|
+
expect(typeof layoutFlow.register_event).toBe('function');
|
|
103
|
+
expect(typeof layoutFlow.register_custom_elements).toBe('function');
|
|
104
|
+
expect(typeof layoutFlow.get_nodes).toBe('function');
|
|
105
|
+
expect(typeof layoutFlow.clear).toBe('function');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('should initialize graph successfully', async () => {
|
|
109
|
+
const layoutFlow = use_layout_flow({});
|
|
110
|
+
|
|
111
|
+
const result = await layoutFlow.init(mockContainer);
|
|
112
|
+
|
|
113
|
+
expect(result).toBe(true);
|
|
114
|
+
expect(mockGraphClass).toHaveBeenCalled();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('should handle init with null container', async () => {
|
|
118
|
+
const layoutFlow = use_layout_flow({});
|
|
119
|
+
|
|
120
|
+
await expect(layoutFlow.init(null as any)).rejects.toThrow('init(): 容器元素不能为空');
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('should add graph elements', async () => {
|
|
124
|
+
const layoutFlow = use_layout_flow({});
|
|
125
|
+
|
|
126
|
+
// 先初始化
|
|
127
|
+
await layoutFlow.init(mockContainer);
|
|
128
|
+
|
|
129
|
+
const testElements = [{ id: 'node1' }, { id: 'edge1' }];
|
|
130
|
+
layoutFlow.add_graph_elements(testElements);
|
|
131
|
+
|
|
132
|
+
expect(mockGraph.resetCells).toHaveBeenCalledWith(testElements);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('should handle add_graph_elements without initialization', () => {
|
|
136
|
+
const layoutFlow = use_layout_flow({});
|
|
137
|
+
|
|
138
|
+
const testElements = [{ id: 'node1' }];
|
|
139
|
+
layoutFlow.add_graph_elements(testElements);
|
|
140
|
+
|
|
141
|
+
expect(mockGraph.resetCells).not.toHaveBeenCalled();
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('should handle add_graph_elements with non-array elements', async () => {
|
|
145
|
+
const layoutFlow = use_layout_flow({});
|
|
146
|
+
|
|
147
|
+
// 先初始化
|
|
148
|
+
await layoutFlow.init(mockContainer);
|
|
149
|
+
|
|
150
|
+
layoutFlow.add_graph_elements('not-an-array' as any);
|
|
151
|
+
|
|
152
|
+
expect(mockGraph.resetCells).not.toHaveBeenCalled();
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('should layout successfully', async () => {
|
|
156
|
+
const layoutFlow = use_layout_flow({});
|
|
157
|
+
|
|
158
|
+
// 先初始化
|
|
159
|
+
await layoutFlow.init(mockContainer);
|
|
160
|
+
|
|
161
|
+
const layoutConfig = {
|
|
162
|
+
node_w: 100,
|
|
163
|
+
node_h: 60,
|
|
164
|
+
nodesep: 20,
|
|
165
|
+
ranksep: 40,
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const result = await layoutFlow.layout(layoutConfig, 'LR');
|
|
169
|
+
|
|
170
|
+
expect(result).toBe(true);
|
|
171
|
+
expect(mockDagre.layout).toHaveBeenCalled();
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('should handle layout without initialization', async () => {
|
|
175
|
+
const layoutFlow = use_layout_flow({});
|
|
176
|
+
|
|
177
|
+
const layoutConfig = {
|
|
178
|
+
node_w: 100,
|
|
179
|
+
node_h: 60,
|
|
180
|
+
nodesep: 20,
|
|
181
|
+
ranksep: 40,
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
const result = await layoutFlow.layout(layoutConfig, 'LR');
|
|
185
|
+
|
|
186
|
+
expect(result).toBe(false);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('should handle layout with invalid config', async () => {
|
|
190
|
+
const layoutFlow = use_layout_flow({});
|
|
191
|
+
|
|
192
|
+
// 先初始化
|
|
193
|
+
await layoutFlow.init(mockContainer);
|
|
194
|
+
|
|
195
|
+
const invalidConfig = {
|
|
196
|
+
node_w: -100, // 无效值
|
|
197
|
+
node_h: 60,
|
|
198
|
+
nodesep: 20,
|
|
199
|
+
ranksep: 40,
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const result = await layoutFlow.layout(invalidConfig as any, 'LR');
|
|
203
|
+
|
|
204
|
+
expect(result).toBe(false);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it('should handle layout with invalid direction', async () => {
|
|
208
|
+
const layoutFlow = use_layout_flow({});
|
|
209
|
+
|
|
210
|
+
// 先初始化
|
|
211
|
+
await layoutFlow.init(mockContainer);
|
|
212
|
+
|
|
213
|
+
const layoutConfig = {
|
|
214
|
+
node_w: 100,
|
|
215
|
+
node_h: 60,
|
|
216
|
+
nodesep: 20,
|
|
217
|
+
ranksep: 40,
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
const result = await layoutFlow.layout(layoutConfig, 'invalid-direction' as any);
|
|
221
|
+
|
|
222
|
+
expect(result).toBe(false);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('should center content', async () => {
|
|
226
|
+
const layoutFlow = use_layout_flow({});
|
|
227
|
+
|
|
228
|
+
// 先初始化
|
|
229
|
+
await layoutFlow.init(mockContainer);
|
|
230
|
+
|
|
231
|
+
layoutFlow.center_content(20);
|
|
232
|
+
|
|
233
|
+
expect(mockGraph.zoomToFit).toHaveBeenCalledWith({ padding: 20, maxScale: 1.2 });
|
|
234
|
+
expect(mockGraph.centerContent).toHaveBeenCalled();
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it('should handle center_content without initialization', () => {
|
|
238
|
+
const layoutFlow = use_layout_flow({});
|
|
239
|
+
|
|
240
|
+
layoutFlow.center_content(20);
|
|
241
|
+
|
|
242
|
+
expect(mockGraph.zoomToFit).not.toHaveBeenCalled();
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it('should create nodes', async () => {
|
|
246
|
+
const layoutFlow = use_layout_flow({});
|
|
247
|
+
|
|
248
|
+
// 先初始化
|
|
249
|
+
await layoutFlow.init(mockContainer);
|
|
250
|
+
|
|
251
|
+
const nodeOptions = [{ id: 'node1' }, { id: 'node2' }];
|
|
252
|
+
const nodes = layoutFlow.create_nodes(nodeOptions);
|
|
253
|
+
|
|
254
|
+
expect(nodes.length).toBe(2);
|
|
255
|
+
expect(mockGraph.createNode).toHaveBeenCalledTimes(2);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it('should handle create_nodes without initialization', () => {
|
|
259
|
+
const layoutFlow = use_layout_flow({});
|
|
260
|
+
|
|
261
|
+
const nodeOptions = [{ id: 'node1' }];
|
|
262
|
+
const nodes = layoutFlow.create_nodes(nodeOptions);
|
|
263
|
+
|
|
264
|
+
expect(nodes.length).toBe(0);
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
it('should create edges', async () => {
|
|
268
|
+
const layoutFlow = use_layout_flow({});
|
|
269
|
+
|
|
270
|
+
// 先初始化
|
|
271
|
+
await layoutFlow.init(mockContainer);
|
|
272
|
+
|
|
273
|
+
const edgeOptions = [
|
|
274
|
+
{ source_id: 'node1', target_id: 'node2' },
|
|
275
|
+
{ source_id: 'node2', target_id: 'node3' },
|
|
276
|
+
];
|
|
277
|
+
const edges = layoutFlow.create_edges(edgeOptions);
|
|
278
|
+
|
|
279
|
+
expect(edges.length).toBe(2);
|
|
280
|
+
expect(mockGraph.createEdge).toHaveBeenCalledTimes(2);
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it('should handle create_edges without initialization', () => {
|
|
284
|
+
const layoutFlow = use_layout_flow({});
|
|
285
|
+
|
|
286
|
+
const edgeOptions = [{ source_id: 'node1', target_id: 'node2' }];
|
|
287
|
+
const edges = layoutFlow.create_edges(edgeOptions);
|
|
288
|
+
|
|
289
|
+
expect(edges.length).toBe(0);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
it('should register events', async () => {
|
|
293
|
+
const layoutFlow = use_layout_flow({});
|
|
294
|
+
|
|
295
|
+
// 先初始化
|
|
296
|
+
await layoutFlow.init(mockContainer);
|
|
297
|
+
|
|
298
|
+
const eventOptions = {
|
|
299
|
+
'node:click': vi.fn(),
|
|
300
|
+
'edge:click': vi.fn(),
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
layoutFlow.register_event(eventOptions);
|
|
304
|
+
|
|
305
|
+
expect(mockGraph.on).toHaveBeenCalledTimes(2);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it('should handle register_event without initialization', () => {
|
|
309
|
+
const layoutFlow = use_layout_flow({});
|
|
310
|
+
|
|
311
|
+
const eventOptions = {
|
|
312
|
+
'node:click': vi.fn(),
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
layoutFlow.register_event(eventOptions);
|
|
316
|
+
|
|
317
|
+
expect(mockGraph.on).not.toHaveBeenCalled();
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
it('should register custom elements', async () => {
|
|
321
|
+
const layoutFlow = use_layout_flow({});
|
|
322
|
+
|
|
323
|
+
const customElements = {
|
|
324
|
+
nodes: {
|
|
325
|
+
'custom-node': { shape: 'rect' },
|
|
326
|
+
},
|
|
327
|
+
edges: {
|
|
328
|
+
'custom-edge': { shape: 'polyline' },
|
|
329
|
+
},
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
// 模拟Graph.registerNode和Graph.registerEdge
|
|
333
|
+
mockGraphClass.registerNode = vi.fn();
|
|
334
|
+
mockGraphClass.registerEdge = vi.fn();
|
|
335
|
+
|
|
336
|
+
const result = await layoutFlow.register_custom_elements(customElements);
|
|
337
|
+
|
|
338
|
+
expect(result).toBe(true);
|
|
339
|
+
expect(mockGraphClass.registerNode).toHaveBeenCalledWith('custom-node', { shape: 'rect' }, true);
|
|
340
|
+
expect(mockGraphClass.registerEdge).toHaveBeenCalledWith('custom-edge', { shape: 'polyline' }, true);
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
it('should get nodes', async () => {
|
|
344
|
+
const layoutFlow = use_layout_flow({});
|
|
345
|
+
|
|
346
|
+
// 先初始化
|
|
347
|
+
await layoutFlow.init(mockContainer);
|
|
348
|
+
|
|
349
|
+
const nodes = layoutFlow.get_nodes();
|
|
350
|
+
|
|
351
|
+
expect(mockGraph.getNodes).toHaveBeenCalled();
|
|
352
|
+
// 期望返回我们mock的节点数组
|
|
353
|
+
expect(nodes).toEqual([{ id: 'node1' }]);
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
it('should handle get_nodes without initialization', () => {
|
|
357
|
+
const layoutFlow = use_layout_flow({});
|
|
358
|
+
|
|
359
|
+
const nodes = layoutFlow.get_nodes();
|
|
360
|
+
|
|
361
|
+
expect(nodes).toEqual([]);
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
it('should clear graph', async () => {
|
|
365
|
+
const layoutFlow = use_layout_flow({});
|
|
366
|
+
|
|
367
|
+
// 先初始化
|
|
368
|
+
await layoutFlow.init(mockContainer);
|
|
369
|
+
|
|
370
|
+
layoutFlow.clear();
|
|
371
|
+
|
|
372
|
+
expect(mockGraph.clearCells).toHaveBeenCalled();
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
it('should handle clear without initialization', () => {
|
|
376
|
+
const layoutFlow = use_layout_flow({});
|
|
377
|
+
|
|
378
|
+
layoutFlow.clear();
|
|
379
|
+
|
|
380
|
+
// 应该不会抛出错误
|
|
381
|
+
});
|
|
382
|
+
});
|