@ar-agents/mercadopago 0.15.3 → 0.16.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.
- package/CHANGELOG.md +24 -0
- package/README.md +1 -0
- package/cookbook/10-cross-package-billing.ts +172 -0
- package/cookbook/11-dunning-sequence.ts +305 -0
- package/cookbook/12-reconciliation-pipeline.ts +277 -0
- package/cookbook/README.md +3 -0
- package/dist/index.d.cts +4 -1084
- package/dist/index.d.ts +4 -1084
- package/dist/testing.cjs +281 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +188 -0
- package/dist/testing.d.ts +188 -0
- package/dist/testing.js +270 -0
- package/dist/testing.js.map +1 -0
- package/dist/types-BaOjfcOt.d.cts +1085 -0
- package/dist/types-BaOjfcOt.d.ts +1085 -0
- package/package.json +14 -1
- package/tools.manifest.json +1 -1
package/dist/testing.cjs
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/testing.ts
|
|
4
|
+
var counter = 0;
|
|
5
|
+
var nextId = () => `mock-${++counter}`;
|
|
6
|
+
function mockPayment(overrides = {}) {
|
|
7
|
+
return {
|
|
8
|
+
id: nextId(),
|
|
9
|
+
status: "approved",
|
|
10
|
+
status_detail: "accredited",
|
|
11
|
+
transaction_amount: 1e3,
|
|
12
|
+
currency_id: "ARS",
|
|
13
|
+
date_created: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14
|
+
date_approved: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15
|
+
external_reference: `mock-ref-${counter}`,
|
|
16
|
+
description: "Mock payment",
|
|
17
|
+
payment_method_id: "visa",
|
|
18
|
+
payment_type_id: "credit_card",
|
|
19
|
+
payer: {
|
|
20
|
+
id: nextId(),
|
|
21
|
+
email: "buyer@example.com"
|
|
22
|
+
},
|
|
23
|
+
...overrides
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function mockPreapproval(overrides = {}) {
|
|
27
|
+
return {
|
|
28
|
+
id: nextId(),
|
|
29
|
+
status: "authorized",
|
|
30
|
+
payer_id: 12345,
|
|
31
|
+
payer_email: "buyer@example.com",
|
|
32
|
+
init_point: `https://www.mercadopago.com.ar/subscriptions/checkout?preapproval_id=${nextId()}`,
|
|
33
|
+
reason: "Mock subscription",
|
|
34
|
+
external_reference: `mock-sub-${counter}`,
|
|
35
|
+
date_created: (/* @__PURE__ */ new Date()).toISOString(),
|
|
36
|
+
auto_recurring: {
|
|
37
|
+
frequency: 1,
|
|
38
|
+
frequency_type: "months",
|
|
39
|
+
transaction_amount: 1e3,
|
|
40
|
+
currency_id: "ARS"
|
|
41
|
+
},
|
|
42
|
+
...overrides
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function mockSubscriptionPayment(overrides = {}) {
|
|
46
|
+
return {
|
|
47
|
+
id: nextId(),
|
|
48
|
+
preapproval_id: nextId(),
|
|
49
|
+
status: "approved",
|
|
50
|
+
payment_id: nextId(),
|
|
51
|
+
transaction_amount: 1e3,
|
|
52
|
+
currency_id: "ARS",
|
|
53
|
+
date_created: (/* @__PURE__ */ new Date()).toISOString(),
|
|
54
|
+
debit_date: (/* @__PURE__ */ new Date()).toISOString(),
|
|
55
|
+
retry_attempt: 0,
|
|
56
|
+
next_retry_date: null,
|
|
57
|
+
...overrides
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function mockPreference(overrides = {}) {
|
|
61
|
+
const id = nextId();
|
|
62
|
+
return {
|
|
63
|
+
id,
|
|
64
|
+
init_point: `https://www.mercadopago.com.ar/checkout/v1/redirect?pref_id=${id}`,
|
|
65
|
+
sandbox_init_point: `https://sandbox.mercadopago.com.ar/checkout/v1/redirect?pref_id=${id}`,
|
|
66
|
+
items: [
|
|
67
|
+
{
|
|
68
|
+
id: "item-1",
|
|
69
|
+
title: "Mock item",
|
|
70
|
+
quantity: 1,
|
|
71
|
+
unit_price: 1e3,
|
|
72
|
+
currency_id: "ARS"
|
|
73
|
+
}
|
|
74
|
+
],
|
|
75
|
+
external_reference: `mock-pref-${counter}`,
|
|
76
|
+
date_created: (/* @__PURE__ */ new Date()).toISOString(),
|
|
77
|
+
...overrides
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function mockRefund(overrides = {}) {
|
|
81
|
+
return {
|
|
82
|
+
id: nextId(),
|
|
83
|
+
payment_id: nextId(),
|
|
84
|
+
amount: 1e3,
|
|
85
|
+
source: { id: nextId(), name: "Mock Source", type: "test" },
|
|
86
|
+
date_created: (/* @__PURE__ */ new Date()).toISOString(),
|
|
87
|
+
status: "approved",
|
|
88
|
+
...overrides
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function mockCustomer(overrides = {}) {
|
|
92
|
+
return {
|
|
93
|
+
id: nextId(),
|
|
94
|
+
email: "buyer@example.com",
|
|
95
|
+
first_name: "Test",
|
|
96
|
+
last_name: "Buyer",
|
|
97
|
+
date_created: (/* @__PURE__ */ new Date()).toISOString(),
|
|
98
|
+
...overrides
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function mockWebhookHeaders(args = {}) {
|
|
102
|
+
const topic = args.topic ?? "payment";
|
|
103
|
+
const dataId = args.dataId ?? nextId();
|
|
104
|
+
const requestId = args.requestId ?? nextId();
|
|
105
|
+
const headers = new Headers({
|
|
106
|
+
"x-request-id": requestId,
|
|
107
|
+
"content-type": "application/json"
|
|
108
|
+
});
|
|
109
|
+
const searchParams = new URLSearchParams({
|
|
110
|
+
topic,
|
|
111
|
+
"data.id": dataId
|
|
112
|
+
});
|
|
113
|
+
const body = JSON.stringify({
|
|
114
|
+
action: "payment.created",
|
|
115
|
+
api_version: "v1",
|
|
116
|
+
data: { id: dataId },
|
|
117
|
+
type: topic,
|
|
118
|
+
user_id: 12345,
|
|
119
|
+
live_mode: false
|
|
120
|
+
});
|
|
121
|
+
return { headers, searchParams, body };
|
|
122
|
+
}
|
|
123
|
+
async function mockSignedWebhook(args) {
|
|
124
|
+
const base = mockWebhookHeaders(args);
|
|
125
|
+
const dataId = base.searchParams.get("data.id");
|
|
126
|
+
const requestId = base.headers.get("x-request-id");
|
|
127
|
+
const ts = args.ts ?? Math.floor(Date.now() / 1e3);
|
|
128
|
+
const manifest = `id:${dataId};request-id:${requestId};ts:${ts};`;
|
|
129
|
+
const enc = new TextEncoder();
|
|
130
|
+
const key = await crypto.subtle.importKey(
|
|
131
|
+
"raw",
|
|
132
|
+
enc.encode(args.secret),
|
|
133
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
134
|
+
false,
|
|
135
|
+
["sign"]
|
|
136
|
+
);
|
|
137
|
+
const sigBytes = await crypto.subtle.sign("HMAC", key, enc.encode(manifest));
|
|
138
|
+
const v1 = Array.from(new Uint8Array(sigBytes)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
139
|
+
base.headers.set("x-signature", `ts=${ts},v1=${v1}`);
|
|
140
|
+
return base;
|
|
141
|
+
}
|
|
142
|
+
var MockNotImplementedError = class extends Error {
|
|
143
|
+
constructor(method) {
|
|
144
|
+
super(
|
|
145
|
+
`MockMercadoPagoClient.${method} is not implemented. Use MSW or a real sandbox token if your test exercises this path.`
|
|
146
|
+
);
|
|
147
|
+
this.name = "MockNotImplementedError";
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
var MockMercadoPagoClient = class {
|
|
151
|
+
payments = /* @__PURE__ */ new Map();
|
|
152
|
+
preapprovals = /* @__PURE__ */ new Map();
|
|
153
|
+
preferences = /* @__PURE__ */ new Map();
|
|
154
|
+
refunds = /* @__PURE__ */ new Map();
|
|
155
|
+
customers = /* @__PURE__ */ new Map();
|
|
156
|
+
/** Seed the in-memory store. */
|
|
157
|
+
seed = {
|
|
158
|
+
payments: (xs) => {
|
|
159
|
+
for (const p of xs) this.payments.set(String(p.id), p);
|
|
160
|
+
},
|
|
161
|
+
preapprovals: (xs) => {
|
|
162
|
+
for (const x of xs) this.preapprovals.set(x.id, x);
|
|
163
|
+
},
|
|
164
|
+
preferences: (xs) => {
|
|
165
|
+
for (const x of xs) this.preferences.set(x.id, x);
|
|
166
|
+
},
|
|
167
|
+
refunds: (xs) => {
|
|
168
|
+
for (const r of xs) this.refunds.set(String(r.id), r);
|
|
169
|
+
},
|
|
170
|
+
customers: (xs) => {
|
|
171
|
+
for (const c of xs) this.customers.set(c.id, c);
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
// Payment methods
|
|
175
|
+
async getPayment(id) {
|
|
176
|
+
const p = this.payments.get(id);
|
|
177
|
+
if (!p) throw new Error(`Payment not found: ${id}`);
|
|
178
|
+
return p;
|
|
179
|
+
}
|
|
180
|
+
async createPayment(params) {
|
|
181
|
+
const p = mockPayment(params);
|
|
182
|
+
this.payments.set(String(p.id), p);
|
|
183
|
+
return p;
|
|
184
|
+
}
|
|
185
|
+
async searchPayments(filter = {}) {
|
|
186
|
+
const all = Array.from(this.payments.values());
|
|
187
|
+
const filtered = all.filter((p) => {
|
|
188
|
+
if (filter.status && p.status !== filter.status) return false;
|
|
189
|
+
if (filter.externalReference && p.external_reference !== filter.externalReference)
|
|
190
|
+
return false;
|
|
191
|
+
return true;
|
|
192
|
+
});
|
|
193
|
+
return {
|
|
194
|
+
paging: { total: filtered.length, limit: 30, offset: 0 },
|
|
195
|
+
results: filtered
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
async cancelPayment(id) {
|
|
199
|
+
const p = await this.getPayment(id);
|
|
200
|
+
const updated = { ...p, status: "cancelled" };
|
|
201
|
+
this.payments.set(id, updated);
|
|
202
|
+
return updated;
|
|
203
|
+
}
|
|
204
|
+
// Preapproval methods
|
|
205
|
+
async getPreapproval(id) {
|
|
206
|
+
const sub = this.preapprovals.get(id);
|
|
207
|
+
if (!sub) throw new Error(`Preapproval not found: ${id}`);
|
|
208
|
+
return sub;
|
|
209
|
+
}
|
|
210
|
+
async createPreapproval(params) {
|
|
211
|
+
const sub = mockPreapproval(params);
|
|
212
|
+
this.preapprovals.set(sub.id, sub);
|
|
213
|
+
return sub;
|
|
214
|
+
}
|
|
215
|
+
async cancelPreapproval(id) {
|
|
216
|
+
const sub = await this.getPreapproval(id);
|
|
217
|
+
const updated = { ...sub, status: "cancelled" };
|
|
218
|
+
this.preapprovals.set(id, updated);
|
|
219
|
+
return updated;
|
|
220
|
+
}
|
|
221
|
+
async pausePreapproval(id) {
|
|
222
|
+
const sub = await this.getPreapproval(id);
|
|
223
|
+
const updated = { ...sub, status: "paused" };
|
|
224
|
+
this.preapprovals.set(id, updated);
|
|
225
|
+
return updated;
|
|
226
|
+
}
|
|
227
|
+
async resumePreapproval(id) {
|
|
228
|
+
const sub = await this.getPreapproval(id);
|
|
229
|
+
const updated = { ...sub, status: "authorized" };
|
|
230
|
+
this.preapprovals.set(id, updated);
|
|
231
|
+
return updated;
|
|
232
|
+
}
|
|
233
|
+
// Refund
|
|
234
|
+
async createRefund(params) {
|
|
235
|
+
const refund = mockRefund({
|
|
236
|
+
payment_id: params.payment_id,
|
|
237
|
+
amount: params.amount ?? 1e3
|
|
238
|
+
});
|
|
239
|
+
this.refunds.set(String(refund.id), refund);
|
|
240
|
+
const payment = this.payments.get(params.payment_id);
|
|
241
|
+
if (payment) {
|
|
242
|
+
this.payments.set(params.payment_id, { ...payment, status: "refunded" });
|
|
243
|
+
}
|
|
244
|
+
return refund;
|
|
245
|
+
}
|
|
246
|
+
// Customer
|
|
247
|
+
async getCustomer(id) {
|
|
248
|
+
const c = this.customers.get(id);
|
|
249
|
+
if (!c) throw new Error(`Customer not found: ${id}`);
|
|
250
|
+
return c;
|
|
251
|
+
}
|
|
252
|
+
async createCustomer(params) {
|
|
253
|
+
const c = mockCustomer(params);
|
|
254
|
+
this.customers.set(c.id, c);
|
|
255
|
+
return c;
|
|
256
|
+
}
|
|
257
|
+
// Preference
|
|
258
|
+
async getPreference(id) {
|
|
259
|
+
const pref = this.preferences.get(id);
|
|
260
|
+
if (!pref) throw new Error(`Preference not found: ${id}`);
|
|
261
|
+
return pref;
|
|
262
|
+
}
|
|
263
|
+
async createPreference(params) {
|
|
264
|
+
const pref = mockPreference(params);
|
|
265
|
+
this.preferences.set(pref.id, pref);
|
|
266
|
+
return pref;
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
exports.MockMercadoPagoClient = MockMercadoPagoClient;
|
|
271
|
+
exports.MockNotImplementedError = MockNotImplementedError;
|
|
272
|
+
exports.mockCustomer = mockCustomer;
|
|
273
|
+
exports.mockPayment = mockPayment;
|
|
274
|
+
exports.mockPreapproval = mockPreapproval;
|
|
275
|
+
exports.mockPreference = mockPreference;
|
|
276
|
+
exports.mockRefund = mockRefund;
|
|
277
|
+
exports.mockSignedWebhook = mockSignedWebhook;
|
|
278
|
+
exports.mockSubscriptionPayment = mockSubscriptionPayment;
|
|
279
|
+
exports.mockWebhookHeaders = mockWebhookHeaders;
|
|
280
|
+
//# sourceMappingURL=testing.cjs.map
|
|
281
|
+
//# sourceMappingURL=testing.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/testing.ts"],"names":[],"mappings":"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","file":"testing.cjs","sourcesContent":["/**\n * `@ar-agents/mercadopago/testing` — fixtures and a mock client for tests.\n *\n * What you get:\n *\n * - **Factories** for every shape a user-side test will need: `mockPayment`,\n * `mockPreapproval`, `mockSubscriptionPayment`, `mockPreference`,\n * `mockRefund`, `mockCustomer`, `mockWebhookHeaders`. Each accepts a\n * partial `overrides` object so you only spell the fields your test\n * actually cares about.\n *\n * - **`MockMercadoPagoClient`** — a class with the same surface as\n * `MercadoPagoClient` but backed by an in-memory store. No network. Its\n * mutations (createPayment, createPreapproval, etc.) update the store\n * so a test can do create-then-get without staging fixtures twice.\n * Read-only methods that don't fit a clean store model (search filters,\n * pagination edge cases) throw `MockNotImplementedError` — by design,\n * so you notice when a test wanders into territory that needs MSW or a\n * real sandbox token.\n *\n * - **`mockSignedWebhook`** — produces a `{ body, headers, searchParams }`\n * bundle whose `x-signature` passes `verifyWebhookSignature` against the\n * same secret. Test the full webhook stack end-to-end without hand-rolling\n * the HMAC.\n *\n * Why a subpath: the testing helpers are dev-time only and would bloat the\n * production bundle if exported from the main entry. Imports compile away\n * cleanly when bundlers tree-shake.\n *\n * @example\n * ```ts\n * import { MockMercadoPagoClient, mockPayment, mockSignedWebhook } from \"@ar-agents/mercadopago/testing\";\n *\n * test(\"approves and stores a payment\", async () => {\n * const mp = new MockMercadoPagoClient();\n * mp.seed.payments([mockPayment({ status: \"approved\", transaction_amount: 1000 })]);\n * const got = await mp.searchPayments({ status: \"approved\" });\n * expect(got.results).toHaveLength(1);\n * });\n *\n * test(\"end-to-end webhook with a verified signature\", async () => {\n * const { body, headers, searchParams } = await mockSignedWebhook({\n * topic: \"payment\",\n * dataId: \"123\",\n * secret: \"test-secret\",\n * });\n * const ok = await verifyWebhookSignature({\n * requestId: headers.get(\"x-request-id\"),\n * dataId: \"123\",\n * signatureHeader: headers.get(\"x-signature\"),\n * secret: \"test-secret\",\n * });\n * expect(ok).toBe(true);\n * });\n * ```\n */\n\nimport type {\n Payment,\n Preapproval,\n SubscriptionPayment,\n Preference,\n Refund,\n Customer,\n} from \"./types\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Factories\n// ─────────────────────────────────────────────────────────────────────────────\n\nlet counter = 0;\nconst nextId = () => `mock-${++counter}`;\n\n/** Build a Payment fixture. Sensible defaults for the most common scenario\n * (an approved $1000 ARS sale with an external_reference). */\nexport function mockPayment(overrides: Partial<Payment> = {}): Payment {\n return {\n id: nextId(),\n status: \"approved\",\n status_detail: \"accredited\",\n transaction_amount: 1000,\n currency_id: \"ARS\",\n date_created: new Date().toISOString(),\n date_approved: new Date().toISOString(),\n external_reference: `mock-ref-${counter}`,\n description: \"Mock payment\",\n payment_method_id: \"visa\",\n payment_type_id: \"credit_card\",\n payer: {\n id: nextId(),\n email: \"buyer@example.com\",\n },\n ...overrides,\n } as Payment;\n}\n\n/** Build a Preapproval (recurring subscription) fixture. */\nexport function mockPreapproval(overrides: Partial<Preapproval> = {}): Preapproval {\n return {\n id: nextId(),\n status: \"authorized\",\n payer_id: 12345,\n payer_email: \"buyer@example.com\",\n init_point: `https://www.mercadopago.com.ar/subscriptions/checkout?preapproval_id=${nextId()}`,\n reason: \"Mock subscription\",\n external_reference: `mock-sub-${counter}`,\n date_created: new Date().toISOString(),\n auto_recurring: {\n frequency: 1,\n frequency_type: \"months\",\n transaction_amount: 1000,\n currency_id: \"ARS\",\n },\n ...overrides,\n } as Preapproval;\n}\n\n/** Build a SubscriptionPayment (single recurring-charge attempt) fixture. */\nexport function mockSubscriptionPayment(\n overrides: Partial<SubscriptionPayment> = {},\n): SubscriptionPayment {\n return {\n id: nextId(),\n preapproval_id: nextId(),\n status: \"approved\",\n payment_id: nextId(),\n transaction_amount: 1000,\n currency_id: \"ARS\",\n date_created: new Date().toISOString(),\n debit_date: new Date().toISOString(),\n retry_attempt: 0,\n next_retry_date: null,\n ...overrides,\n } as SubscriptionPayment;\n}\n\n/** Build a Preference (Checkout Pro) fixture. */\nexport function mockPreference(overrides: Partial<Preference> = {}): Preference {\n const id = nextId();\n return {\n id,\n init_point: `https://www.mercadopago.com.ar/checkout/v1/redirect?pref_id=${id}`,\n sandbox_init_point: `https://sandbox.mercadopago.com.ar/checkout/v1/redirect?pref_id=${id}`,\n items: [\n {\n id: \"item-1\",\n title: \"Mock item\",\n quantity: 1,\n unit_price: 1000,\n currency_id: \"ARS\",\n },\n ],\n external_reference: `mock-pref-${counter}`,\n date_created: new Date().toISOString(),\n ...overrides,\n } as Preference;\n}\n\n/** Build a Refund fixture. */\nexport function mockRefund(overrides: Partial<Refund> = {}): Refund {\n return {\n id: nextId(),\n payment_id: nextId(),\n amount: 1000,\n source: { id: nextId(), name: \"Mock Source\", type: \"test\" },\n date_created: new Date().toISOString(),\n status: \"approved\",\n ...overrides,\n } as Refund;\n}\n\n/** Build a Customer fixture. */\nexport function mockCustomer(overrides: Partial<Customer> = {}): Customer {\n return {\n id: nextId(),\n email: \"buyer@example.com\",\n first_name: \"Test\",\n last_name: \"Buyer\",\n date_created: new Date().toISOString(),\n ...overrides,\n } as Customer;\n}\n\n/** Build a `webhookHeaders + searchParams + body` triple for a `payment.created`\n * topic. Use directly when you don't need a verified signature. */\nexport function mockWebhookHeaders(args: {\n topic?: string;\n dataId?: string;\n requestId?: string;\n} = {}): { headers: Headers; searchParams: URLSearchParams; body: string } {\n const topic = args.topic ?? \"payment\";\n const dataId = args.dataId ?? nextId();\n const requestId = args.requestId ?? nextId();\n const headers = new Headers({\n \"x-request-id\": requestId,\n \"content-type\": \"application/json\",\n });\n const searchParams = new URLSearchParams({\n topic,\n \"data.id\": dataId,\n });\n const body = JSON.stringify({\n action: \"payment.created\",\n api_version: \"v1\",\n data: { id: dataId },\n type: topic,\n user_id: 12345,\n live_mode: false,\n });\n return { headers, searchParams, body };\n}\n\n/**\n * Like `mockWebhookHeaders`, but also computes a real HMAC-SHA256 signature\n * against `secret` so `verifyWebhookSignature` accepts it. Use this in tests\n * for the full webhook handler stack.\n */\nexport async function mockSignedWebhook(args: {\n topic?: string;\n dataId?: string;\n requestId?: string;\n secret: string;\n ts?: number; // override for replay-window tests\n}): Promise<{ headers: Headers; searchParams: URLSearchParams; body: string }> {\n const base = mockWebhookHeaders(args);\n const dataId = base.searchParams.get(\"data.id\")!;\n const requestId = base.headers.get(\"x-request-id\")!;\n const ts = args.ts ?? Math.floor(Date.now() / 1000);\n const manifest = `id:${dataId};request-id:${requestId};ts:${ts};`;\n\n const enc = new TextEncoder();\n const key = await crypto.subtle.importKey(\n \"raw\",\n enc.encode(args.secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"],\n );\n const sigBytes = await crypto.subtle.sign(\"HMAC\", key, enc.encode(manifest));\n const v1 = Array.from(new Uint8Array(sigBytes))\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n\n base.headers.set(\"x-signature\", `ts=${ts},v1=${v1}`);\n return base;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// MockMercadoPagoClient\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Thrown when a mock client method has no in-memory implementation. By design:\n * if your test relied on the missing path, switch to MSW or a real sandbox\n * token rather than expanding the mock surface ad-hoc.\n */\nexport class MockNotImplementedError extends Error {\n constructor(method: string) {\n super(\n `MockMercadoPagoClient.${method} is not implemented. Use MSW or a real ` +\n `sandbox token if your test exercises this path.`,\n );\n this.name = \"MockNotImplementedError\";\n }\n}\n\n/**\n * In-memory client. Implements the most-commonly-needed read + write paths.\n * Tests that need long-tail behaviour (search by complex filters, error\n * injection) should reach for MSW.\n */\nexport class MockMercadoPagoClient {\n private payments = new Map<string, Payment>();\n private preapprovals = new Map<string, Preapproval>();\n private preferences = new Map<string, Preference>();\n private refunds = new Map<string, Refund>();\n private customers = new Map<string, Customer>();\n\n /** Seed the in-memory store. */\n seed = {\n payments: (xs: Payment[]) => {\n for (const p of xs) this.payments.set(String(p.id), p);\n },\n preapprovals: (xs: Preapproval[]) => {\n for (const x of xs) this.preapprovals.set(x.id, x);\n },\n preferences: (xs: Preference[]) => {\n for (const x of xs) this.preferences.set(x.id, x);\n },\n refunds: (xs: Refund[]) => {\n for (const r of xs) this.refunds.set(String(r.id), r);\n },\n customers: (xs: Customer[]) => {\n for (const c of xs) this.customers.set(c.id, c);\n },\n };\n\n // Payment methods\n async getPayment(id: string): Promise<Payment> {\n const p = this.payments.get(id);\n if (!p) throw new Error(`Payment not found: ${id}`);\n return p;\n }\n\n async createPayment(params: Partial<Payment>): Promise<Payment> {\n const p = mockPayment(params);\n this.payments.set(String(p.id), p);\n return p;\n }\n\n async searchPayments(filter: { status?: string; externalReference?: string } = {}) {\n const all = Array.from(this.payments.values());\n const filtered = all.filter((p) => {\n if (filter.status && p.status !== filter.status) return false;\n if (\n filter.externalReference &&\n p.external_reference !== filter.externalReference\n )\n return false;\n return true;\n });\n return {\n paging: { total: filtered.length, limit: 30, offset: 0 },\n results: filtered,\n };\n }\n\n async cancelPayment(id: string): Promise<Payment> {\n const p = await this.getPayment(id);\n const updated = { ...p, status: \"cancelled\" as const };\n this.payments.set(id, updated);\n return updated;\n }\n\n // Preapproval methods\n async getPreapproval(id: string): Promise<Preapproval> {\n const sub = this.preapprovals.get(id);\n if (!sub) throw new Error(`Preapproval not found: ${id}`);\n return sub;\n }\n\n async createPreapproval(params: Partial<Preapproval>): Promise<Preapproval> {\n const sub = mockPreapproval(params);\n this.preapprovals.set(sub.id, sub);\n return sub;\n }\n\n async cancelPreapproval(id: string): Promise<Preapproval> {\n const sub = await this.getPreapproval(id);\n const updated = { ...sub, status: \"cancelled\" as const };\n this.preapprovals.set(id, updated);\n return updated;\n }\n\n async pausePreapproval(id: string): Promise<Preapproval> {\n const sub = await this.getPreapproval(id);\n const updated = { ...sub, status: \"paused\" as const };\n this.preapprovals.set(id, updated);\n return updated;\n }\n\n async resumePreapproval(id: string): Promise<Preapproval> {\n const sub = await this.getPreapproval(id);\n const updated = { ...sub, status: \"authorized\" as const };\n this.preapprovals.set(id, updated);\n return updated;\n }\n\n // Refund\n async createRefund(params: { payment_id: string; amount?: number }): Promise<Refund> {\n const refund = mockRefund({\n payment_id: params.payment_id,\n amount: params.amount ?? 1000,\n });\n this.refunds.set(String(refund.id), refund);\n // Mark the payment as refunded.\n const payment = this.payments.get(params.payment_id);\n if (payment) {\n this.payments.set(params.payment_id, { ...payment, status: \"refunded\" });\n }\n return refund;\n }\n\n // Customer\n async getCustomer(id: string): Promise<Customer> {\n const c = this.customers.get(id);\n if (!c) throw new Error(`Customer not found: ${id}`);\n return c;\n }\n\n async createCustomer(params: Partial<Customer>): Promise<Customer> {\n const c = mockCustomer(params);\n this.customers.set(c.id, c);\n return c;\n }\n\n // Preference\n async getPreference(id: string): Promise<Preference> {\n const pref = this.preferences.get(id);\n if (!pref) throw new Error(`Preference not found: ${id}`);\n return pref;\n }\n\n async createPreference(params: Partial<Preference>): Promise<Preference> {\n const pref = mockPreference(params);\n this.preferences.set(pref.id, pref);\n return pref;\n }\n\n // Catch-all for unimplemented surface — tests can still construct the client\n // and only fail on the method they actually need that's missing.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: any;\n}\n"]}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { b as Payment, P as Preapproval, f as Preference, R as Refund, h as Customer, p as SubscriptionPayment } from './types-BaOjfcOt.cjs';
|
|
2
|
+
import 'zod';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* `@ar-agents/mercadopago/testing` — fixtures and a mock client for tests.
|
|
6
|
+
*
|
|
7
|
+
* What you get:
|
|
8
|
+
*
|
|
9
|
+
* - **Factories** for every shape a user-side test will need: `mockPayment`,
|
|
10
|
+
* `mockPreapproval`, `mockSubscriptionPayment`, `mockPreference`,
|
|
11
|
+
* `mockRefund`, `mockCustomer`, `mockWebhookHeaders`. Each accepts a
|
|
12
|
+
* partial `overrides` object so you only spell the fields your test
|
|
13
|
+
* actually cares about.
|
|
14
|
+
*
|
|
15
|
+
* - **`MockMercadoPagoClient`** — a class with the same surface as
|
|
16
|
+
* `MercadoPagoClient` but backed by an in-memory store. No network. Its
|
|
17
|
+
* mutations (createPayment, createPreapproval, etc.) update the store
|
|
18
|
+
* so a test can do create-then-get without staging fixtures twice.
|
|
19
|
+
* Read-only methods that don't fit a clean store model (search filters,
|
|
20
|
+
* pagination edge cases) throw `MockNotImplementedError` — by design,
|
|
21
|
+
* so you notice when a test wanders into territory that needs MSW or a
|
|
22
|
+
* real sandbox token.
|
|
23
|
+
*
|
|
24
|
+
* - **`mockSignedWebhook`** — produces a `{ body, headers, searchParams }`
|
|
25
|
+
* bundle whose `x-signature` passes `verifyWebhookSignature` against the
|
|
26
|
+
* same secret. Test the full webhook stack end-to-end without hand-rolling
|
|
27
|
+
* the HMAC.
|
|
28
|
+
*
|
|
29
|
+
* Why a subpath: the testing helpers are dev-time only and would bloat the
|
|
30
|
+
* production bundle if exported from the main entry. Imports compile away
|
|
31
|
+
* cleanly when bundlers tree-shake.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* import { MockMercadoPagoClient, mockPayment, mockSignedWebhook } from "@ar-agents/mercadopago/testing";
|
|
36
|
+
*
|
|
37
|
+
* test("approves and stores a payment", async () => {
|
|
38
|
+
* const mp = new MockMercadoPagoClient();
|
|
39
|
+
* mp.seed.payments([mockPayment({ status: "approved", transaction_amount: 1000 })]);
|
|
40
|
+
* const got = await mp.searchPayments({ status: "approved" });
|
|
41
|
+
* expect(got.results).toHaveLength(1);
|
|
42
|
+
* });
|
|
43
|
+
*
|
|
44
|
+
* test("end-to-end webhook with a verified signature", async () => {
|
|
45
|
+
* const { body, headers, searchParams } = await mockSignedWebhook({
|
|
46
|
+
* topic: "payment",
|
|
47
|
+
* dataId: "123",
|
|
48
|
+
* secret: "test-secret",
|
|
49
|
+
* });
|
|
50
|
+
* const ok = await verifyWebhookSignature({
|
|
51
|
+
* requestId: headers.get("x-request-id"),
|
|
52
|
+
* dataId: "123",
|
|
53
|
+
* signatureHeader: headers.get("x-signature"),
|
|
54
|
+
* secret: "test-secret",
|
|
55
|
+
* });
|
|
56
|
+
* expect(ok).toBe(true);
|
|
57
|
+
* });
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
|
|
61
|
+
/** Build a Payment fixture. Sensible defaults for the most common scenario
|
|
62
|
+
* (an approved $1000 ARS sale with an external_reference). */
|
|
63
|
+
declare function mockPayment(overrides?: Partial<Payment>): Payment;
|
|
64
|
+
/** Build a Preapproval (recurring subscription) fixture. */
|
|
65
|
+
declare function mockPreapproval(overrides?: Partial<Preapproval>): Preapproval;
|
|
66
|
+
/** Build a SubscriptionPayment (single recurring-charge attempt) fixture. */
|
|
67
|
+
declare function mockSubscriptionPayment(overrides?: Partial<SubscriptionPayment>): SubscriptionPayment;
|
|
68
|
+
/** Build a Preference (Checkout Pro) fixture. */
|
|
69
|
+
declare function mockPreference(overrides?: Partial<Preference>): Preference;
|
|
70
|
+
/** Build a Refund fixture. */
|
|
71
|
+
declare function mockRefund(overrides?: Partial<Refund>): Refund;
|
|
72
|
+
/** Build a Customer fixture. */
|
|
73
|
+
declare function mockCustomer(overrides?: Partial<Customer>): Customer;
|
|
74
|
+
/** Build a `webhookHeaders + searchParams + body` triple for a `payment.created`
|
|
75
|
+
* topic. Use directly when you don't need a verified signature. */
|
|
76
|
+
declare function mockWebhookHeaders(args?: {
|
|
77
|
+
topic?: string;
|
|
78
|
+
dataId?: string;
|
|
79
|
+
requestId?: string;
|
|
80
|
+
}): {
|
|
81
|
+
headers: Headers;
|
|
82
|
+
searchParams: URLSearchParams;
|
|
83
|
+
body: string;
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Like `mockWebhookHeaders`, but also computes a real HMAC-SHA256 signature
|
|
87
|
+
* against `secret` so `verifyWebhookSignature` accepts it. Use this in tests
|
|
88
|
+
* for the full webhook handler stack.
|
|
89
|
+
*/
|
|
90
|
+
declare function mockSignedWebhook(args: {
|
|
91
|
+
topic?: string;
|
|
92
|
+
dataId?: string;
|
|
93
|
+
requestId?: string;
|
|
94
|
+
secret: string;
|
|
95
|
+
ts?: number;
|
|
96
|
+
}): Promise<{
|
|
97
|
+
headers: Headers;
|
|
98
|
+
searchParams: URLSearchParams;
|
|
99
|
+
body: string;
|
|
100
|
+
}>;
|
|
101
|
+
/**
|
|
102
|
+
* Thrown when a mock client method has no in-memory implementation. By design:
|
|
103
|
+
* if your test relied on the missing path, switch to MSW or a real sandbox
|
|
104
|
+
* token rather than expanding the mock surface ad-hoc.
|
|
105
|
+
*/
|
|
106
|
+
declare class MockNotImplementedError extends Error {
|
|
107
|
+
constructor(method: string);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* In-memory client. Implements the most-commonly-needed read + write paths.
|
|
111
|
+
* Tests that need long-tail behaviour (search by complex filters, error
|
|
112
|
+
* injection) should reach for MSW.
|
|
113
|
+
*/
|
|
114
|
+
declare class MockMercadoPagoClient {
|
|
115
|
+
private payments;
|
|
116
|
+
private preapprovals;
|
|
117
|
+
private preferences;
|
|
118
|
+
private refunds;
|
|
119
|
+
private customers;
|
|
120
|
+
/** Seed the in-memory store. */
|
|
121
|
+
seed: {
|
|
122
|
+
payments: (xs: Payment[]) => void;
|
|
123
|
+
preapprovals: (xs: Preapproval[]) => void;
|
|
124
|
+
preferences: (xs: Preference[]) => void;
|
|
125
|
+
refunds: (xs: Refund[]) => void;
|
|
126
|
+
customers: (xs: Customer[]) => void;
|
|
127
|
+
};
|
|
128
|
+
getPayment(id: string): Promise<Payment>;
|
|
129
|
+
createPayment(params: Partial<Payment>): Promise<Payment>;
|
|
130
|
+
searchPayments(filter?: {
|
|
131
|
+
status?: string;
|
|
132
|
+
externalReference?: string;
|
|
133
|
+
}): Promise<{
|
|
134
|
+
paging: {
|
|
135
|
+
total: number;
|
|
136
|
+
limit: number;
|
|
137
|
+
offset: number;
|
|
138
|
+
};
|
|
139
|
+
results: {
|
|
140
|
+
[x: string]: unknown;
|
|
141
|
+
id: string;
|
|
142
|
+
status: string;
|
|
143
|
+
transaction_amount: number;
|
|
144
|
+
currency_id: string;
|
|
145
|
+
status_detail?: string | null | undefined;
|
|
146
|
+
date_created?: string | null | undefined;
|
|
147
|
+
date_approved?: string | null | undefined;
|
|
148
|
+
date_last_updated?: string | null | undefined;
|
|
149
|
+
installments?: number | null | undefined;
|
|
150
|
+
payment_method_id?: string | null | undefined;
|
|
151
|
+
payment_type_id?: string | null | undefined;
|
|
152
|
+
external_reference?: string | null | undefined;
|
|
153
|
+
description?: string | null | undefined;
|
|
154
|
+
payer?: {
|
|
155
|
+
[x: string]: unknown;
|
|
156
|
+
id?: string | number | undefined;
|
|
157
|
+
email?: string | null | undefined;
|
|
158
|
+
identification?: {
|
|
159
|
+
type?: string | null | undefined;
|
|
160
|
+
number?: string | null | undefined;
|
|
161
|
+
} | null | undefined;
|
|
162
|
+
} | undefined;
|
|
163
|
+
transaction_details?: {
|
|
164
|
+
[x: string]: unknown;
|
|
165
|
+
net_received_amount?: number | null | undefined;
|
|
166
|
+
total_paid_amount?: number | null | undefined;
|
|
167
|
+
installment_amount?: number | null | undefined;
|
|
168
|
+
} | undefined;
|
|
169
|
+
}[];
|
|
170
|
+
}>;
|
|
171
|
+
cancelPayment(id: string): Promise<Payment>;
|
|
172
|
+
getPreapproval(id: string): Promise<Preapproval>;
|
|
173
|
+
createPreapproval(params: Partial<Preapproval>): Promise<Preapproval>;
|
|
174
|
+
cancelPreapproval(id: string): Promise<Preapproval>;
|
|
175
|
+
pausePreapproval(id: string): Promise<Preapproval>;
|
|
176
|
+
resumePreapproval(id: string): Promise<Preapproval>;
|
|
177
|
+
createRefund(params: {
|
|
178
|
+
payment_id: string;
|
|
179
|
+
amount?: number;
|
|
180
|
+
}): Promise<Refund>;
|
|
181
|
+
getCustomer(id: string): Promise<Customer>;
|
|
182
|
+
createCustomer(params: Partial<Customer>): Promise<Customer>;
|
|
183
|
+
getPreference(id: string): Promise<Preference>;
|
|
184
|
+
createPreference(params: Partial<Preference>): Promise<Preference>;
|
|
185
|
+
[key: string]: any;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export { MockMercadoPagoClient, MockNotImplementedError, mockCustomer, mockPayment, mockPreapproval, mockPreference, mockRefund, mockSignedWebhook, mockSubscriptionPayment, mockWebhookHeaders };
|