@thorprovider/medusa-extended 1.3.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,685 @@
1
+ /**
2
+ * @fileoverview Dropshipper Order Creation — Live Integration Tests
3
+ *
4
+ * Exercises the DropshipperClient against a real Medusa backend to verify
5
+ * that orders are created correctly based on payment method, address,
6
+ * shipping options, and geozone parameters.
7
+ *
8
+ * Guarded by DROPSHIPPER_SMOKE_TEST=1 environment variable.
9
+ *
10
+ * Environment variables (all required when DROPSHIPPER_SMOKE_TEST=1):
11
+ * MEDUSA_BACKEND_URL - Backend URL (e.g. https://dev.erpthor.com)
12
+ * TEST_EMAIL - Dropshipper admin email
13
+ * TEST_PASSWORD - Dropshipper admin password
14
+ *
15
+ * These tests CREATE real orders on the backend and then CANCEL them.
16
+ * Run against a staging/test environment, NOT production.
17
+ */
18
+
19
+ import { describe, expect, it, beforeAll, afterAll } from 'vitest'
20
+ import { server } from '../stelorder/client.test-helpers'
21
+ import { DropshipperClient } from './dropshipper'
22
+ import type {
23
+ ExtendedCreateDropshipperOrderBody,
24
+ GetDropshipperProductsResponse,
25
+ GetDropshipperCustomersResponse,
26
+ GetDropshipperShippingOptionsResponse,
27
+ GetDropshipperAccountResponse,
28
+ } from '@thorprovider/types'
29
+
30
+ const runLive = process.env.DROPSHIPPER_SMOKE_TEST === '1'
31
+
32
+ function requiredEnv(name: string): string {
33
+ const value = process.env[name]
34
+ if (!value) throw new Error(`Missing required env var: ${name}`)
35
+ return value
36
+ }
37
+
38
+ if (!runLive) {
39
+ describe('Dropshipper order creation live smoke', () => {
40
+ it.skip('disabled unless DROPSHIPPER_SMOKE_TEST=1', () => {})
41
+ })
42
+ } else {
43
+ const baseUrl = requiredEnv('MEDUSA_BACKEND_URL')
44
+ const email = requiredEnv('TEST_EMAIL')
45
+ const password = requiredEnv('TEST_PASSWORD')
46
+
47
+ // --------------------------------------------------------------------------
48
+ // Helpers
49
+ // --------------------------------------------------------------------------
50
+
51
+ let jwtToken: string
52
+ let client: DropshipperClient
53
+
54
+ /** Login and obtain a JWT token for the dropshipper */
55
+ const login = async (): Promise<string> => {
56
+ const res = await fetch(`${baseUrl}/auth/user/emailpass`, {
57
+ method: 'POST',
58
+ headers: { 'Content-Type': 'application/json' },
59
+ body: JSON.stringify({ email, password }),
60
+ })
61
+ if (!res.ok) {
62
+ const text = await res.text()
63
+ throw new Error(`Login failed (${res.status}): ${text}`)
64
+ }
65
+ const data = (await res.json()) as { token: string }
66
+ if (!data.token) throw new Error('Login succeeded but no token returned')
67
+ return data.token
68
+ }
69
+
70
+ /** Cancel a test order to clean up */
71
+ const cancelOrder = async (orderId: string): Promise<void> => {
72
+ try {
73
+ await client.cancelOrder(orderId)
74
+ } catch {
75
+ // Best-effort cleanup — ignore failures
76
+ }
77
+ }
78
+
79
+ beforeAll(async () => {
80
+ // Stop MSW so real HTTP requests reach the backend
81
+ server.close()
82
+ jwtToken = await login()
83
+ client = new DropshipperClient({ baseUrl, token: jwtToken })
84
+ })
85
+
86
+ afterAll(() => {
87
+ // Restore MSW for other tests
88
+ server.listen({ onUnhandledRequest: 'error' })
89
+ })
90
+
91
+ // --------------------------------------------------------------------------
92
+ // Test Data Discovery
93
+ // --------------------------------------------------------------------------
94
+
95
+ describe('Test data discovery', () => {
96
+ let products: GetDropshipperProductsResponse['products']
97
+ let customers: GetDropshipperCustomersResponse['customers']
98
+ let shippingOptions: GetDropshipperShippingOptionsResponse['shipping_options']
99
+ let account: GetDropshipperAccountResponse['account']
100
+
101
+ it('fetches products to find valid variant IDs', async () => {
102
+ const res = await client.getProducts({ limit: 5 })
103
+ expect(res.products.length).toBeGreaterThan(0)
104
+ products = res.products
105
+ })
106
+
107
+ it('fetches customers to find a valid customer ID', async () => {
108
+ const res = await client.getCustomers({ limit: 5 })
109
+ expect(res.customers.length).toBeGreaterThan(0)
110
+ customers = res.customers
111
+ })
112
+
113
+ it('fetches account to find payment method configs', async () => {
114
+ const res = await client.getAccount()
115
+ expect(res.account.payment_method_configs?.length).toBeGreaterThan(0)
116
+ account = res.account
117
+ })
118
+
119
+ it('fetches shipping options for the account currency', async () => {
120
+ const res = await client.getOrderShippingOptions({
121
+ currency_code: account.currency_code,
122
+ })
123
+ expect(res.shipping_options.length).toBeGreaterThan(0)
124
+ shippingOptions = res.shipping_options
125
+ })
126
+
127
+ it('fetches shipping options with country code (geozone filter)', async () => {
128
+ // Use the customer's default shipping address country if available
129
+ const customerDetail = await client.getCustomer(customers[0].id)
130
+ const addr = customerDetail.customer?.default_shipping_address
131
+ if (!addr?.country_code) {
132
+ console.log('Skipping: customer has no default shipping address with country_code')
133
+ return
134
+ }
135
+
136
+ const res = await client.getOrderShippingOptions({
137
+ currency_code: account.currency_code,
138
+ country_code: addr.country_code,
139
+ province: addr.province ?? undefined,
140
+ city: addr.city ?? undefined,
141
+ })
142
+ expect(res.shipping_options).toBeInstanceOf(Array)
143
+ console.log(
144
+ `Shipping options for ${addr.country_code}/${addr.province ?? 'any'}/${addr.city ?? 'any'}: ${res.shipping_options.length} found`,
145
+ )
146
+ })
147
+ })
148
+
149
+ // --------------------------------------------------------------------------
150
+ // Order Creation
151
+ // --------------------------------------------------------------------------
152
+
153
+ describe('Order creation', () => {
154
+ let products: GetDropshipperProductsResponse['products']
155
+ let customers: GetDropshipperCustomersResponse['customers']
156
+ let account: GetDropshipperAccountResponse['account']
157
+ let shippingOptions: GetDropshipperShippingOptionsResponse['shipping_options']
158
+ let createdOrderIds: string[] = []
159
+
160
+ beforeAll(async () => {
161
+ const [productsRes, customersRes, accountRes] = await Promise.all([
162
+ client.getProducts({ limit: 5 }),
163
+ client.getCustomers({ limit: 5 }),
164
+ client.getAccount(),
165
+ ])
166
+ products = productsRes.products
167
+ customers = customersRes.customers
168
+ account = accountRes.account
169
+
170
+ const shippingRes = await client.getOrderShippingOptions({
171
+ currency_code: account.currency_code,
172
+ })
173
+ shippingOptions = shippingRes.shipping_options
174
+ })
175
+
176
+ afterAll(async () => {
177
+ // Clean up all created orders
178
+ for (const orderId of createdOrderIds) {
179
+ await cancelOrder(orderId)
180
+ }
181
+ })
182
+
183
+ function getFirstVariantId(): string {
184
+ for (const product of products) {
185
+ if (product.variants && product.variants.length > 0) {
186
+ return product.variants[0].id
187
+ }
188
+ }
189
+ throw new Error('No products with variants found')
190
+ }
191
+
192
+ function buildOrderBody(overrides?: Partial<ExtendedCreateDropshipperOrderBody>): ExtendedCreateDropshipperOrderBody {
193
+ const variantId = getFirstVariantId()
194
+ const paymentMethodId = account.payment_method_configs?.find((c) => c.is_enabled)?.payment_provider_id
195
+ if (!paymentMethodId) throw new Error('No enabled payment method configs found')
196
+
197
+ return {
198
+ customer_id: customers[0].id,
199
+ currency_code: account.currency_code.toLowerCase(),
200
+ items: [{ variant_id: variantId, quantity: 1 }],
201
+ shipping_address: {
202
+ full_name: `${customers[0].first_name ?? 'Test'} ${customers[0].last_name ?? 'User'}`,
203
+ address_1: '123 Test Street',
204
+ city: 'Test City',
205
+ province: '',
206
+ postal_code: '00000',
207
+ country_code: 'mx',
208
+ phone: undefined,
209
+ },
210
+ payment_method_id: paymentMethodId,
211
+ ...overrides,
212
+ }
213
+ }
214
+
215
+ it('creates an order with default settings', async () => {
216
+ const body = buildOrderBody()
217
+ const res = await client.createOrder(body)
218
+ expect(res.order).toBeDefined()
219
+ expect(res.order.id).toBeTruthy()
220
+ expect(res.order.display_id).toBeGreaterThan(0)
221
+ expect(res.order.status).toBe('pending')
222
+ expect(res.order.total).toBeGreaterThan(0)
223
+ expect(res.order.created_at).toBeTruthy()
224
+
225
+ createdOrderIds.push(res.order.id)
226
+ console.log(`Created order ${res.order.display_id} (${res.order.id}) — total: ${res.order.total}`)
227
+ })
228
+
229
+ it('creates an order with shipping_method_id', async () => {
230
+ if (shippingOptions.length === 0) {
231
+ console.log('Skipping: no shipping options available')
232
+ return
233
+ }
234
+
235
+ const body = buildOrderBody({ shipping_method_id: shippingOptions[0].id })
236
+ const res = await client.createOrder(body)
237
+ expect(res.order.id).toBeTruthy()
238
+ expect(res.order.status).toBe('pending')
239
+
240
+ createdOrderIds.push(res.order.id)
241
+ console.log(`Created order with shipping method: ${shippingOptions[0].name}`)
242
+ })
243
+
244
+ it('creates an order with billing_address', async () => {
245
+ const body = buildOrderBody({
246
+ billing_address: {
247
+ full_name: 'Billing User',
248
+ address_1: '456 Billing Ave',
249
+ city: 'Billing City',
250
+ province: '',
251
+ postal_code: '11111',
252
+ country_code: 'mx',
253
+ phone: undefined,
254
+ },
255
+ })
256
+ const res = await client.createOrder(body)
257
+ expect(res.order.id).toBeTruthy()
258
+
259
+ createdOrderIds.push(res.order.id)
260
+ })
261
+
262
+ it('creates an order with province and city in shipping address (geozone match)', async () => {
263
+ const body = buildOrderBody({
264
+ shipping_address: {
265
+ full_name: `${customers[0].first_name ?? 'Test'} ${customers[0].last_name ?? 'User'}`,
266
+ address_1: 'Av. Revolucion 123',
267
+ city: 'Monterrey',
268
+ province: 'Nuevo Leon',
269
+ postal_code: '64000',
270
+ country_code: 'mx',
271
+ phone: undefined,
272
+ },
273
+ })
274
+ const res = await client.createOrder(body)
275
+ expect(res.order.id).toBeTruthy()
276
+
277
+ createdOrderIds.push(res.order.id)
278
+ console.log(`Created order with geozone address: Monterrey, Nuevo Leon`)
279
+ })
280
+
281
+ it('creates an order with dropshipper-collected payment method', async () => {
282
+ const dropshipperPayment = account.payment_method_configs?.find(
283
+ (c) => c.is_enabled && c.collected_by === 'dropshipper',
284
+ )
285
+ if (!dropshipperPayment) {
286
+ console.log('Skipping: no dropshipper-collected payment method available')
287
+ return
288
+ }
289
+
290
+ const body = buildOrderBody({ payment_method_id: dropshipperPayment.payment_provider_id })
291
+ const res = await client.createOrder(body)
292
+ expect(res.order.id).toBeTruthy()
293
+
294
+ createdOrderIds.push(res.order.id)
295
+ console.log(`Created order with dropshipper-collected payment: ${dropshipperPayment.label}`)
296
+ })
297
+
298
+ it('creates an order with provider-collected payment method', async () => {
299
+ const providerPayment = account.payment_method_configs?.find(
300
+ (c) => c.is_enabled && c.collected_by === 'provider',
301
+ )
302
+ if (!providerPayment) {
303
+ console.log('Skipping: no provider-collected payment method available')
304
+ return
305
+ }
306
+
307
+ const body = buildOrderBody({ payment_method_id: providerPayment.payment_provider_id })
308
+ const res = await client.createOrder(body)
309
+ expect(res.order.id).toBeTruthy()
310
+
311
+ createdOrderIds.push(res.order.id)
312
+ console.log(`Created order with provider-collected payment: ${providerPayment.label}`)
313
+ })
314
+
315
+ it('creates an order with promo_codes', async () => {
316
+ // Try to find a valid promotion first
317
+ let promoCode: string | undefined
318
+ try {
319
+ const promos = await client.getPromotions({ limit: 1 })
320
+ if (promos.promotions && promos.promotions.length > 0) {
321
+ promoCode = promos.promotions[0].code
322
+ }
323
+ } catch {
324
+ // Ignore — promotions may not exist
325
+ }
326
+
327
+ if (!promoCode) {
328
+ console.log('Skipping: no promotions available')
329
+ return
330
+ }
331
+
332
+ const body = buildOrderBody({ promo_codes: [promoCode] })
333
+ const res = await client.createOrder(body)
334
+ expect(res.order.id).toBeTruthy()
335
+
336
+ createdOrderIds.push(res.order.id)
337
+ console.log(`Created order with promo code: ${promoCode}`)
338
+ })
339
+
340
+ it('creates an order with multiple items', async () => {
341
+ const variantIds: string[] = []
342
+ for (const product of products) {
343
+ if (product.variants && product.variants.length > 0) {
344
+ variantIds.push(product.variants[0].id)
345
+ if (variantIds.length >= 2) break
346
+ }
347
+ }
348
+
349
+ if (variantIds.length < 2) {
350
+ console.log('Skipping: need at least 2 variants for multi-item test')
351
+ return
352
+ }
353
+
354
+ const paymentMethodId = account.payment_method_configs?.find((c) => c.is_enabled)?.payment_provider_id
355
+ if (!paymentMethodId) throw new Error('No enabled payment method configs found')
356
+
357
+ const body: ExtendedCreateDropshipperOrderBody = {
358
+ customer_id: customers[0].id,
359
+ currency_code: account.currency_code.toLowerCase(),
360
+ items: [
361
+ { variant_id: variantIds[0], quantity: 2 },
362
+ { variant_id: variantIds[1], quantity: 1 },
363
+ ],
364
+ shipping_address: {
365
+ full_name: `${customers[0].first_name ?? 'Test'} ${customers[0].last_name ?? 'User'}`,
366
+ address_1: '789 Multi Item St',
367
+ city: 'Multi City',
368
+ province: '',
369
+ postal_code: '22222',
370
+ country_code: 'mx',
371
+ phone: undefined,
372
+ },
373
+ payment_method_id: paymentMethodId,
374
+ }
375
+
376
+ const res = await client.createOrder(body)
377
+ expect(res.order.id).toBeTruthy()
378
+ expect(res.order.total).toBeGreaterThan(0)
379
+
380
+ createdOrderIds.push(res.order.id)
381
+ console.log(`Created multi-item order: ${res.order.display_id} — total: ${res.order.total}`)
382
+ })
383
+ })
384
+
385
+ // --------------------------------------------------------------------------
386
+ // Order Verification
387
+ // --------------------------------------------------------------------------
388
+
389
+ describe('Order verification', () => {
390
+ let products: GetDropshipperProductsResponse['products']
391
+ let customers: GetDropshipperCustomersResponse['customers']
392
+ let account: GetDropshipperAccountResponse['account']
393
+ let createdOrderId: string
394
+
395
+ beforeAll(async () => {
396
+ const [productsRes, customersRes, accountRes] = await Promise.all([
397
+ client.getProducts({ limit: 5 }),
398
+ client.getCustomers({ limit: 5 }),
399
+ client.getAccount(),
400
+ ])
401
+ products = productsRes.products
402
+ customers = customersRes.customers
403
+ account = accountRes.account
404
+
405
+ // Create a single order to verify
406
+ const variantId = (() => {
407
+ for (const product of products) {
408
+ if (product.variants && product.variants.length > 0) {
409
+ return product.variants[0].id
410
+ }
411
+ }
412
+ throw new Error('No products with variants found')
413
+ })()
414
+
415
+ const paymentMethodId = account.payment_method_configs?.find((c) => c.is_enabled)?.payment_provider_id
416
+ if (!paymentMethodId) throw new Error('No enabled payment method configs found')
417
+
418
+ const res = await client.createOrder({
419
+ customer_id: customers[0].id,
420
+ currency_code: account.currency_code.toLowerCase(),
421
+ items: [{ variant_id: variantId, quantity: 1 }],
422
+ shipping_address: {
423
+ full_name: `${customers[0].first_name ?? 'Test'} ${customers[0].last_name ?? 'User'}`,
424
+ address_1: '123 Verification St',
425
+ city: 'Verification City',
426
+ province: '',
427
+ postal_code: '33333',
428
+ country_code: 'mx',
429
+ phone: undefined,
430
+ },
431
+ payment_method_id: paymentMethodId,
432
+ })
433
+ createdOrderId = res.order.id
434
+ })
435
+
436
+ afterAll(async () => {
437
+ if (createdOrderId) {
438
+ await cancelOrder(createdOrderId)
439
+ }
440
+ })
441
+
442
+ it('retrieves the created order by ID', async () => {
443
+ const res = await client.getOrder(createdOrderId)
444
+ expect(res.order.id).toBe(createdOrderId)
445
+ expect(res.order.display_id).toBeGreaterThan(0)
446
+ expect(res.order.status).toBe('pending')
447
+ expect(res.order.totals).toBeDefined()
448
+ expect(res.order.totals.total).toBeGreaterThan(0)
449
+ console.log(
450
+ `Verified order ${res.order.display_id}: subtotal=${res.order.totals.subtotal}, total=${res.order.totals.total}, profit=${res.order.totals.profit}`,
451
+ )
452
+ })
453
+
454
+ it('includes the order in the orders list', async () => {
455
+ const res = await client.getOrders({ limit: 20 })
456
+ const found = res.orders.find((o) => o.id === createdOrderId)
457
+ expect(found).toBeDefined()
458
+ expect(found!.status).toBe('pending')
459
+ })
460
+
461
+ it('cancels the order successfully', async () => {
462
+ const res = await client.cancelOrder(createdOrderId)
463
+ expect(res.order.status).toBeDefined()
464
+
465
+ // Verify it's cancelled
466
+ const detail = await client.getOrder(createdOrderId)
467
+ expect(detail.order.status).toBe('canceled')
468
+ console.log(`Order ${createdOrderId} cancelled successfully`)
469
+ })
470
+ })
471
+
472
+ // --------------------------------------------------------------------------
473
+ // Error Handling
474
+ // --------------------------------------------------------------------------
475
+
476
+ describe('Error handling', () => {
477
+ let products: GetDropshipperProductsResponse['products']
478
+ let customers: GetDropshipperCustomersResponse['customers']
479
+ let account: GetDropshipperAccountResponse['account']
480
+
481
+ beforeAll(async () => {
482
+ const [productsRes, customersRes, accountRes] = await Promise.all([
483
+ client.getProducts({ limit: 5 }),
484
+ client.getCustomers({ limit: 5 }),
485
+ client.getAccount(),
486
+ ])
487
+ products = productsRes.products
488
+ customers = customersRes.customers
489
+ account = accountRes.account
490
+ })
491
+
492
+ it('rejects order creation with invalid variant ID', async () => {
493
+ const paymentMethodId = account.payment_method_configs?.find((c) => c.is_enabled)?.payment_provider_id
494
+ if (!paymentMethodId) throw new Error('No enabled payment method configs found')
495
+
496
+ await expect(
497
+ client.createOrder({
498
+ customer_id: customers[0].id,
499
+ currency_code: account.currency_code.toLowerCase(),
500
+ items: [{ variant_id: 'variant_does_not_exist_xyz', quantity: 1 }],
501
+ shipping_address: {
502
+ full_name: 'Test User',
503
+ address_1: '123 Test St',
504
+ city: 'Test City',
505
+ province: '',
506
+ postal_code: '00000',
507
+ country_code: 'mx',
508
+ },
509
+ payment_method_id: paymentMethodId,
510
+ }),
511
+ ).rejects.toThrow()
512
+ })
513
+
514
+ it('rejects order creation with empty items array', async () => {
515
+ const paymentMethodId = account.payment_method_configs?.find((c) => c.is_enabled)?.payment_provider_id
516
+ if (!paymentMethodId) throw new Error('No enabled payment method configs found')
517
+
518
+ await expect(
519
+ client.createOrder({
520
+ customer_id: customers[0].id,
521
+ currency_code: account.currency_code.toLowerCase(),
522
+ items: [],
523
+ shipping_address: {
524
+ full_name: 'Test User',
525
+ address_1: '123 Test St',
526
+ city: 'Test City',
527
+ province: '',
528
+ postal_code: '00000',
529
+ country_code: 'mx',
530
+ },
531
+ payment_method_id: paymentMethodId,
532
+ }),
533
+ ).rejects.toThrow()
534
+ })
535
+
536
+ it('rejects order creation with invalid customer ID', async () => {
537
+ const paymentMethodId = account.payment_method_configs?.find((c) => c.is_enabled)?.payment_provider_id
538
+ if (!paymentMethodId) throw new Error('No enabled payment method configs found')
539
+
540
+ const variantId = (() => {
541
+ for (const product of products) {
542
+ if (product.variants && product.variants.length > 0) {
543
+ return product.variants[0].id
544
+ }
545
+ }
546
+ throw new Error('No products with variants found')
547
+ })()
548
+
549
+ await expect(
550
+ client.createOrder({
551
+ customer_id: 'customer_does_not_exist_xyz',
552
+ currency_code: account.currency_code.toLowerCase(),
553
+ items: [{ variant_id: variantId, quantity: 1 }],
554
+ shipping_address: {
555
+ full_name: 'Test User',
556
+ address_1: '123 Test St',
557
+ city: 'Test City',
558
+ province: '',
559
+ postal_code: '00000',
560
+ country_code: 'mx',
561
+ },
562
+ payment_method_id: paymentMethodId,
563
+ }),
564
+ ).rejects.toThrow()
565
+ })
566
+ })
567
+
568
+ // --------------------------------------------------------------------------
569
+ // Shipping Options with Geozone Parameters
570
+ // --------------------------------------------------------------------------
571
+
572
+ describe('Shipping options with geozone parameters', () => {
573
+ let account: GetDropshipperAccountResponse['account']
574
+
575
+ beforeAll(async () => {
576
+ const res = await client.getAccount()
577
+ account = res.account
578
+ })
579
+
580
+ it('returns shipping options with currency_code only', async () => {
581
+ const res = await client.getOrderShippingOptions({
582
+ currency_code: account.currency_code,
583
+ })
584
+ expect(res.shipping_options).toBeInstanceOf(Array)
585
+ console.log(`Shipping options (currency only): ${res.shipping_options.length} found`)
586
+ if (res.shipping_options.length > 0) {
587
+ expect(res.shipping_options[0]).toHaveProperty('id')
588
+ expect(res.shipping_options[0]).toHaveProperty('name')
589
+ expect(res.shipping_options[0]).toHaveProperty('amount')
590
+ }
591
+ })
592
+
593
+ it('returns shipping options filtered by country_code', async () => {
594
+ const res = await client.getOrderShippingOptions({
595
+ currency_code: account.currency_code,
596
+ country_code: 'mx',
597
+ })
598
+ expect(res.shipping_options).toBeInstanceOf(Array)
599
+ console.log(`Shipping options (MX): ${res.shipping_options.length} found`)
600
+ })
601
+
602
+ it('returns shipping options filtered by country_code and province', async () => {
603
+ const res = await client.getOrderShippingOptions({
604
+ currency_code: account.currency_code,
605
+ country_code: 'mx',
606
+ province: 'Nuevo Leon',
607
+ })
608
+ expect(res.shipping_options).toBeInstanceOf(Array)
609
+ console.log(`Shipping options (MX/Nuevo Leon): ${res.shipping_options.length} found`)
610
+ })
611
+
612
+ it('returns shipping options filtered by country_code, province, and city', async () => {
613
+ const res = await client.getOrderShippingOptions({
614
+ currency_code: account.currency_code,
615
+ country_code: 'mx',
616
+ province: 'Nuevo Leon',
617
+ city: 'Monterrey',
618
+ })
619
+ expect(res.shipping_options).toBeInstanceOf(Array)
620
+ console.log(`Shipping options (MX/Nuevo Leon/Monterrey): ${res.shipping_options.length} found`)
621
+ })
622
+
623
+ it('returns different results for different countries (geozone differentiation)', async () => {
624
+ const [mxOptions, usOptions] = await Promise.all([
625
+ client.getOrderShippingOptions({
626
+ currency_code: account.currency_code,
627
+ country_code: 'mx',
628
+ }),
629
+ client.getOrderShippingOptions({
630
+ currency_code: account.currency_code,
631
+ country_code: 'us',
632
+ }),
633
+ ])
634
+
635
+ console.log(`MX options: ${mxOptions.shipping_options.length}, US options: ${usOptions.shipping_options.length}`)
636
+
637
+ // The options MAY differ by country — log the difference
638
+ const mxNames = mxOptions.shipping_options.map((o) => o.name).join(', ')
639
+ const usNames = usOptions.shipping_options.map((o) => o.name).join(', ')
640
+ console.log(`MX: [${mxNames}]`)
641
+ console.log(`US: [${usNames}]`)
642
+ })
643
+ })
644
+
645
+ // --------------------------------------------------------------------------
646
+ // Payment Methods
647
+ // --------------------------------------------------------------------------
648
+
649
+ describe('Payment methods from account', () => {
650
+ it('returns payment method configs from account', async () => {
651
+ const res = await client.getAccount()
652
+ expect(res.account.payment_method_configs).toBeInstanceOf(Array)
653
+
654
+ const configs = res.account.payment_method_configs!
655
+ console.log(`Payment method configs: ${configs.length} found`)
656
+
657
+ for (const config of configs) {
658
+ console.log(` - ${config.label} (${config.payment_provider_id}): collected_by=${config.collected_by}, enabled=${config.is_enabled}`)
659
+ expect(config).toHaveProperty('payment_provider_id')
660
+ expect(config).toHaveProperty('label')
661
+ expect(config).toHaveProperty('collected_by')
662
+ expect(config).toHaveProperty('is_enabled')
663
+ expect(['dropshipper', 'provider']).toContain(config.collected_by)
664
+ }
665
+
666
+ const enabled = configs.filter((c) => c.is_enabled)
667
+ expect(enabled.length).toBeGreaterThan(0)
668
+ console.log(`Enabled payment methods: ${enabled.length}`)
669
+ })
670
+
671
+ it('has at least one dropshipper-collected or provider-collected method', async () => {
672
+ const res = await client.getAccount()
673
+ const configs = res.account.payment_method_configs ?? []
674
+
675
+ const dropshipperMethods = configs.filter((c) => c.collected_by === 'dropshipper' && c.is_enabled)
676
+ const providerMethods = configs.filter((c) => c.collected_by === 'provider' && c.is_enabled)
677
+
678
+ console.log(`Dropshipper-collected enabled: ${dropshipperMethods.length}`)
679
+ console.log(`Provider-collected enabled: ${providerMethods.length}`)
680
+
681
+ // At least one type should be available
682
+ expect(dropshipperMethods.length + providerMethods.length).toBeGreaterThan(0)
683
+ })
684
+ })
685
+ }