@payloadcms/plugin-ecommerce 4.0.0-canary.35 → 4.0.0-canary.37
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/dist/collections/carts/beforeChange.d.ts.map +1 -1
- package/dist/collections/carts/beforeChange.js +2 -0
- package/dist/collections/carts/beforeChange.js.map +1 -1
- package/dist/collections/variants/createVariantsCollection/hooks/beforeChange.d.ts.map +1 -1
- package/dist/collections/variants/createVariantsCollection/hooks/beforeChange.js +2 -0
- package/dist/collections/variants/createVariantsCollection/hooks/beforeChange.js.map +1 -1
- package/dist/collections/variants/createVariantsCollection/hooks/validateOptions.d.ts.map +1 -1
- package/dist/collections/variants/createVariantsCollection/hooks/validateOptions.js +1 -0
- package/dist/collections/variants/createVariantsCollection/hooks/validateOptions.js.map +1 -1
- package/dist/endpoints/confirmOrder.js +7 -0
- package/dist/endpoints/confirmOrder.js.map +1 -1
- package/dist/endpoints/initiatePayment.d.ts.map +1 -1
- package/dist/endpoints/initiatePayment.js +2 -0
- package/dist/endpoints/initiatePayment.js.map +1 -1
- package/dist/payments/adapters/stripe/confirmOrder.js +1 -0
- package/dist/payments/adapters/stripe/confirmOrder.js.map +1 -1
- package/dist/payments/adapters/stripe/initiatePayment.d.ts.map +1 -1
- package/dist/payments/adapters/stripe/initiatePayment.js +1 -0
- package/dist/payments/adapters/stripe/initiatePayment.js.map +1 -1
- package/dist/react/provider/index.d.ts.map +1 -1
- package/dist/react/provider/index.js +75 -34
- package/dist/react/provider/index.js.map +1 -1
- package/dist/ui/VariantOptionsSelector/index.d.ts.map +1 -1
- package/dist/ui/VariantOptionsSelector/index.js +3 -1
- package/dist/ui/VariantOptionsSelector/index.js.map +1 -1
- package/package.json +8 -8
- package/dist/collections/carts/operations/defaultCartItemMatcher.spec.js +0 -358
- package/dist/collections/carts/operations/defaultCartItemMatcher.spec.js.map +0 -1
- package/dist/collections/orders/createOrdersCollection.spec.js +0 -20
- package/dist/collections/orders/createOrdersCollection.spec.js.map +0 -1
- package/dist/endpoints/confirmOrder.spec.js +0 -509
- package/dist/endpoints/confirmOrder.spec.js.map +0 -1
- package/dist/fields/statusField.spec.js +0 -9
- package/dist/fields/statusField.spec.js.map +0 -1
- package/dist/payments/adapters/stripe/confirmOrder.spec.js +0 -255
- package/dist/payments/adapters/stripe/confirmOrder.spec.js.map +0 -1
- package/dist/payments/adapters/stripe/validateSettlement.spec.js +0 -434
- package/dist/payments/adapters/stripe/validateSettlement.spec.js.map +0 -1
- package/dist/utilities/accessComposition.spec.js +0 -765
- package/dist/utilities/accessComposition.spec.js.map +0 -1
- package/dist/utilities/defaultProductsValidation.spec.js +0 -384
- package/dist/utilities/defaultProductsValidation.spec.js.map +0 -1
- package/dist/utilities/getCollectionSlugMap.spec.js +0 -254
- package/dist/utilities/getCollectionSlugMap.spec.js.map +0 -1
- package/dist/utilities/sanitizePluginConfig.spec.js +0 -516
- package/dist/utilities/sanitizePluginConfig.spec.js.map +0 -1
|
@@ -1,434 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { getRelationshipID, normalizeCartItems, normalizeEmail, validateSettlement } from './validateSettlement.js';
|
|
3
|
-
const createTransaction = (overrides = {})=>({
|
|
4
|
-
amount: 1000,
|
|
5
|
-
cart: 'cart-123',
|
|
6
|
-
currency: 'USD',
|
|
7
|
-
customer: 'user-123',
|
|
8
|
-
id: 'txn-123',
|
|
9
|
-
items: [
|
|
10
|
-
{
|
|
11
|
-
id: 'item-1',
|
|
12
|
-
product: 'product-123',
|
|
13
|
-
quantity: 1
|
|
14
|
-
}
|
|
15
|
-
],
|
|
16
|
-
status: 'pending',
|
|
17
|
-
stripe: {
|
|
18
|
-
customerID: 'cus-123',
|
|
19
|
-
paymentIntentID: 'pi_123'
|
|
20
|
-
},
|
|
21
|
-
...overrides
|
|
22
|
-
});
|
|
23
|
-
const createPaymentIntent = (overrides = {})=>({
|
|
24
|
-
amount: 1000,
|
|
25
|
-
currency: 'usd',
|
|
26
|
-
customer: 'cus-123',
|
|
27
|
-
id: 'pi_123',
|
|
28
|
-
metadata: {
|
|
29
|
-
cartID: 'cart-123'
|
|
30
|
-
},
|
|
31
|
-
status: 'succeeded',
|
|
32
|
-
...overrides
|
|
33
|
-
});
|
|
34
|
-
const createAuthenticatedValidation = (overrides = {})=>({
|
|
35
|
-
canonicalCartID: 'cart-123',
|
|
36
|
-
cartItemsSnapshot: [
|
|
37
|
-
{
|
|
38
|
-
id: 'item-1',
|
|
39
|
-
product: 'product-123',
|
|
40
|
-
quantity: 1
|
|
41
|
-
}
|
|
42
|
-
],
|
|
43
|
-
customerEmail: 'buyer@example.com',
|
|
44
|
-
paymentIntent: createPaymentIntent(),
|
|
45
|
-
paymentIntentID: 'pi_123',
|
|
46
|
-
transaction: createTransaction(),
|
|
47
|
-
user: {
|
|
48
|
-
id: 'user-123'
|
|
49
|
-
},
|
|
50
|
-
...overrides
|
|
51
|
-
});
|
|
52
|
-
describe('Stripe settlement normalization', ()=>{
|
|
53
|
-
it('should extract relationship IDs as strings', ()=>{
|
|
54
|
-
expect(getRelationshipID({
|
|
55
|
-
id: 123
|
|
56
|
-
})).toBe('123');
|
|
57
|
-
expect(getRelationshipID(123)).toBe('123');
|
|
58
|
-
expect(getRelationshipID('123')).toBe('123');
|
|
59
|
-
});
|
|
60
|
-
it('should reject empty or malformed relationship IDs', ()=>{
|
|
61
|
-
expect(getRelationshipID('')).toBeUndefined();
|
|
62
|
-
expect(getRelationshipID({
|
|
63
|
-
id: ''
|
|
64
|
-
})).toBeUndefined();
|
|
65
|
-
expect(getRelationshipID({
|
|
66
|
-
id: {
|
|
67
|
-
id: 'nested-id'
|
|
68
|
-
}
|
|
69
|
-
})).toBeUndefined();
|
|
70
|
-
});
|
|
71
|
-
it('should normalize email case and outer whitespace', ()=>{
|
|
72
|
-
expect(normalizeEmail(' Buyer@Example.COM ')).toBe('buyer@example.com');
|
|
73
|
-
});
|
|
74
|
-
it('should normalize only root relationships while preserving nested custom data', ()=>{
|
|
75
|
-
expect(normalizeCartItems([
|
|
76
|
-
{
|
|
77
|
-
custom: {
|
|
78
|
-
gift: true
|
|
79
|
-
},
|
|
80
|
-
product: {
|
|
81
|
-
id: 123
|
|
82
|
-
},
|
|
83
|
-
quantity: 2,
|
|
84
|
-
selections: [
|
|
85
|
-
{
|
|
86
|
-
variant: {
|
|
87
|
-
id: 'variant-456'
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
],
|
|
91
|
-
variant: 456
|
|
92
|
-
}
|
|
93
|
-
])).toEqual([
|
|
94
|
-
{
|
|
95
|
-
custom: {
|
|
96
|
-
gift: true
|
|
97
|
-
},
|
|
98
|
-
product: '123',
|
|
99
|
-
quantity: 2,
|
|
100
|
-
selections: [
|
|
101
|
-
{
|
|
102
|
-
variant: {
|
|
103
|
-
id: 'variant-456'
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
],
|
|
107
|
-
variant: '456'
|
|
108
|
-
}
|
|
109
|
-
]);
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
describe('validateSettlement', ()=>{
|
|
113
|
-
it('should accept a valid authenticated settlement that is pending and unlinked', ()=>{
|
|
114
|
-
expect(()=>validateSettlement(createAuthenticatedValidation())).not.toThrow();
|
|
115
|
-
});
|
|
116
|
-
it('should accept a valid guest settlement with normalized emails', ()=>{
|
|
117
|
-
const transaction = createTransaction({
|
|
118
|
-
customer: undefined,
|
|
119
|
-
customerEmail: ' Buyer@Example.com '
|
|
120
|
-
});
|
|
121
|
-
expect(()=>validateSettlement(createAuthenticatedValidation({
|
|
122
|
-
customerEmail: 'buyer@example.COM',
|
|
123
|
-
transaction,
|
|
124
|
-
user: undefined
|
|
125
|
-
}))).not.toThrow();
|
|
126
|
-
});
|
|
127
|
-
it.each([
|
|
128
|
-
{
|
|
129
|
-
label: 'missing',
|
|
130
|
-
user: {}
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
label: 'empty',
|
|
134
|
-
user: {
|
|
135
|
-
id: ''
|
|
136
|
-
}
|
|
137
|
-
},
|
|
138
|
-
{
|
|
139
|
-
label: 'malformed',
|
|
140
|
-
user: {
|
|
141
|
-
id: {}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
])('should reject a $label ID on a present authenticated principal', ({ user })=>{
|
|
145
|
-
const transaction = createTransaction({
|
|
146
|
-
customer: undefined,
|
|
147
|
-
customerEmail: 'buyer@example.com'
|
|
148
|
-
});
|
|
149
|
-
expect(()=>validateSettlement(createAuthenticatedValidation({
|
|
150
|
-
transaction,
|
|
151
|
-
user
|
|
152
|
-
}))).toThrow('customer');
|
|
153
|
-
});
|
|
154
|
-
it('should reject a requested PaymentIntent that does not match the transaction', ()=>{
|
|
155
|
-
expect(()=>validateSettlement(createAuthenticatedValidation({
|
|
156
|
-
transaction: createTransaction({
|
|
157
|
-
stripe: {
|
|
158
|
-
customerID: 'cus-123',
|
|
159
|
-
paymentIntentID: 'pi_other'
|
|
160
|
-
}
|
|
161
|
-
})
|
|
162
|
-
}))).toThrow('PaymentIntent');
|
|
163
|
-
});
|
|
164
|
-
it('should reject a canonical cart that does not match the transaction cart', ()=>{
|
|
165
|
-
expect(()=>validateSettlement(createAuthenticatedValidation({
|
|
166
|
-
transaction: createTransaction({
|
|
167
|
-
cart: 'cart-other'
|
|
168
|
-
})
|
|
169
|
-
}))).toThrow('cart');
|
|
170
|
-
});
|
|
171
|
-
it('should reject a canonical cart that does not match PaymentIntent metadata', ()=>{
|
|
172
|
-
expect(()=>validateSettlement(createAuthenticatedValidation({
|
|
173
|
-
paymentIntent: createPaymentIntent({
|
|
174
|
-
metadata: {
|
|
175
|
-
cartID: 'cart-other'
|
|
176
|
-
}
|
|
177
|
-
})
|
|
178
|
-
}))).toThrow('cart');
|
|
179
|
-
});
|
|
180
|
-
it('should reject an authenticated customer that does not own the transaction', ()=>{
|
|
181
|
-
expect(()=>validateSettlement(createAuthenticatedValidation({
|
|
182
|
-
transaction: createTransaction({
|
|
183
|
-
customer: 'user-other'
|
|
184
|
-
})
|
|
185
|
-
}))).toThrow('customer');
|
|
186
|
-
});
|
|
187
|
-
it('should reject a guest transaction that belongs to an authenticated customer', ()=>{
|
|
188
|
-
expect(()=>validateSettlement(createAuthenticatedValidation({
|
|
189
|
-
transaction: createTransaction({
|
|
190
|
-
customerEmail: 'buyer@example.com'
|
|
191
|
-
}),
|
|
192
|
-
user: undefined
|
|
193
|
-
}))).toThrow('customer');
|
|
194
|
-
});
|
|
195
|
-
it('should reject a guest transaction with a different email', ()=>{
|
|
196
|
-
expect(()=>validateSettlement(createAuthenticatedValidation({
|
|
197
|
-
transaction: createTransaction({
|
|
198
|
-
customer: undefined,
|
|
199
|
-
customerEmail: 'other@example.com'
|
|
200
|
-
}),
|
|
201
|
-
user: undefined
|
|
202
|
-
}))).toThrow('email');
|
|
203
|
-
});
|
|
204
|
-
it('should reject a Stripe customer that does not match the transaction', ()=>{
|
|
205
|
-
expect(()=>validateSettlement(createAuthenticatedValidation({
|
|
206
|
-
paymentIntent: createPaymentIntent({
|
|
207
|
-
customer: 'cus-other'
|
|
208
|
-
})
|
|
209
|
-
}))).toThrow('Stripe customer');
|
|
210
|
-
});
|
|
211
|
-
it('should reject a Stripe amount that does not match the transaction', ()=>{
|
|
212
|
-
expect(()=>validateSettlement(createAuthenticatedValidation({
|
|
213
|
-
paymentIntent: createPaymentIntent({
|
|
214
|
-
amount: 999
|
|
215
|
-
})
|
|
216
|
-
}))).toThrow('amount');
|
|
217
|
-
});
|
|
218
|
-
it('should reject a Stripe currency that does not match after uppercasing', ()=>{
|
|
219
|
-
expect(()=>validateSettlement(createAuthenticatedValidation({
|
|
220
|
-
paymentIntent: createPaymentIntent({
|
|
221
|
-
currency: 'eur'
|
|
222
|
-
})
|
|
223
|
-
}))).toThrow('currency');
|
|
224
|
-
});
|
|
225
|
-
it('should reject a lower-case stored transaction currency', ()=>{
|
|
226
|
-
expect(()=>validateSettlement(createAuthenticatedValidation({
|
|
227
|
-
transaction: createTransaction({
|
|
228
|
-
currency: 'usd'
|
|
229
|
-
})
|
|
230
|
-
}))).toThrow('currency');
|
|
231
|
-
});
|
|
232
|
-
it('should accept relationship objects and scalar IDs as equivalent item data', ()=>{
|
|
233
|
-
const transaction = createTransaction({
|
|
234
|
-
items: [
|
|
235
|
-
{
|
|
236
|
-
id: 'item-1',
|
|
237
|
-
product: {
|
|
238
|
-
id: 123
|
|
239
|
-
},
|
|
240
|
-
quantity: 1,
|
|
241
|
-
variant: {
|
|
242
|
-
id: 456
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
]
|
|
246
|
-
});
|
|
247
|
-
expect(()=>validateSettlement(createAuthenticatedValidation({
|
|
248
|
-
cartItemsSnapshot: [
|
|
249
|
-
{
|
|
250
|
-
id: 'item-1',
|
|
251
|
-
product: '123',
|
|
252
|
-
quantity: 1,
|
|
253
|
-
variant: '456'
|
|
254
|
-
}
|
|
255
|
-
],
|
|
256
|
-
transaction
|
|
257
|
-
}))).not.toThrow();
|
|
258
|
-
});
|
|
259
|
-
it('should reject an item quantity mismatch', ()=>{
|
|
260
|
-
expect(()=>validateSettlement(createAuthenticatedValidation({
|
|
261
|
-
cartItemsSnapshot: [
|
|
262
|
-
{
|
|
263
|
-
id: 'item-1',
|
|
264
|
-
product: 'product-123',
|
|
265
|
-
quantity: 2
|
|
266
|
-
}
|
|
267
|
-
]
|
|
268
|
-
}))).toThrow('items');
|
|
269
|
-
});
|
|
270
|
-
it('should reject an item custom-property mismatch', ()=>{
|
|
271
|
-
expect(()=>validateSettlement(createAuthenticatedValidation({
|
|
272
|
-
cartItemsSnapshot: [
|
|
273
|
-
{
|
|
274
|
-
giftMessage: 'surprise',
|
|
275
|
-
id: 'item-1',
|
|
276
|
-
product: 'product-123',
|
|
277
|
-
quantity: 1
|
|
278
|
-
}
|
|
279
|
-
]
|
|
280
|
-
}))).toThrow('items');
|
|
281
|
-
});
|
|
282
|
-
it('should treat a persisted null root variant as equivalent to an omitted snapshot variant', ()=>{
|
|
283
|
-
expect(()=>validateSettlement(createAuthenticatedValidation({
|
|
284
|
-
transaction: createTransaction({
|
|
285
|
-
items: [
|
|
286
|
-
{
|
|
287
|
-
id: 'item-1',
|
|
288
|
-
product: 'product-123',
|
|
289
|
-
quantity: 1,
|
|
290
|
-
variant: null
|
|
291
|
-
}
|
|
292
|
-
]
|
|
293
|
-
})
|
|
294
|
-
}))).not.toThrow();
|
|
295
|
-
});
|
|
296
|
-
it('should reject a null root product', ()=>{
|
|
297
|
-
expect(()=>validateSettlement(createAuthenticatedValidation({
|
|
298
|
-
cartItemsSnapshot: [
|
|
299
|
-
{
|
|
300
|
-
id: 'item-1',
|
|
301
|
-
product: null,
|
|
302
|
-
quantity: 1
|
|
303
|
-
}
|
|
304
|
-
]
|
|
305
|
-
}))).toThrow();
|
|
306
|
-
});
|
|
307
|
-
it.each([
|
|
308
|
-
{
|
|
309
|
-
label: 'malformed object',
|
|
310
|
-
variant: {}
|
|
311
|
-
},
|
|
312
|
-
{
|
|
313
|
-
label: 'blank scalar ID',
|
|
314
|
-
variant: ''
|
|
315
|
-
},
|
|
316
|
-
{
|
|
317
|
-
label: 'blank object ID',
|
|
318
|
-
variant: {
|
|
319
|
-
id: ''
|
|
320
|
-
}
|
|
321
|
-
},
|
|
322
|
-
{
|
|
323
|
-
label: 'nested object ID',
|
|
324
|
-
variant: {
|
|
325
|
-
id: {
|
|
326
|
-
id: 'variant-123'
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
])('should reject a $label for a non-null root variant', ({ variant })=>{
|
|
331
|
-
expect(()=>validateSettlement(createAuthenticatedValidation({
|
|
332
|
-
cartItemsSnapshot: [
|
|
333
|
-
{
|
|
334
|
-
id: 'item-1',
|
|
335
|
-
product: 'product-123',
|
|
336
|
-
quantity: 1,
|
|
337
|
-
variant
|
|
338
|
-
}
|
|
339
|
-
]
|
|
340
|
-
}))).toThrow();
|
|
341
|
-
});
|
|
342
|
-
it('should reject equivalent empty scalar and object relationship IDs', ()=>{
|
|
343
|
-
expect(()=>validateSettlement(createAuthenticatedValidation({
|
|
344
|
-
cartItemsSnapshot: [
|
|
345
|
-
{
|
|
346
|
-
id: 'item-1',
|
|
347
|
-
product: 'product-123',
|
|
348
|
-
quantity: 1,
|
|
349
|
-
variant: ''
|
|
350
|
-
}
|
|
351
|
-
],
|
|
352
|
-
transaction: createTransaction({
|
|
353
|
-
items: [
|
|
354
|
-
{
|
|
355
|
-
id: 'item-1',
|
|
356
|
-
product: 'product-123',
|
|
357
|
-
quantity: 1,
|
|
358
|
-
variant: {
|
|
359
|
-
id: ''
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
]
|
|
363
|
-
})
|
|
364
|
-
}))).toThrow();
|
|
365
|
-
});
|
|
366
|
-
it('should preserve nested custom variant null when comparing against a missing nested key', ()=>{
|
|
367
|
-
expect(()=>validateSettlement(createAuthenticatedValidation({
|
|
368
|
-
cartItemsSnapshot: [
|
|
369
|
-
{
|
|
370
|
-
id: 'item-1',
|
|
371
|
-
product: 'product-123',
|
|
372
|
-
quantity: 1,
|
|
373
|
-
selection: {
|
|
374
|
-
variant: null
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
],
|
|
378
|
-
transaction: createTransaction({
|
|
379
|
-
items: [
|
|
380
|
-
{
|
|
381
|
-
id: 'item-1',
|
|
382
|
-
product: 'product-123',
|
|
383
|
-
quantity: 1,
|
|
384
|
-
selection: {}
|
|
385
|
-
}
|
|
386
|
-
]
|
|
387
|
-
})
|
|
388
|
-
}))).toThrow('items');
|
|
389
|
-
});
|
|
390
|
-
it('should preserve nested custom values while ignoring object key order', ()=>{
|
|
391
|
-
expect(()=>validateSettlement(createAuthenticatedValidation({
|
|
392
|
-
cartItemsSnapshot: [
|
|
393
|
-
{
|
|
394
|
-
id: 'item-1',
|
|
395
|
-
product: 'product-123',
|
|
396
|
-
quantity: 1,
|
|
397
|
-
selection: {
|
|
398
|
-
color: 'blue',
|
|
399
|
-
variant: null
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
],
|
|
403
|
-
transaction: createTransaction({
|
|
404
|
-
items: [
|
|
405
|
-
{
|
|
406
|
-
id: 'item-1',
|
|
407
|
-
product: 'product-123',
|
|
408
|
-
quantity: 1,
|
|
409
|
-
selection: {
|
|
410
|
-
variant: null,
|
|
411
|
-
color: 'blue'
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
]
|
|
415
|
-
})
|
|
416
|
-
}))).not.toThrow();
|
|
417
|
-
});
|
|
418
|
-
it('should reject malformed item metadata', ()=>{
|
|
419
|
-
expect(()=>validateSettlement(createAuthenticatedValidation({
|
|
420
|
-
cartItemsSnapshot: {
|
|
421
|
-
quantity: 1
|
|
422
|
-
}
|
|
423
|
-
}))).toThrow('items');
|
|
424
|
-
});
|
|
425
|
-
it('should reject a PaymentIntent that has not succeeded', ()=>{
|
|
426
|
-
expect(()=>validateSettlement(createAuthenticatedValidation({
|
|
427
|
-
paymentIntent: createPaymentIntent({
|
|
428
|
-
status: 'processing'
|
|
429
|
-
})
|
|
430
|
-
}))).toThrow('completed');
|
|
431
|
-
});
|
|
432
|
-
});
|
|
433
|
-
|
|
434
|
-
//# sourceMappingURL=validateSettlement.spec.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/payments/adapters/stripe/validateSettlement.spec.ts"],"sourcesContent":["import { describe, expect, it } from 'vitest'\n\nimport {\n getRelationshipID,\n normalizeCartItems,\n normalizeEmail,\n validateSettlement,\n} from './validateSettlement.js'\n\nconst createTransaction = (overrides: Record<string, unknown> = {}) => ({\n amount: 1000,\n cart: 'cart-123',\n currency: 'USD',\n customer: 'user-123',\n id: 'txn-123',\n items: [{ id: 'item-1', product: 'product-123', quantity: 1 }],\n status: 'pending',\n stripe: {\n customerID: 'cus-123',\n paymentIntentID: 'pi_123',\n },\n ...overrides,\n})\n\nconst createPaymentIntent = (overrides: Record<string, unknown> = {}) => ({\n amount: 1000,\n currency: 'usd',\n customer: 'cus-123',\n id: 'pi_123',\n metadata: {\n cartID: 'cart-123',\n },\n status: 'succeeded',\n ...overrides,\n})\n\nconst createAuthenticatedValidation = (overrides: Record<string, unknown> = {}) => ({\n canonicalCartID: 'cart-123',\n cartItemsSnapshot: [{ id: 'item-1', product: 'product-123', quantity: 1 }],\n customerEmail: 'buyer@example.com',\n paymentIntent: createPaymentIntent(),\n paymentIntentID: 'pi_123',\n transaction: createTransaction(),\n user: { id: 'user-123' },\n ...overrides,\n})\n\ndescribe('Stripe settlement normalization', () => {\n it('should extract relationship IDs as strings', () => {\n expect(getRelationshipID({ id: 123 })).toBe('123')\n expect(getRelationshipID(123)).toBe('123')\n expect(getRelationshipID('123')).toBe('123')\n })\n\n it('should reject empty or malformed relationship IDs', () => {\n expect(getRelationshipID('')).toBeUndefined()\n expect(getRelationshipID({ id: '' })).toBeUndefined()\n expect(getRelationshipID({ id: { id: 'nested-id' } })).toBeUndefined()\n })\n\n it('should normalize email case and outer whitespace', () => {\n expect(normalizeEmail(' Buyer@Example.COM ')).toBe('buyer@example.com')\n })\n\n it('should normalize only root relationships while preserving nested custom data', () => {\n expect(\n normalizeCartItems([\n {\n custom: { gift: true },\n product: { id: 123 },\n quantity: 2,\n selections: [{ variant: { id: 'variant-456' } }],\n variant: 456,\n },\n ]),\n ).toEqual([\n {\n custom: { gift: true },\n product: '123',\n quantity: 2,\n selections: [{ variant: { id: 'variant-456' } }],\n variant: '456',\n },\n ])\n })\n})\n\ndescribe('validateSettlement', () => {\n it('should accept a valid authenticated settlement that is pending and unlinked', () => {\n expect(() => validateSettlement(createAuthenticatedValidation())).not.toThrow()\n })\n\n it('should accept a valid guest settlement with normalized emails', () => {\n const transaction = createTransaction({\n customer: undefined,\n customerEmail: ' Buyer@Example.com ',\n })\n\n expect(() =>\n validateSettlement(\n createAuthenticatedValidation({\n customerEmail: 'buyer@example.COM',\n transaction,\n user: undefined,\n }),\n ),\n ).not.toThrow()\n })\n\n it.each([\n { label: 'missing', user: {} },\n { label: 'empty', user: { id: '' } },\n { label: 'malformed', user: { id: {} } },\n ])('should reject a $label ID on a present authenticated principal', ({ user }) => {\n const transaction = createTransaction({\n customer: undefined,\n customerEmail: 'buyer@example.com',\n })\n\n expect(() => validateSettlement(createAuthenticatedValidation({ transaction, user }))).toThrow(\n 'customer',\n )\n })\n\n it('should reject a requested PaymentIntent that does not match the transaction', () => {\n expect(() =>\n validateSettlement(\n createAuthenticatedValidation({\n transaction: createTransaction({\n stripe: { customerID: 'cus-123', paymentIntentID: 'pi_other' },\n }),\n }),\n ),\n ).toThrow('PaymentIntent')\n })\n\n it('should reject a canonical cart that does not match the transaction cart', () => {\n expect(() =>\n validateSettlement(\n createAuthenticatedValidation({\n transaction: createTransaction({ cart: 'cart-other' }),\n }),\n ),\n ).toThrow('cart')\n })\n\n it('should reject a canonical cart that does not match PaymentIntent metadata', () => {\n expect(() =>\n validateSettlement(\n createAuthenticatedValidation({\n paymentIntent: createPaymentIntent({ metadata: { cartID: 'cart-other' } }),\n }),\n ),\n ).toThrow('cart')\n })\n\n it('should reject an authenticated customer that does not own the transaction', () => {\n expect(() =>\n validateSettlement(\n createAuthenticatedValidation({\n transaction: createTransaction({ customer: 'user-other' }),\n }),\n ),\n ).toThrow('customer')\n })\n\n it('should reject a guest transaction that belongs to an authenticated customer', () => {\n expect(() =>\n validateSettlement(\n createAuthenticatedValidation({\n transaction: createTransaction({ customerEmail: 'buyer@example.com' }),\n user: undefined,\n }),\n ),\n ).toThrow('customer')\n })\n\n it('should reject a guest transaction with a different email', () => {\n expect(() =>\n validateSettlement(\n createAuthenticatedValidation({\n transaction: createTransaction({\n customer: undefined,\n customerEmail: 'other@example.com',\n }),\n user: undefined,\n }),\n ),\n ).toThrow('email')\n })\n\n it('should reject a Stripe customer that does not match the transaction', () => {\n expect(() =>\n validateSettlement(\n createAuthenticatedValidation({\n paymentIntent: createPaymentIntent({ customer: 'cus-other' }),\n }),\n ),\n ).toThrow('Stripe customer')\n })\n\n it('should reject a Stripe amount that does not match the transaction', () => {\n expect(() =>\n validateSettlement(\n createAuthenticatedValidation({ paymentIntent: createPaymentIntent({ amount: 999 }) }),\n ),\n ).toThrow('amount')\n })\n\n it('should reject a Stripe currency that does not match after uppercasing', () => {\n expect(() =>\n validateSettlement(\n createAuthenticatedValidation({\n paymentIntent: createPaymentIntent({ currency: 'eur' }),\n }),\n ),\n ).toThrow('currency')\n })\n\n it('should reject a lower-case stored transaction currency', () => {\n expect(() =>\n validateSettlement(\n createAuthenticatedValidation({\n transaction: createTransaction({ currency: 'usd' }),\n }),\n ),\n ).toThrow('currency')\n })\n\n it('should accept relationship objects and scalar IDs as equivalent item data', () => {\n const transaction = createTransaction({\n items: [{ id: 'item-1', product: { id: 123 }, quantity: 1, variant: { id: 456 } }],\n })\n\n expect(() =>\n validateSettlement(\n createAuthenticatedValidation({\n cartItemsSnapshot: [{ id: 'item-1', product: '123', quantity: 1, variant: '456' }],\n transaction,\n }),\n ),\n ).not.toThrow()\n })\n\n it('should reject an item quantity mismatch', () => {\n expect(() =>\n validateSettlement(\n createAuthenticatedValidation({\n cartItemsSnapshot: [{ id: 'item-1', product: 'product-123', quantity: 2 }],\n }),\n ),\n ).toThrow('items')\n })\n\n it('should reject an item custom-property mismatch', () => {\n expect(() =>\n validateSettlement(\n createAuthenticatedValidation({\n cartItemsSnapshot: [\n { giftMessage: 'surprise', id: 'item-1', product: 'product-123', quantity: 1 },\n ],\n }),\n ),\n ).toThrow('items')\n })\n\n it('should treat a persisted null root variant as equivalent to an omitted snapshot variant', () => {\n expect(() =>\n validateSettlement(\n createAuthenticatedValidation({\n transaction: createTransaction({\n items: [{ id: 'item-1', product: 'product-123', quantity: 1, variant: null }],\n }),\n }),\n ),\n ).not.toThrow()\n })\n\n it('should reject a null root product', () => {\n expect(() =>\n validateSettlement(\n createAuthenticatedValidation({\n cartItemsSnapshot: [{ id: 'item-1', product: null, quantity: 1 }],\n }),\n ),\n ).toThrow()\n })\n\n it.each([\n { label: 'malformed object', variant: {} },\n { label: 'blank scalar ID', variant: '' },\n { label: 'blank object ID', variant: { id: '' } },\n { label: 'nested object ID', variant: { id: { id: 'variant-123' } } },\n ])('should reject a $label for a non-null root variant', ({ variant }) => {\n expect(() =>\n validateSettlement(\n createAuthenticatedValidation({\n cartItemsSnapshot: [{ id: 'item-1', product: 'product-123', quantity: 1, variant }],\n }),\n ),\n ).toThrow()\n })\n\n it('should reject equivalent empty scalar and object relationship IDs', () => {\n expect(() =>\n validateSettlement(\n createAuthenticatedValidation({\n cartItemsSnapshot: [{ id: 'item-1', product: 'product-123', quantity: 1, variant: '' }],\n transaction: createTransaction({\n items: [{ id: 'item-1', product: 'product-123', quantity: 1, variant: { id: '' } }],\n }),\n }),\n ),\n ).toThrow()\n })\n\n it('should preserve nested custom variant null when comparing against a missing nested key', () => {\n expect(() =>\n validateSettlement(\n createAuthenticatedValidation({\n cartItemsSnapshot: [\n {\n id: 'item-1',\n product: 'product-123',\n quantity: 1,\n selection: { variant: null },\n },\n ],\n transaction: createTransaction({\n items: [{ id: 'item-1', product: 'product-123', quantity: 1, selection: {} }],\n }),\n }),\n ),\n ).toThrow('items')\n })\n\n it('should preserve nested custom values while ignoring object key order', () => {\n expect(() =>\n validateSettlement(\n createAuthenticatedValidation({\n cartItemsSnapshot: [\n {\n id: 'item-1',\n product: 'product-123',\n quantity: 1,\n selection: { color: 'blue', variant: null },\n },\n ],\n transaction: createTransaction({\n items: [\n {\n id: 'item-1',\n product: 'product-123',\n quantity: 1,\n selection: { variant: null, color: 'blue' },\n },\n ],\n }),\n }),\n ),\n ).not.toThrow()\n })\n\n it('should reject malformed item metadata', () => {\n expect(() =>\n validateSettlement(createAuthenticatedValidation({ cartItemsSnapshot: { quantity: 1 } })),\n ).toThrow('items')\n })\n\n it('should reject a PaymentIntent that has not succeeded', () => {\n expect(() =>\n validateSettlement(\n createAuthenticatedValidation({\n paymentIntent: createPaymentIntent({ status: 'processing' }),\n }),\n ),\n ).toThrow('completed')\n })\n})\n"],"names":["describe","expect","it","getRelationshipID","normalizeCartItems","normalizeEmail","validateSettlement","createTransaction","overrides","amount","cart","currency","customer","id","items","product","quantity","status","stripe","customerID","paymentIntentID","createPaymentIntent","metadata","cartID","createAuthenticatedValidation","canonicalCartID","cartItemsSnapshot","customerEmail","paymentIntent","transaction","user","toBe","toBeUndefined","custom","gift","selections","variant","toEqual","not","toThrow","undefined","each","label","giftMessage","selection","color"],"mappings":"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"}
|