@agions/taroviz 1.1.0 → 1.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 (73) hide show
  1. package/README.md +318 -53
  2. package/dist/index.esm.js +67955 -3318
  3. package/package.json +102 -20
  4. package/src/__tests__/integration.test.tsx +168 -0
  5. package/src/adapters/__tests__/index.test.ts +91 -0
  6. package/src/adapters/h5/__tests__/index.test.ts +156 -0
  7. package/src/adapters/h5/index.ts +301 -0
  8. package/src/adapters/harmony/index.ts +274 -0
  9. package/src/adapters/index.ts +234 -0
  10. package/src/adapters/swan/index.ts +274 -0
  11. package/src/adapters/tt/index.ts +274 -0
  12. package/src/adapters/types.ts +162 -0
  13. package/src/adapters/weapp/index.ts +237 -0
  14. package/src/charts/bar/__tests__/index.test.tsx +113 -0
  15. package/src/charts/bar/index.tsx +27 -0
  16. package/src/charts/common/BaseChartWrapper.tsx +136 -0
  17. package/src/charts/funnel/index.tsx +33 -0
  18. package/src/charts/gauge/index.tsx +33 -0
  19. package/src/charts/heatmap/index.tsx +33 -0
  20. package/src/charts/index.ts +21 -0
  21. package/src/charts/line/__tests__/index.test.tsx +107 -0
  22. package/src/charts/line/index.tsx +27 -0
  23. package/src/charts/pie/__tests__/index.test.tsx +112 -0
  24. package/src/charts/pie/index.tsx +22 -0
  25. package/src/charts/radar/index.tsx +33 -0
  26. package/src/charts/scatter/index.tsx +33 -0
  27. package/src/charts/types.ts +146 -0
  28. package/src/charts/utils.ts +56 -0
  29. package/src/core/__tests__/platform.test.ts +48 -0
  30. package/src/core/animation/AnimationManager.ts +391 -0
  31. package/src/core/animation/index.ts +20 -0
  32. package/src/core/animation/types.ts +248 -0
  33. package/src/core/components/BaseChart.tsx +1319 -0
  34. package/src/core/index.ts +19 -0
  35. package/src/core/types/chart.ts +66 -0
  36. package/src/core/types/common.ts +224 -0
  37. package/src/core/types/index.ts +281 -0
  38. package/src/core/types/platform.ts +325 -0
  39. package/src/core/utils/__tests__/common.test.ts +52 -0
  40. package/src/core/utils/__tests__/environment.test.ts +94 -0
  41. package/src/core/utils/__tests__/i18n.test.ts +247 -0
  42. package/src/core/utils/__tests__/index.test.ts +219 -0
  43. package/src/core/utils/__tests__/uuid.test.ts +78 -0
  44. package/src/core/utils/chartInstances.ts +69 -0
  45. package/src/core/utils/codeGenerator/CodeGenerator.ts +655 -0
  46. package/src/core/utils/codeGenerator/index.ts +13 -0
  47. package/src/core/utils/codeGenerator/types.ts +200 -0
  48. package/src/core/utils/common.ts +58 -0
  49. package/src/core/utils/configGenerator/ConfigGenerator.ts +583 -0
  50. package/src/core/utils/configGenerator/index.ts +13 -0
  51. package/src/core/utils/configGenerator/types.ts +445 -0
  52. package/src/core/utils/debug/DebugPanel.tsx +637 -0
  53. package/src/core/utils/debug/debugger.ts +322 -0
  54. package/src/core/utils/debug/index.ts +21 -0
  55. package/src/core/utils/debug/types.ts +142 -0
  56. package/src/core/utils/i18n.ts +452 -0
  57. package/src/core/utils/index.ts +162 -0
  58. package/src/core/utils/performance/PerformanceAnalyzer.ts +586 -0
  59. package/src/core/utils/performance/index.ts +13 -0
  60. package/src/core/utils/performance/types.ts +180 -0
  61. package/src/core/utils/uuid.ts +30 -0
  62. package/src/editor/ThemeEditor.tsx +449 -0
  63. package/src/editor/index.ts +10 -0
  64. package/src/hooks/__tests__/index.test.tsx +333 -0
  65. package/src/hooks/index.ts +214 -0
  66. package/src/index.ts +75 -0
  67. package/src/main.tsx +247 -0
  68. package/src/react-dom.d.ts +7 -0
  69. package/src/themes/__tests__/index.test.ts +91 -0
  70. package/src/themes/index.ts +465 -0
  71. package/dist/index.esm.js.map +0 -1
  72. package/dist/index.js +0 -4012
  73. package/dist/index.js.map +0 -1
@@ -0,0 +1,325 @@
1
+ /**
2
+ * 支持的平台类型
3
+ */
4
+ export enum PlatformType {
5
+ H5 = 'h5',
6
+ WEAPP = 'weapp', // 微信小程序
7
+ ALIPAY = 'alipay', // 支付宝小程序
8
+ SWAN = 'swan', // 百度小程序
9
+ TT = 'tt', // 字节跳动小程序
10
+ QQ = 'qq', // QQ小程序
11
+ JD = 'jd', // 京东小程序
12
+ HARMONY = 'harmony', // 鸿蒙OS
13
+ DD = 'dd', // 钉钉小程序
14
+ QYWX = 'qywx', // 企业微信小程序
15
+ LARK = 'lark', // 飞书小程序
16
+ KWAI = 'kwai', // 快手小程序
17
+ }
18
+
19
+ // 导出平台类型字符串联合类型
20
+ export type Platform = `${PlatformType}` | 'web' | 'ks';
21
+
22
+ /**
23
+ * 事件处理器类型
24
+ */
25
+ export type EventHandler = (params: any) => void;
26
+
27
+ /**
28
+ * 适配器通用选项
29
+ */
30
+ export interface AdapterOptions {
31
+ /**
32
+ * 平台类型
33
+ */
34
+ platform?: Platform;
35
+
36
+ /**
37
+ * 画布ID
38
+ */
39
+ canvasId?: string;
40
+
41
+ /**
42
+ * 宽度
43
+ */
44
+ width?: number | string;
45
+
46
+ /**
47
+ * 高度
48
+ */
49
+ height?: number | string;
50
+
51
+ /**
52
+ * 主题
53
+ */
54
+ theme?: string | object;
55
+
56
+ /**
57
+ * 是否自动调整大小
58
+ */
59
+ autoResize?: boolean;
60
+
61
+ /**
62
+ * 设备像素比
63
+ */
64
+ devicePixelRatio?: number;
65
+
66
+ /**
67
+ * 初始化回调
68
+ */
69
+ onInit?: (instance: any) => void;
70
+
71
+ /**
72
+ * 容器引用
73
+ */
74
+ containerRef?: any;
75
+
76
+ /**
77
+ * 图表选项
78
+ */
79
+ option?: any;
80
+
81
+ /**
82
+ * 渲染器类型
83
+ */
84
+ renderer?: 'canvas' | 'svg';
85
+
86
+ /**
87
+ * 样式对象
88
+ */
89
+ style?: any;
90
+
91
+ /**
92
+ * CSS类名
93
+ */
94
+ className?: string;
95
+ }
96
+
97
+ /**
98
+ * H5环境适配器选项
99
+ */
100
+ export interface H5AdapterOptions extends AdapterOptions {
101
+ /**
102
+ * 容器引用
103
+ */
104
+ containerRef?: React.RefObject<HTMLDivElement>;
105
+
106
+ /**
107
+ * 图表选项
108
+ */
109
+ option?: any;
110
+
111
+ /**
112
+ * 是否不合并选项
113
+ */
114
+ notMerge?: boolean;
115
+
116
+ /**
117
+ * 是否延迟更新
118
+ */
119
+ lazyUpdate?: boolean;
120
+
121
+ /**
122
+ * 样式
123
+ */
124
+ style?: React.CSSProperties;
125
+
126
+ /**
127
+ * 类名
128
+ */
129
+ className?: string;
130
+
131
+ /**
132
+ * 渲染器类型
133
+ */
134
+ renderer?: 'canvas' | 'svg';
135
+ }
136
+
137
+ /**
138
+ * 小程序适配器基础选项
139
+ */
140
+ export interface MiniAppAdapterOptions extends AdapterOptions {
141
+ /**
142
+ * 小程序组件实例
143
+ */
144
+ componentInstance?: any;
145
+
146
+ /**
147
+ * 是否禁用touch事件
148
+ */
149
+ disableTouch?: boolean;
150
+
151
+ /**
152
+ * 渲染模式
153
+ */
154
+ renderMode?: '2d' | 'webgl';
155
+
156
+ /**
157
+ * 图表配置选项
158
+ */
159
+ option?: any;
160
+
161
+ /**
162
+ * 样式属性
163
+ */
164
+ style?: React.CSSProperties;
165
+ }
166
+
167
+ /**
168
+ * 微信小程序适配器选项
169
+ */
170
+ export interface WeappAdapterOptions extends MiniAppAdapterOptions {
171
+ /**
172
+ * 微信特有选项
173
+ */
174
+ weappOptions?: {
175
+ /**
176
+ * 是否启用右侧菜单
177
+ */
178
+ enableContextMenu?: boolean;
179
+
180
+ /**
181
+ * 是否启用跨端同层渲染
182
+ */
183
+ enableCrossPageTransfer?: boolean;
184
+ };
185
+ }
186
+
187
+ /**
188
+ * 支付宝小程序适配器选项
189
+ */
190
+ export interface AlipayAdapterOptions extends MiniAppAdapterOptions {
191
+ /**
192
+ * 支付宝特有选项
193
+ */
194
+ alipayOptions?: {
195
+ /**
196
+ * 是否启用离屏渲染
197
+ */
198
+ enableOffscreenRendering?: boolean;
199
+ };
200
+ }
201
+
202
+ /**
203
+ * 百度小程序适配器选项
204
+ */
205
+ export interface SwanAdapterOptions extends MiniAppAdapterOptions {
206
+ /**
207
+ * 百度智能小程序特有选项
208
+ */
209
+ swanOptions?: {
210
+ /**
211
+ * 是否启用复杂交互
212
+ */
213
+ enableComplexInteraction?: boolean;
214
+
215
+ /**
216
+ * 是否启用性能优化
217
+ */
218
+ enablePerformanceOptimization?: boolean;
219
+ };
220
+ }
221
+
222
+ /**
223
+ * 鸿蒙OS适配器选项
224
+ */
225
+ export interface HarmonyAdapterOptions extends AdapterOptions {
226
+ /**
227
+ * 鸿蒙特有选项
228
+ */
229
+ harmonyOptions?: {
230
+ /**
231
+ * 是否启用硬件加速
232
+ */
233
+ enableHardwareAcceleration?: boolean;
234
+ };
235
+ }
236
+
237
+ /**
238
+ * 适配器接口
239
+ */
240
+ export interface Adapter {
241
+ /**
242
+ * 初始化图表
243
+ */
244
+ init(): any;
245
+
246
+ /**
247
+ * 获取图表实例
248
+ */
249
+ getInstance(): any;
250
+
251
+ /**
252
+ * 设置图表配置项
253
+ */
254
+ setOption(option: any, opts?: any): void;
255
+
256
+ /**
257
+ * 获取图表宽度
258
+ */
259
+ getWidth(): number;
260
+
261
+ /**
262
+ * 获取图表高度
263
+ */
264
+ getHeight(): number;
265
+
266
+ /**
267
+ * 获取DOM元素
268
+ */
269
+ getDom(): HTMLElement | null;
270
+
271
+ /**
272
+ * 调整图表大小
273
+ */
274
+ resize(opts?: any): void;
275
+
276
+ /**
277
+ * 触发图表行为
278
+ */
279
+ dispatchAction(payload: any): void;
280
+
281
+ /**
282
+ * 转换为DataURL
283
+ */
284
+ convertToDataURL(opts?: any): string | undefined;
285
+
286
+ /**
287
+ * 清空图表
288
+ */
289
+ clear(): void;
290
+
291
+ /**
292
+ * 获取DataURL
293
+ */
294
+ getDataURL(opts?: any): string | undefined;
295
+
296
+ /**
297
+ * 绑定事件
298
+ */
299
+ on(eventName: string, handler: EventHandler, context?: object): void;
300
+
301
+ /**
302
+ * 解绑事件
303
+ */
304
+ off(eventName: string, handler?: EventHandler): void;
305
+
306
+ /**
307
+ * 显示加载动画
308
+ */
309
+ showLoading(opts?: object): void;
310
+
311
+ /**
312
+ * 隐藏加载动画
313
+ */
314
+ hideLoading(): void;
315
+
316
+ /**
317
+ * 销毁图表实例
318
+ */
319
+ dispose(): void;
320
+
321
+ /**
322
+ * 渲染图表
323
+ */
324
+ render(): JSX.Element;
325
+ }
@@ -0,0 +1,52 @@
1
+ import { deepMerge, debounce, throttle } from '../index';
2
+
3
+ describe('Common Utils', () => {
4
+ describe('deepMerge', () => {
5
+ it('should merge two objects deeply', () => {
6
+ const target = { a: 1, b: { c: 2 } };
7
+ const source = { b: { d: 3 }, e: 4 };
8
+ const result = deepMerge(target, source);
9
+
10
+ expect(result).toEqual({ a: 1, b: { c: 2, d: 3 }, e: 4 });
11
+ });
12
+
13
+ it('should return the target object when source is empty', () => {
14
+ const target = { a: 1, b: { c: 2 } };
15
+ const source = {};
16
+ const result = deepMerge(target, source);
17
+
18
+ expect(result).toEqual(target);
19
+ });
20
+ });
21
+
22
+ describe('debounce', () => {
23
+ it('should debounce a function call', done => {
24
+ let count = 0;
25
+ const debouncedFn = debounce(() => {
26
+ count++;
27
+ done();
28
+ }, 100);
29
+
30
+ debouncedFn();
31
+ debouncedFn();
32
+ debouncedFn();
33
+
34
+ expect(count).toBe(0);
35
+ });
36
+ });
37
+
38
+ describe('throttle', () => {
39
+ it('should throttle a function call', () => {
40
+ let count = 0;
41
+ const throttledFn = throttle(() => {
42
+ count++;
43
+ }, 100);
44
+
45
+ throttledFn();
46
+ throttledFn();
47
+ throttledFn();
48
+
49
+ expect(count).toBe(1);
50
+ });
51
+ });
52
+ });
@@ -0,0 +1,94 @@
1
+ import { getEnvironment } from '../index';
2
+
3
+ describe('Cross-Platform Compatibility', () => {
4
+ describe('Environment Detection', () => {
5
+ it('should detect client environment correctly in Jest', () => {
6
+ const env = getEnvironment();
7
+ // In Jest test environment with jsdom, it should be client-side
8
+ expect(env.isServer).toBe(false);
9
+ expect(env.isClient).toBe(true);
10
+ });
11
+
12
+ it('should detect web environment when window is available', () => {
13
+ // Mock window object for web environment
14
+ const originalWindow = global.window;
15
+ // Use any type assertion to bypass TypeScript checks for testing
16
+ global.window = {} as any;
17
+
18
+ // Mock wx and my objects as undefined to simulate web environment
19
+ Object.defineProperty(global.window, 'wx', { value: undefined, writable: true });
20
+ Object.defineProperty(global.window, 'my', { value: undefined, writable: true });
21
+
22
+ const env = getEnvironment();
23
+ expect(env.isWeb).toBe(true);
24
+ expect(env.isWeapp).toBe(false);
25
+ expect(env.isAlipay).toBe(false);
26
+
27
+ // Restore original window object
28
+ global.window = originalWindow;
29
+ });
30
+
31
+ it('should detect WeChat Mini Program environment correctly', () => {
32
+ // Mock window object with wx for WeChat Mini Program environment
33
+ const originalWindow = global.window;
34
+ // Use any type assertion to bypass TypeScript checks for testing
35
+ global.window = {} as any;
36
+
37
+ Object.defineProperty(global.window, 'wx', {
38
+ value: {
39
+ getSystemInfoSync: jest.fn(),
40
+ },
41
+ writable: true,
42
+ });
43
+ Object.defineProperty(global.window, 'my', { value: undefined, writable: true });
44
+
45
+ const env = getEnvironment();
46
+ expect(env.isWeapp).toBe(true);
47
+ expect(env.isWeb).toBe(false);
48
+ expect(env.isAlipay).toBe(false);
49
+
50
+ // Restore original window object
51
+ global.window = originalWindow;
52
+ });
53
+
54
+ it('should detect Alipay Mini Program environment correctly', () => {
55
+ // Mock window object with my for Alipay Mini Program environment
56
+ const originalWindow = global.window;
57
+ // Use any type assertion to bypass TypeScript checks for testing
58
+ global.window = {} as any;
59
+
60
+ Object.defineProperty(global.window, 'wx', { value: undefined, writable: true });
61
+ Object.defineProperty(global.window, 'my', {
62
+ value: {
63
+ getSystemInfoSync: jest.fn(),
64
+ },
65
+ writable: true,
66
+ });
67
+
68
+ const env = getEnvironment();
69
+ expect(env.isAlipay).toBe(true);
70
+ expect(env.isWeb).toBe(false);
71
+ expect(env.isWeapp).toBe(false);
72
+
73
+ // Restore original window object
74
+ global.window = originalWindow;
75
+ });
76
+
77
+ it('should return consistent environment object structure', () => {
78
+ const env = getEnvironment();
79
+
80
+ expect(env).toHaveProperty('isServer');
81
+ expect(env).toHaveProperty('isClient');
82
+ expect(env).toHaveProperty('isWeapp');
83
+ expect(env).toHaveProperty('isAlipay');
84
+ expect(env).toHaveProperty('isWeb');
85
+
86
+ // All properties should be boolean values
87
+ expect(typeof env.isServer).toBe('boolean');
88
+ expect(typeof env.isClient).toBe('boolean');
89
+ expect(typeof env.isWeapp).toBe('boolean');
90
+ expect(typeof env.isAlipay).toBe('boolean');
91
+ expect(typeof env.isWeb).toBe('boolean');
92
+ });
93
+ });
94
+ });
@@ -0,0 +1,247 @@
1
+ import {
2
+ formatDateTime,
3
+ formatDate,
4
+ formatTime,
5
+ formatCurrency,
6
+ formatPercent,
7
+ formatNumber,
8
+ getSupportedLocales,
9
+ getSystemLocale,
10
+ getSystemTimeZone,
11
+ Localization,
12
+ defaultLocalization,
13
+ } from '../i18n';
14
+
15
+ describe('Internationalization Utilities', () => {
16
+ const testDate = new Date('2023-10-15T14:30:45.123Z');
17
+
18
+ describe('formatDateTime', () => {
19
+ it('should format date time with default options', () => {
20
+ const result = formatDateTime(testDate);
21
+ expect(typeof result).toBe('string');
22
+ expect(result).not.toBe('');
23
+ });
24
+
25
+ it('should format date time with different locales', () => {
26
+ const enResult = formatDateTime(testDate, { locale: 'en-US' });
27
+ const zhResult = formatDateTime(testDate, { locale: 'zh-CN' });
28
+ const deResult = formatDateTime(testDate, { locale: 'de-DE' });
29
+
30
+ expect(typeof enResult).toBe('string');
31
+ expect(typeof zhResult).toBe('string');
32
+ expect(typeof deResult).toBe('string');
33
+ expect(enResult).not.toBe(zhResult);
34
+ expect(enResult).not.toBe(deResult);
35
+ });
36
+
37
+ it('should format date time with custom styles', () => {
38
+ const fullResult = formatDateTime(testDate, { dateStyle: 'full', timeStyle: 'full' });
39
+ const shortResult = formatDateTime(testDate, { dateStyle: 'short', timeStyle: 'short' });
40
+
41
+ expect(typeof fullResult).toBe('string');
42
+ expect(typeof shortResult).toBe('string');
43
+ expect(fullResult.length).toBeGreaterThan(shortResult.length);
44
+ });
45
+ });
46
+
47
+ describe('formatDate', () => {
48
+ it('should format date with default options', () => {
49
+ const result = formatDate(testDate);
50
+ expect(typeof result).toBe('string');
51
+ expect(result).not.toBe('');
52
+ });
53
+
54
+ it('should format date with different locales', () => {
55
+ const enResult = formatDate(testDate, { locale: 'en-US' });
56
+ const zhResult = formatDate(testDate, { locale: 'zh-CN' });
57
+
58
+ expect(typeof enResult).toBe('string');
59
+ expect(typeof zhResult).toBe('string');
60
+ expect(enResult).not.toBe(zhResult);
61
+ });
62
+ });
63
+
64
+ describe('formatTime', () => {
65
+ it('should format time with default options', () => {
66
+ const result = formatTime(testDate);
67
+ expect(typeof result).toBe('string');
68
+ expect(result).not.toBe('');
69
+ });
70
+
71
+ it('should format time with different locales', () => {
72
+ const enResult = formatTime(testDate, { locale: 'en-US' });
73
+ const zhResult = formatTime(testDate, { locale: 'zh-CN' });
74
+
75
+ expect(typeof enResult).toBe('string');
76
+ expect(typeof zhResult).toBe('string');
77
+ expect(enResult).not.toBe(zhResult);
78
+ });
79
+
80
+ it('should format time with 12-hour format', () => {
81
+ const result = formatTime(testDate, { locale: 'en-US', hour12: true });
82
+ expect(typeof result).toBe('string');
83
+ expect(result).toMatch(/AM|PM/i);
84
+ });
85
+ });
86
+
87
+ describe('formatCurrency', () => {
88
+ it('should format currency with default options', () => {
89
+ const result = formatCurrency(1234.56, { currency: 'CNY' });
90
+ expect(typeof result).toBe('string');
91
+ expect(result).not.toBe('');
92
+ });
93
+
94
+ it('should format currency with different currencies', () => {
95
+ const cnyResult = formatCurrency(1234.56, { currency: 'CNY' });
96
+ const usdResult = formatCurrency(1234.56, { currency: 'USD' });
97
+ const eurResult = formatCurrency(1234.56, { currency: 'EUR' });
98
+
99
+ expect(typeof cnyResult).toBe('string');
100
+ expect(typeof usdResult).toBe('string');
101
+ expect(typeof eurResult).toBe('string');
102
+ expect(cnyResult).not.toBe(usdResult);
103
+ expect(cnyResult).not.toBe(eurResult);
104
+ });
105
+
106
+ it('should format currency with different locales', () => {
107
+ const enResult = formatCurrency(1234.56, { currency: 'USD', locale: 'en-US' });
108
+ const deResult = formatCurrency(1234.56, { currency: 'EUR', locale: 'de-DE' });
109
+
110
+ expect(typeof enResult).toBe('string');
111
+ expect(typeof deResult).toBe('string');
112
+ expect(enResult).not.toBe(deResult);
113
+ });
114
+ });
115
+
116
+ describe('formatPercent', () => {
117
+ it('should format percent with default options', () => {
118
+ const result = formatPercent(0.75);
119
+ expect(typeof result).toBe('string');
120
+ expect(result).not.toBe('');
121
+ });
122
+
123
+ it('should format percent with different locales', () => {
124
+ const enResult = formatPercent(0.75, { locale: 'en-US' });
125
+ const deResult = formatPercent(0.75, { locale: 'de-DE' });
126
+
127
+ expect(typeof enResult).toBe('string');
128
+ expect(typeof deResult).toBe('string');
129
+ expect(enResult).not.toBe(deResult);
130
+ });
131
+
132
+ it('should format percent with custom decimal digits', () => {
133
+ const result = formatPercent(0.75123, { digits: 3 });
134
+ expect(typeof result).toBe('string');
135
+ });
136
+ });
137
+
138
+ describe('formatNumber', () => {
139
+ it('should format number with default options', () => {
140
+ const result = formatNumber(1234.5678);
141
+ expect(typeof result).toBe('string');
142
+ expect(result).not.toBe('');
143
+ });
144
+
145
+ it('should format number with different locales', () => {
146
+ const enResult = formatNumber(1234.5678, { locale: 'en-US' });
147
+ const deResult = formatNumber(1234.5678, { locale: 'de-DE' });
148
+
149
+ expect(typeof enResult).toBe('string');
150
+ expect(typeof deResult).toBe('string');
151
+ expect(enResult).not.toBe(deResult);
152
+ });
153
+
154
+ it('should format number with custom decimal digits', () => {
155
+ const result = formatNumber(1234.5678, { digits: 3 });
156
+ expect(typeof result).toBe('string');
157
+ });
158
+
159
+ it('should format number without grouping', () => {
160
+ const result = formatNumber(1234.5678, { useGrouping: false });
161
+ expect(typeof result).toBe('string');
162
+ });
163
+ });
164
+
165
+ describe('getSupportedLocales', () => {
166
+ it('should return an array of supported locales', () => {
167
+ const locales = getSupportedLocales();
168
+ expect(Array.isArray(locales)).toBe(true);
169
+ expect(locales.length).toBeGreaterThan(0);
170
+ });
171
+ });
172
+
173
+ describe('getSystemLocale', () => {
174
+ it('should return a string', () => {
175
+ const locale = getSystemLocale();
176
+ expect(typeof locale).toBe('string');
177
+ expect(locale).not.toBe('');
178
+ });
179
+ });
180
+
181
+ describe('getSystemTimeZone', () => {
182
+ it('should return a string', () => {
183
+ const timeZone = getSystemTimeZone();
184
+ expect(typeof timeZone).toBe('string');
185
+ expect(timeZone).not.toBe('');
186
+ });
187
+ });
188
+
189
+ describe('Localization class', () => {
190
+ it('should create an instance with default options', () => {
191
+ const localization = new Localization();
192
+ expect(localization).toBeInstanceOf(Localization);
193
+ });
194
+
195
+ it('should create an instance with custom options', () => {
196
+ const localization = new Localization({ locale: 'en-US', timeZone: 'America/New_York' });
197
+ expect(localization).toBeInstanceOf(Localization);
198
+ });
199
+
200
+ it('should get and set locale', () => {
201
+ const localization = new Localization();
202
+ const initialLocale = localization.getLocale();
203
+
204
+ localization.setLocale('fr-FR');
205
+ expect(localization.getLocale()).toBe('fr-FR');
206
+ expect(localization.getLocale()).not.toBe(initialLocale);
207
+ });
208
+
209
+ it('should get and set timeZone', () => {
210
+ const localization = new Localization();
211
+ const initialTimeZone = localization.getTimeZone();
212
+
213
+ localization.setTimeZone('Europe/London');
214
+ expect(localization.getTimeZone()).toBe('Europe/London');
215
+ expect(localization.getTimeZone()).not.toBe(initialTimeZone);
216
+ });
217
+
218
+ it('should format date time using instance methods', () => {
219
+ const localization = new Localization({ locale: 'en-US' });
220
+ const result = localization.formatDateTime(testDate);
221
+ expect(typeof result).toBe('string');
222
+ expect(result).not.toBe('');
223
+ });
224
+
225
+ it('should format currency using instance methods', () => {
226
+ const localization = new Localization({ locale: 'en-US' });
227
+ const result = localization.formatCurrency(1234.56, { currency: 'USD' });
228
+ expect(typeof result).toBe('string');
229
+ expect(result).not.toBe('');
230
+ });
231
+ });
232
+
233
+ describe('defaultLocalization', () => {
234
+ it('should be an instance of Localization', () => {
235
+ expect(defaultLocalization).toBeInstanceOf(Localization);
236
+ });
237
+
238
+ it('should have format methods', () => {
239
+ expect(typeof defaultLocalization.formatDateTime).toBe('function');
240
+ expect(typeof defaultLocalization.formatDate).toBe('function');
241
+ expect(typeof defaultLocalization.formatTime).toBe('function');
242
+ expect(typeof defaultLocalization.formatCurrency).toBe('function');
243
+ expect(typeof defaultLocalization.formatPercent).toBe('function');
244
+ expect(typeof defaultLocalization.formatNumber).toBe('function');
245
+ });
246
+ });
247
+ });