-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtest-e2e.js
More file actions
138 lines (113 loc) · 5.81 KB
/
test-e2e.js
File metadata and controls
138 lines (113 loc) · 5.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#!/usr/bin/env node
/**
* SENTINEL SDK — FULL E2E TEST RUNNER
*
* Runs every test suite in order. All suites that need chain access use
* the MNEMONIC from ../ ai-path/.env or a local .env.
*
* Usage:
* node test-e2e.js # run everything
* node test-e2e.js --offline # logic tests only (no network)
* node test-e2e.js --quick # offline + chain queries, no TX or connection
*
* Suites (in order):
* 1. Logic — 127 pure-logic tests, no network (test-all-logic.js)
* 2. FeeGrant E2E — isActiveStatus, error codes, queryFeeGrant offline + live (test-plan-connect-e2e.js)
* 3. Mainnet — wallet, queries, cache, preflight, WireGuard connect (test-mainnet.js)
* 4. Subscriptions — subscribe, share, feegrant, onboard, renew, cancel (test-subscription-flows.js)
*
* Suites 3-4 broadcast real TXs and cost ~1–3 P2P per run.
* Suite 3 opens and closes one WireGuard session.
* Never run suites in parallel — chain rate limits apply (7s between TXs).
*/
import { config as dotenvConfig } from 'dotenv';
import { resolve, dirname } from 'path';
import { fileURLToPath } from 'url';
import { spawnSync } from 'child_process';
const __dirname = dirname(fileURLToPath(import.meta.url));
dotenvConfig({ path: resolve(__dirname, '../ai-path/.env') });
dotenvConfig(); // also try CWD .env
const MNEMONIC = process.env.MNEMONIC;
const args = process.argv.slice(2);
const offlineOnly = args.includes('--offline');
const quickMode = args.includes('--quick');
const FEE_GRANTER = 'sent1t0xjyflrah5n36rfkpfeuw6pz6vl2g27x2793l';
const FEE_GRANTEE = MNEMONIC ? undefined : null; // resolved from wallet
const PLAN_ID = '42';
console.log('═══════════════════════════════════════════════════════════');
console.log(' SENTINEL SDK — FULL E2E TEST RUNNER');
console.log('═══════════════════════════════════════════════════════════');
console.log(` Mode : ${offlineOnly ? 'offline-only' : quickMode ? 'quick (no TX)' : 'full (chain + TX)'}`);
console.log(` MNEMONIC : ${MNEMONIC ? 'set' : 'NOT SET — chain tests will fail'}`);
console.log('');
// ─── Suite runner ─────────────────────────────────────────────────────────────
const results = [];
function runSuite(name, file, env = {}) {
console.log(`\n${'─'.repeat(60)}`);
console.log(` SUITE: ${name}`);
console.log(`${'─'.repeat(60)}`);
const merged = { ...process.env, ...env };
const r = spawnSync('node', [file], { cwd: __dirname, env: merged, stdio: 'inherit' });
const ok = r.status === 0;
results.push({ name, ok, status: r.status });
if (!ok) console.log(`\n [SUITE FAILED — exit ${r.status}]`);
return ok;
}
// ─── Suite 1: Pure logic ───────────────────────────────────────────────────
runSuite('Logic (offline, no network)', 'test-all-logic.js');
if (offlineOnly) {
printSummary();
process.exit(results.every(r => r.ok) ? 0 : 1);
}
// ─── Suite 2: FeeGrant E2E (offline + live LCD) ───────────────────────────
// Resolve the grantee address from the wallet if mnemonic is available.
let granteeAddr = FEE_GRANTEE;
if (MNEMONIC && !granteeAddr) {
try {
const { createWallet } = await import('./index.js');
const { account } = await createWallet(MNEMONIC);
granteeAddr = account.address;
} catch (_) {
// leave undefined — live LCD section will be skipped
}
}
runSuite('FeeGrant + isActiveStatus + error codes (offline + live LCD)',
'test-plan-connect-e2e.js',
{
E2E_LIVE: MNEMONIC ? '1' : '0',
FEE_GRANTER,
FEE_GRANTEE: granteeAddr || '',
PLAN_ID,
},
);
if (quickMode) {
printSummary();
process.exit(results.every(r => r.ok) ? 0 : 1);
}
// ─── Suite 3: Mainnet — wallet + queries + WireGuard connect ─────────────
if (!MNEMONIC) {
console.log('\n SKIP Suite 3+4 — MNEMONIC not set');
} else {
runSuite('Mainnet (wallet, chain queries, WireGuard connect)', 'test-mainnet.js',
{ MNEMONIC });
// 60s gap between full suites to let chain settle
console.log('\n Waiting 60s between suites (chain settle)...');
await new Promise(r => setTimeout(r, 60000));
// ─── Suite 4: Subscription flows ─────────────────────────────────────────
runSuite('Subscription flows (subscribe, share, feegrant, onboard, renew, cancel)',
'test-subscription-flows.js', { MNEMONIC });
}
// ─── Summary ──────────────────────────────────────────────────────────────
printSummary();
process.exit(results.every(r => r.ok) ? 0 : 1);
function printSummary() {
const pass = results.filter(r => r.ok).length;
const fail = results.filter(r => !r.ok).length;
console.log('\n');
console.log('═══════════════════════════════════════════════════════════');
console.log(` FINAL: ${pass} suite(s) passed, ${fail} failed`);
for (const r of results) {
console.log(` ${r.ok ? '✓' : '✗'} ${r.name}`);
}
console.log('═══════════════════════════════════════════════════════════');
}