@wutiange/log-listener-plugin 2.0.2-alpha.1 → 2.0.2-alpha.3

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 (56) hide show
  1. package/README.md +166 -163
  2. package/dist/index.cjs.js +1450 -0
  3. package/dist/index.cjs.js.map +1 -0
  4. package/dist/index.d.ts +34 -2
  5. package/dist/index.esm.js +1448 -0
  6. package/dist/index.esm.js.map +1 -0
  7. package/index.ts +3 -3
  8. package/package.json +52 -59
  9. package/src/HTTPInterceptor.ts +336 -340
  10. package/src/Server.ts +174 -178
  11. package/src/__mocks__/react-native/Libraries/Blob/FileReader.js +44 -44
  12. package/src/__mocks__/react-native/Libraries/Network/XHRInterceptor.js +39 -39
  13. package/src/__tests__/HTTPInterceptor.test.ts +362 -322
  14. package/src/__tests__/Server.test.ts +150 -150
  15. package/src/__tests__/utils.test.ts +236 -114
  16. package/src/common.ts +57 -57
  17. package/src/logPlugin.ts +235 -231
  18. package/src/logger.ts +15 -15
  19. package/src/utils.ts +72 -112
  20. package/LICENSE +0 -201
  21. package/dist/index.js +0 -8
  22. package/dist/index.js.map +0 -1
  23. package/dist/src/HTTPInterceptor.d.ts +0 -50
  24. package/dist/src/HTTPInterceptor.js +0 -227
  25. package/dist/src/HTTPInterceptor.js.map +0 -1
  26. package/dist/src/Server.d.ts +0 -21
  27. package/dist/src/Server.js +0 -178
  28. package/dist/src/Server.js.map +0 -1
  29. package/dist/src/__mocks__/react-native/Libraries/Blob/FileReader.d.ts +0 -14
  30. package/dist/src/__mocks__/react-native/Libraries/Blob/FileReader.js +0 -41
  31. package/dist/src/__mocks__/react-native/Libraries/Blob/FileReader.js.map +0 -1
  32. package/dist/src/__mocks__/react-native/Libraries/Network/XHRInterceptor.d.ts +0 -17
  33. package/dist/src/__mocks__/react-native/Libraries/Network/XHRInterceptor.js +0 -34
  34. package/dist/src/__mocks__/react-native/Libraries/Network/XHRInterceptor.js.map +0 -1
  35. package/dist/src/__tests__/HTTPInterceptor.test.d.ts +0 -9
  36. package/dist/src/__tests__/HTTPInterceptor.test.js +0 -281
  37. package/dist/src/__tests__/HTTPInterceptor.test.js.map +0 -1
  38. package/dist/src/__tests__/Server.test.d.ts +0 -1
  39. package/dist/src/__tests__/Server.test.js +0 -116
  40. package/dist/src/__tests__/Server.test.js.map +0 -1
  41. package/dist/src/__tests__/utils.test.d.ts +0 -1
  42. package/dist/src/__tests__/utils.test.js +0 -112
  43. package/dist/src/__tests__/utils.test.js.map +0 -1
  44. package/dist/src/common.d.ts +0 -14
  45. package/dist/src/common.js +0 -54
  46. package/dist/src/common.js.map +0 -1
  47. package/dist/src/logPlugin.d.ts +0 -35
  48. package/dist/src/logPlugin.js +0 -188
  49. package/dist/src/logPlugin.js.map +0 -1
  50. package/dist/src/logger.d.ts +0 -6
  51. package/dist/src/logger.js +0 -16
  52. package/dist/src/logger.js.map +0 -1
  53. package/dist/src/utils.d.ts +0 -6
  54. package/dist/src/utils.js +0 -106
  55. package/dist/src/utils.js.map +0 -1
  56. package/tsconfig.json +0 -27
@@ -1,150 +1,150 @@
1
- import Server from '../Server';
2
- import { sleep } from '../utils';
3
-
4
- // Mock dependencies
5
- jest.mock('../utils', () => {
6
- const actual = jest.requireActual('../utils');
7
- return {
8
- ...actual, // 保留所有真实实现
9
- sleep: jest.fn() // 只模拟 sleep 函数
10
- };
11
- });
12
-
13
-
14
- // Mock require for react-native-zeroconf
15
- jest.mock('react-native-zeroconf', () => undefined, { virtual: true });
16
-
17
- // Mock fetch
18
- global.fetch = jest.fn();
19
-
20
- describe('Server', () => {
21
- let server: Server;
22
-
23
- beforeEach(() => {
24
- // Clear all mocks before each test
25
- jest.clearAllMocks();
26
- (global.fetch as jest.Mock).mockReset();
27
- });
28
-
29
- describe('Constructor and URL Management', () => {
30
- it('should initialize with default values', () => {
31
- server = new Server();
32
- expect(server.getBaseUrlArr()).toEqual(new Set([]));
33
- });
34
-
35
- it('should initialize with custom URL', () => {
36
- server = new Server('localhost:8080');
37
- expect(server.getBaseUrlArr()).toEqual(new Set(['http://localhost:8080']));
38
- });
39
-
40
- it('should handle URLs with and without http prefix', () => {
41
- server = new Server();
42
- server.updateUrl('localhost:8080');
43
- expect(server.getBaseUrlArr()).toEqual(new Set(['http://localhost:8080']));
44
-
45
- server.updateUrl('http://localhost:8080');
46
- expect(server.getBaseUrlArr()).toEqual(new Set(['http://localhost:8080']));
47
- });
48
- });
49
-
50
- describe('ZeroConf Handling', () => {
51
- it('should handle case when zeroconf is not available', () => {
52
- server = new Server();
53
- const mockListener = jest.fn();
54
- server.addUrlsListener(mockListener);
55
-
56
- // Since Zeroconf is not available, the listener should not be called
57
- expect(mockListener).not.toHaveBeenCalled();
58
- });
59
-
60
- // Test with mock Zeroconf implementation
61
- it('should handle case when zeroconf is available', () => {
62
- // Temporarily mock require to return a mock Zeroconf implementation
63
- const mockZeroconfInstance = {
64
- on: jest.fn(),
65
- scan: jest.fn()
66
- };
67
-
68
- jest.doMock('react-native-zeroconf', () => ({
69
- __esModule: true,
70
- default: jest.fn(() => mockZeroconfInstance)
71
- }), { virtual: true });
72
-
73
- server = new Server();
74
- const mockListener = jest.fn();
75
- server.addUrlsListener(mockListener);
76
-
77
- // Verify that Zeroconf methods were not called since module is mocked as undefined
78
- expect(mockListener).not.toHaveBeenCalled();
79
- });
80
- });
81
-
82
- describe('Data Sending', () => {
83
- beforeEach(() => {
84
- server = new Server('localhost:8080');
85
- (global.fetch as jest.Mock).mockImplementation(() =>
86
- Promise.resolve({ ok: true })
87
- );
88
- });
89
-
90
- it('should send log data', async () => {
91
- const testData = { message: 'test log' };
92
- await server.log(testData);
93
-
94
- expect(global.fetch).toHaveBeenCalledWith(
95
- 'http://localhost:8080/log',
96
- expect.objectContaining({
97
- method: 'POST',
98
- headers: {
99
- 'Content-Type': 'application/json;charset=utf-8'
100
- },
101
- body: expect.any(String)
102
- })
103
- );
104
- });
105
-
106
- it('should send network data', async () => {
107
- const testData = { url: 'test.com' };
108
- await server.network(testData);
109
-
110
- expect(global.fetch).toHaveBeenCalledWith(
111
- 'http://localhost:8080/network',
112
- expect.objectContaining({
113
- method: 'POST',
114
- headers: {
115
- 'Content-Type': 'application/json;charset=utf-8'
116
- },
117
- body: expect.any(String)
118
- })
119
- );
120
- });
121
-
122
- it('should handle timeout', async () => {
123
- server.updateTimeout(100);
124
- (sleep as jest.Mock).mockImplementation(() => Promise.reject(new Error('Timeout')));
125
-
126
- const testData = { message: 'test' };
127
- await server.log(testData);
128
-
129
- expect(global.fetch).toHaveBeenCalled();
130
- expect(sleep).toHaveBeenCalledWith(100, true);
131
- });
132
- });
133
-
134
- describe('Base Data Management', () => {
135
- it('should update base data', async () => {
136
- server = new Server('localhost:8080');
137
- const baseData = { userId: '123' };
138
- server.updateBaseData(baseData);
139
-
140
- await server.log({ message: 'test' });
141
-
142
- expect(global.fetch).toHaveBeenCalledWith(
143
- expect.any(String),
144
- expect.objectContaining({
145
- body: expect.stringContaining('"userId":"123"')
146
- })
147
- );
148
- });
149
- });
150
- });
1
+ import Server from '../Server';
2
+ import { sleep } from '../utils';
3
+
4
+ // Mock dependencies
5
+ jest.mock('../utils', () => {
6
+ const actual = jest.requireActual('../utils');
7
+ return {
8
+ ...actual, // 保留所有真实实现
9
+ sleep: jest.fn() // 只模拟 sleep 函数
10
+ };
11
+ });
12
+
13
+
14
+ // Mock require for react-native-zeroconf
15
+ jest.mock('react-native-zeroconf', () => undefined, { virtual: true });
16
+
17
+ // Mock fetch
18
+ global.fetch = jest.fn();
19
+
20
+ describe('Server', () => {
21
+ let server: Server;
22
+
23
+ beforeEach(() => {
24
+ // Clear all mocks before each test
25
+ jest.clearAllMocks();
26
+ (global.fetch as jest.Mock).mockReset();
27
+ });
28
+
29
+ describe('Constructor and URL Management', () => {
30
+ it('should initialize with default values', () => {
31
+ server = new Server();
32
+ expect(server.getBaseUrlArr()).toEqual(new Set([]));
33
+ });
34
+
35
+ it('should initialize with custom URL', () => {
36
+ server = new Server('localhost:8080');
37
+ expect(server.getBaseUrlArr()).toEqual(new Set(['http://localhost:8080']));
38
+ });
39
+
40
+ it('should handle URLs with and without http prefix', () => {
41
+ server = new Server();
42
+ server.updateUrl('localhost:8080');
43
+ expect(server.getBaseUrlArr()).toEqual(new Set(['http://localhost:8080']));
44
+
45
+ server.updateUrl('http://localhost:8080');
46
+ expect(server.getBaseUrlArr()).toEqual(new Set(['http://localhost:8080']));
47
+ });
48
+ });
49
+
50
+ describe('ZeroConf Handling', () => {
51
+ it('should handle case when zeroconf is not available', () => {
52
+ server = new Server();
53
+ const mockListener = jest.fn();
54
+ server.addUrlsListener(mockListener);
55
+
56
+ // Since Zeroconf is not available, the listener should not be called
57
+ expect(mockListener).not.toHaveBeenCalled();
58
+ });
59
+
60
+ // Test with mock Zeroconf implementation
61
+ it('should handle case when zeroconf is available', () => {
62
+ // Temporarily mock require to return a mock Zeroconf implementation
63
+ const mockZeroconfInstance = {
64
+ on: jest.fn(),
65
+ scan: jest.fn()
66
+ };
67
+
68
+ jest.doMock('react-native-zeroconf', () => ({
69
+ __esModule: true,
70
+ default: jest.fn(() => mockZeroconfInstance)
71
+ }), { virtual: true });
72
+
73
+ server = new Server();
74
+ const mockListener = jest.fn();
75
+ server.addUrlsListener(mockListener);
76
+
77
+ // Verify that Zeroconf methods were not called since module is mocked as undefined
78
+ expect(mockListener).not.toHaveBeenCalled();
79
+ });
80
+ });
81
+
82
+ describe('Data Sending', () => {
83
+ beforeEach(() => {
84
+ server = new Server('localhost:8080');
85
+ (global.fetch as jest.Mock).mockImplementation(() =>
86
+ Promise.resolve({ ok: true })
87
+ );
88
+ });
89
+
90
+ it('should send log data', async () => {
91
+ const testData = { message: 'test log' };
92
+ await server.log(testData);
93
+
94
+ expect(global.fetch).toHaveBeenCalledWith(
95
+ 'http://localhost:8080/log',
96
+ expect.objectContaining({
97
+ method: 'POST',
98
+ headers: {
99
+ 'Content-Type': 'application/json;charset=utf-8'
100
+ },
101
+ body: expect.any(String)
102
+ })
103
+ );
104
+ });
105
+
106
+ it('should send network data', async () => {
107
+ const testData = { url: 'test.com' };
108
+ await server.network(testData);
109
+
110
+ expect(global.fetch).toHaveBeenCalledWith(
111
+ 'http://localhost:8080/network',
112
+ expect.objectContaining({
113
+ method: 'POST',
114
+ headers: {
115
+ 'Content-Type': 'application/json;charset=utf-8'
116
+ },
117
+ body: expect.any(String)
118
+ })
119
+ );
120
+ });
121
+
122
+ it('should handle timeout', async () => {
123
+ server.updateTimeout(100);
124
+ (sleep as jest.Mock).mockImplementation(() => Promise.reject(new Error('Timeout')));
125
+
126
+ const testData = { message: 'test' };
127
+ await server.log(testData);
128
+
129
+ expect(global.fetch).toHaveBeenCalled();
130
+ expect(sleep).toHaveBeenCalledWith(100, true);
131
+ });
132
+ });
133
+
134
+ describe('Base Data Management', () => {
135
+ it('should update base data', async () => {
136
+ server = new Server('localhost:8080');
137
+ const baseData = { userId: '123' };
138
+ server.updateBaseData(baseData);
139
+
140
+ await server.log({ message: 'test' });
141
+
142
+ expect(global.fetch).toHaveBeenCalledWith(
143
+ expect.any(String),
144
+ expect.objectContaining({
145
+ body: expect.stringContaining('"userId":"123"')
146
+ })
147
+ );
148
+ });
149
+ });
150
+ });
@@ -1,114 +1,236 @@
1
- import logger from '../logger';
2
- import { createClassWithErrorHandling, hasPort } from '../utils';
3
-
4
- describe('createClassWithErrorHandling', () => {
5
- class TestClass {
6
- normalMethod(): string {
7
- return 'normal';
8
- }
9
-
10
- errorMethod(): void {
11
- throw new Error('Test error');
12
- }
13
-
14
- async asyncMethod(): Promise<string> {
15
- return 'async';
16
- }
17
-
18
- async asyncErrorMethod(): Promise<void> {
19
- throw new Error('Async test error');
20
- }
21
- }
22
-
23
- let consoleErrorSpy: jest.SpyInstance;
24
-
25
- beforeEach(() => {
26
- consoleErrorSpy = jest.spyOn(logger, 'error').mockImplementation(() => {});
27
- });
28
-
29
- afterEach(() => {
30
- consoleErrorSpy.mockRestore();
31
- });
32
-
33
- test('should not interfere with normal methods', () => {
34
- const EnhancedClass = createClassWithErrorHandling(TestClass);
35
- const instance = new EnhancedClass();
36
- expect(instance.normalMethod()).toBe('normal');
37
- });
38
-
39
- test('should catch and log errors from methods', () => {
40
- const EnhancedClass = createClassWithErrorHandling(TestClass);
41
- const instance = new EnhancedClass();
42
- expect(() => instance.errorMethod()).toThrow('Test error');
43
- expect(consoleErrorSpy).toHaveBeenCalledWith('Error in errorMethod:', expect.any(Error));
44
- });
45
-
46
- test('should not interfere with async methods that resolve', async () => {
47
- const EnhancedClass = createClassWithErrorHandling(TestClass);
48
- const instance = new EnhancedClass();
49
- await expect(instance.asyncMethod()).resolves.toBe('async');
50
- });
51
-
52
- test('should catch and log errors from async methods that reject', async () => {
53
- const EnhancedClass = createClassWithErrorHandling(TestClass);
54
- const instance = new EnhancedClass();
55
- await expect(instance.asyncErrorMethod()).rejects.toThrow('Async test error');
56
- expect(consoleErrorSpy).toHaveBeenCalledWith('Error in asyncErrorMethod:', expect.any(Error));
57
- });
58
-
59
- test('should handle methods added after instantiation', () => {
60
- const EnhancedClass = createClassWithErrorHandling(TestClass);
61
- const instance = new EnhancedClass();
62
- (instance as any).dynamicMethod = function(): void {
63
- throw new Error('Dynamic method error');
64
- };
65
- expect(() => (instance as any).dynamicMethod()).toThrow('Dynamic method error');
66
- expect(consoleErrorSpy).toHaveBeenCalledWith('Error in dynamicMethod:', expect.any(Error));
67
- });
68
- });
69
-
70
-
71
- describe('hasPort function', () => {
72
- test('should return true for URLs with explicit ports', () => {
73
- expect(hasPort('http://example.com:8080')).toBe(true);
74
- expect(hasPort('ftp://example.com:210')).toBe(true);
75
- });
76
-
77
- test('should return false for URLs without explicit ports', () => {
78
- expect(hasPort('http://example.com')).toBe(false);
79
- expect(hasPort('https://example.com')).toBe(false);
80
- expect(hasPort('ftp://example.com')).toBe(false);
81
- });
82
-
83
- test('should return false for invalid URLs', () => {
84
- expect(hasPort('not a url')).toBe(false);
85
- expect(hasPort('http:/example.com')).toBe(false);
86
- expect(hasPort('example.com:8080')).toBe(false);
87
- });
88
-
89
- test('should return false for empty input', () => {
90
- expect(hasPort('')).toBe(false);
91
- });
92
-
93
- test('should return false for non-string input', () => {
94
- expect(hasPort(null as any)).toBe(false);
95
- expect(hasPort(undefined as any)).toBe(false);
96
- expect(hasPort(123 as any)).toBe(false);
97
- expect(hasPort({} as any)).toBe(false);
98
- });
99
-
100
- test('should handle URLs with default ports correctly', () => {
101
- expect(hasPort('http://example.com:80')).toBe(false);
102
- expect(hasPort('https://example.com:443')).toBe(false);
103
- });
104
-
105
- test('should handle URLs with IPv6 addresses', () => {
106
- expect(hasPort('http://[2001:db8::1]:8080')).toBe(true);
107
- expect(hasPort('https://[2001:db8::1]')).toBe(false);
108
- });
109
-
110
- test('should handle URLs with userinfo', () => {
111
- expect(hasPort('http://user:pass@example.com:8080')).toBe(true);
112
- expect(hasPort('http://user:pass@example.com')).toBe(false);
113
- });
114
- });
1
+ import { hasPort, formDataToString, sleep, typeReplacer } from '../utils';
2
+
3
+ describe('hasPort function', () => {
4
+ it('should return true for URLs with explicit ports', () => {
5
+ expect(hasPort('http://example.com:8080')).toBe(true);
6
+ expect(hasPort('ftp://example.com:210')).toBe(true);
7
+ });
8
+
9
+ it('should return false for URLs without explicit ports', () => {
10
+ expect(hasPort('http://example.com')).toBe(false);
11
+ expect(hasPort('https://example.com')).toBe(false);
12
+ expect(hasPort('ftp://example.com')).toBe(false);
13
+ });
14
+
15
+ it('should return false for invalid URLs', () => {
16
+ expect(hasPort('not a url')).toBe(false);
17
+ expect(hasPort('http:/example.com')).toBe(false);
18
+ expect(hasPort('example.com:8080')).toBe(false);
19
+ });
20
+
21
+ it('should return false for empty input', () => {
22
+ expect(hasPort('')).toBe(false);
23
+ });
24
+
25
+ it('should return false for non-string input', () => {
26
+ expect(hasPort(null as any)).toBe(false);
27
+ expect(hasPort(undefined as any)).toBe(false);
28
+ expect(hasPort(123 as any)).toBe(false);
29
+ expect(hasPort({} as any)).toBe(false);
30
+ });
31
+
32
+ it('should handle URLs with default ports correctly', () => {
33
+ expect(hasPort('http://example.com:80')).toBe(false);
34
+ expect(hasPort('https://example.com:443')).toBe(false);
35
+ });
36
+
37
+ it('should handle URLs with IPv6 addresses', () => {
38
+ expect(hasPort('http://[2001:db8::1]:8080')).toBe(true);
39
+ expect(hasPort('https://[2001:db8::1]')).toBe(false);
40
+ });
41
+
42
+ it('should handle URLs with userinfo', () => {
43
+ expect(hasPort('http://user:pass@example.com:8080')).toBe(true);
44
+ expect(hasPort('http://user:pass@example.com')).toBe(false);
45
+ });
46
+ });
47
+
48
+ describe('formDataToString', () => {
49
+ let mockFormData: FormData;
50
+
51
+ beforeEach(() => {
52
+ // 创建一个模拟的 FormData 对象
53
+ mockFormData = new FormData();
54
+ // 模拟 getParts 方法
55
+ (mockFormData as any).getParts = jest.fn();
56
+ });
57
+
58
+ it('should convert form data with text fields to string', () => {
59
+ // 模拟 getParts 返回包含文本字段的数据
60
+ (mockFormData as any).getParts.mockReturnValue([
61
+ {
62
+ headers: {
63
+ 'content-disposition': 'form-data; name="field1"',
64
+ },
65
+ string: 'value1',
66
+ },
67
+ ]);
68
+
69
+ const result = formDataToString(mockFormData);
70
+
71
+ // 验证基本结构
72
+ expect(result).toMatch(/^------WebKitFormBoundary.*\r\n/);
73
+ expect(result).toMatch(/Content-Disposition: form-data; name="field1"\r\n/);
74
+ expect(result).toMatch(/Content-Length: 6\r\n/);
75
+ expect(result).toMatch(/value1\r\n/);
76
+ expect(result).toMatch(/----WebKitFormBoundary.*--\r\n$/);
77
+ });
78
+
79
+ it('should handle form data with content-type header', () => {
80
+ // 模拟 getParts 返回包含 content-type 的数据
81
+ (mockFormData as any).getParts.mockReturnValue([
82
+ {
83
+ headers: {
84
+ 'content-disposition': 'form-data; name="file"; filename="test.txt"',
85
+ 'content-type': 'text/plain',
86
+ },
87
+ string: 'file content',
88
+ },
89
+ ]);
90
+
91
+ const result = formDataToString(mockFormData);
92
+
93
+ expect(result).toMatch(
94
+ /Content-Disposition: form-data; name="file"; filename="test.txt"\r\n/,
95
+ );
96
+ expect(result).toMatch(/Content-Type: text\/plain\r\n/);
97
+ expect(result).toMatch(/Content-Length: 12\r\n/);
98
+ expect(result).toMatch(/file content\r\n/);
99
+ });
100
+
101
+ it('should handle multiple form fields', () => {
102
+ // 模拟 getParts 返回多个字段
103
+ (mockFormData as any).getParts.mockReturnValue([
104
+ {
105
+ headers: {
106
+ 'content-disposition': 'form-data; name="field1"',
107
+ },
108
+ string: 'value1',
109
+ },
110
+ {
111
+ headers: {
112
+ 'content-disposition': 'form-data; name="field2"',
113
+ },
114
+ string: 'value2',
115
+ },
116
+ ]);
117
+
118
+ const result = formDataToString(mockFormData);
119
+
120
+ expect(result).toMatch(/field1.*value1.*field2.*value2/s);
121
+ expect((result.match(/----WebKitFormBoundary/g) || []).length).toBe(3); // 开始、中间、结束
122
+ });
123
+
124
+ it('should handle URI parts', () => {
125
+ // 模拟 getParts 返回包含 URI 的数据
126
+ (mockFormData as any).getParts.mockReturnValue([
127
+ {
128
+ headers: {
129
+ 'content-disposition': 'form-data; name="file"',
130
+ 'content-type': 'image/jpeg',
131
+ },
132
+ uri: 'file:///path/to/image.jpg',
133
+ },
134
+ ]);
135
+
136
+ const result = formDataToString(mockFormData);
137
+
138
+ expect(result).toMatch(/Content-Type: image\/jpeg\r\n/);
139
+ expect(result).toMatch(/file:\/\/\/path\/to\/image.jpg\r\n/);
140
+ });
141
+ });
142
+
143
+ describe('sleep function', () => {
144
+ // 测试正常延迟情况
145
+ it('should resolve after specified delay', async () => {
146
+ const startTime = Date.now();
147
+ const delay = 100;
148
+
149
+ await sleep(delay);
150
+ const endTime = Date.now();
151
+ const actualDelay = endTime - startTime;
152
+
153
+ // 由于 JavaScript 定时器的不精确性,我们允许一个小的误差范围
154
+ expect(actualDelay).toBeGreaterThanOrEqual(delay);
155
+ expect(actualDelay).toBeLessThan(delay + 50); // 允许 50ms 的误差
156
+ });
157
+
158
+ // 测试超时拒绝情况
159
+ it('should reject with timeout error when isReject is true', async () => {
160
+ const delay = 100;
161
+
162
+ await expect(sleep(delay, true)).rejects.toEqual({
163
+ code: 11001,
164
+ key: '@wutiange/log-listener-plugin%%timeout',
165
+ message: 'Timeout',
166
+ });
167
+ });
168
+ });
169
+
170
+ describe('typeReplacer', () => {
171
+ // 测试 Error 类型转换
172
+ it('should convert Error to string', () => {
173
+ const error = new Error('test error');
174
+ expect(typeReplacer('error', error)).toBe('Error: test error');
175
+ });
176
+
177
+ // 测试 Function 类型转换
178
+ it('should convert Function to string', () => {
179
+ const fn = function test() {
180
+ return 'hello';
181
+ };
182
+ const result = typeReplacer('fn', fn);
183
+ expect(result).toContain('function test()');
184
+ });
185
+
186
+ // 测试 Symbol 类型转换
187
+ it('should convert Symbol to string', () => {
188
+ const sym = Symbol('test');
189
+ expect(typeReplacer('symbol', sym)).toBe('Symbol(test)');
190
+ });
191
+
192
+ // 测试 BigInt 类型转换
193
+ it('should convert BigInt to string', () => {
194
+ const big = BigInt(9007199254740991);
195
+ expect(typeReplacer('bigint', big)).toBe('9007199254740991');
196
+ });
197
+
198
+ // 测试 RegExp 类型转换
199
+ it('should convert RegExp to string', () => {
200
+ const regex = /test/g;
201
+ expect(typeReplacer('regex', regex)).toBe('/test/g');
202
+ });
203
+
204
+ // 测试 Set 类型转换
205
+ it('should convert Set to array', () => {
206
+ const set = new Set([1, 2, 3]);
207
+ expect(typeReplacer('set', set)).toEqual([1, 2, 3]);
208
+ });
209
+
210
+ // 测试 Map 类型转换
211
+ it('should convert Map to object', () => {
212
+ const map = new Map([
213
+ ['key1', 'value1'],
214
+ ['key2', 'value2'],
215
+ ]);
216
+ expect(typeReplacer('map', map)).toEqual({
217
+ key1: 'value1',
218
+ key2: 'value2',
219
+ });
220
+ });
221
+
222
+ // 测试普通值不变
223
+ it('should return primitive values as is', () => {
224
+ expect(typeReplacer('string', 'test')).toBe('test');
225
+ expect(typeReplacer('number', 42)).toBe(42);
226
+ expect(typeReplacer('boolean', true)).toBe(true);
227
+ expect(typeReplacer('null', null)).toBe(null);
228
+ expect(typeReplacer('undefined', undefined)).toBe(undefined);
229
+ });
230
+
231
+ // 测试普通对象不变
232
+ it('should return objects as is', () => {
233
+ const obj = { name: 'test', age: 25 };
234
+ expect(typeReplacer('object', obj)).toEqual(obj);
235
+ });
236
+ });