@zat-design/sisyphus-react 3.13.18-beta.8 → 3.13.18

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/babel.config.js CHANGED
@@ -1,3 +1,13 @@
1
1
  module.exports = {
2
- presets: ['@babel/preset-env', ['@babel/preset-react', { runtime: 'automatic' }]],
2
+ presets: [
3
+ ['@babel/preset-env', { loose: true }],
4
+ ['@babel/preset-react', { runtime: 'automatic' }],
5
+ '@babel/preset-typescript'
6
+ ],
7
+ plugins: [
8
+ ['@babel/plugin-proposal-decorators', { legacy: true }],
9
+ ['@babel/plugin-proposal-class-properties', { loose: true }],
10
+ ['@babel/plugin-transform-private-methods', { loose: true }],
11
+ ['@babel/plugin-transform-private-property-in-object', { loose: true }],
12
+ ]
3
13
  };
@@ -1,10 +1,9 @@
1
1
  import "antd/es/date-picker/style";
2
2
  import _DatePicker from "antd/es/date-picker";
3
3
  import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
4
- import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
5
4
  import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
6
5
  import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
7
- import _uniq from "lodash/uniq";
6
+ import _omit from "lodash/omit";
8
7
  import _isObject from "lodash/isObject";
9
8
  import _isString from "lodash/isString";
10
9
  import _isFunction from "lodash/isFunction";
@@ -25,18 +24,11 @@ var DatePicker = function DatePicker(props) {
25
24
  viewEmpty = _ref.viewEmpty,
26
25
  valueType = _ref.valueType;
27
26
  var isView = typeof props.isView === 'boolean' ? props.isView : isViewCon; // 组件可直接接收isView参数, 优先级高
28
- var initialConfig = useProConfig('DatePicker');
29
- var _className = classNames(_defineProperty({
27
+ var initialConfig = useProConfig('DatePicker') || {};
28
+ var nextFormat = format;
29
+ var nextClassName = classNames(_defineProperty({
30
30
  'full-form-item': true
31
31
  }, className, !!className));
32
- var _viewFormat = Array.isArray(format) ? format[0] : format;
33
- var tempFormat = Array.isArray(format) ? format : [format];
34
- if (_isFunction(format)) {
35
- tempFormat = [];
36
- }
37
- var _format = _uniq([].concat(_toConsumableArray(tempFormat), ['YYYY-MM-DD', 'YYYYMMDD', 'YYYY/MM/DD', 'YYYY_MM_DD', 'YYYY.MM.DD'])).filter(function (formatKey) {
38
- return !!formatKey;
39
- });
40
32
  if (isView) {
41
33
  var value = rest.value;
42
34
  var viewChildren = null;
@@ -47,38 +39,30 @@ var DatePicker = function DatePicker(props) {
47
39
  } else if (_isFunction(format)) {
48
40
  viewChildren = format(value);
49
41
  } else if (_isString(value)) {
50
- viewChildren = moment(value).format(_viewFormat);
42
+ viewChildren = moment(value).format(format);
51
43
  }
52
44
  return _jsx(Container, {
53
45
  viewEmpty: viewEmpty,
54
46
  children: viewChildren
55
47
  });
56
48
  }
57
- var _defaultShowTime = {
58
- format: 'HH:mm:ss'
59
- };
60
49
  // dateTime模式下默认开启time选择
61
- var _rest = _objectSpread({}, rest);
50
+ var restProps = _objectSpread({}, rest);
62
51
  // showTime默认值受valueType属性影响
63
- if (rest.showTime === undefined) {
64
- if (valueType === 'dateTime') {
65
- _rest.showTime = true;
66
- }
52
+ if (restProps.showTime === false) {
53
+ restProps.showTime = false;
54
+ } else if (valueType === 'dateTime') {
55
+ restProps.showTime = true;
56
+ nextFormat = 'YYYY-MM-DD HH:mm:ss';
67
57
  }
68
58
  // 字符串时间格式兼容
69
- if (_isString(_rest.value)) {
70
- _rest.value = moment(_rest.value);
71
- }
72
- if (_rest.showTime === true) {
73
- _rest.showTime = _objectSpread({}, _defaultShowTime);
74
- }
75
- if (_isObject(_rest.showTime)) {
76
- _rest.showTime = Object.assign(_defaultShowTime, _rest.showTime);
59
+ if (_isString(restProps.value)) {
60
+ restProps.value = moment(restProps.value);
77
61
  }
78
62
  return _jsx(_DatePicker, _objectSpread(_objectSpread(_objectSpread({}, initialConfig), {}, {
79
- format: _format
80
- }, _rest), {}, {
81
- className: _className
63
+ format: nextFormat
64
+ }, _omit(restProps, ['otherProps'])), {}, {
65
+ className: nextClassName
82
66
  }));
83
67
  };
84
68
  export default DatePicker;
@@ -165,14 +165,9 @@ export var useTransformColumns = function useTransformColumns(params) {
165
165
  getValueProps: transform === null || transform === void 0 ? void 0 : transform.getValueProps,
166
166
  fieldProps: _objectSpread(_objectSpread(_objectSpread({}, column === null || column === void 0 ? void 0 : column.fieldProps), reactiveProps === null || reactiveProps === void 0 ? void 0 : reactiveProps.fieldProps), {}, {
167
167
  onChange: handleChange,
168
- onBlur: handleBlur
169
- }, names ? {
170
- value: form.getFieldValue(columnName)
171
- } // 独立字段模式
172
- : {
168
+ onBlur: handleBlur,
173
169
  value: value === null || value === void 0 ? void 0 : value[index]
174
- } // 数组值模式
175
- )
170
+ })
176
171
  });
177
172
  });
178
173
  };
package/jest.config.js CHANGED
@@ -1,8 +1,50 @@
1
- const React = require('react');
2
-
3
1
  module.exports = {
4
2
  setupFiles: ['jest-canvas-mock'],
5
- globals: {
6
- React,
3
+ setupFilesAfterEnv: ['<rootDir>/tests/setup.ts'],
4
+ testEnvironment: 'jsdom',
5
+ testEnvironmentOptions: {
6
+ url: 'http://localhost',
7
7
  },
8
+ moduleNameMapper: {
9
+ '^@/(.*)$': '<rootDir>/src/$1',
10
+ '^@zat-design/sisyphus-react$': '<rootDir>/src/index.ts',
11
+ '\\.(css|less|scss)$': 'identity-obj-proxy',
12
+ '\\.(png|jpg|jpeg|gif|svg)$': '<rootDir>/tests/__mocks__/fileMock.js',
13
+ '@zat-design/utils': '<rootDir>/tests/__mocks__/zatUtils.js',
14
+ },
15
+ collectCoverageFrom: [
16
+ 'src/**/*.{ts,tsx}',
17
+ '!src/**/*.d.ts',
18
+ '!src/**/demos/**',
19
+ '!src/**/test/**',
20
+ '!src/old/**',
21
+ '!src/style/**',
22
+ '!src/**/symbolIcon.js',
23
+ '!src/index.ts',
24
+ '!src/tokens.ts',
25
+ '!src/utils/**',
26
+ '!src/locale/**',
27
+ ],
28
+ testMatch: [
29
+ '<rootDir>/src/**/__tests__/**/*.{ts,tsx}',
30
+ '<rootDir>/src/**/*.(test|spec).{ts,tsx}',
31
+ ],
32
+ testTimeout: 15000,
33
+ transform: {
34
+ '^.+\\.(ts|tsx)$': 'babel-jest',
35
+ '^.+\\.(js|jsx)$': 'babel-jest',
36
+ },
37
+ moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'],
38
+ transformIgnorePatterns: [
39
+ 'node_modules/(?!(antd|@ant-design|@pansy|rc-.+|@babel/runtime|@zat-design)/)',
40
+ ],
41
+ coverageThreshold: {
42
+ global: {
43
+ branches: 80,
44
+ functions: 80,
45
+ lines: 80,
46
+ statements: 80,
47
+ },
48
+ },
49
+ coverageReporters: ['text', 'lcov', 'html'],
8
50
  };
@@ -8,10 +8,9 @@ exports.default = void 0;
8
8
  require("antd/es/date-picker/style");
9
9
  var _datePicker = _interopRequireDefault(require("antd/es/date-picker"));
10
10
  var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
11
- var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
12
11
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
13
12
  var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
14
- var _uniq2 = _interopRequireDefault(require("lodash/uniq"));
13
+ var _omit2 = _interopRequireDefault(require("lodash/omit"));
15
14
  var _isObject2 = _interopRequireDefault(require("lodash/isObject"));
16
15
  var _isString2 = _interopRequireDefault(require("lodash/isString"));
17
16
  var _isFunction2 = _interopRequireDefault(require("lodash/isFunction"));
@@ -32,18 +31,11 @@ var DatePicker = function DatePicker(props) {
32
31
  viewEmpty = _ref.viewEmpty,
33
32
  valueType = _ref.valueType;
34
33
  var isView = typeof props.isView === 'boolean' ? props.isView : isViewCon; // 组件可直接接收isView参数, 优先级高
35
- var initialConfig = (0, _ProConfigProvider.useProConfig)('DatePicker');
36
- var _className = (0, _classnames.default)((0, _defineProperty2.default)({
34
+ var initialConfig = (0, _ProConfigProvider.useProConfig)('DatePicker') || {};
35
+ var nextFormat = format;
36
+ var nextClassName = (0, _classnames.default)((0, _defineProperty2.default)({
37
37
  'full-form-item': true
38
38
  }, className, !!className));
39
- var _viewFormat = Array.isArray(format) ? format[0] : format;
40
- var tempFormat = Array.isArray(format) ? format : [format];
41
- if ((0, _isFunction2.default)(format)) {
42
- tempFormat = [];
43
- }
44
- var _format = (0, _uniq2.default)([].concat((0, _toConsumableArray2.default)(tempFormat), ['YYYY-MM-DD', 'YYYYMMDD', 'YYYY/MM/DD', 'YYYY_MM_DD', 'YYYY.MM.DD'])).filter(function (formatKey) {
45
- return !!formatKey;
46
- });
47
39
  if (isView) {
48
40
  var value = rest.value;
49
41
  var viewChildren = null;
@@ -54,38 +46,30 @@ var DatePicker = function DatePicker(props) {
54
46
  } else if ((0, _isFunction2.default)(format)) {
55
47
  viewChildren = format(value);
56
48
  } else if ((0, _isString2.default)(value)) {
57
- viewChildren = (0, _moment.default)(value).format(_viewFormat);
49
+ viewChildren = (0, _moment.default)(value).format(format);
58
50
  }
59
51
  return (0, _jsxRuntime.jsx)(_Container.default, {
60
52
  viewEmpty: viewEmpty,
61
53
  children: viewChildren
62
54
  });
63
55
  }
64
- var _defaultShowTime = {
65
- format: 'HH:mm:ss'
66
- };
67
56
  // dateTime模式下默认开启time选择
68
- var _rest = (0, _objectSpread2.default)({}, rest);
57
+ var restProps = (0, _objectSpread2.default)({}, rest);
69
58
  // showTime默认值受valueType属性影响
70
- if (rest.showTime === undefined) {
71
- if (valueType === 'dateTime') {
72
- _rest.showTime = true;
73
- }
59
+ if (restProps.showTime === false) {
60
+ restProps.showTime = false;
61
+ } else if (valueType === 'dateTime') {
62
+ restProps.showTime = true;
63
+ nextFormat = 'YYYY-MM-DD HH:mm:ss';
74
64
  }
75
65
  // 字符串时间格式兼容
76
- if ((0, _isString2.default)(_rest.value)) {
77
- _rest.value = (0, _moment.default)(_rest.value);
78
- }
79
- if (_rest.showTime === true) {
80
- _rest.showTime = (0, _objectSpread2.default)({}, _defaultShowTime);
81
- }
82
- if ((0, _isObject2.default)(_rest.showTime)) {
83
- _rest.showTime = Object.assign(_defaultShowTime, _rest.showTime);
66
+ if ((0, _isString2.default)(restProps.value)) {
67
+ restProps.value = (0, _moment.default)(restProps.value);
84
68
  }
85
69
  return (0, _jsxRuntime.jsx)(_datePicker.default, (0, _objectSpread2.default)((0, _objectSpread2.default)((0, _objectSpread2.default)({}, initialConfig), {}, {
86
- format: _format
87
- }, _rest), {}, {
88
- className: _className
70
+ format: nextFormat
71
+ }, (0, _omit2.default)(restProps, ['otherProps'])), {}, {
72
+ className: nextClassName
89
73
  }));
90
74
  };
91
75
  var _default = exports.default = DatePicker;
@@ -173,14 +173,9 @@ var useTransformColumns = exports.useTransformColumns = function useTransformCol
173
173
  getValueProps: transform === null || transform === void 0 ? void 0 : transform.getValueProps,
174
174
  fieldProps: (0, _objectSpread2.default)((0, _objectSpread2.default)((0, _objectSpread2.default)({}, column === null || column === void 0 ? void 0 : column.fieldProps), reactiveProps === null || reactiveProps === void 0 ? void 0 : reactiveProps.fieldProps), {}, {
175
175
  onChange: handleChange,
176
- onBlur: handleBlur
177
- }, names ? {
178
- value: form.getFieldValue(columnName)
179
- } // 独立字段模式
180
- : {
176
+ onBlur: handleBlur,
181
177
  value: value === null || value === void 0 ? void 0 : value[index]
182
- } // 数组值模式
183
- )
178
+ })
184
179
  });
185
180
  });
186
181
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zat-design/sisyphus-react",
3
- "version": "3.13.18-beta.8",
3
+ "version": "3.13.18",
4
4
  "license": "MIT",
5
5
  "main": "lib/index.js",
6
6
  "module": "es/index.js",
@@ -17,7 +17,7 @@
17
17
  "docs:deploy": "gh-pages -d docs-dist",
18
18
  "lint": "npm run lint:js && npm run lint:style && npm run lint:prettier",
19
19
  "lint-staged": "lint-staged",
20
- "lint-staged:js": "eslint --ext .js,.jsx,.ts,.tsx",
20
+ "lint-staged:js": "eslint --ext .js,.jsx,.ts,.tsx --ignore-pattern '**/__tests__/**' --ignore-pattern '**/*.test.*' --ignore-pattern '**/*.spec.*'",
21
21
  "lint:fix": "eslint --fix --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src",
22
22
  "lint:js": "eslint --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src",
23
23
  "lint:prettier": "prettier --check \"**/*\" --end-of-line auto",
@@ -0,0 +1 @@
1
+ module.exports = 'test-file-stub';
@@ -0,0 +1,27 @@
1
+ // Mock @zat-design/utils
2
+ module.exports = {
3
+ tools: {
4
+ isValidUrl: jest.fn(() => true),
5
+ formatCurrency: jest.fn((value) => `¥${value}`),
6
+ formatDate: jest.fn((date) => new Date(date).toLocaleDateString()),
7
+ },
8
+ transforms: {
9
+ transformDate: jest.fn((value, params) => {
10
+ if (!value) return '';
11
+ return new Date(value).toLocaleDateString();
12
+ }),
13
+ transformSwitch: jest.fn((value) => value ? '是' : '否'),
14
+ transformMoney: jest.fn((value) => `¥${value || 0}`),
15
+ transformPercent: jest.fn((value) => `${(value || 0) * 100}%`),
16
+ },
17
+ validate: {
18
+ isEmail: jest.fn((email) => /\S+@\S+\.\S+/.test(email)),
19
+ isPhone: jest.fn((phone) => /^1[3-9]\d{9}$/.test(phone)),
20
+ isIdCard: jest.fn(() => true),
21
+ },
22
+ validateNameMap: {
23
+ email: 'isEmail',
24
+ phone: 'isPhone',
25
+ idCard: 'isIdCard',
26
+ },
27
+ };
package/tests/setup.ts ADDED
@@ -0,0 +1,477 @@
1
+ import '@testing-library/jest-dom';
2
+ import 'jest-canvas-mock';
3
+ import React from 'react';
4
+
5
+ // Ensure JSDOM document.body exists and setup proper DOM environment
6
+ if (typeof document !== 'undefined') {
7
+ // Ensure documentElement exists
8
+ if (!document.documentElement) {
9
+ const html = document.createElement('html');
10
+ document.appendChild(html);
11
+ }
12
+
13
+ // Ensure head exists
14
+ if (!document.head) {
15
+ const head = document.createElement('head');
16
+ document.documentElement.appendChild(head);
17
+ }
18
+
19
+ // Ensure body exists
20
+ if (!document.body) {
21
+ const body = document.createElement('body');
22
+ document.documentElement.appendChild(body);
23
+ }
24
+ }
25
+
26
+ // Mock testing library environment setup
27
+ Object.defineProperty(global, 'MutationObserver', {
28
+ writable: true,
29
+ value: jest.fn().mockImplementation(() => ({
30
+ observe: jest.fn(),
31
+ disconnect: jest.fn(),
32
+ takeRecords: jest.fn(),
33
+ })),
34
+ });
35
+
36
+ // Setup test container div
37
+ beforeEach(() => {
38
+ if (typeof document !== 'undefined' && document.body) {
39
+ try {
40
+ // Clean up any existing test containers
41
+ const existingContainers = document.querySelectorAll('[data-testid="test-container"]');
42
+ existingContainers.forEach(container => {
43
+ if (container.parentNode) {
44
+ try {
45
+ container.parentNode.removeChild(container);
46
+ } catch (e) {
47
+ // Ignore cleanup errors
48
+ }
49
+ }
50
+ });
51
+
52
+ // Create a fresh test container
53
+ const testContainer = document.createElement('div');
54
+ testContainer.setAttribute('data-testid', 'test-container');
55
+ testContainer.id = 'test-container';
56
+ document.body.appendChild(testContainer);
57
+ } catch (e) {
58
+ // Ignore setup errors - React Testing Library will handle this
59
+ }
60
+ }
61
+ });
62
+
63
+ // 抑制控制台错误
64
+ const originalError = console.error;
65
+ beforeAll(() => {
66
+ console.error = (...args: any[]) => {
67
+ if (
68
+ args.find(
69
+ arg =>
70
+ typeof arg === 'string' &&
71
+ (
72
+ arg.includes('Warning: ReactDOM.render is deprecated') ||
73
+ arg.includes('Warning: componentWillReceiveProps') ||
74
+ arg.includes('validateDOMNesting') ||
75
+ arg.includes('Warning: componentWillMount') ||
76
+ arg.includes('Warning: React.createFactory() is deprecated') ||
77
+ arg.includes('Warning: findDOMNode is deprecated') ||
78
+ arg.includes('act(...)') ||
79
+ arg.includes('useLayoutEffect does nothing on the server') ||
80
+ arg.includes('Invalid hook call') ||
81
+ arg.includes('Hooks can only be called inside') ||
82
+ arg.includes('Warning: Each child in a list should have a unique') ||
83
+ arg.includes('Warning: validateDOMNesting')
84
+ )
85
+ )
86
+ ) {
87
+ return;
88
+ }
89
+ originalError.call(console, ...args);
90
+ };
91
+ });
92
+
93
+ afterAll(() => {
94
+ console.error = originalError;
95
+ });
96
+
97
+ // Mock window APIs
98
+ Object.defineProperty(window, 'matchMedia', {
99
+ writable: true,
100
+ value: jest.fn().mockImplementation(query => ({
101
+ matches: false,
102
+ media: query,
103
+ onchange: null,
104
+ addListener: jest.fn(),
105
+ removeListener: jest.fn(),
106
+ addEventListener: jest.fn(),
107
+ removeEventListener: jest.fn(),
108
+ dispatchEvent: jest.fn(),
109
+ })),
110
+ });
111
+
112
+ // Mock ahooks hooks - 基于ahooks官方测试实践改进
113
+ jest.mock('ahooks', () => ({
114
+ useSetState: jest.fn((initialState) => {
115
+ const mockState = { current: initialState || {} };
116
+ const mockSetState = jest.fn((patch) => {
117
+ if (typeof patch === 'function') {
118
+ mockState.current = patch(mockState.current);
119
+ } else {
120
+ mockState.current = { ...mockState.current, ...patch };
121
+ }
122
+ return mockState.current;
123
+ });
124
+ return [mockState.current, mockSetState];
125
+ }),
126
+
127
+ useRequest: jest.fn((service, options = {}) => {
128
+ const mockState = {
129
+ loading: false,
130
+ data: null,
131
+ error: null,
132
+ params: [],
133
+ };
134
+
135
+ const mockActions = {
136
+ run: jest.fn((...params) => {
137
+ mockState.loading = true;
138
+ mockState.params = params;
139
+ // 模拟异步操作
140
+ setTimeout(() => {
141
+ mockState.loading = false;
142
+ mockState.data = 'mock-data';
143
+ }, 100);
144
+ return Promise.resolve('mock-data');
145
+ }),
146
+ refresh: jest.fn(() => {
147
+ mockState.loading = true;
148
+ setTimeout(() => {
149
+ mockState.loading = false;
150
+ }, 100);
151
+ return Promise.resolve('mock-data');
152
+ }),
153
+ cancel: jest.fn(() => {
154
+ mockState.loading = false;
155
+ }),
156
+ mutate: jest.fn((data) => {
157
+ mockState.data = data;
158
+ }),
159
+ };
160
+
161
+ const result = {
162
+ ...mockState,
163
+ ...mockActions,
164
+ };
165
+
166
+ // 如果提供了service函数,模拟调用
167
+ if (service && typeof service === 'function') {
168
+ result.run = jest.fn((...params) => {
169
+ mockState.loading = true;
170
+ mockState.params = params;
171
+
172
+ return new Promise((resolve, reject) => {
173
+ setTimeout(() => {
174
+ try {
175
+ const serviceResult = service(...params);
176
+ if (serviceResult instanceof Promise) {
177
+ serviceResult.then(resolve).catch(reject);
178
+ } else {
179
+ resolve(serviceResult);
180
+ }
181
+ } catch (error) {
182
+ reject(error);
183
+ } finally {
184
+ mockState.loading = false;
185
+ }
186
+ }, 100);
187
+ });
188
+ });
189
+ }
190
+
191
+ // 处理options
192
+ if (options.manual !== true) {
193
+ // 自动执行
194
+ setTimeout(() => {
195
+ result.run();
196
+ }, 0);
197
+ }
198
+
199
+ return result;
200
+ }),
201
+
202
+ useDebounce: jest.fn((value, delay) => value),
203
+
204
+ useThrottle: jest.fn((value, delay) => value),
205
+
206
+ useLocalStorageState: jest.fn((key, defaultValue) => {
207
+ const [state, setState] = [defaultValue, jest.fn()];
208
+ return [state, setState];
209
+ }),
210
+
211
+ useSessionStorageState: jest.fn((key, defaultValue) => {
212
+ const [state, setState] = [defaultValue, jest.fn()];
213
+ return [state, setState];
214
+ }),
215
+
216
+ useDeepCompareEffect: jest.fn((effect, deps) => {
217
+ if (effect && typeof effect === 'function') {
218
+ effect();
219
+ }
220
+ }),
221
+
222
+ useUpdateEffect: jest.fn((effect, deps) => {
223
+ if (effect && typeof effect === 'function') {
224
+ effect();
225
+ }
226
+ }),
227
+
228
+ useSize: jest.fn(() => ({ width: 100, height: 100 })),
229
+
230
+ useInViewport: jest.fn(() => [true, jest.fn()]),
231
+
232
+ useMemoizedFn: jest.fn((fn) => fn),
233
+
234
+ useMount: jest.fn((fn) => {
235
+ if (fn && typeof fn === 'function') {
236
+ fn();
237
+ }
238
+ }),
239
+
240
+ useUnmount: jest.fn((fn) => {
241
+ if (fn && typeof fn === 'function') {
242
+ fn();
243
+ }
244
+ }),
245
+
246
+ useDebounceEffect: jest.fn((effect, deps, wait) => {
247
+ if (effect && typeof effect === 'function') {
248
+ effect();
249
+ }
250
+ }),
251
+
252
+ useThrottleEffect: jest.fn((effect, deps, wait) => {
253
+ if (effect && typeof effect === 'function') {
254
+ effect();
255
+ }
256
+ }),
257
+ }));
258
+
259
+ Object.defineProperty(window, 'ResizeObserver', {
260
+ writable: true,
261
+ value: jest.fn().mockImplementation(() => ({
262
+ observe: jest.fn(),
263
+ unobserve: jest.fn(),
264
+ disconnect: jest.fn(),
265
+ })),
266
+ });
267
+
268
+ Object.defineProperty(window, 'IntersectionObserver', {
269
+ writable: true,
270
+ value: jest.fn().mockImplementation(() => ({
271
+ observe: jest.fn(),
272
+ unobserve: jest.fn(),
273
+ disconnect: jest.fn(),
274
+ })),
275
+ });
276
+
277
+ // Mock getBoundingClientRect
278
+ Element.prototype.getBoundingClientRect = jest.fn(() => ({
279
+ width: 120,
280
+ height: 120,
281
+ top: 0,
282
+ left: 0,
283
+ bottom: 0,
284
+ right: 0,
285
+ x: 0,
286
+ y: 0,
287
+ toJSON: jest.fn(),
288
+ }));
289
+
290
+ // Mock scrollIntoView
291
+ Element.prototype.scrollIntoView = jest.fn();
292
+
293
+ // Mock getComputedStyle
294
+ window.getComputedStyle = jest.fn(() => ({
295
+ getPropertyValue: jest.fn(() => ''),
296
+ setProperty: jest.fn(),
297
+ removeProperty: jest.fn(),
298
+ } as any));
299
+
300
+ // Mock URL methods
301
+ global.URL.createObjectURL = jest.fn(() => 'mock-url');
302
+ global.URL.revokeObjectURL = jest.fn();
303
+
304
+ // Mock fetch
305
+ global.fetch = jest.fn(() =>
306
+ Promise.resolve({
307
+ ok: true,
308
+ json: () => Promise.resolve({}),
309
+ blob: () => Promise.resolve(new Blob()),
310
+ text: () => Promise.resolve(''),
311
+ } as Response)
312
+ );
313
+
314
+ // Mock String methods to prevent format.match and format.replace errors
315
+ String.prototype.match = String.prototype.match || jest.fn(() => []);
316
+ String.prototype.replace = String.prototype.replace || jest.fn((pattern, replacement) => {
317
+ if (typeof pattern === 'string') {
318
+ return this.split(pattern).join(replacement);
319
+ }
320
+ return this;
321
+ });
322
+
323
+ // Mock FileReader
324
+ class MockFileReader {
325
+ result: any = null;
326
+ error: any = null;
327
+ readyState: number = 0;
328
+ onload: ((this: FileReader, ev: ProgressEvent<FileReader>) => any) | null = null;
329
+ onerror: ((this: FileReader, ev: ProgressEvent<FileReader>) => any) | null = null;
330
+ onloadend: ((this: FileReader, ev: ProgressEvent<FileReader>) => any) | null = null;
331
+
332
+ readAsDataURL = jest.fn(() => {
333
+ this.readyState = 2;
334
+ this.result = 'data:image/png;base64,test';
335
+ setTimeout(() => {
336
+ if (this.onload) this.onload({} as ProgressEvent<FileReader>);
337
+ if (this.onloadend) this.onloadend({} as ProgressEvent<FileReader>);
338
+ }, 0);
339
+ });
340
+
341
+ readAsText = jest.fn(() => {
342
+ this.readyState = 2;
343
+ this.result = 'test content';
344
+ setTimeout(() => {
345
+ if (this.onload) this.onload({} as ProgressEvent<FileReader>);
346
+ if (this.onloadend) this.onloadend({} as ProgressEvent<FileReader>);
347
+ }, 0);
348
+ });
349
+
350
+ abort = jest.fn();
351
+ addEventListener = jest.fn();
352
+ removeEventListener = jest.fn();
353
+ dispatchEvent = jest.fn();
354
+ }
355
+
356
+ global.FileReader = MockFileReader as any;
357
+
358
+ // Mock Blob
359
+ global.Blob = jest.fn().mockImplementation(() => ({
360
+ size: 1024,
361
+ type: 'image/png',
362
+ slice: jest.fn(),
363
+ stream: jest.fn(),
364
+ text: jest.fn(() => Promise.resolve('mock text')),
365
+ arrayBuffer: jest.fn(() => Promise.resolve(new ArrayBuffer(8))),
366
+ }));
367
+
368
+ // Store original createElement
369
+ const originalCreateElement = document.createElement;
370
+
371
+ // Simple mock for specific elements only when needed
372
+ document.createElement = jest.fn((tagName: string) => {
373
+ try {
374
+ return originalCreateElement.call(document, tagName);
375
+ } catch (e) {
376
+ // Fallback for special cases
377
+ const mockElement = {
378
+ tagName: tagName.toUpperCase(),
379
+ style: {},
380
+ className: '',
381
+ textContent: '',
382
+ innerHTML: '',
383
+ addEventListener: jest.fn(),
384
+ removeEventListener: jest.fn(),
385
+ dispatchEvent: jest.fn(),
386
+ setAttribute: jest.fn(),
387
+ getAttribute: jest.fn(),
388
+ removeAttribute: jest.fn(),
389
+ appendChild: jest.fn(),
390
+ removeChild: jest.fn(),
391
+ insertBefore: jest.fn(),
392
+ querySelector: jest.fn(),
393
+ querySelectorAll: jest.fn(() => []),
394
+ parentNode: null,
395
+ childNodes: [],
396
+ children: [],
397
+ };
398
+
399
+ // Add specific properties for different elements
400
+ if (tagName === 'canvas') {
401
+ Object.assign(mockElement, {
402
+ getContext: jest.fn(() => ({
403
+ drawImage: jest.fn(),
404
+ getImageData: jest.fn(),
405
+ putImageData: jest.fn(),
406
+ toDataURL: jest.fn(() => 'data:image/png;base64,test'),
407
+ })),
408
+ toDataURL: jest.fn(() => 'data:image/png;base64,test'),
409
+ width: 100,
410
+ height: 100,
411
+ });
412
+ } else if (tagName === 'a') {
413
+ Object.assign(mockElement, {
414
+ click: jest.fn(),
415
+ download: '',
416
+ href: '',
417
+ });
418
+ }
419
+
420
+ return mockElement as any;
421
+ }
422
+ });
423
+
424
+ // Store original methods
425
+ const originalAppendChild = document.body.appendChild;
426
+ const originalRemoveChild = document.body.removeChild;
427
+
428
+ // Mock but still allow actual functionality for testing
429
+ document.body.appendChild = jest.fn((node) => {
430
+ try {
431
+ // Check if node is a valid DOM element
432
+ if (node && typeof node === 'object' && node.nodeType !== undefined) {
433
+ return originalAppendChild.call(document.body, node);
434
+ }
435
+ // For non-DOM elements, just return the node
436
+ return node;
437
+ } catch (e) {
438
+ // If original fails, just return the node
439
+ return node;
440
+ }
441
+ });
442
+
443
+ document.body.removeChild = jest.fn((node) => {
444
+ try {
445
+ // Check if node is a valid DOM element
446
+ if (node && typeof node === 'object' && node.nodeType !== undefined) {
447
+ return originalRemoveChild.call(document.body, node);
448
+ }
449
+ // For non-DOM elements, just return the node
450
+ return node;
451
+ } catch (e) {
452
+ // If original fails, just return the node
453
+ return node;
454
+ }
455
+ });
456
+
457
+ // Mock getElementsByTagName to prevent ProIcon DOM access issues
458
+ const originalGetElementsByTagName = document.getElementsByTagName;
459
+ document.getElementsByTagName = jest.fn((tagName: string) => {
460
+ if (tagName === 'script') {
461
+ // Return empty collection for script tags to prevent ProIcon issues
462
+ return [];
463
+ }
464
+ try {
465
+ return originalGetElementsByTagName.call(document, tagName);
466
+ } catch (e) {
467
+ // Fallback for testing
468
+ return [];
469
+ }
470
+ });
471
+
472
+ // Mock ProIcon to prevent DOM manipulation
473
+ jest.mock('../src/ProIcon', () => ({
474
+ __esModule: true,
475
+ default: jest.fn(() => null),
476
+ ProIcon: jest.fn(() => null),
477
+ }));
@@ -0,0 +1,81 @@
1
+ import React from 'react';
2
+ import { render, RenderOptions } from '@testing-library/react';
3
+ import { ConfigProvider } from 'antd';
4
+ import zhCN from 'antd/locale/zh_CN';
5
+
6
+ // 确保document.body存在
7
+ const ensureDocumentSetup = () => {
8
+ if (typeof document !== 'undefined') {
9
+ if (!document.body) {
10
+ document.body = document.createElement('body');
11
+ document.documentElement.appendChild(document.body);
12
+ }
13
+
14
+ // 创建一个测试容器
15
+ let testContainer = document.getElementById('test-container');
16
+ if (!testContainer) {
17
+ testContainer = document.createElement('div');
18
+ testContainer.id = 'test-container';
19
+ document.body.appendChild(testContainer);
20
+ }
21
+ }
22
+ };
23
+
24
+ // Mock ProConfigProvider
25
+ const MockProConfigProvider = ({ children }: { children: React.ReactNode }) => {
26
+ const mockValue = {
27
+ state: {
28
+ ProTable: {},
29
+ ProForm: {},
30
+ ProEnum: {},
31
+ ProSelect: {},
32
+ storage: {},
33
+ theme: {},
34
+ locale: {},
35
+ },
36
+ setState: jest.fn(),
37
+ };
38
+
39
+ const MockContext = React.createContext(mockValue);
40
+ return React.createElement(MockContext.Provider, { value: mockValue }, children);
41
+ };
42
+
43
+ // Mock FieldProvider
44
+ const MockFieldProvider = ({ children }: { children: React.ReactNode }) => {
45
+ const mockValue = {
46
+ readonly: false,
47
+ disabled: false,
48
+ };
49
+
50
+ const MockFieldContext = React.createContext(mockValue);
51
+ return React.createElement(MockFieldContext.Provider, { value: mockValue }, children);
52
+ };
53
+
54
+ // All providers wrapper
55
+ const AllTheProviders = ({ children }: { children: React.ReactNode }) => {
56
+ ensureDocumentSetup();
57
+
58
+ return (
59
+ <ConfigProvider locale={zhCN}>
60
+ <MockProConfigProvider>
61
+ <MockFieldProvider>
62
+ {children}
63
+ </MockFieldProvider>
64
+ </MockProConfigProvider>
65
+ </ConfigProvider>
66
+ );
67
+ };
68
+
69
+ const customRender = (ui: React.ReactElement, options?: Omit<RenderOptions, 'wrapper'>) => {
70
+ ensureDocumentSetup();
71
+
72
+ return render(ui, {
73
+ wrapper: AllTheProviders,
74
+ container: document.getElementById('test-container') || document.body,
75
+ ...options
76
+ });
77
+ };
78
+
79
+ export * from '@testing-library/react';
80
+ export { customRender as render };
81
+ export { AllTheProviders, ensureDocumentSetup };
@@ -1,9 +0,0 @@
1
- import { DurationInputArg1, DurationInputArg2, Moment } from 'moment';
2
- interface Props {
3
- range?: [Moment?, Moment?];
4
- limit?: [DurationInputArg1, DurationInputArg2];
5
- }
6
- export declare const useDateLimit: (props: Props) => {
7
- onCalendarChange: (val: any) => void;
8
- };
9
- export {};
@@ -1,15 +0,0 @@
1
- import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
2
- import { useState } from 'react';
3
- export var useDateLimit = function useDateLimit(props) {
4
- var range = props.range,
5
- limit = props.limit;
6
- var _useState = useState(),
7
- _useState2 = _slicedToArray(_useState, 2),
8
- dates = _useState2[0],
9
- setDates = _useState2[1];
10
- return {
11
- onCalendarChange: function onCalendarChange(val) {
12
- return setDates(val);
13
- }
14
- };
15
- };
@@ -1,9 +0,0 @@
1
- import { DurationInputArg1, DurationInputArg2, Moment } from 'moment';
2
- interface Props {
3
- range?: [Moment?, Moment?];
4
- limit?: [DurationInputArg1, DurationInputArg2];
5
- }
6
- export declare const useDateLimit: (props: Props) => {
7
- onCalendarChange: (val: any) => void;
8
- };
9
- export {};
@@ -1,22 +0,0 @@
1
- "use strict";
2
-
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
- Object.defineProperty(exports, "__esModule", {
5
- value: true
6
- });
7
- exports.useDateLimit = void 0;
8
- var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
9
- var _react = require("react");
10
- var useDateLimit = exports.useDateLimit = function useDateLimit(props) {
11
- var range = props.range,
12
- limit = props.limit;
13
- var _useState = (0, _react.useState)(),
14
- _useState2 = (0, _slicedToArray2.default)(_useState, 2),
15
- dates = _useState2[0],
16
- setDates = _useState2[1];
17
- return {
18
- onCalendarChange: function onCalendarChange(val) {
19
- return setDates(val);
20
- }
21
- };
22
- };