@hy_ong/zod-kit 0.2.0 → 0.2.1
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/.github/workflows/ci.yml +24 -0
- package/CLAUDE.md +64 -22
- package/dist/chunk-36NWHESN.js +124 -0
- package/dist/chunk-4LYZAO3P.js +165 -0
- package/dist/chunk-5GAZQDVS.cjs +206 -0
- package/dist/chunk-5LS4DSRQ.cjs +127 -0
- package/dist/chunk-5OGW2ERW.js +181 -0
- package/dist/chunk-5ZEKWPSE.cjs +69 -0
- package/dist/chunk-6OGDPSWT.js +135 -0
- package/dist/chunk-6X22I6NQ.cjs +136 -0
- package/dist/chunk-77KZUPPN.cjs +177 -0
- package/dist/chunk-AANSHH2O.cjs +165 -0
- package/dist/chunk-AI72FMOF.cjs +130 -0
- package/dist/chunk-AWV2IT66.js +146 -0
- package/dist/chunk-B3U5G3AA.js +160 -0
- package/dist/chunk-CFFCBWYL.cjs +99 -0
- package/dist/chunk-DPXRMSB2.js +130 -0
- package/dist/chunk-DRXPGQM6.cjs +135 -0
- package/dist/chunk-EAU42EVH.js +161 -0
- package/dist/chunk-FC6VDOC7.js +206 -0
- package/dist/chunk-FVO4743A.cjs +134 -0
- package/dist/chunk-G6DV7LX7.cjs +161 -0
- package/dist/chunk-I2RJMDXN.js +90 -0
- package/dist/chunk-IJEEM3DI.js +136 -0
- package/dist/chunk-JBNCMS42.cjs +151 -0
- package/dist/chunk-JZ2SHRGZ.js +87 -0
- package/dist/chunk-KARFFIMP.js +696 -0
- package/dist/chunk-LIQSVJLS.js +177 -0
- package/dist/chunk-LKPXHW5N.cjs +181 -0
- package/dist/chunk-MAQRXYE6.js +118 -0
- package/dist/chunk-MCDESS3T.js +69 -0
- package/dist/chunk-MG25BEV4.cjs +160 -0
- package/dist/chunk-NKCYXBGX.js +99 -0
- package/dist/chunk-OEK7QSQP.js +75 -0
- package/dist/chunk-OMFQ7Z63.cjs +696 -0
- package/dist/chunk-OP4KV3BY.cjs +124 -0
- package/dist/chunk-P2NONIMS.js +257 -0
- package/dist/chunk-P364KRO5.js +61 -0
- package/dist/chunk-PGSDXR2I.js +71 -0
- package/dist/chunk-PL2GERLG.cjs +61 -0
- package/dist/chunk-R5G4V7C6.cjs +75 -0
- package/dist/chunk-RKHX3DGH.js +127 -0
- package/dist/chunk-TSHL7ZO2.js +134 -0
- package/dist/chunk-UFNVCUPQ.cjs +301 -0
- package/dist/chunk-VCRKYMJM.js +301 -0
- package/dist/chunk-VDOAPLA6.cjs +257 -0
- package/dist/chunk-VP5CCP5F.cjs +90 -0
- package/dist/chunk-W2EWMV3A.cjs +87 -0
- package/dist/chunk-WWRFBLCR.cjs +146 -0
- package/dist/chunk-YALLOVNO.cjs +118 -0
- package/dist/chunk-YAU6JCYL.cjs +71 -0
- package/dist/chunk-YWV2BBXN.cjs +2526 -0
- package/dist/chunk-ZBOQCXD4.js +2526 -0
- package/dist/chunk-ZFQQXWNB.js +151 -0
- package/dist/common/boolean.cjs +7 -0
- package/dist/common/boolean.d.cts +119 -0
- package/dist/common/boolean.d.ts +119 -0
- package/dist/common/boolean.js +7 -0
- package/dist/common/color.cjs +9 -0
- package/dist/common/color.d.cts +26 -0
- package/dist/common/color.d.ts +26 -0
- package/dist/common/color.js +9 -0
- package/dist/common/coordinate.cjs +11 -0
- package/dist/common/coordinate.d.cts +23 -0
- package/dist/common/coordinate.d.ts +23 -0
- package/dist/common/coordinate.js +11 -0
- package/dist/common/credit-card.cjs +11 -0
- package/dist/common/credit-card.d.cts +22 -0
- package/dist/common/credit-card.d.ts +22 -0
- package/dist/common/credit-card.js +11 -0
- package/dist/common/date.cjs +7 -0
- package/dist/common/date.d.cts +174 -0
- package/dist/common/date.d.ts +174 -0
- package/dist/common/date.js +7 -0
- package/dist/common/datetime.cjs +15 -0
- package/dist/common/datetime.d.cts +301 -0
- package/dist/common/datetime.d.ts +301 -0
- package/dist/common/datetime.js +15 -0
- package/dist/common/email.cjs +7 -0
- package/dist/common/email.d.cts +149 -0
- package/dist/common/email.d.ts +149 -0
- package/dist/common/email.js +7 -0
- package/dist/common/file.cjs +7 -0
- package/dist/common/file.d.cts +178 -0
- package/dist/common/file.d.ts +178 -0
- package/dist/common/file.js +7 -0
- package/dist/common/id.cjs +13 -0
- package/dist/common/id.d.cts +262 -0
- package/dist/common/id.d.ts +262 -0
- package/dist/common/id.js +13 -0
- package/dist/common/ip.cjs +11 -0
- package/dist/common/ip.d.cts +25 -0
- package/dist/common/ip.d.ts +25 -0
- package/dist/common/ip.js +11 -0
- package/dist/common/number.cjs +7 -0
- package/dist/common/number.d.cts +167 -0
- package/dist/common/number.d.ts +167 -0
- package/dist/common/number.js +7 -0
- package/dist/common/password.cjs +7 -0
- package/dist/common/password.d.cts +192 -0
- package/dist/common/password.d.ts +192 -0
- package/dist/common/password.js +7 -0
- package/dist/common/text.cjs +7 -0
- package/dist/common/text.d.cts +156 -0
- package/dist/common/text.d.ts +156 -0
- package/dist/common/text.js +7 -0
- package/dist/common/time.cjs +15 -0
- package/dist/common/time.d.cts +268 -0
- package/dist/common/time.d.ts +268 -0
- package/dist/common/time.js +15 -0
- package/dist/common/url.cjs +7 -0
- package/dist/common/url.d.cts +196 -0
- package/dist/common/url.d.ts +196 -0
- package/dist/common/url.js +7 -0
- package/dist/config-CABSSvAp.d.cts +5 -0
- package/dist/config-CABSSvAp.d.ts +5 -0
- package/dist/index.cjs +180 -5255
- package/dist/index.d.cts +28 -3150
- package/dist/index.d.ts +28 -3150
- package/dist/index.js +135 -5131
- package/dist/taiwan/bank-account.cjs +11 -0
- package/dist/taiwan/bank-account.d.cts +22 -0
- package/dist/taiwan/bank-account.d.ts +22 -0
- package/dist/taiwan/bank-account.js +11 -0
- package/dist/taiwan/business-id.cjs +9 -0
- package/dist/taiwan/business-id.d.cts +133 -0
- package/dist/taiwan/business-id.d.ts +133 -0
- package/dist/taiwan/business-id.js +9 -0
- package/dist/taiwan/fax.cjs +9 -0
- package/dist/taiwan/fax.d.cts +157 -0
- package/dist/taiwan/fax.d.ts +157 -0
- package/dist/taiwan/fax.js +9 -0
- package/dist/taiwan/invoice.cjs +9 -0
- package/dist/taiwan/invoice.d.cts +17 -0
- package/dist/taiwan/invoice.d.ts +17 -0
- package/dist/taiwan/invoice.js +9 -0
- package/dist/taiwan/license-plate.cjs +9 -0
- package/dist/taiwan/license-plate.d.cts +19 -0
- package/dist/taiwan/license-plate.d.ts +19 -0
- package/dist/taiwan/license-plate.js +9 -0
- package/dist/taiwan/mobile.cjs +9 -0
- package/dist/taiwan/mobile.d.cts +146 -0
- package/dist/taiwan/mobile.d.ts +146 -0
- package/dist/taiwan/mobile.js +9 -0
- package/dist/taiwan/national-id.cjs +15 -0
- package/dist/taiwan/national-id.d.cts +214 -0
- package/dist/taiwan/national-id.d.ts +214 -0
- package/dist/taiwan/national-id.js +15 -0
- package/dist/taiwan/passport.cjs +9 -0
- package/dist/taiwan/passport.d.cts +19 -0
- package/dist/taiwan/passport.d.ts +19 -0
- package/dist/taiwan/passport.js +9 -0
- package/dist/taiwan/postal-code.cjs +17 -0
- package/dist/taiwan/postal-code.d.cts +237 -0
- package/dist/taiwan/postal-code.d.ts +237 -0
- package/dist/taiwan/postal-code.js +17 -0
- package/dist/taiwan/tel.cjs +9 -0
- package/dist/taiwan/tel.d.cts +162 -0
- package/dist/taiwan/tel.d.ts +162 -0
- package/dist/taiwan/tel.js +9 -0
- package/package.json +128 -2
- package/src/i18n/locales/en-GB.json +43 -0
- package/src/i18n/locales/en-US.json +43 -0
- package/src/i18n/locales/id-ID.json +43 -0
- package/src/i18n/locales/ja-JP.json +43 -0
- package/src/i18n/locales/ko-KR.json +43 -0
- package/src/i18n/locales/ms-MY.json +43 -0
- package/src/i18n/locales/th-TH.json +43 -0
- package/src/i18n/locales/vi-VN.json +43 -0
- package/src/i18n/locales/zh-CN.json +43 -0
- package/src/i18n/locales/zh-TW.json +43 -0
- package/src/index.ts +10 -2
- package/src/validators/common/color.ts +192 -0
- package/src/validators/common/coordinate.ts +159 -0
- package/src/validators/common/credit-card.ts +134 -0
- package/src/validators/common/ip.ts +210 -0
- package/src/validators/taiwan/bank-account.ts +176 -0
- package/src/validators/taiwan/invoice.ts +84 -0
- package/src/validators/taiwan/license-plate.ts +110 -0
- package/src/validators/taiwan/passport.ts +103 -0
- package/tests/common/color.test.ts +587 -0
- package/tests/common/coordinate.test.ts +345 -0
- package/tests/common/credit-card.test.ts +378 -0
- package/tests/common/ip.test.ts +419 -0
- package/tests/taiwan/bank-account.test.ts +286 -0
- package/tests/taiwan/invoice.test.ts +227 -0
- package/tests/taiwan/license-plate.test.ts +280 -0
- package/tests/taiwan/passport.test.ts +277 -0
- package/tsup.config.ts +36 -0
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from "vitest"
|
|
2
|
+
import { creditCard, setLocale, validateCreditCard, detectCardType } from "../../src"
|
|
3
|
+
|
|
4
|
+
describe("creditCard(true) validator", () => {
|
|
5
|
+
beforeEach(() => setLocale("en-US"))
|
|
6
|
+
|
|
7
|
+
describe("basic functionality", () => {
|
|
8
|
+
it("should validate correct Luhn numbers", () => {
|
|
9
|
+
const schema = creditCard(true)
|
|
10
|
+
|
|
11
|
+
expect(schema.parse("4111111111111111")).toBe("4111111111111111")
|
|
12
|
+
expect(schema.parse("4012888888881881")).toBe("4012888888881881")
|
|
13
|
+
expect(schema.parse("5500000000000004")).toBe("5500000000000004")
|
|
14
|
+
expect(schema.parse("5105105105105100")).toBe("5105105105105100")
|
|
15
|
+
expect(schema.parse("378282246310005")).toBe("378282246310005")
|
|
16
|
+
expect(schema.parse("371449635398431")).toBe("371449635398431")
|
|
17
|
+
expect(schema.parse("3530111333300000")).toBe("3530111333300000")
|
|
18
|
+
expect(schema.parse("6011111111111117")).toBe("6011111111111117")
|
|
19
|
+
expect(schema.parse("6200000000000005")).toBe("6200000000000005")
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it("should reject invalid Luhn numbers", () => {
|
|
23
|
+
const schema = creditCard(true)
|
|
24
|
+
|
|
25
|
+
expect(() => schema.parse("4111111111111112")).toThrow("Invalid credit card number")
|
|
26
|
+
expect(() => schema.parse("1234567890123456")).toThrow("Invalid credit card number")
|
|
27
|
+
})
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
describe("card type detection", () => {
|
|
31
|
+
it("should detect Visa cards", () => {
|
|
32
|
+
const schema = creditCard(true, { cardType: "visa" })
|
|
33
|
+
|
|
34
|
+
expect(schema.parse("4111111111111111")).toBe("4111111111111111")
|
|
35
|
+
expect(schema.parse("4012888888881881")).toBe("4012888888881881")
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it("should detect Mastercard cards", () => {
|
|
39
|
+
const schema = creditCard(true, { cardType: "mastercard" })
|
|
40
|
+
|
|
41
|
+
expect(schema.parse("5500000000000004")).toBe("5500000000000004")
|
|
42
|
+
expect(schema.parse("5105105105105100")).toBe("5105105105105100")
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it("should detect AMEX cards", () => {
|
|
46
|
+
const schema = creditCard(true, { cardType: "amex" })
|
|
47
|
+
|
|
48
|
+
expect(schema.parse("378282246310005")).toBe("378282246310005")
|
|
49
|
+
expect(schema.parse("371449635398431")).toBe("371449635398431")
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it("should detect JCB cards", () => {
|
|
53
|
+
const schema = creditCard(true, { cardType: "jcb" })
|
|
54
|
+
|
|
55
|
+
expect(schema.parse("3530111333300000")).toBe("3530111333300000")
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it("should detect Discover cards", () => {
|
|
59
|
+
const schema = creditCard(true, { cardType: "discover" })
|
|
60
|
+
|
|
61
|
+
expect(schema.parse("6011111111111117")).toBe("6011111111111117")
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it("should detect UnionPay cards", () => {
|
|
65
|
+
const schema = creditCard(true, { cardType: "unionpay" })
|
|
66
|
+
|
|
67
|
+
expect(schema.parse("6200000000000005")).toBe("6200000000000005")
|
|
68
|
+
})
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
describe("card type filtering", () => {
|
|
72
|
+
it("should reject cards not matching the required type", () => {
|
|
73
|
+
const visaOnly = creditCard(true, { cardType: "visa" })
|
|
74
|
+
|
|
75
|
+
expect(() => visaOnly.parse("5500000000000004")).toThrow("Invalid credit card number")
|
|
76
|
+
expect(() => visaOnly.parse("378282246310005")).toThrow("Invalid credit card number")
|
|
77
|
+
expect(() => visaOnly.parse("3530111333300000")).toThrow("Invalid credit card number")
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it("should accept multiple card types", () => {
|
|
81
|
+
const visaOrMc = creditCard(true, { cardType: ["visa", "mastercard"] })
|
|
82
|
+
|
|
83
|
+
expect(visaOrMc.parse("4111111111111111")).toBe("4111111111111111")
|
|
84
|
+
expect(visaOrMc.parse("5500000000000004")).toBe("5500000000000004")
|
|
85
|
+
expect(() => visaOrMc.parse("378282246310005")).toThrow("Invalid credit card number")
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
it("should accept any card type when 'any' is specified", () => {
|
|
89
|
+
const anyType = creditCard(true, { cardType: "any" })
|
|
90
|
+
|
|
91
|
+
expect(anyType.parse("4111111111111111")).toBe("4111111111111111")
|
|
92
|
+
expect(anyType.parse("5500000000000004")).toBe("5500000000000004")
|
|
93
|
+
expect(anyType.parse("378282246310005")).toBe("378282246310005")
|
|
94
|
+
expect(anyType.parse("3530111333300000")).toBe("3530111333300000")
|
|
95
|
+
expect(anyType.parse("6011111111111117")).toBe("6011111111111117")
|
|
96
|
+
expect(anyType.parse("6200000000000005")).toBe("6200000000000005")
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it("should accept any card type when 'any' is included in array", () => {
|
|
100
|
+
const withAny = creditCard(true, { cardType: ["any", "visa"] })
|
|
101
|
+
|
|
102
|
+
expect(withAny.parse("5500000000000004")).toBe("5500000000000004")
|
|
103
|
+
expect(withAny.parse("378282246310005")).toBe("378282246310005")
|
|
104
|
+
})
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
describe("whitelist", () => {
|
|
108
|
+
it("should accept whitelisted card numbers", () => {
|
|
109
|
+
const schema = creditCard(true, { whitelist: ["4111111111111111", "5500000000000004"] })
|
|
110
|
+
|
|
111
|
+
expect(schema.parse("4111111111111111")).toBe("4111111111111111")
|
|
112
|
+
expect(schema.parse("5500000000000004")).toBe("5500000000000004")
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
it("should reject non-whitelisted card numbers", () => {
|
|
116
|
+
const schema = creditCard(true, { whitelist: ["4111111111111111"] })
|
|
117
|
+
|
|
118
|
+
expect(() => schema.parse("5500000000000004")).toThrow("Credit card number is not in the allowed list")
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it("should normalize whitelist entries by stripping spaces and hyphens", () => {
|
|
122
|
+
const schema = creditCard(true, { whitelist: ["4111-1111-1111-1111"] })
|
|
123
|
+
|
|
124
|
+
expect(schema.parse("4111111111111111")).toBe("4111111111111111")
|
|
125
|
+
})
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
describe("required/optional behavior", () => {
|
|
129
|
+
it("should handle required=true", () => {
|
|
130
|
+
const schema = creditCard(true)
|
|
131
|
+
|
|
132
|
+
expect(() => schema.parse("")).toThrow("Required")
|
|
133
|
+
expect(() => schema.parse(null)).toThrow()
|
|
134
|
+
expect(() => schema.parse(undefined)).toThrow()
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
it("should handle required=false", () => {
|
|
138
|
+
const schema = creditCard(false)
|
|
139
|
+
|
|
140
|
+
expect(schema.parse("")).toBe(null)
|
|
141
|
+
expect(schema.parse(null)).toBe(null)
|
|
142
|
+
expect(schema.parse(undefined)).toBe(null)
|
|
143
|
+
expect(schema.parse("4111111111111111")).toBe("4111111111111111")
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
it("should use default values", () => {
|
|
147
|
+
const requiredSchema = creditCard(true, { defaultValue: "4111111111111111" })
|
|
148
|
+
const optionalSchema = creditCard(false, { defaultValue: "4111111111111111" })
|
|
149
|
+
|
|
150
|
+
expect(requiredSchema.parse("")).toBe("4111111111111111")
|
|
151
|
+
expect(optionalSchema.parse("")).toBe("4111111111111111")
|
|
152
|
+
})
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
describe("transform function", () => {
|
|
156
|
+
it("should apply custom transform before validation", () => {
|
|
157
|
+
const schema = creditCard(true, {
|
|
158
|
+
transform: (val) => val.toUpperCase(),
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
expect(schema.parse("4111111111111111")).toBe("4111111111111111")
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
it("should apply transform on the stripped value", () => {
|
|
165
|
+
const transformed: string[] = []
|
|
166
|
+
const schema = creditCard(true, {
|
|
167
|
+
transform: (val) => {
|
|
168
|
+
transformed.push(val)
|
|
169
|
+
return val
|
|
170
|
+
},
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
schema.parse("4111 1111 1111 1111")
|
|
174
|
+
expect(transformed[0]).toBe("4111111111111111")
|
|
175
|
+
})
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
describe("input preprocessing", () => {
|
|
179
|
+
it("should strip spaces from input", () => {
|
|
180
|
+
const schema = creditCard(true)
|
|
181
|
+
|
|
182
|
+
expect(schema.parse("4111 1111 1111 1111")).toBe("4111111111111111")
|
|
183
|
+
expect(schema.parse(" 4111 1111 1111 1111 ")).toBe("4111111111111111")
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
it("should strip hyphens from input", () => {
|
|
187
|
+
const schema = creditCard(true)
|
|
188
|
+
|
|
189
|
+
expect(schema.parse("4111-1111-1111-1111")).toBe("4111111111111111")
|
|
190
|
+
expect(schema.parse("5500-0000-0000-0004")).toBe("5500000000000004")
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
it("should handle mixed spaces and hyphens", () => {
|
|
194
|
+
const schema = creditCard(true)
|
|
195
|
+
|
|
196
|
+
expect(schema.parse("4111 - 1111 - 1111 - 1111")).toBe("4111111111111111")
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
it("should handle string conversion from numbers", () => {
|
|
200
|
+
const schema = creditCard(true)
|
|
201
|
+
|
|
202
|
+
expect(schema.parse(4111111111111111)).toBe("4111111111111111")
|
|
203
|
+
})
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
describe("i18n support", () => {
|
|
207
|
+
it("should use English messages by default", () => {
|
|
208
|
+
setLocale("en-US")
|
|
209
|
+
const schema = creditCard(true)
|
|
210
|
+
|
|
211
|
+
expect(() => schema.parse("")).toThrow("Required")
|
|
212
|
+
expect(() => schema.parse("4111111111111112")).toThrow("Invalid credit card number")
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
it("should use Chinese messages when locale is zh-TW", () => {
|
|
216
|
+
setLocale("zh-TW")
|
|
217
|
+
const schema = creditCard(true)
|
|
218
|
+
|
|
219
|
+
expect(() => schema.parse("")).toThrow("必填")
|
|
220
|
+
expect(() => schema.parse("4111111111111112")).toThrow("無效的信用卡號碼")
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
it("should support custom i18n messages", () => {
|
|
224
|
+
const schema = creditCard(true, {
|
|
225
|
+
i18n: {
|
|
226
|
+
"en-US": {
|
|
227
|
+
required: "Card number is required",
|
|
228
|
+
invalid: "Card number is invalid",
|
|
229
|
+
notInWhitelist: "Card not allowed",
|
|
230
|
+
},
|
|
231
|
+
"zh-TW": {
|
|
232
|
+
required: "請輸入信用卡號",
|
|
233
|
+
invalid: "信用卡號格式錯誤",
|
|
234
|
+
notInWhitelist: "此卡號不允許使用",
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
setLocale("en-US")
|
|
240
|
+
expect(() => schema.parse("")).toThrow("Card number is required")
|
|
241
|
+
expect(() => schema.parse("4111111111111112")).toThrow("Card number is invalid")
|
|
242
|
+
|
|
243
|
+
setLocale("zh-TW")
|
|
244
|
+
expect(() => schema.parse("")).toThrow("請輸入信用卡號")
|
|
245
|
+
expect(() => schema.parse("4111111111111112")).toThrow("信用卡號格式錯誤")
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
it("should use custom notInWhitelist message", () => {
|
|
249
|
+
const schema = creditCard(true, {
|
|
250
|
+
whitelist: ["4111111111111111"],
|
|
251
|
+
i18n: {
|
|
252
|
+
"en-US": {
|
|
253
|
+
notInWhitelist: "This card is not accepted",
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
})
|
|
257
|
+
|
|
258
|
+
expect(() => schema.parse("5500000000000004")).toThrow("This card is not accepted")
|
|
259
|
+
})
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
describe("edge cases", () => {
|
|
263
|
+
it("should reject numbers that are too short", () => {
|
|
264
|
+
const schema = creditCard(true)
|
|
265
|
+
|
|
266
|
+
expect(() => schema.parse("411111111111")).toThrow("Invalid credit card number")
|
|
267
|
+
expect(() => schema.parse("41111")).toThrow("Invalid credit card number")
|
|
268
|
+
expect(() => schema.parse("1")).toThrow("Invalid credit card number")
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
it("should reject numbers that are too long", () => {
|
|
272
|
+
const schema = creditCard(true)
|
|
273
|
+
|
|
274
|
+
expect(() => schema.parse("41111111111111111111")).toThrow("Invalid credit card number")
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
it("should reject non-numeric input", () => {
|
|
278
|
+
const schema = creditCard(true)
|
|
279
|
+
|
|
280
|
+
expect(() => schema.parse("abcdefghijklmnop")).toThrow("Invalid credit card number")
|
|
281
|
+
expect(() => schema.parse("4111-ABCD-1111-1111")).toThrow("Invalid credit card number")
|
|
282
|
+
expect(() => schema.parse("41111111111111xx")).toThrow("Invalid credit card number")
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
it("should handle 'null' and 'undefined' string values as required", () => {
|
|
286
|
+
const schema = creditCard(true)
|
|
287
|
+
|
|
288
|
+
expect(() => schema.parse("null")).toThrow("Required")
|
|
289
|
+
expect(() => schema.parse("undefined")).toThrow("Required")
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
it("should handle empty and whitespace inputs", () => {
|
|
293
|
+
const schema = creditCard(true)
|
|
294
|
+
const optionalSchema = creditCard(false)
|
|
295
|
+
|
|
296
|
+
expect(() => schema.parse("")).toThrow("Required")
|
|
297
|
+
expect(() => schema.parse(" ")).toThrow("Required")
|
|
298
|
+
|
|
299
|
+
expect(optionalSchema.parse("")).toBe(null)
|
|
300
|
+
expect(optionalSchema.parse(" ")).toBe(null)
|
|
301
|
+
})
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
describe("utility functions", () => {
|
|
305
|
+
describe("validateCreditCard", () => {
|
|
306
|
+
it("should return true for valid Luhn numbers", () => {
|
|
307
|
+
expect(validateCreditCard("4111111111111111")).toBe(true)
|
|
308
|
+
expect(validateCreditCard("4012888888881881")).toBe(true)
|
|
309
|
+
expect(validateCreditCard("5500000000000004")).toBe(true)
|
|
310
|
+
expect(validateCreditCard("5105105105105100")).toBe(true)
|
|
311
|
+
expect(validateCreditCard("378282246310005")).toBe(true)
|
|
312
|
+
expect(validateCreditCard("371449635398431")).toBe(true)
|
|
313
|
+
expect(validateCreditCard("3530111333300000")).toBe(true)
|
|
314
|
+
expect(validateCreditCard("6011111111111117")).toBe(true)
|
|
315
|
+
expect(validateCreditCard("6200000000000005")).toBe(true)
|
|
316
|
+
})
|
|
317
|
+
|
|
318
|
+
it("should return false for invalid Luhn numbers", () => {
|
|
319
|
+
expect(validateCreditCard("4111111111111112")).toBe(false)
|
|
320
|
+
expect(validateCreditCard("1234567890123456")).toBe(false)
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
it("should return false for non-numeric strings", () => {
|
|
324
|
+
expect(validateCreditCard("abcdefghijklmnop")).toBe(false)
|
|
325
|
+
expect(validateCreditCard("")).toBe(false)
|
|
326
|
+
})
|
|
327
|
+
|
|
328
|
+
it("should return false for wrong-length strings", () => {
|
|
329
|
+
expect(validateCreditCard("41111")).toBe(false)
|
|
330
|
+
expect(validateCreditCard("41111111111111111111")).toBe(false)
|
|
331
|
+
})
|
|
332
|
+
|
|
333
|
+
it("should handle strings with spaces and hyphens", () => {
|
|
334
|
+
expect(validateCreditCard("4111 1111 1111 1111")).toBe(true)
|
|
335
|
+
expect(validateCreditCard("4111-1111-1111-1111")).toBe(true)
|
|
336
|
+
})
|
|
337
|
+
})
|
|
338
|
+
|
|
339
|
+
describe("detectCardType", () => {
|
|
340
|
+
it("should detect Visa", () => {
|
|
341
|
+
expect(detectCardType("4111111111111111")).toBe("visa")
|
|
342
|
+
expect(detectCardType("4012888888881881")).toBe("visa")
|
|
343
|
+
})
|
|
344
|
+
|
|
345
|
+
it("should detect Mastercard", () => {
|
|
346
|
+
expect(detectCardType("5500000000000004")).toBe("mastercard")
|
|
347
|
+
expect(detectCardType("5105105105105100")).toBe("mastercard")
|
|
348
|
+
})
|
|
349
|
+
|
|
350
|
+
it("should detect AMEX", () => {
|
|
351
|
+
expect(detectCardType("378282246310005")).toBe("amex")
|
|
352
|
+
expect(detectCardType("371449635398431")).toBe("amex")
|
|
353
|
+
})
|
|
354
|
+
|
|
355
|
+
it("should detect JCB", () => {
|
|
356
|
+
expect(detectCardType("3530111333300000")).toBe("jcb")
|
|
357
|
+
})
|
|
358
|
+
|
|
359
|
+
it("should detect Discover", () => {
|
|
360
|
+
expect(detectCardType("6011111111111117")).toBe("discover")
|
|
361
|
+
})
|
|
362
|
+
|
|
363
|
+
it("should detect UnionPay", () => {
|
|
364
|
+
expect(detectCardType("6200000000000005")).toBe("unionpay")
|
|
365
|
+
})
|
|
366
|
+
|
|
367
|
+
it("should return 'any' for unrecognized prefixes", () => {
|
|
368
|
+
expect(detectCardType("9999999999999999")).toBe("any")
|
|
369
|
+
expect(detectCardType("1111111111111111")).toBe("any")
|
|
370
|
+
})
|
|
371
|
+
|
|
372
|
+
it("should handle strings with spaces and hyphens", () => {
|
|
373
|
+
expect(detectCardType("4111 1111 1111 1111")).toBe("visa")
|
|
374
|
+
expect(detectCardType("5500-0000-0000-0004")).toBe("mastercard")
|
|
375
|
+
})
|
|
376
|
+
})
|
|
377
|
+
})
|
|
378
|
+
})
|