befly 3.10.1 → 3.10.2

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 (66) hide show
  1. package/.gitignore +0 -0
  2. package/configs/presetFields.ts +10 -0
  3. package/configs/presetRegexp.ts +225 -0
  4. package/package.json +15 -16
  5. package/tests/_mocks/mockSqliteDb.ts +0 -204
  6. package/tests/addonHelper-cache.test.ts +0 -32
  7. package/tests/api-integration-array-number.test.ts +0 -282
  8. package/tests/apiHandler-routePath-only.test.ts +0 -32
  9. package/tests/befly-config-env.test.ts +0 -78
  10. package/tests/cacheHelper.test.ts +0 -323
  11. package/tests/cacheKeys.test.ts +0 -41
  12. package/tests/checkApi-routePath-strict.test.ts +0 -166
  13. package/tests/checkMenu.test.ts +0 -346
  14. package/tests/checkTable-smoke.test.ts +0 -157
  15. package/tests/cipher.test.ts +0 -249
  16. package/tests/dbDialect-cache.test.ts +0 -23
  17. package/tests/dbDialect.test.ts +0 -46
  18. package/tests/dbHelper-advanced.test.ts +0 -723
  19. package/tests/dbHelper-all-array-types.test.ts +0 -316
  20. package/tests/dbHelper-array-serialization.test.ts +0 -258
  21. package/tests/dbHelper-batch-write.test.ts +0 -90
  22. package/tests/dbHelper-columns.test.ts +0 -234
  23. package/tests/dbHelper-execute.test.ts +0 -187
  24. package/tests/dbHelper-joins.test.ts +0 -221
  25. package/tests/fields-redis-cache.test.ts +0 -127
  26. package/tests/fields-validate.test.ts +0 -99
  27. package/tests/fixtures/scanFilesAddon/node_modules/@befly-addon/demo/apis/sub/b.ts +0 -3
  28. package/tests/fixtures/scanFilesApis/a.ts +0 -3
  29. package/tests/fixtures/scanFilesApis/sub/b.ts +0 -3
  30. package/tests/getClientIp.test.ts +0 -54
  31. package/tests/integration.test.ts +0 -189
  32. package/tests/jwt.test.ts +0 -65
  33. package/tests/loadPlugins-order-smoke.test.ts +0 -75
  34. package/tests/logger.test.ts +0 -325
  35. package/tests/redisHelper.test.ts +0 -495
  36. package/tests/redisKeys.test.ts +0 -9
  37. package/tests/scanConfig.test.ts +0 -144
  38. package/tests/scanFiles-routePath.test.ts +0 -46
  39. package/tests/smoke-sql.test.ts +0 -24
  40. package/tests/sqlBuilder-advanced.test.ts +0 -608
  41. package/tests/sqlBuilder.test.ts +0 -209
  42. package/tests/sync-connection.test.ts +0 -183
  43. package/tests/sync-init-guard.test.ts +0 -105
  44. package/tests/syncApi-insBatch-fields-consistent.test.ts +0 -61
  45. package/tests/syncApi-obsolete-records.test.ts +0 -69
  46. package/tests/syncApi-type-compat.test.ts +0 -72
  47. package/tests/syncDev-permissions.test.ts +0 -81
  48. package/tests/syncMenu-disableMenus-hard-delete.test.ts +0 -88
  49. package/tests/syncMenu-duplicate-path.test.ts +0 -122
  50. package/tests/syncMenu-obsolete-records.test.ts +0 -161
  51. package/tests/syncMenu-parentPath-from-tree.test.ts +0 -75
  52. package/tests/syncMenu-paths.test.ts +0 -59
  53. package/tests/syncTable-apply.test.ts +0 -279
  54. package/tests/syncTable-array-number.test.ts +0 -160
  55. package/tests/syncTable-constants.test.ts +0 -101
  56. package/tests/syncTable-db-integration.test.ts +0 -237
  57. package/tests/syncTable-ddl.test.ts +0 -245
  58. package/tests/syncTable-helpers.test.ts +0 -99
  59. package/tests/syncTable-schema.test.ts +0 -99
  60. package/tests/syncTable-testkit.test.ts +0 -25
  61. package/tests/syncTable-types.test.ts +0 -122
  62. package/tests/tableRef-and-deserialize.test.ts +0 -67
  63. package/tests/util.test.ts +0 -100
  64. package/tests/validator-array-number.test.ts +0 -310
  65. package/tests/validator-default.test.ts +0 -373
  66. package/tests/validator.test.ts +0 -679
@@ -1,25 +0,0 @@
1
- import { describe, expect, it } from "bun:test";
2
-
3
- import { syncTable } from "../sync/syncTable.js";
4
-
5
- describe("syncTable - TestKit 挂载", () => {
6
- it("should expose TestKit as a stable object", () => {
7
- expect(typeof syncTable).toBe("function");
8
- expect(syncTable.TestKit).toBeDefined();
9
-
10
- const descriptor = Object.getOwnPropertyDescriptor(syncTable, "TestKit");
11
- expect(descriptor).toBeDefined();
12
- expect(descriptor?.writable).toBe(false);
13
- expect(descriptor?.configurable).toBe(false);
14
- expect(descriptor?.enumerable).toBe(true);
15
-
16
- expect(typeof syncTable.TestKit.quoteIdentifier).toBe("function");
17
- expect(typeof syncTable.TestKit.getTypeMapping).toBe("function");
18
-
19
- expect(syncTable.TestKit.DB_VERSION_REQUIREMENTS.MYSQL_MIN_MAJOR).toBe(8);
20
-
21
- const firstRef = syncTable.TestKit;
22
- const secondRef = syncTable.TestKit;
23
- expect(firstRef).toBe(secondRef);
24
- });
25
- });
@@ -1,122 +0,0 @@
1
- /**
2
- * syncTable 类型处理模块测试
3
- *
4
- * 测试 types.ts 中的函数:
5
- * - isStringOrArrayType
6
- * - getSqlType
7
- * - resolveDefaultValue
8
- * - generateDefaultSql
9
- */
10
-
11
- import { describe, test, expect } from "bun:test";
12
-
13
- import { syncTable } from "../sync/syncTable.js";
14
-
15
- describe("isStringOrArrayType", () => {
16
- test("string 类型返回 true", () => {
17
- expect(syncTable.TestKit.isStringOrArrayType("string")).toBe(true);
18
- });
19
-
20
- test("array_string 类型返回 true", () => {
21
- expect(syncTable.TestKit.isStringOrArrayType("array_string")).toBe(true);
22
- });
23
-
24
- test("number 类型返回 false", () => {
25
- expect(syncTable.TestKit.isStringOrArrayType("number")).toBe(false);
26
- });
27
-
28
- test("text 类型返回 false", () => {
29
- expect(syncTable.TestKit.isStringOrArrayType("text")).toBe(false);
30
- });
31
-
32
- test("array_text 类型返回 false", () => {
33
- expect(syncTable.TestKit.isStringOrArrayType("array_text")).toBe(false);
34
- });
35
- });
36
-
37
- describe("resolveDefaultValue", () => {
38
- test("null 值 + string 类型 => 空字符串", () => {
39
- expect(syncTable.TestKit.resolveDefaultValue(null, "string")).toBe("");
40
- });
41
-
42
- test("null 值 + number 类型 => 0", () => {
43
- expect(syncTable.TestKit.resolveDefaultValue(null, "number")).toBe(0);
44
- });
45
-
46
- test('"null" 字符串 + number 类型 => 0', () => {
47
- expect(syncTable.TestKit.resolveDefaultValue("null", "number")).toBe(0);
48
- });
49
-
50
- test('null 值 + array_string 类型 => "[]"', () => {
51
- expect(syncTable.TestKit.resolveDefaultValue(null, "array_string")).toBe("[]");
52
- });
53
-
54
- test('null 值 + text 类型 => "null"', () => {
55
- expect(syncTable.TestKit.resolveDefaultValue(null, "text")).toBe("null");
56
- });
57
-
58
- test('null 值 + array_text 类型 => "null"(TEXT 不支持默认值)', () => {
59
- expect(syncTable.TestKit.resolveDefaultValue(null, "array_text")).toBe("null");
60
- });
61
-
62
- test("有实际值时直接返回", () => {
63
- expect(syncTable.TestKit.resolveDefaultValue("admin", "string")).toBe("admin");
64
- expect(syncTable.TestKit.resolveDefaultValue(100, "number")).toBe(100);
65
- expect(syncTable.TestKit.resolveDefaultValue(0, "number")).toBe(0);
66
- });
67
- });
68
-
69
- describe("generateDefaultSql", () => {
70
- test("number 类型生成数字默认值", () => {
71
- expect(syncTable.TestKit.generateDefaultSql(0, "number")).toBe(" DEFAULT 0");
72
- expect(syncTable.TestKit.generateDefaultSql(100, "number")).toBe(" DEFAULT 100");
73
- });
74
-
75
- test("string 类型生成带引号默认值", () => {
76
- expect(syncTable.TestKit.generateDefaultSql("admin", "string")).toBe(" DEFAULT 'admin'");
77
- expect(syncTable.TestKit.generateDefaultSql("", "string")).toBe(" DEFAULT ''");
78
- });
79
-
80
- test("text 类型不生成默认值", () => {
81
- expect(syncTable.TestKit.generateDefaultSql("null", "text")).toBe("");
82
- });
83
-
84
- test("array_string 类型生成 JSON 数组默认值", () => {
85
- expect(syncTable.TestKit.generateDefaultSql("[]", "array_string")).toBe(" DEFAULT '[]'");
86
- });
87
-
88
- test("array_text 类型不生成默认值(MySQL TEXT 不支持)", () => {
89
- expect(syncTable.TestKit.generateDefaultSql("[]", "array_text")).toBe("");
90
- });
91
-
92
- test("单引号被正确转义", () => {
93
- expect(syncTable.TestKit.generateDefaultSql("it's", "string")).toBe(" DEFAULT 'it''s'");
94
- });
95
- });
96
-
97
- describe("getSqlType", () => {
98
- test("string 类型带长度", () => {
99
- const result = syncTable.TestKit.getSqlType("mysql", "string", 100);
100
- expect(result).toBe("VARCHAR(100)");
101
- });
102
-
103
- test("array_string 类型带长度", () => {
104
- const result = syncTable.TestKit.getSqlType("mysql", "array_string", 500);
105
- expect(result).toBe("VARCHAR(500)");
106
- });
107
-
108
- test("number 类型无符号", () => {
109
- const result = syncTable.TestKit.getSqlType("mysql", "number", null, true);
110
- expect(result).toBe("BIGINT UNSIGNED");
111
- });
112
-
113
- test("number 类型有符号", () => {
114
- const result = syncTable.TestKit.getSqlType("mysql", "number", null, false);
115
- expect(result).toBe("BIGINT");
116
- });
117
-
118
- test("text 类型", () => {
119
- const result = syncTable.TestKit.getSqlType("mysql", "text", null);
120
- expect(result).toBe("MEDIUMTEXT");
121
- });
122
- });
@@ -1,67 +0,0 @@
1
- import { describe, expect, it, mock } from "bun:test";
2
-
3
- import { MySqlDialect } from "../lib/dbDialect.js";
4
- import { DbHelper } from "../lib/dbHelper.js";
5
- import { DbUtils } from "../lib/dbUtils.js";
6
- import { SqlBuilder } from "../lib/sqlBuilder.js";
7
-
8
- describe("tableRef normalize + escape", () => {
9
- it("DbUtils.normalizeTableRef: 保留 alias,仅 snakeCase 表名", () => {
10
- expect(DbUtils.normalizeTableRef("UserProfile up")).toBe("user_profile up");
11
- expect(DbUtils.normalizeTableRef("order o")).toBe("order o");
12
- });
13
-
14
- it("SqlBuilder.from: 支持 table alias", () => {
15
- const sql = new SqlBuilder().select(["*"]).from("order o").toSelectSql().sql;
16
- expect(sql).toContain("FROM `order` o");
17
- });
18
-
19
- it("SqlBuilder.from: 支持 schema.table alias", () => {
20
- const sql = new SqlBuilder().select(["*"]).from("my_db.users u").toSelectSql().sql;
21
- expect(sql).toContain("FROM `my_db`.`users` u");
22
- });
23
-
24
- it("SqlBuilder.from: 复杂表引用要求显式 fromRaw", () => {
25
- expect(() => new SqlBuilder().select(["*"]).from("users u FORCE INDEX (idx_user)")).toThrow();
26
- });
27
- });
28
-
29
- describe("DbHelper.getList deserialize", () => {
30
- it("getList: 数组字段应被 DbUtils.deserializeArrayFields 反序列化", async () => {
31
- const sqlMock = {
32
- unsafe: mock(async (sql: string, _params?: any[]) => {
33
- if (sql.includes("COUNT(*) as total")) {
34
- return [{ total: 1 }];
35
- }
36
- return [
37
- {
38
- id: "1",
39
- tags: '["a","b"]',
40
- state: 1,
41
- created_at: 0,
42
- updated_at: 0
43
- }
44
- ];
45
- })
46
- };
47
-
48
- const redisMock = {
49
- getObject: mock(async () => null),
50
- setObject: mock(async () => "OK"),
51
- genTimeID: mock(async () => 1)
52
- };
53
-
54
- const dbHelper = new DbHelper({ redis: redisMock as any, sql: sqlMock as any, dialect: new MySqlDialect() });
55
-
56
- const result = await dbHelper.getList<{ id: number; tags: string[] }>({
57
- table: "users",
58
- fields: ["id", "tags"],
59
- where: {}
60
- });
61
-
62
- expect(result.total).toBe(1);
63
- expect(result.lists.length).toBe(1);
64
- expect(Array.isArray(result.lists[0].tags)).toBe(true);
65
- expect(result.lists[0].tags).toEqual(["a", "b"]);
66
- });
67
- });
@@ -1,100 +0,0 @@
1
- import { describe, test, expect } from "bun:test";
2
-
3
- import { arrayKeysToCamel } from "../utils/arrayKeysToCamel.js";
4
- import { calcPerfTime } from "../utils/calcPerfTime.js";
5
- import { fieldClear } from "../utils/fieldClear.js";
6
- import { keysToCamel } from "../utils/keysToCamel.js";
7
- import { keysToSnake } from "../utils/keysToSnake.js";
8
-
9
- describe("Util - keysToCamel", () => {
10
- test("转换对象键名为驼峰", () => {
11
- const result = keysToCamel({ user_name: "John", user_id: 123 });
12
- expect(result.userName).toBe("John");
13
- expect(result.userId).toBe(123);
14
- });
15
-
16
- test("保持已有驼峰格式", () => {
17
- const result = keysToCamel({ userName: "John", userId: 123 });
18
- expect(result.userName).toBe("John");
19
- expect(result.userId).toBe(123);
20
- });
21
-
22
- test("处理空对象", () => {
23
- const result = keysToCamel({});
24
- expect(Object.keys(result).length).toBe(0);
25
- });
26
-
27
- test("处理嵌套对象", () => {
28
- const result = keysToCamel({ user_info: { first_name: "John" } });
29
- expect(result.userInfo).toBeDefined();
30
- });
31
- });
32
-
33
- describe("Util - keysToSnake", () => {
34
- test("转换对象键名为下划线", () => {
35
- const result = keysToSnake({ userName: "John", userId: 123 });
36
- expect(result.user_name).toBe("John");
37
- expect(result.user_id).toBe(123);
38
- });
39
-
40
- test("保持已有下划线格式", () => {
41
- const result = keysToSnake({ user_name: "John", user_id: 123 });
42
- expect(result.user_name).toBe("John");
43
- expect(result.user_id).toBe(123);
44
- });
45
-
46
- test("处理空对象", () => {
47
- const result = keysToSnake({});
48
- expect(Object.keys(result).length).toBe(0);
49
- });
50
- });
51
-
52
- describe("Util - arrayKeysToCamel", () => {
53
- test("转换数组中对象键名为驼峰", () => {
54
- const result = arrayKeysToCamel([
55
- { user_name: "John", user_id: 1 },
56
- { user_name: "Jane", user_id: 2 }
57
- ]);
58
- expect(result[0].userName).toBe("John");
59
- expect(result[0].userId).toBe(1);
60
- expect(result[1].userName).toBe("Jane");
61
- expect(result[1].userId).toBe(2);
62
- });
63
-
64
- test("处理空数组", () => {
65
- const result = arrayKeysToCamel([]);
66
- expect(result.length).toBe(0);
67
- });
68
- });
69
-
70
- describe("Util - fieldClear", () => {
71
- test("移除 null 和 undefined", () => {
72
- const result = fieldClear({ a: 1, b: null, c: undefined, d: "test" }, { excludeValues: [null, undefined] });
73
- expect(result.a).toBe(1);
74
- expect(result.b).toBeUndefined();
75
- expect(result.c).toBeUndefined();
76
- expect(result.d).toBe("test");
77
- });
78
-
79
- test("保留指定值", () => {
80
- const result = fieldClear({ a: 1, b: null, c: 0 }, { excludeValues: [null, undefined], keepMap: { c: 0 } });
81
- expect(result.a).toBe(1);
82
- expect(result.b).toBeUndefined();
83
- expect(result.c).toBe(0);
84
- });
85
-
86
- test("处理空对象", () => {
87
- const result = fieldClear({});
88
- expect(Object.keys(result).length).toBe(0);
89
- });
90
- });
91
-
92
- describe("Util - calcPerfTime", () => {
93
- test("计算性能时间", () => {
94
- const start = Bun.nanoseconds();
95
- const result = calcPerfTime(start);
96
- expect(result).toContain("毫秒");
97
- expect(typeof result).toBe("string");
98
- expect(result).toMatch(/\d+(\.\d+)?\s*毫秒/);
99
- });
100
- });
@@ -1,310 +0,0 @@
1
- /**
2
- * 测试 Validator 对 array_number_string 和 array_number_text 类型的支持
3
- */
4
-
5
- import type { FieldDefinition } from "befly/types/validate";
6
-
7
- import { describe, expect, test } from "bun:test";
8
-
9
- import { Validator } from "../lib/validator.js";
10
-
11
- describe("Validator - array_number 类型验证", () => {
12
- // ==================== 类型转换测试 ====================
13
-
14
- test("array_number_string: 接受数字数组", () => {
15
- const field: FieldDefinition = {
16
- name: "数字数组",
17
- type: "array_number_string",
18
- min: null,
19
- max: null,
20
- default: null,
21
- regexp: null
22
- };
23
-
24
- const result = Validator.single([1, 2, 3], field);
25
- expect(result.error).toBeNull();
26
- expect(result.value).toEqual([1, 2, 3]);
27
- });
28
-
29
- test("array_number_string: 拒绝字符串数组", () => {
30
- const field: FieldDefinition = {
31
- name: "数字数组",
32
- type: "array_number_string",
33
- min: null,
34
- max: null,
35
- default: null,
36
- regexp: null
37
- };
38
-
39
- const result = Validator.single(["1", "2", "3"], field);
40
- expect(result.error).toBe("数组元素必须是数字");
41
- expect(result.value).toBeNull();
42
- });
43
-
44
- test("array_number_string: 拒绝混合类型数组", () => {
45
- const field: FieldDefinition = {
46
- name: "数字数组",
47
- type: "array_number_string",
48
- min: null,
49
- max: null,
50
- default: null,
51
- regexp: null
52
- };
53
-
54
- const result = Validator.single([1, "2", 3], field);
55
- expect(result.error).toBe("数组元素必须是数字");
56
- });
57
-
58
- test("array_number_string: 拒绝非数组值", () => {
59
- const field: FieldDefinition = {
60
- name: "数字数组",
61
- type: "array_number_string",
62
- min: null,
63
- max: null,
64
- default: null,
65
- regexp: null
66
- };
67
-
68
- const result = Validator.single("123", field);
69
- expect(result.error).toBe("必须是数组");
70
- });
71
-
72
- test("array_number_text: 接受数字数组", () => {
73
- const field: FieldDefinition = {
74
- name: "长数字数组",
75
- type: "array_number_text",
76
- min: null,
77
- max: null,
78
- default: null,
79
- regexp: null
80
- };
81
-
82
- const result = Validator.single([100, 200, 300], field);
83
- expect(result.error).toBeNull();
84
- expect(result.value).toEqual([100, 200, 300]);
85
- });
86
-
87
- test("array_number_text: 拒绝 NaN 和 Infinity", () => {
88
- const field: FieldDefinition = {
89
- name: "数字数组",
90
- type: "array_number_text",
91
- min: null,
92
- max: null,
93
- default: null,
94
- regexp: null
95
- };
96
-
97
- const result1 = Validator.single([1, NaN, 3], field);
98
- expect(result1.error).toBe("数组元素必须是数字");
99
-
100
- const result2 = Validator.single([1, Infinity, 3], field);
101
- expect(result2.error).toBe("数组元素必须是数字");
102
- });
103
-
104
- // ==================== 规则验证测试 ====================
105
-
106
- test("array_number_string: min 规则验证", () => {
107
- const field: FieldDefinition = {
108
- name: "数字数组",
109
- type: "array_number_string",
110
- min: 2,
111
- max: null,
112
- default: null,
113
- regexp: null
114
- };
115
-
116
- const result1 = Validator.single([1], field);
117
- expect(result1.error).toBe("至少需要2个元素");
118
-
119
- const result2 = Validator.single([1, 2], field);
120
- expect(result2.error).toBeNull();
121
-
122
- const result3 = Validator.single([1, 2, 3], field);
123
- expect(result3.error).toBeNull();
124
- });
125
-
126
- test("array_number_string: max 规则验证", () => {
127
- const field: FieldDefinition = {
128
- name: "数字数组",
129
- type: "array_number_string",
130
- min: null,
131
- max: 3,
132
- default: null,
133
- regexp: null
134
- };
135
-
136
- const result1 = Validator.single([1, 2, 3], field);
137
- expect(result1.error).toBeNull();
138
-
139
- const result2 = Validator.single([1, 2, 3, 4], field);
140
- expect(result2.error).toBe("最多只能有3个元素");
141
- });
142
-
143
- test("array_number_text: min + max 规则验证", () => {
144
- const field: FieldDefinition = {
145
- name: "长数字数组",
146
- type: "array_number_text",
147
- min: 1,
148
- max: 5,
149
- default: null,
150
- regexp: null
151
- };
152
-
153
- const result1 = Validator.single([], field);
154
- expect(result1.error).toBe("至少需要1个元素");
155
-
156
- const result2 = Validator.single([1, 2, 3], field);
157
- expect(result2.error).toBeNull();
158
-
159
- const result3 = Validator.single([1, 2, 3, 4, 5, 6], field);
160
- expect(result3.error).toBe("最多只能有5个元素");
161
- });
162
-
163
- // ==================== 默认值测试 ====================
164
-
165
- test("array_number_string: 无 default 时返回空数组", () => {
166
- const field: FieldDefinition = {
167
- name: "数字数组",
168
- type: "array_number_string",
169
- min: null,
170
- max: null,
171
- default: null,
172
- regexp: null
173
- };
174
-
175
- const result1 = Validator.single(undefined, field);
176
- expect(result1.error).toBeNull();
177
- expect(result1.value).toEqual([]);
178
-
179
- const result2 = Validator.single(null, field);
180
- expect(result2.error).toBeNull();
181
- expect(result2.value).toEqual([]);
182
-
183
- const result3 = Validator.single("", field);
184
- expect(result3.error).toBeNull();
185
- expect(result3.value).toEqual([]);
186
- });
187
-
188
- test("array_number_string: 有 default 时返回自定义默认值", () => {
189
- const field: FieldDefinition = {
190
- name: "数字数组",
191
- type: "array_number_string",
192
- min: null,
193
- max: null,
194
- default: [10, 20, 30],
195
- regexp: null
196
- };
197
-
198
- const result = Validator.single(undefined, field);
199
- expect(result.error).toBeNull();
200
- expect(result.value).toEqual([10, 20, 30]);
201
- });
202
-
203
- test('array_number_string: default 为字符串 "[]" 时返回空数组', () => {
204
- const field: FieldDefinition = {
205
- name: "数字数组",
206
- type: "array_number_string",
207
- min: null,
208
- max: null,
209
- default: "[]",
210
- regexp: null
211
- };
212
-
213
- const result = Validator.single(null, field);
214
- expect(result.error).toBeNull();
215
- expect(result.value).toEqual([]);
216
- });
217
-
218
- test("array_number_text: 无 default 时返回空数组", () => {
219
- const field: FieldDefinition = {
220
- name: "长数字数组",
221
- type: "array_number_text",
222
- min: null,
223
- max: null,
224
- default: null,
225
- regexp: null
226
- };
227
-
228
- const result = Validator.single(undefined, field);
229
- expect(result.error).toBeNull();
230
- expect(result.value).toEqual([]);
231
- });
232
-
233
- test("array_number_text: 有 default 时返回自定义默认值", () => {
234
- const field: FieldDefinition = {
235
- name: "长数字数组",
236
- type: "array_number_text",
237
- min: null,
238
- max: null,
239
- default: [100, 200],
240
- regexp: null
241
- };
242
-
243
- const result = Validator.single(undefined, field);
244
- expect(result.error).toBeNull();
245
- expect(result.value).toEqual([100, 200]);
246
- });
247
-
248
- // ==================== validate 方法测试 ====================
249
-
250
- test("validate: array_number_string 字段验证", () => {
251
- const rules = {
252
- tags: {
253
- name: "标签ID",
254
- type: "array_number_string",
255
- min: 1,
256
- max: 10,
257
- default: null,
258
- regexp: null
259
- }
260
- };
261
-
262
- const result1 = Validator.validate({ tags: [1, 2, 3] }, rules as any, ["tags"]);
263
- expect(result1.failed).toBe(false);
264
-
265
- const result2 = Validator.validate({ tags: [] }, rules as any, ["tags"]);
266
- expect(result2.failed).toBe(true);
267
- expect(result2.firstError).toBe("标签ID至少需要1个元素");
268
-
269
- const result3 = Validator.validate({ tags: ["1", "2"] }, rules as any, ["tags"]);
270
- expect(result3.failed).toBe(true);
271
- expect(result3.firstError).toBe("标签ID数组元素必须是数字");
272
- });
273
-
274
- test("validate: array_number_text 字段验证", () => {
275
- const rules = {
276
- ids: {
277
- name: "关联ID",
278
- type: "array_number_text",
279
- min: null,
280
- max: null,
281
- default: null,
282
- regexp: null
283
- }
284
- };
285
-
286
- const result1 = Validator.validate({ ids: [100, 200, 300] }, rules as any, []);
287
- expect(result1.failed).toBe(false);
288
-
289
- const result2 = Validator.validate({ ids: "not-array" }, rules as any, []);
290
- expect(result2.failed).toBe(true);
291
- expect(result2.firstError).toBe("关联ID必须是数组");
292
- });
293
-
294
- test("validate: undefined 参数跳过验证", () => {
295
- const rules = {
296
- tags: {
297
- name: "标签",
298
- type: "array_number_string",
299
- min: 1,
300
- max: null,
301
- default: null,
302
- regexp: null
303
- }
304
- };
305
-
306
- // undefined 且不是必填字段,应跳过验证
307
- const result = Validator.validate({ other: "value" }, rules as any, []);
308
- expect(result.failed).toBe(false);
309
- });
310
- });