@aura-labs-ai/scout 0.2.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/README.md +237 -0
- package/bin/scout-cli.js +325 -0
- package/examples/basic-purchase.js +112 -0
- package/examples/protocol-integration.js +294 -0
- package/package.json +63 -0
- package/src/activity.js +420 -0
- package/src/ap2/mandates.js +366 -0
- package/src/client.js +217 -0
- package/src/errors.js +66 -0
- package/src/index.js +655 -0
- package/src/intent-session.js +233 -0
- package/src/key-manager.js +204 -0
- package/src/key-manager.test.js +293 -0
- package/src/mcp/client.js +458 -0
- package/src/session.js +603 -0
- package/src/tap/visa.js +345 -0
- package/src/tests/README.md +157 -0
- package/src/tests/ap2-mandates.test.js +413 -0
- package/src/tests/intent-session.test.js +292 -0
- package/src/tests/mcp-client.test.js +224 -0
- package/src/tests/ping.test.js +282 -0
- package/src/tests/run-protocol-tests.js +57 -0
- package/src/tests/scenarios/ap2-scenarios.test.js +422 -0
- package/src/tests/scenarios/index.js +60 -0
- package/src/tests/scenarios/integration-scenarios.test.js +514 -0
- package/src/tests/scenarios/mcp-scenarios.test.js +419 -0
- package/src/tests/scenarios/tap-scenarios.test.js +461 -0
- package/src/tests/visa-tap.test.js +376 -0
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AP2 Protocol Scenario Tests
|
|
3
|
+
*
|
|
4
|
+
* Real-world scenario tests for Google's Agent Payments Protocol (AP2).
|
|
5
|
+
* These tests verify the full mandate lifecycle in common shopping scenarios.
|
|
6
|
+
*
|
|
7
|
+
* Run:
|
|
8
|
+
* node --test src/tests/scenarios/ap2-scenarios.test.js
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { test, describe } from 'node:test';
|
|
12
|
+
import assert from 'node:assert';
|
|
13
|
+
import { AP2Mandates, generateKeyPair } from '../../ap2/mandates.js';
|
|
14
|
+
|
|
15
|
+
// =============================================================================
|
|
16
|
+
// Test Setup
|
|
17
|
+
// =============================================================================
|
|
18
|
+
|
|
19
|
+
const userKeys = generateKeyPair();
|
|
20
|
+
const agentKeys = generateKeyPair();
|
|
21
|
+
|
|
22
|
+
// =============================================================================
|
|
23
|
+
// Scenario 1: Basic Shopping Flow
|
|
24
|
+
// =============================================================================
|
|
25
|
+
|
|
26
|
+
describe('Scenario: Basic Shopping Flow', () => {
|
|
27
|
+
let intentMandate;
|
|
28
|
+
let cartMandate;
|
|
29
|
+
let paymentMandate;
|
|
30
|
+
|
|
31
|
+
test('Step 1: User creates intent mandate for shopping', async () => {
|
|
32
|
+
intentMandate = await AP2Mandates.createIntent({
|
|
33
|
+
agentId: 'shopping-scout-001',
|
|
34
|
+
userId: 'user-alice-001',
|
|
35
|
+
userKey: userKeys.privateKey,
|
|
36
|
+
constraints: {
|
|
37
|
+
maxAmount: 500,
|
|
38
|
+
currency: 'USD',
|
|
39
|
+
categories: ['electronics', 'office-supplies'],
|
|
40
|
+
validUntil: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(), // 24 hours
|
|
41
|
+
},
|
|
42
|
+
metadata: {
|
|
43
|
+
purpose: 'Office supplies shopping',
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
assert.strictEqual(intentMandate.type, 'intent');
|
|
48
|
+
assert.strictEqual(intentMandate.constraints.maxAmount, 500);
|
|
49
|
+
assert.ok(intentMandate.proof.proofValue, 'Should be signed');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('Step 2: Agent finds offer within constraints', async () => {
|
|
53
|
+
const offer = {
|
|
54
|
+
id: 'offer-laptop-stand-001',
|
|
55
|
+
beaconId: 'beacon-techmart',
|
|
56
|
+
beaconName: 'TechMart Office',
|
|
57
|
+
product: { name: 'Ergonomic Laptop Stand', sku: 'ERGO-LS-100' },
|
|
58
|
+
unitPrice: 79.99,
|
|
59
|
+
quantity: 2,
|
|
60
|
+
totalPrice: 159.98,
|
|
61
|
+
currency: 'USD',
|
|
62
|
+
deliveryDate: '2026-02-15',
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// Validate offer against intent
|
|
66
|
+
const validation = AP2Mandates.validateIntentCoverage(intentMandate, {
|
|
67
|
+
totalAmount: offer.totalPrice,
|
|
68
|
+
currency: offer.currency,
|
|
69
|
+
category: 'office-supplies',
|
|
70
|
+
merchantId: offer.beaconId,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
assert.strictEqual(validation.valid, true);
|
|
74
|
+
assert.strictEqual(validation.errors.length, 0);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test('Step 3: User approves specific purchase with cart mandate', async () => {
|
|
78
|
+
const offer = {
|
|
79
|
+
id: 'offer-laptop-stand-001',
|
|
80
|
+
beaconId: 'beacon-techmart',
|
|
81
|
+
beaconName: 'TechMart Office',
|
|
82
|
+
product: { name: 'Ergonomic Laptop Stand', sku: 'ERGO-LS-100' },
|
|
83
|
+
unitPrice: 79.99,
|
|
84
|
+
quantity: 2,
|
|
85
|
+
totalPrice: 159.98,
|
|
86
|
+
currency: 'USD',
|
|
87
|
+
deliveryDate: '2026-02-15',
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
cartMandate = await AP2Mandates.createCart({
|
|
91
|
+
sessionId: 'session-shop-001',
|
|
92
|
+
offer,
|
|
93
|
+
userKey: userKeys.privateKey,
|
|
94
|
+
userId: 'user-alice-001',
|
|
95
|
+
intentMandateId: intentMandate.id,
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
assert.strictEqual(cartMandate.type, 'cart');
|
|
99
|
+
assert.strictEqual(cartMandate.intentMandateRef, intentMandate.id);
|
|
100
|
+
assert.strictEqual(cartMandate.cart.totalAmount, 159.98);
|
|
101
|
+
assert.strictEqual(cartMandate.userPresent, true);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('Step 4: Agent creates payment mandate for processor', async () => {
|
|
105
|
+
paymentMandate = await AP2Mandates.createPayment({
|
|
106
|
+
cartMandate,
|
|
107
|
+
paymentMethod: { type: 'card', network: 'visa' },
|
|
108
|
+
agentId: 'shopping-scout-001',
|
|
109
|
+
agentKey: agentKeys.privateKey,
|
|
110
|
+
tapCredentials: { tapId: 'tap_scout_001_abc123' },
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
assert.strictEqual(paymentMandate.type, 'payment');
|
|
114
|
+
assert.strictEqual(paymentMandate.cartMandateRef, cartMandate.id);
|
|
115
|
+
assert.strictEqual(paymentMandate.agent.tapId, 'tap_scout_001_abc123');
|
|
116
|
+
assert.strictEqual(paymentMandate.transaction.amount, 159.98);
|
|
117
|
+
assert.ok(paymentMandate.riskSignals.intentMandatePresent);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test('Step 5: Verify complete audit trail', () => {
|
|
121
|
+
// Intent -> Cart -> Payment chain is intact
|
|
122
|
+
assert.strictEqual(cartMandate.intentMandateRef, intentMandate.id);
|
|
123
|
+
assert.strictEqual(paymentMandate.cartMandateRef, cartMandate.id);
|
|
124
|
+
|
|
125
|
+
// All mandates are signed
|
|
126
|
+
assert.ok(intentMandate.proof.proofValue);
|
|
127
|
+
assert.ok(cartMandate.proof.proofValue);
|
|
128
|
+
assert.ok(paymentMandate.proof.proofValue);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// =============================================================================
|
|
133
|
+
// Scenario 2: Budget Limit Enforcement
|
|
134
|
+
// =============================================================================
|
|
135
|
+
|
|
136
|
+
describe('Scenario: Budget Limit Enforcement', () => {
|
|
137
|
+
test('Rejects purchase exceeding budget', async () => {
|
|
138
|
+
const intentMandate = await AP2Mandates.createIntent({
|
|
139
|
+
agentId: 'budget-scout',
|
|
140
|
+
userId: 'user-bob',
|
|
141
|
+
userKey: userKeys.privateKey,
|
|
142
|
+
constraints: {
|
|
143
|
+
maxAmount: 100,
|
|
144
|
+
currency: 'USD',
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const expensiveOffer = {
|
|
149
|
+
totalAmount: 250,
|
|
150
|
+
currency: 'USD',
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const validation = AP2Mandates.validateIntentCoverage(intentMandate, expensiveOffer);
|
|
154
|
+
|
|
155
|
+
assert.strictEqual(validation.valid, false);
|
|
156
|
+
assert.ok(validation.errors[0].includes('exceeds max'));
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
test('Allows purchase at exact budget limit', async () => {
|
|
160
|
+
const intentMandate = await AP2Mandates.createIntent({
|
|
161
|
+
agentId: 'budget-scout',
|
|
162
|
+
userId: 'user-bob',
|
|
163
|
+
userKey: userKeys.privateKey,
|
|
164
|
+
constraints: {
|
|
165
|
+
maxAmount: 100,
|
|
166
|
+
currency: 'USD',
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
const exactOffer = {
|
|
171
|
+
totalAmount: 100,
|
|
172
|
+
currency: 'USD',
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const validation = AP2Mandates.validateIntentCoverage(intentMandate, exactOffer);
|
|
176
|
+
|
|
177
|
+
assert.strictEqual(validation.valid, true);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// =============================================================================
|
|
182
|
+
// Scenario 3: Category Restrictions
|
|
183
|
+
// =============================================================================
|
|
184
|
+
|
|
185
|
+
describe('Scenario: Category Restrictions', () => {
|
|
186
|
+
let intentMandate;
|
|
187
|
+
|
|
188
|
+
test('Setup: Create intent with category restrictions', async () => {
|
|
189
|
+
intentMandate = await AP2Mandates.createIntent({
|
|
190
|
+
agentId: 'category-scout',
|
|
191
|
+
userId: 'user-carol',
|
|
192
|
+
userKey: userKeys.privateKey,
|
|
193
|
+
constraints: {
|
|
194
|
+
maxAmount: 1000,
|
|
195
|
+
currency: 'USD',
|
|
196
|
+
categories: ['office-supplies', 'electronics'],
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
assert.deepStrictEqual(intentMandate.constraints.categories, ['office-supplies', 'electronics']);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
test('Allows purchase in permitted category', () => {
|
|
204
|
+
const validation = AP2Mandates.validateIntentCoverage(intentMandate, {
|
|
205
|
+
totalAmount: 200,
|
|
206
|
+
currency: 'USD',
|
|
207
|
+
category: 'electronics',
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
assert.strictEqual(validation.valid, true);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
test('Rejects purchase in forbidden category', () => {
|
|
214
|
+
const validation = AP2Mandates.validateIntentCoverage(intentMandate, {
|
|
215
|
+
totalAmount: 200,
|
|
216
|
+
currency: 'USD',
|
|
217
|
+
category: 'luxury-goods',
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
assert.strictEqual(validation.valid, false);
|
|
221
|
+
assert.ok(validation.errors[0].includes('Category'));
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
// =============================================================================
|
|
226
|
+
// Scenario 4: Merchant Allowlist/Blocklist
|
|
227
|
+
// =============================================================================
|
|
228
|
+
|
|
229
|
+
describe('Scenario: Merchant Restrictions', () => {
|
|
230
|
+
test('Allowlist: Only permits specified merchants', async () => {
|
|
231
|
+
const intentMandate = await AP2Mandates.createIntent({
|
|
232
|
+
agentId: 'merchant-scout',
|
|
233
|
+
userId: 'user-dave',
|
|
234
|
+
userKey: userKeys.privateKey,
|
|
235
|
+
constraints: {
|
|
236
|
+
maxAmount: 500,
|
|
237
|
+
merchantAllowlist: ['trusted-vendor-1', 'trusted-vendor-2'],
|
|
238
|
+
},
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// Trusted merchant allowed
|
|
242
|
+
const trustedValidation = AP2Mandates.validateIntentCoverage(intentMandate, {
|
|
243
|
+
totalAmount: 100,
|
|
244
|
+
merchantId: 'trusted-vendor-1',
|
|
245
|
+
});
|
|
246
|
+
assert.strictEqual(trustedValidation.valid, true);
|
|
247
|
+
|
|
248
|
+
// Unknown merchant blocked
|
|
249
|
+
const unknownValidation = AP2Mandates.validateIntentCoverage(intentMandate, {
|
|
250
|
+
totalAmount: 100,
|
|
251
|
+
merchantId: 'random-vendor',
|
|
252
|
+
});
|
|
253
|
+
assert.strictEqual(unknownValidation.valid, false);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
test('Blocklist: Blocks specified merchants', async () => {
|
|
257
|
+
const intentMandate = await AP2Mandates.createIntent({
|
|
258
|
+
agentId: 'blocklist-scout',
|
|
259
|
+
userId: 'user-eve',
|
|
260
|
+
userKey: userKeys.privateKey,
|
|
261
|
+
constraints: {
|
|
262
|
+
maxAmount: 500,
|
|
263
|
+
merchantBlocklist: ['sketchy-vendor', 'banned-seller'],
|
|
264
|
+
},
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// Normal merchant allowed
|
|
268
|
+
const normalValidation = AP2Mandates.validateIntentCoverage(intentMandate, {
|
|
269
|
+
totalAmount: 100,
|
|
270
|
+
merchantId: 'normal-store',
|
|
271
|
+
});
|
|
272
|
+
assert.strictEqual(normalValidation.valid, true);
|
|
273
|
+
|
|
274
|
+
// Blocked merchant rejected
|
|
275
|
+
const blockedValidation = AP2Mandates.validateIntentCoverage(intentMandate, {
|
|
276
|
+
totalAmount: 100,
|
|
277
|
+
merchantId: 'sketchy-vendor',
|
|
278
|
+
});
|
|
279
|
+
assert.strictEqual(blockedValidation.valid, false);
|
|
280
|
+
assert.ok(blockedValidation.errors[0].includes('blocklisted'));
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
// =============================================================================
|
|
285
|
+
// Scenario 5: Time-Limited Authorization
|
|
286
|
+
// =============================================================================
|
|
287
|
+
|
|
288
|
+
describe('Scenario: Time-Limited Authorization', () => {
|
|
289
|
+
test('Rejects expired intent mandate', async () => {
|
|
290
|
+
const expiredMandate = await AP2Mandates.createIntent({
|
|
291
|
+
agentId: 'time-scout',
|
|
292
|
+
userId: 'user-frank',
|
|
293
|
+
userKey: userKeys.privateKey,
|
|
294
|
+
constraints: {
|
|
295
|
+
maxAmount: 500,
|
|
296
|
+
validUntil: new Date(Date.now() - 1000).toISOString(), // Already expired
|
|
297
|
+
},
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
const validation = AP2Mandates.validateIntentCoverage(expiredMandate, {
|
|
301
|
+
totalAmount: 100,
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
assert.strictEqual(validation.valid, false);
|
|
305
|
+
assert.ok(validation.errors[0].includes('expired'));
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
test('Rejects mandate not yet valid', async () => {
|
|
309
|
+
const futureMandate = await AP2Mandates.createIntent({
|
|
310
|
+
agentId: 'time-scout',
|
|
311
|
+
userId: 'user-grace',
|
|
312
|
+
userKey: userKeys.privateKey,
|
|
313
|
+
constraints: {
|
|
314
|
+
maxAmount: 500,
|
|
315
|
+
validFrom: new Date(Date.now() + 60 * 60 * 1000).toISOString(), // 1 hour from now
|
|
316
|
+
validUntil: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
|
|
317
|
+
},
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
const validation = AP2Mandates.validateIntentCoverage(futureMandate, {
|
|
321
|
+
totalAmount: 100,
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
assert.strictEqual(validation.valid, false);
|
|
325
|
+
assert.ok(validation.errors[0].includes('not yet valid'));
|
|
326
|
+
});
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
// =============================================================================
|
|
330
|
+
// Scenario 6: Currency Mismatch
|
|
331
|
+
// =============================================================================
|
|
332
|
+
|
|
333
|
+
describe('Scenario: Currency Handling', () => {
|
|
334
|
+
test('Rejects mismatched currency', async () => {
|
|
335
|
+
const usdMandate = await AP2Mandates.createIntent({
|
|
336
|
+
agentId: 'currency-scout',
|
|
337
|
+
userId: 'user-henry',
|
|
338
|
+
userKey: userKeys.privateKey,
|
|
339
|
+
constraints: {
|
|
340
|
+
maxAmount: 500,
|
|
341
|
+
currency: 'USD',
|
|
342
|
+
},
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
const euroOffer = {
|
|
346
|
+
totalAmount: 100,
|
|
347
|
+
currency: 'EUR',
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
const validation = AP2Mandates.validateIntentCoverage(usdMandate, euroOffer);
|
|
351
|
+
|
|
352
|
+
assert.strictEqual(validation.valid, false);
|
|
353
|
+
assert.ok(validation.errors[0].includes('Currency'));
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
// =============================================================================
|
|
358
|
+
// Scenario 7: Multiple Constraint Violations
|
|
359
|
+
// =============================================================================
|
|
360
|
+
|
|
361
|
+
describe('Scenario: Multiple Constraint Violations', () => {
|
|
362
|
+
test('Reports all violations', async () => {
|
|
363
|
+
const strictMandate = await AP2Mandates.createIntent({
|
|
364
|
+
agentId: 'strict-scout',
|
|
365
|
+
userId: 'user-iris',
|
|
366
|
+
userKey: userKeys.privateKey,
|
|
367
|
+
constraints: {
|
|
368
|
+
maxAmount: 100,
|
|
369
|
+
currency: 'USD',
|
|
370
|
+
categories: ['electronics'],
|
|
371
|
+
merchantBlocklist: ['bad-vendor'],
|
|
372
|
+
validUntil: new Date(Date.now() - 1000).toISOString(), // Expired
|
|
373
|
+
},
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
const badOffer = {
|
|
377
|
+
totalAmount: 500, // Over budget
|
|
378
|
+
currency: 'EUR', // Wrong currency
|
|
379
|
+
category: 'furniture', // Wrong category
|
|
380
|
+
merchantId: 'bad-vendor', // Blocklisted
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
const validation = AP2Mandates.validateIntentCoverage(strictMandate, badOffer);
|
|
384
|
+
|
|
385
|
+
assert.strictEqual(validation.valid, false);
|
|
386
|
+
assert.ok(validation.errors.length >= 4, 'Should report multiple errors');
|
|
387
|
+
});
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
// =============================================================================
|
|
391
|
+
// Scenario 8: Signature Verification
|
|
392
|
+
// =============================================================================
|
|
393
|
+
|
|
394
|
+
describe('Scenario: Mandate Signature Verification', () => {
|
|
395
|
+
test('Verifies valid mandate signature', async () => {
|
|
396
|
+
const mandate = await AP2Mandates.createIntent({
|
|
397
|
+
agentId: 'verify-scout',
|
|
398
|
+
userId: 'user-jack',
|
|
399
|
+
userKey: userKeys.privateKey,
|
|
400
|
+
constraints: { maxAmount: 100 },
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
const result = await AP2Mandates.verify(mandate, userKeys.publicKey);
|
|
404
|
+
|
|
405
|
+
// In dev mode uses mock signatures
|
|
406
|
+
assert.ok(result.valid !== undefined);
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
test('Detects mandate without signature', async () => {
|
|
410
|
+
const unsignedMandate = {
|
|
411
|
+
type: 'intent',
|
|
412
|
+
id: 'fake-mandate',
|
|
413
|
+
constraints: { maxAmount: 100 },
|
|
414
|
+
// No proof field
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
const result = await AP2Mandates.verify(unsignedMandate, userKeys.publicKey);
|
|
418
|
+
|
|
419
|
+
assert.strictEqual(result.valid, false);
|
|
420
|
+
assert.ok(result.error.includes('No proof'));
|
|
421
|
+
});
|
|
422
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Protocol Scenario Test Runner
|
|
5
|
+
*
|
|
6
|
+
* Runs all protocol scenario tests for the Scout SDK:
|
|
7
|
+
* - AP2 Mandates scenarios
|
|
8
|
+
* - Visa TAP scenarios
|
|
9
|
+
* - MCP Client scenarios
|
|
10
|
+
* - Integration scenarios
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* node src/tests/scenarios/index.js
|
|
14
|
+
*
|
|
15
|
+
* Or via npm:
|
|
16
|
+
* npm run test:scenarios
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { spawn } from 'child_process';
|
|
20
|
+
import { fileURLToPath } from 'url';
|
|
21
|
+
import { dirname, join } from 'path';
|
|
22
|
+
|
|
23
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
24
|
+
const __dirname = dirname(__filename);
|
|
25
|
+
|
|
26
|
+
const scenarioFiles = [
|
|
27
|
+
'ap2-scenarios.test.js',
|
|
28
|
+
'tap-scenarios.test.js',
|
|
29
|
+
'mcp-scenarios.test.js',
|
|
30
|
+
'integration-scenarios.test.js',
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
console.log('\n' + '═'.repeat(70));
|
|
34
|
+
console.log(' AURA Scout SDK - Protocol Scenario Tests');
|
|
35
|
+
console.log('═'.repeat(70) + '\n');
|
|
36
|
+
|
|
37
|
+
console.log('Running scenario tests for:');
|
|
38
|
+
console.log(' • AP2 Mandates (Google Agent Payments Protocol)');
|
|
39
|
+
console.log(' • Visa TAP (Trusted Agent Protocol)');
|
|
40
|
+
console.log(' • MCP Client (Model Context Protocol)');
|
|
41
|
+
console.log(' • Integration (All protocols combined)');
|
|
42
|
+
console.log('');
|
|
43
|
+
|
|
44
|
+
const testPaths = scenarioFiles.map(f => join(__dirname, f));
|
|
45
|
+
|
|
46
|
+
const child = spawn('node', ['--test', ...testPaths], {
|
|
47
|
+
stdio: 'inherit',
|
|
48
|
+
cwd: join(__dirname, '../../..'),
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
child.on('exit', (code) => {
|
|
52
|
+
console.log('\n' + '═'.repeat(70));
|
|
53
|
+
if (code === 0) {
|
|
54
|
+
console.log(' ✅ All scenario tests passed!');
|
|
55
|
+
} else {
|
|
56
|
+
console.log(' ❌ Some tests failed');
|
|
57
|
+
}
|
|
58
|
+
console.log('═'.repeat(70) + '\n');
|
|
59
|
+
process.exit(code);
|
|
60
|
+
});
|