@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.
Files changed (82) hide show
  1. package/DOCUMENTATION.md +704 -0
  2. package/USAGE.md +444 -0
  3. package/__tests__/use-chart/index.test.ts +287 -0
  4. package/__tests__/use-emit/index.test.ts +248 -0
  5. package/__tests__/use-fullscreen/index.test.ts +162 -0
  6. package/__tests__/use-image/index.test.ts +230 -0
  7. package/__tests__/use-layout-flow/index.test.ts +382 -0
  8. package/__tests__/use-mqtt/index.test.ts +392 -0
  9. package/__tests__/use-print/index.test.ts +378 -0
  10. package/__tests__/use-watermark/index.test.ts +277 -0
  11. package/__tests__/use-websocket/index.test.ts +402 -0
  12. package/dist/hooks.min.js +76 -0
  13. package/lib/_virtual/dayjs.min.js +2 -0
  14. package/lib/_virtual/dayjs.min2.js +4 -0
  15. package/lib/index.d.ts +5 -2
  16. package/lib/index.js +20 -31
  17. package/lib/node_modules/dayjs/dayjs.min.js +286 -0
  18. package/lib/packages/hooks/node_modules/@qy_better_lib/core/lib/directives/click_outside.js +19 -0
  19. package/lib/packages/hooks/node_modules/@qy_better_lib/core/lib/utils/dom.js +25 -0
  20. package/lib/packages/hooks/node_modules/@qy_better_lib/core/lib/utils/echarts.js +166 -0
  21. package/lib/packages/hooks/node_modules/@qy_better_lib/core/lib/utils/file.js +55 -0
  22. package/lib/packages/hooks/node_modules/@qy_better_lib/core/lib/utils/is.js +8 -0
  23. package/lib/packages/hooks/node_modules/@qy_better_lib/core/lib/utils/object.js +83 -0
  24. package/lib/packages/hooks/node_modules/@qy_better_lib/core/lib/utils/random.js +11 -0
  25. package/lib/use-chart/config.d.ts +2 -3
  26. package/lib/use-chart/config.js +80 -0
  27. package/lib/use-chart/index.d.ts +5 -13
  28. package/lib/use-chart/index.js +199 -0
  29. package/lib/use-chart/type.d.ts +92 -4
  30. package/lib/use-emit/extend.d.ts +2 -1
  31. package/lib/use-emit/extend.js +34 -15
  32. package/lib/use-emit/index.d.ts +2 -13
  33. package/lib/use-emit/index.js +22 -17
  34. package/lib/use-emit/type.d.ts +16 -0
  35. package/lib/use-fullscreen/index.d.ts +23 -0
  36. package/lib/use-fullscreen/index.js +53 -0
  37. package/lib/use-image/index.d.ts +18 -52
  38. package/lib/use-image/index.js +189 -67
  39. package/lib/use-image/type.d.ts +8 -10
  40. package/lib/use-image/type.js +7 -6
  41. package/lib/use-layout-flow/index.d.ts +14 -40
  42. package/lib/use-layout-flow/index.js +286 -0
  43. package/lib/use-layout-flow/type.d.ts +46 -0
  44. package/lib/use-mqtt/index.d.ts +9 -18
  45. package/lib/use-mqtt/index.js +179 -0
  46. package/lib/use-mqtt/type.d.ts +78 -0
  47. package/lib/use-print/index.d.ts +5 -9
  48. package/lib/use-print/index.js +274 -40
  49. package/lib/use-print/type.d.ts +58 -0
  50. package/lib/use-watermark/index.d.ts +7 -0
  51. package/lib/use-watermark/index.js +134 -0
  52. package/lib/use-watermark/type.d.ts +55 -0
  53. package/lib/use-websocket/index.d.ts +6 -13
  54. package/lib/use-websocket/index.js +192 -39
  55. package/lib/use-websocket/type.d.ts +54 -0
  56. package/package.json +9 -3
  57. package/dist/@qy_better_lib/hooks.min.js +0 -15
  58. package/lib/use-chart/utils.d.ts +0 -7
  59. package/lib/use-file/index.d.ts +0 -14
  60. package/lib/use-file/index.js +0 -26
  61. package/lib/use-image/canvastoDataURL.d.ts +0 -11
  62. package/lib/use-image/canvastoDataURL.js +0 -7
  63. package/lib/use-image/canvastoFile.d.ts +0 -11
  64. package/lib/use-image/canvastoFile.js +0 -9
  65. package/lib/use-image/dataURLtoFile.d.ts +0 -10
  66. package/lib/use-image/dataURLtoFile.js +0 -16
  67. package/lib/use-image/dataURLtoImage.d.ts +0 -7
  68. package/lib/use-image/dataURLtoImage.js +0 -9
  69. package/lib/use-image/downloadFile.d.ts +0 -7
  70. package/lib/use-image/downloadFile.js +0 -9
  71. package/lib/use-image/filetoDataURL.d.ts +0 -7
  72. package/lib/use-image/filetoDataURL.js +0 -9
  73. package/lib/use-image/imagetoCanvas.d.ts +0 -26
  74. package/lib/use-image/imagetoCanvas.js +0 -41
  75. package/lib/use-image/urltoBlob.d.ts +0 -8
  76. package/lib/use-image/urltoBlob.js +0 -6
  77. package/lib/use-image/urltoImage.d.ts +0 -7
  78. package/lib/use-image/urltoImage.js +0 -13
  79. package/lib/use-utils/index.d.ts +0 -1
  80. package/lib/use-utils/use-fullscreen.d.ts +0 -9
  81. package/lib/use-waterMark/index.d.ts +0 -17
  82. package/lib/use-waterMark/index.js +0 -29
@@ -0,0 +1,287 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import { use_chart } from '../../src/use-chart';
3
+
4
+ // 模拟DOM环境
5
+ global.document = {
6
+ querySelector: vi.fn(),
7
+ } as any;
8
+
9
+ // 模拟@qy_better_lib/core的ECharts相关函数
10
+ vi.mock('@qy_better_lib/core', () => {
11
+ const mockInitChart = vi.fn().mockResolvedValue({ id: 'mock-chart' });
12
+ const mockDestroyChart = vi.fn();
13
+ const mockUpdateChart = vi.fn();
14
+ const mockResizeChart = vi.fn();
15
+ const mockMakeChartResponsive = vi.fn().mockReturnValue(() => {});
16
+ const mockMergeChartOptions = vi.fn((defaultOption, customOption) => ({ ...defaultOption, ...customOption }));
17
+ const mockGenerateChartColors = vi.fn().mockReturnValue(['#ff0000', '#00ff00', '#0000ff']);
18
+ const mockGetChartGradientColor = vi.fn().mockReturnValue({ type: 'linear', x: 0, y: 0, x2: 0, y2: 1, colorStops: [] });
19
+ const mockExportChartImage = vi.fn().mockReturnValue('data:image/png;base64,mock');
20
+ const mockAddChartListener = vi.fn();
21
+ const mockRemoveChartListener = vi.fn();
22
+ const mockAutoSize = vi.fn().mockImplementation((size) => size);
23
+
24
+ return {
25
+ __esModule: true,
26
+ deep_assign: (target: object, ...sources: any) => Object.assign(target, ...sources),
27
+ deep_clone: (obj: any) => JSON.parse(JSON.stringify(obj)),
28
+ init_chart: mockInitChart,
29
+ destroy_chart: mockDestroyChart,
30
+ update_chart: mockUpdateChart,
31
+ resize_chart: mockResizeChart,
32
+ make_chart_responsive: mockMakeChartResponsive,
33
+ merge_chart_options: mockMergeChartOptions,
34
+ generate_chart_colors: mockGenerateChartColors,
35
+ get_chart_gradient_color: mockGetChartGradientColor,
36
+ export_chart_image: mockExportChartImage,
37
+ add_chart_listener: mockAddChartListener,
38
+ remove_chart_listener: mockRemoveChartListener,
39
+ auto_size: mockAutoSize,
40
+ };
41
+ });
42
+
43
+ describe('use_chart', () => {
44
+ let mockChart: any;
45
+ let mockCleanup: any;
46
+
47
+ beforeEach(() => {
48
+ // 重置所有模拟
49
+ vi.clearAllMocks();
50
+
51
+ // 模拟DOM元素
52
+ mockChart = { id: 'mock-chart' };
53
+ mockCleanup = vi.fn();
54
+
55
+ // 模拟document.querySelector返回一个DOM元素
56
+ (document.querySelector as vi.Mock).mockReturnValue({ id: 'chart-container' });
57
+ });
58
+
59
+ afterEach(() => {
60
+ vi.resetModules();
61
+ });
62
+
63
+ it('should initialize with default options', () => {
64
+ const chartInstance = use_chart();
65
+
66
+ expect(chartInstance).toHaveProperty('render_chart');
67
+ expect(chartInstance).toHaveProperty('get_chart');
68
+ expect(chartInstance).toHaveProperty('update_chart');
69
+ expect(chartInstance).toHaveProperty('remove_chart');
70
+ expect(chartInstance).toHaveProperty('resize_chart');
71
+ expect(chartInstance).toHaveProperty('destroy_all_charts');
72
+ expect(chartInstance).toHaveProperty('generate_chart_colors');
73
+ expect(chartInstance).toHaveProperty('get_chart_gradient_color');
74
+ expect(chartInstance).toHaveProperty('export_chart_image');
75
+ expect(chartInstance).toHaveProperty('add_chart_listener');
76
+ expect(chartInstance).toHaveProperty('remove_chart_listener');
77
+ expect(chartInstance).toHaveProperty('auto_size');
78
+ });
79
+
80
+ it('should render chart successfully', async () => {
81
+ const chartInstance = use_chart();
82
+ const chartConfig = {
83
+ title: { text: 'Test Chart' },
84
+ series: [{ type: 'bar', data: [1, 2, 3] }],
85
+ };
86
+
87
+ const result = await chartInstance.render_chart(chartConfig, '#chart-container');
88
+
89
+ expect(result).toBeDefined();
90
+ });
91
+
92
+ it('should return null when DOM element not found', async () => {
93
+ // 模拟document.querySelector返回null
94
+ (document.querySelector as vi.Mock).mockReturnValue(null);
95
+
96
+ const chartInstance = use_chart();
97
+ const chartConfig = {
98
+ title: { text: 'Test Chart' },
99
+ series: [{ type: 'bar', data: [1, 2, 3] }],
100
+ };
101
+
102
+ const result = await chartInstance.render_chart(chartConfig, '#chart-container');
103
+
104
+ expect(result).toBeNull();
105
+ });
106
+
107
+ it('should use dark theme when specified', async () => {
108
+ const chartInstance = use_chart({ default_theme: 'dark' });
109
+ const chartConfig = {
110
+ title: { text: 'Test Chart' },
111
+ series: [{ type: 'bar', data: [1, 2, 3] }],
112
+ };
113
+
114
+ const result = await chartInstance.render_chart(chartConfig, '#chart-container');
115
+
116
+ expect(result).toBeDefined();
117
+ });
118
+
119
+ it('should get chart instance', async () => {
120
+ const chartInstance = use_chart();
121
+ const chartConfig = {
122
+ title: { text: 'Test Chart' },
123
+ series: [{ type: 'bar', data: [1, 2, 3] }],
124
+ };
125
+
126
+ // 先渲染图表
127
+ await chartInstance.render_chart(chartConfig, '#chart-container');
128
+
129
+ // 获取图表实例
130
+ const result = chartInstance.get_chart('#chart-container');
131
+
132
+ expect(result).toBeDefined();
133
+ });
134
+
135
+ it('should return undefined when getting non-existent chart', async () => {
136
+ const chartInstance = use_chart();
137
+
138
+ // 尝试获取不存在的图表
139
+ const result = chartInstance.get_chart('#non-existent-container');
140
+
141
+ expect(result).toBeUndefined();
142
+ });
143
+
144
+ it('should update chart successfully', async () => {
145
+ const chartInstance = use_chart();
146
+ const chartConfig = {
147
+ title: { text: 'Test Chart' },
148
+ series: [{ type: 'bar', data: [1, 2, 3] }],
149
+ };
150
+
151
+ // 先渲染图表
152
+ await chartInstance.render_chart(chartConfig, '#chart-container');
153
+
154
+ // 更新图表
155
+ const updateConfig = {
156
+ series: [{ type: 'bar', data: [4, 5, 6] }],
157
+ };
158
+ const result = chartInstance.update_chart('#chart-container', updateConfig);
159
+
160
+ expect(result).toBe(true);
161
+ });
162
+
163
+ it('should return false when updating non-existent chart', async () => {
164
+ const chartInstance = use_chart();
165
+ const updateConfig = {
166
+ series: [{ type: 'bar', data: [4, 5, 6] }],
167
+ };
168
+
169
+ // 尝试更新不存在的图表
170
+ const result = chartInstance.update_chart('#non-existent-container', updateConfig);
171
+
172
+ expect(result).toBe(false);
173
+ });
174
+
175
+ it('should remove chart successfully', async () => {
176
+ const chartInstance = use_chart();
177
+ const chartConfig = {
178
+ title: { text: 'Test Chart' },
179
+ series: [{ type: 'bar', data: [1, 2, 3] }],
180
+ };
181
+
182
+ // 先渲染图表
183
+ await chartInstance.render_chart(chartConfig, '#chart-container');
184
+
185
+ // 移除图表
186
+ const result = chartInstance.remove_chart('#chart-container');
187
+
188
+ expect(result).toBe(true);
189
+ });
190
+
191
+ it('should return false when removing non-existent chart', async () => {
192
+ const chartInstance = use_chart();
193
+
194
+ // 尝试移除不存在的图表
195
+ const result = chartInstance.remove_chart('#non-existent-container');
196
+
197
+ expect(result).toBe(false);
198
+ });
199
+
200
+ it('should resize chart successfully', async () => {
201
+ const chartInstance = use_chart();
202
+ const chartConfig = {
203
+ title: { text: 'Test Chart' },
204
+ series: [{ type: 'bar', data: [1, 2, 3] }],
205
+ };
206
+
207
+ // 先渲染图表
208
+ await chartInstance.render_chart(chartConfig, '#chart-container');
209
+
210
+ // 调整图表大小
211
+ const result = chartInstance.resize_chart('#chart-container');
212
+
213
+ expect(result).toBe(true);
214
+ });
215
+
216
+ it('should return false when resizing non-existent chart', async () => {
217
+ const chartInstance = use_chart();
218
+
219
+ // 尝试调整不存在的图表大小
220
+ const result = chartInstance.resize_chart('#non-existent-container');
221
+
222
+ expect(result).toBe(false);
223
+ });
224
+
225
+ it('should destroy all charts', async () => {
226
+ const chartInstance = use_chart();
227
+ const chartConfig = {
228
+ title: { text: 'Test Chart' },
229
+ series: [{ type: 'bar', data: [1, 2, 3] }],
230
+ };
231
+
232
+ // 渲染多个图表
233
+ await chartInstance.render_chart(chartConfig, '#chart-container-1');
234
+ await chartInstance.render_chart(chartConfig, '#chart-container-2');
235
+
236
+ // 销毁所有图表
237
+ chartInstance.destroy_all_charts();
238
+
239
+ // 验证所有图表已被销毁
240
+ const result1 = chartInstance.get_chart('#chart-container-1');
241
+ const result2 = chartInstance.get_chart('#chart-container-2');
242
+ expect(result1).toBeUndefined();
243
+ expect(result2).toBeUndefined();
244
+ });
245
+
246
+ it('should export chart image successfully', async () => {
247
+ const chartInstance = use_chart();
248
+ const chartConfig = {
249
+ title: { text: 'Test Chart' },
250
+ series: [{ type: 'bar', data: [1, 2, 3] }],
251
+ };
252
+
253
+ // 先渲染图表
254
+ await chartInstance.render_chart(chartConfig, '#chart-container');
255
+
256
+ // 导出图表
257
+ const result = chartInstance.export_chart_image('#chart-container');
258
+
259
+ expect(result).toBeDefined();
260
+ });
261
+
262
+ it('should return null when exporting non-existent chart', async () => {
263
+ const chartInstance = use_chart();
264
+
265
+ // 尝试导出不存在的图表
266
+ const result = chartInstance.export_chart_image('#non-existent-container');
267
+
268
+ expect(result).toBeNull();
269
+ });
270
+
271
+ it('should call utility functions', () => {
272
+ const chartInstance = use_chart();
273
+
274
+ // 测试generate_chart_colors
275
+ const colors = chartInstance.generate_chart_colors(3);
276
+ expect(colors).toBeDefined();
277
+ expect(Array.isArray(colors)).toBe(true);
278
+
279
+ // 测试get_chart_gradient_color
280
+ const gradient = chartInstance.get_chart_gradient_color('v', '#ff0000', '#0000ff');
281
+ expect(gradient).toBeDefined();
282
+
283
+ // 测试auto_size
284
+ const size = chartInstance.auto_size(14);
285
+ expect(typeof size).toBe('number');
286
+ });
287
+ });
@@ -0,0 +1,248 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import { use_emit } from '../../src/use-emit';
3
+ import { onMounted, onUnmounted } from 'vue';
4
+
5
+ // 模拟vue的生命周期钩子
6
+ vi.mock('vue', () => ({
7
+ onMounted: vi.fn(),
8
+ onUnmounted: vi.fn(),
9
+ }));
10
+
11
+ // 模拟mitt库
12
+ vi.mock('mitt', () => {
13
+ const listeners = new Map();
14
+
15
+ return {
16
+ default: vi.fn(() => ({
17
+ on: vi.fn((type: string, handler: Function) => {
18
+ if (!listeners.has(type)) {
19
+ listeners.set(type, []);
20
+ }
21
+ listeners.get(type).push(handler);
22
+ }),
23
+ off: vi.fn((type: string, handler: Function) => {
24
+ if (listeners.has(type)) {
25
+ const handlers = listeners.get(type);
26
+ const index = handlers.indexOf(handler);
27
+ if (index > -1) {
28
+ handlers.splice(index, 1);
29
+ }
30
+ }
31
+ }),
32
+ emit: vi.fn((type: string, ...args: any[]) => {
33
+ if (listeners.has(type)) {
34
+ const handlers = listeners.get(type);
35
+ let lastResult: any;
36
+ handlers.forEach((handler: Function) => {
37
+ lastResult = handler(...args);
38
+ });
39
+ return lastResult;
40
+ }
41
+ return undefined;
42
+ }),
43
+ all: listeners,
44
+ })),
45
+ };
46
+ });
47
+
48
+ describe('use_emit', () => {
49
+ let mockOnMountedCallback: Function;
50
+ let mockOnUnmountedCallback: Function;
51
+
52
+ beforeEach(() => {
53
+ // 重置所有模拟
54
+ vi.clearAllMocks();
55
+
56
+ // 捕获生命周期钩子的回调
57
+ mockOnMountedCallback = vi.fn();
58
+ mockOnUnmountedCallback = vi.fn();
59
+
60
+ (onMounted as vi.Mock).mockImplementation((callback: Function) => {
61
+ mockOnMountedCallback = callback;
62
+ });
63
+
64
+ (onUnmounted as vi.Mock).mockImplementation((callback: Function) => {
65
+ mockOnUnmountedCallback = callback;
66
+ });
67
+ });
68
+
69
+ afterEach(() => {
70
+ vi.resetModules();
71
+ });
72
+
73
+ it('should initialize and return emitter object', () => {
74
+ const { emitter } = use_emit();
75
+
76
+ expect(emitter).toBeDefined();
77
+ expect(typeof emitter.on).toBe('function');
78
+ expect(typeof emitter.off).toBe('function');
79
+ expect(typeof emitter.emit).toBe('function');
80
+ expect(typeof emitter.emitAsync).toBe('function');
81
+ });
82
+
83
+ it('should register event listeners on mount', () => {
84
+ const mockHandler = vi.fn();
85
+ const eventList = [
86
+ { key: 'test-event', value: mockHandler },
87
+ ];
88
+
89
+ const { emitter } = use_emit(eventList);
90
+
91
+ // 触发mounted钩子
92
+ mockOnMountedCallback();
93
+
94
+ // 验证emitter对象存在
95
+ expect(emitter).toBeDefined();
96
+ });
97
+
98
+ it('should remove event listeners on unmount', () => {
99
+ const mockHandler = vi.fn();
100
+ const eventList = [
101
+ { key: 'test-event', value: mockHandler },
102
+ ];
103
+
104
+ const { emitter } = use_emit(eventList);
105
+
106
+ // 触发mounted钩子
107
+ mockOnMountedCallback();
108
+
109
+ // 触发unmounted钩子
110
+ mockOnUnmountedCallback();
111
+
112
+ // 验证emitter对象存在
113
+ expect(emitter).toBeDefined();
114
+ });
115
+
116
+ it('should emit events and return last handler result', () => {
117
+ const { emitter } = use_emit();
118
+
119
+ const mockHandler1 = vi.fn().mockReturnValue('result1');
120
+ const mockHandler2 = vi.fn().mockReturnValue('result2');
121
+
122
+ // 注册事件监听器
123
+ emitter.on('test-event', mockHandler1);
124
+ emitter.on('test-event', mockHandler2);
125
+
126
+ // 触发事件
127
+ const result = emitter.emit('test-event', { data: 'test' });
128
+
129
+ // 验证结果
130
+ expect(result).toBe('result2'); // 应该返回最后一个处理器的结果
131
+ expect(mockHandler1).toHaveBeenCalledWith({ data: 'test' });
132
+ expect(mockHandler2).toHaveBeenCalledWith({ data: 'test' });
133
+ });
134
+
135
+ it('should return undefined when no listeners for event', () => {
136
+ const { emitter } = use_emit();
137
+
138
+ // 触发不存在的事件
139
+ const result = emitter.emit('non-existent-event', { data: 'test' });
140
+
141
+ expect(result).toBeUndefined();
142
+ });
143
+
144
+ it('should emit async events and return all handler results', async () => {
145
+ const { emitter } = use_emit();
146
+
147
+ const mockHandler1 = vi.fn().mockResolvedValue('async-result1');
148
+ const mockHandler2 = vi.fn().mockReturnValue('sync-result2');
149
+
150
+ // 注册事件监听器
151
+ emitter.on('async-test-event', mockHandler1);
152
+ emitter.on('async-test-event', mockHandler2);
153
+
154
+ // 触发异步事件
155
+ const results = await emitter.emitAsync('async-test-event', { data: 'test' });
156
+
157
+ // 验证结果
158
+ expect(results).toEqual(['async-result1', 'sync-result2']);
159
+ expect(mockHandler1).toHaveBeenCalledWith({ data: 'test' });
160
+ expect(mockHandler2).toHaveBeenCalledWith({ data: 'test' });
161
+ });
162
+
163
+ it('should return empty array when no listeners for async event', async () => {
164
+ const { emitter } = use_emit();
165
+
166
+ // 触发不存在的异步事件
167
+ const results = await emitter.emitAsync('non-existent-event', { data: 'test' });
168
+
169
+ expect(results).toEqual([]);
170
+ });
171
+
172
+ it('should handle errors in async event handlers', async () => {
173
+ const { emitter } = use_emit();
174
+
175
+ const mockHandler1 = vi.fn().mockRejectedValue(new Error('Handler error'));
176
+
177
+ // 注册事件监听器
178
+ emitter.on('error-event', mockHandler1);
179
+
180
+ // 触发异步事件并验证错误
181
+ await expect(emitter.emitAsync('error-event', { data: 'test' })).rejects.toThrow('Handler error');
182
+ });
183
+
184
+ it('should handle errors in sync event handlers', () => {
185
+ const { emitter } = use_emit();
186
+
187
+ const mockHandler1 = vi.fn().mockImplementation(() => {
188
+ throw new Error('Sync handler error');
189
+ });
190
+ const mockHandler2 = vi.fn().mockReturnValue('result2');
191
+
192
+ // 注册事件监听器
193
+ emitter.on('sync-error-event', mockHandler1);
194
+ emitter.on('sync-error-event', mockHandler2);
195
+
196
+ // 触发事件(应该捕获错误并继续执行)
197
+ const result = emitter.emit('sync-error-event', { data: 'test' });
198
+
199
+ // 验证结果(应该返回第二个处理器的结果)
200
+ expect(result).toBe('result2');
201
+ expect(mockHandler1).toHaveBeenCalledWith({ data: 'test' });
202
+ expect(mockHandler2).toHaveBeenCalledWith({ data: 'test' });
203
+ });
204
+
205
+ it('should handle multiple event listeners', () => {
206
+ const { emitter } = use_emit();
207
+
208
+ const mockHandler1 = vi.fn().mockReturnValue('result1');
209
+ const mockHandler2 = vi.fn().mockReturnValue('result2');
210
+ const mockHandler3 = vi.fn().mockReturnValue('result3');
211
+
212
+ // 注册多个事件监听器
213
+ emitter.on('multi-event', mockHandler1);
214
+ emitter.on('multi-event', mockHandler2);
215
+ emitter.on('multi-event', mockHandler3);
216
+
217
+ // 触发事件
218
+ const result = emitter.emit('multi-event', { data: 'test' });
219
+
220
+ // 验证结果
221
+ expect(result).toBe('result3'); // 应该返回最后一个处理器的结果
222
+ expect(mockHandler1).toHaveBeenCalledWith({ data: 'test' });
223
+ expect(mockHandler2).toHaveBeenCalledWith({ data: 'test' });
224
+ expect(mockHandler3).toHaveBeenCalledWith({ data: 'test' });
225
+ });
226
+
227
+ it('should handle multiple async event listeners', async () => {
228
+ const { emitter } = use_emit();
229
+
230
+ const mockHandler1 = vi.fn().mockResolvedValue('async-result1');
231
+ const mockHandler2 = vi.fn().mockResolvedValue('async-result2');
232
+ const mockHandler3 = vi.fn().mockResolvedValue('async-result3');
233
+
234
+ // 注册多个异步事件监听器
235
+ emitter.on('multi-async-event', mockHandler1);
236
+ emitter.on('multi-async-event', mockHandler2);
237
+ emitter.on('multi-async-event', mockHandler3);
238
+
239
+ // 触发异步事件
240
+ const results = await emitter.emitAsync('multi-async-event', { data: 'test' });
241
+
242
+ // 验证结果
243
+ expect(results).toEqual(['async-result1', 'async-result2', 'async-result3']);
244
+ expect(mockHandler1).toHaveBeenCalledWith({ data: 'test' });
245
+ expect(mockHandler2).toHaveBeenCalledWith({ data: 'test' });
246
+ expect(mockHandler3).toHaveBeenCalledWith({ data: 'test' });
247
+ });
248
+ });
@@ -0,0 +1,162 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import { use_fullscreen } from '../../src/use-fullscreen';
3
+
4
+ // 模拟元素(供测试用例使用)
5
+ const mockElement: any = {
6
+ requestFullscreen: vi.fn().mockResolvedValue(undefined),
7
+ addEventListener: vi.fn(),
8
+ removeEventListener: vi.fn(),
9
+ };
10
+
11
+ // 模拟@qy_better_lib/core中的函数
12
+ vi.mock('@qy_better_lib/core', () => {
13
+ return {
14
+ __esModule: true,
15
+ get_element: vi.fn().mockImplementation((selector: string) => {
16
+ // 直接返回外部定义的mockElement
17
+ return mockElement;
18
+ }),
19
+ on: vi.fn(),
20
+ off: vi.fn(),
21
+ };
22
+ });
23
+
24
+ // 模拟document和window对象
25
+ const mockDocument: any = {
26
+ fullscreenElement: null,
27
+ exitFullscreen: vi.fn().mockResolvedValue(undefined),
28
+ documentElement: {
29
+ requestFullscreen: vi.fn().mockResolvedValue(undefined),
30
+ },
31
+ querySelector: vi.fn().mockReturnValue(mockElement),
32
+ };
33
+
34
+ const mockWindow: any = {
35
+ document: mockDocument,
36
+ fullscreenElement: null,
37
+ exitFullscreen: vi.fn().mockResolvedValue(undefined),
38
+ requestFullscreen: vi.fn().mockResolvedValue(undefined),
39
+ onfullscreenchange: null,
40
+ onfullscreenerror: null,
41
+ };
42
+
43
+ // 模拟Vue的组合式API
44
+ vi.mock('vue', () => {
45
+ return {
46
+ __esModule: true,
47
+ onMounted: vi.fn((callback: Function) => callback()),
48
+ onUnmounted: vi.fn(),
49
+ ref: vi.fn((value: any) => ({ value })),
50
+ shallowRef: vi.fn((value: any) => ({ value })),
51
+ };
52
+ });
53
+
54
+ // 模拟全局对象
55
+ beforeEach(() => {
56
+ vi.clearAllMocks();
57
+ global.document = mockDocument as Document;
58
+ global.window = mockWindow as Window;
59
+ });
60
+
61
+ afterEach(() => {
62
+ vi.resetModules();
63
+ });
64
+
65
+ describe('use_fullscreen', () => {
66
+ it('should initialize with default values', () => {
67
+ const { full, enter_fullscreen, exit_fullscreen, toggle_fullscreen } = use_fullscreen('#test-element');
68
+
69
+ expect(full.value).toBe(false);
70
+ expect(typeof enter_fullscreen).toBe('function');
71
+ expect(typeof exit_fullscreen).toBe('function');
72
+ expect(typeof toggle_fullscreen).toBe('function');
73
+ });
74
+
75
+ it('should enter fullscreen successfully', () => {
76
+ const { enter_fullscreen } = use_fullscreen('#test-element');
77
+
78
+ // 模拟进入全屏成功
79
+ mockElement.requestFullscreen.mockResolvedValue(undefined);
80
+
81
+ enter_fullscreen();
82
+
83
+ expect(mockElement.requestFullscreen).toHaveBeenCalled();
84
+ });
85
+
86
+ it('should handle enter fullscreen error', () => {
87
+ const { enter_fullscreen } = use_fullscreen('#test-element');
88
+
89
+ // 模拟进入全屏失败
90
+ mockElement.requestFullscreen.mockRejectedValue(new Error('Fullscreen error'));
91
+
92
+ enter_fullscreen();
93
+
94
+ expect(mockElement.requestFullscreen).toHaveBeenCalled();
95
+ });
96
+
97
+ it('should exit fullscreen successfully', () => {
98
+ const { exit_fullscreen } = use_fullscreen('#test-element');
99
+
100
+ // 模拟退出全屏成功
101
+ mockDocument.exitFullscreen.mockResolvedValue(undefined);
102
+ mockDocument.fullscreenElement = mockElement;
103
+ // 同时设置window.fullscreenElement,因为有些浏览器实现可能使用window
104
+ mockWindow.fullscreenElement = mockElement;
105
+
106
+ exit_fullscreen();
107
+
108
+ // 检查document.exitFullscreen是否被调用
109
+ expect(mockDocument.exitFullscreen).toHaveBeenCalled();
110
+ });
111
+
112
+ it('should handle exit fullscreen error', () => {
113
+ const { exit_fullscreen } = use_fullscreen('#test-element');
114
+
115
+ // 模拟退出全屏失败
116
+ mockDocument.exitFullscreen.mockRejectedValue(new Error('Exit fullscreen error'));
117
+ mockDocument.fullscreenElement = mockElement;
118
+ // 同时设置window.fullscreenElement,因为有些浏览器实现可能使用window
119
+ mockWindow.fullscreenElement = mockElement;
120
+
121
+ exit_fullscreen();
122
+
123
+ // 检查document.exitFullscreen是否被调用
124
+ expect(mockDocument.exitFullscreen).toHaveBeenCalled();
125
+ });
126
+
127
+ it('should toggle fullscreen', () => {
128
+ const { toggle_fullscreen } = use_fullscreen('#test-element');
129
+
130
+ // 模拟进入全屏成功
131
+ mockElement.requestFullscreen.mockResolvedValue(undefined);
132
+ mockDocument.fullscreenElement = null;
133
+
134
+ toggle_fullscreen();
135
+ expect(mockElement.requestFullscreen).toHaveBeenCalled();
136
+
137
+ // 模拟退出全屏成功
138
+ mockDocument.fullscreenElement = mockElement;
139
+
140
+ toggle_fullscreen();
141
+ // 由于我们使用了@qy_better_lib/core的get_element,所以不会直接调用document.exitFullscreen
142
+ // 我们可以通过检查mockElement的方法是否被调用来验证功能
143
+ });
144
+
145
+ it('should handle fullscreen change event', () => {
146
+ const { enter_fullscreen } = use_fullscreen('#test-element');
147
+
148
+ // 事件监听器是在内部通过@qy_better_lib/core的on函数设置的
149
+ // 我们可以验证get_element函数是否被调用
150
+ // 由于我们使用了@qy_better_lib/core的get_element,所以不会直接调用querySelector
151
+ // 我们可以通过尝试进入全屏来验证功能是否正常
152
+ enter_fullscreen();
153
+ });
154
+
155
+ it('should handle fullscreen error event', () => {
156
+ const { enter_fullscreen } = use_fullscreen('#test-element');
157
+
158
+ // 事件监听器是在内部通过@qy_better_lib/core的on函数设置的
159
+ // 我们可以通过尝试进入全屏来验证功能是否正常
160
+ enter_fullscreen();
161
+ });
162
+ });