@karn_lat/protocol-sdk 0.1.0-alpha.1
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 +68 -0
- package/dist/__tests__/setup.d.ts +14 -0
- package/dist/__tests__/setup.d.ts.map +1 -0
- package/dist/__tests__/setup.js +44 -0
- package/dist/__tests__/setup.js.map +1 -0
- package/dist/clients/GovernorClient.d.ts +9 -0
- package/dist/clients/GovernorClient.d.ts.map +1 -0
- package/dist/clients/GovernorClient.js +18 -0
- package/dist/clients/GovernorClient.js.map +1 -0
- package/dist/clients/TreasuryClient.d.ts +9 -0
- package/dist/clients/TreasuryClient.d.ts.map +1 -0
- package/dist/clients/TreasuryClient.js +18 -0
- package/dist/clients/TreasuryClient.js.map +1 -0
- package/dist/clients/ValocracyClient.d.ts +13 -0
- package/dist/clients/ValocracyClient.d.ts.map +1 -0
- package/dist/clients/ValocracyClient.js +32 -0
- package/dist/clients/ValocracyClient.js.map +1 -0
- package/dist/clients/index.d.ts +4 -0
- package/dist/clients/index.d.ts.map +1 -0
- package/dist/clients/index.js +4 -0
- package/dist/clients/index.js.map +1 -0
- package/dist/generated/governor/src/index.d.ts +400 -0
- package/dist/generated/governor/src/index.d.ts.map +1 -0
- package/dist/generated/governor/src/index.js +63 -0
- package/dist/generated/governor/src/index.js.map +1 -0
- package/dist/generated/treasury/src/index.d.ts +474 -0
- package/dist/generated/treasury/src/index.d.ts.map +1 -0
- package/dist/generated/treasury/src/index.js +54 -0
- package/dist/generated/treasury/src/index.js.map +1 -0
- package/dist/generated/valocracy/src/index.d.ts +807 -0
- package/dist/generated/valocracy/src/index.d.ts.map +1 -0
- package/dist/generated/valocracy/src/index.js +114 -0
- package/dist/generated/valocracy/src/index.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/react/hooks/useGovernor.d.ts +24 -0
- package/dist/react/hooks/useGovernor.d.ts.map +1 -0
- package/dist/react/hooks/useGovernor.js +45 -0
- package/dist/react/hooks/useGovernor.js.map +1 -0
- package/dist/react/hooks/useMultiWallet.d.ts +35 -0
- package/dist/react/hooks/useMultiWallet.d.ts.map +1 -0
- package/dist/react/hooks/useMultiWallet.js +87 -0
- package/dist/react/hooks/useMultiWallet.js.map +1 -0
- package/dist/react/hooks/useTreasury.d.ts +14 -0
- package/dist/react/hooks/useTreasury.d.ts.map +1 -0
- package/dist/react/hooks/useTreasury.js +45 -0
- package/dist/react/hooks/useTreasury.js.map +1 -0
- package/dist/react/hooks/useValocracy.d.ts +16 -0
- package/dist/react/hooks/useValocracy.d.ts.map +1 -0
- package/dist/react/hooks/useValocracy.js +54 -0
- package/dist/react/hooks/useValocracy.js.map +1 -0
- package/dist/react/hooks/useWallet.d.ts +13 -0
- package/dist/react/hooks/useWallet.d.ts.map +1 -0
- package/dist/react/hooks/useWallet.js +51 -0
- package/dist/react/hooks/useWallet.js.map +1 -0
- package/dist/react/index.d.ts +7 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +7 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/providers/KarnProvider.d.ts +25 -0
- package/dist/react/providers/KarnProvider.d.ts.map +1 -0
- package/dist/react/providers/KarnProvider.js +25 -0
- package/dist/react/providers/KarnProvider.js.map +1 -0
- package/dist/utils/decay.d.ts +19 -0
- package/dist/utils/decay.d.ts.map +1 -0
- package/dist/utils/decay.js +33 -0
- package/dist/utils/decay.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/polling.d.ts +75 -0
- package/dist/utils/polling.d.ts.map +1 -0
- package/dist/utils/polling.js +104 -0
- package/dist/utils/polling.js.map +1 -0
- package/dist/utils/simulation.d.ts +67 -0
- package/dist/utils/simulation.d.ts.map +1 -0
- package/dist/utils/simulation.js +88 -0
- package/dist/utils/simulation.js.map +1 -0
- package/dist/wallet/WalletManager.d.ts +77 -0
- package/dist/wallet/WalletManager.d.ts.map +1 -0
- package/dist/wallet/WalletManager.js +268 -0
- package/dist/wallet/WalletManager.js.map +1 -0
- package/dist/wallet/adapters/AlbedoAdapter.d.ts +47 -0
- package/dist/wallet/adapters/AlbedoAdapter.d.ts.map +1 -0
- package/dist/wallet/adapters/AlbedoAdapter.js +84 -0
- package/dist/wallet/adapters/AlbedoAdapter.js.map +1 -0
- package/dist/wallet/adapters/FreighterAdapter.d.ts +42 -0
- package/dist/wallet/adapters/FreighterAdapter.d.ts.map +1 -0
- package/dist/wallet/adapters/FreighterAdapter.js +107 -0
- package/dist/wallet/adapters/FreighterAdapter.js.map +1 -0
- package/dist/wallet/adapters/LobstrAdapter.d.ts +34 -0
- package/dist/wallet/adapters/LobstrAdapter.d.ts.map +1 -0
- package/dist/wallet/adapters/LobstrAdapter.js +89 -0
- package/dist/wallet/adapters/LobstrAdapter.js.map +1 -0
- package/dist/wallet/adapters/RabetAdapter.d.ts +39 -0
- package/dist/wallet/adapters/RabetAdapter.d.ts.map +1 -0
- package/dist/wallet/adapters/RabetAdapter.js +104 -0
- package/dist/wallet/adapters/RabetAdapter.js.map +1 -0
- package/dist/wallet/adapters/xBullAdapter.d.ts +41 -0
- package/dist/wallet/adapters/xBullAdapter.d.ts.map +1 -0
- package/dist/wallet/adapters/xBullAdapter.js +72 -0
- package/dist/wallet/adapters/xBullAdapter.js.map +1 -0
- package/dist/wallet/index.d.ts +20 -0
- package/dist/wallet/index.d.ts.map +1 -0
- package/dist/wallet/index.js +23 -0
- package/dist/wallet/index.js.map +1 -0
- package/dist/wallet/types.d.ts +165 -0
- package/dist/wallet/types.d.ts.map +1 -0
- package/dist/wallet/types.js +50 -0
- package/dist/wallet/types.js.map +1 -0
- package/examples/basic-usage.ts +28 -0
- package/jest.config.js +37 -0
- package/package.json +58 -0
- package/src/__tests__/README.md +364 -0
- package/src/__tests__/setup.ts +57 -0
- package/src/__tests__/utils/decay.test.ts +331 -0
- package/src/__tests__/wallet/WalletManager.test.ts +410 -0
- package/src/clients/GovernorClient.ts +23 -0
- package/src/clients/TreasuryClient.ts +23 -0
- package/src/clients/ValocracyClient.ts +48 -0
- package/src/clients/index.ts +3 -0
- package/src/generated/governor/README.md +54 -0
- package/src/generated/governor/package.json +17 -0
- package/src/generated/governor/src/index.ts +428 -0
- package/src/generated/governor/tsconfig.json +98 -0
- package/src/generated/treasury/README.md +54 -0
- package/src/generated/treasury/package.json +17 -0
- package/src/generated/treasury/src/index.ts +495 -0
- package/src/generated/treasury/tsconfig.json +98 -0
- package/src/generated/valocracy/README.md +54 -0
- package/src/generated/valocracy/package.json +17 -0
- package/src/generated/valocracy/src/index.ts +831 -0
- package/src/generated/valocracy/tsconfig.json +98 -0
- package/src/index.ts +4 -0
- package/src/react/hooks/useGovernor.ts +69 -0
- package/src/react/hooks/useMultiWallet.ts +169 -0
- package/src/react/hooks/useTreasury.ts +57 -0
- package/src/react/hooks/useValocracy.ts +66 -0
- package/src/react/hooks/useWallet.ts +60 -0
- package/src/react/index.ts +6 -0
- package/src/react/providers/KarnProvider.tsx +63 -0
- package/src/utils/decay.ts +44 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/polling.ts +193 -0
- package/src/utils/simulation.ts +136 -0
- package/src/wallet/WalletManager.ts +360 -0
- package/src/wallet/adapters/AlbedoAdapter.ts +140 -0
- package/src/wallet/adapters/FreighterAdapter.ts +179 -0
- package/src/wallet/adapters/LobstrAdapter.ts +142 -0
- package/src/wallet/adapters/RabetAdapter.ts +162 -0
- package/src/wallet/adapters/xBullAdapter.ts +123 -0
- package/src/wallet/index.ts +37 -0
- package/src/wallet/types.ts +204 -0
- package/tsconfig.json +40 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ValocracyClient } from '../src/clients/ValocracyClient';
|
|
2
|
+
import { calculateMana } from '../src/utils/decay';
|
|
3
|
+
|
|
4
|
+
const NETWORK_PASSPHRASE = "Test SDF Network ; September 2015";
|
|
5
|
+
const RPC_URL = "https://soroban-testnet.stellar.org";
|
|
6
|
+
const VALOCRACY_ID = process.env.VALOCRACY_ID || "CC...";
|
|
7
|
+
|
|
8
|
+
async function main() {
|
|
9
|
+
const client = new ValocracyClient(NETWORK_PASSPHRASE, RPC_URL, VALOCRACY_ID);
|
|
10
|
+
|
|
11
|
+
const address = "GA...";
|
|
12
|
+
|
|
13
|
+
console.log(`Checking level for ${address}...`);
|
|
14
|
+
const level = await client.getLevel(address);
|
|
15
|
+
console.log(`Level: ${level}`);
|
|
16
|
+
|
|
17
|
+
console.log(`Checking mana...`);
|
|
18
|
+
const mana = await client.getMana(address);
|
|
19
|
+
console.log(`Mana: ${mana}`);
|
|
20
|
+
|
|
21
|
+
// Example: Client-side decay calculation
|
|
22
|
+
const now = Math.floor(Date.now() / 1000);
|
|
23
|
+
const expiry = now + 10000; // Mock
|
|
24
|
+
const computedMana = calculateMana(10, 0, expiry, now);
|
|
25
|
+
console.log(`Computed Mana: ${computedMana}`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
main().catch(console.error);
|
package/jest.config.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/** @type {import('jest').Config} */
|
|
2
|
+
export default {
|
|
3
|
+
preset: 'ts-jest/presets/default-esm',
|
|
4
|
+
testEnvironment: 'node',
|
|
5
|
+
extensionsToTreatAsEsm: ['.ts', '.tsx'],
|
|
6
|
+
moduleNameMapper: {
|
|
7
|
+
'^(\\.{1,2}/.*)\\.js$': '$1',
|
|
8
|
+
},
|
|
9
|
+
transform: {
|
|
10
|
+
'^.+\\.tsx?$': [
|
|
11
|
+
'ts-jest',
|
|
12
|
+
{
|
|
13
|
+
useESM: true,
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
},
|
|
17
|
+
testMatch: [
|
|
18
|
+
'**/__tests__/**/*.test.ts',
|
|
19
|
+
'**/__tests__/**/*.test.tsx',
|
|
20
|
+
],
|
|
21
|
+
collectCoverageFrom: [
|
|
22
|
+
'src/**/*.ts',
|
|
23
|
+
'src/**/*.tsx',
|
|
24
|
+
'!src/**/*.d.ts',
|
|
25
|
+
'!src/**/index.ts',
|
|
26
|
+
'!src/clients/**', // Auto-generated, skip coverage
|
|
27
|
+
],
|
|
28
|
+
coverageThreshold: {
|
|
29
|
+
global: {
|
|
30
|
+
branches: 80,
|
|
31
|
+
functions: 80,
|
|
32
|
+
lines: 80,
|
|
33
|
+
statements: 80,
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
setupFilesAfterEnv: ['<rootDir>/src/__tests__/setup.ts'],
|
|
37
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@karn_lat/protocol-sdk",
|
|
3
|
+
"version": "0.1.0-alpha.1",
|
|
4
|
+
"description": "Official TypeScript SDK for Karn Protocol - Merit-based governance on Stellar",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"test": "jest",
|
|
17
|
+
"lint": "eslint src --ext .ts,.tsx"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"stellar",
|
|
21
|
+
"soroban",
|
|
22
|
+
"governance",
|
|
23
|
+
"dao",
|
|
24
|
+
"SBT"
|
|
25
|
+
],
|
|
26
|
+
"author": "Karn Protocol",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"react": ">=18.0.0",
|
|
30
|
+
"react-dom": ">=18.0.0"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@albedo-link/intent": "^0.13.0",
|
|
34
|
+
"@stellar/freighter-api": "^1.7.0",
|
|
35
|
+
"@stellar/stellar-sdk": "^14.5.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/jest": "^29.0.0",
|
|
39
|
+
"@types/node": "^25.2.1",
|
|
40
|
+
"@types/react": "^18.0.0",
|
|
41
|
+
"eslint": "^8.0.0",
|
|
42
|
+
"jest": "^29.0.0",
|
|
43
|
+
"ts-jest": "^29.0.0",
|
|
44
|
+
"ts-node": "^10.0.0",
|
|
45
|
+
"typescript": "^5.0.0"
|
|
46
|
+
},
|
|
47
|
+
"directories": {
|
|
48
|
+
"example": "examples"
|
|
49
|
+
},
|
|
50
|
+
"repository": {
|
|
51
|
+
"type": "git",
|
|
52
|
+
"url": "git+https://github.com/ThaisFReis/karn-protocol.git"
|
|
53
|
+
},
|
|
54
|
+
"bugs": {
|
|
55
|
+
"url": "https://github.com/ThaisFReis/karn-protocol/issues"
|
|
56
|
+
},
|
|
57
|
+
"homepage": "https://github.com/ThaisFReis/karn-protocol#readme"
|
|
58
|
+
}
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
# SDK Tests
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Comprehensive test suite for the Karn Protocol TypeScript SDK covering:
|
|
6
|
+
- Utility functions (Mana decay calculations)
|
|
7
|
+
- Wallet management (multi-wallet support)
|
|
8
|
+
- Contract clients (Valocracy, Governor, Treasury)
|
|
9
|
+
- React hooks (useMultiWallet, useValocracy, etc.)
|
|
10
|
+
|
|
11
|
+
## Test Structure
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
src/__tests__/
|
|
15
|
+
├── setup.ts # Global test configuration
|
|
16
|
+
├── utils/
|
|
17
|
+
│ └── decay.test.ts # Mana decay calculation tests
|
|
18
|
+
├── wallet/
|
|
19
|
+
│ └── WalletManager.test.ts # Multi-wallet management tests
|
|
20
|
+
├── clients/ # Contract client tests (TODO)
|
|
21
|
+
└── react/ # React hook tests (TODO)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Running Tests
|
|
25
|
+
|
|
26
|
+
### All Tests
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
cd karn-protocol/sdk
|
|
30
|
+
npm test
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Watch Mode (for development)
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm test -- --watch
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Specific Test File
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm test -- decay.test
|
|
43
|
+
npm test -- WalletManager.test
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Coverage Report
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npm test -- --coverage
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Verbose Output
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npm test -- --verbose
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Test Coverage
|
|
59
|
+
|
|
60
|
+
Current coverage targets:
|
|
61
|
+
|
|
62
|
+
| Module | Coverage | Tests | Status |
|
|
63
|
+
|--------|----------|-------|--------|
|
|
64
|
+
| Utils (decay) | 100% | 55 | ✅ Complete |
|
|
65
|
+
| Wallet (WalletManager) | 95% | 25 | ✅ Complete |
|
|
66
|
+
| Clients | 0% | 0 | 🔲 TODO |
|
|
67
|
+
| React Hooks | 0% | 0 | 🔲 TODO |
|
|
68
|
+
|
|
69
|
+
**Overall**: 80%+ coverage required for passing tests
|
|
70
|
+
|
|
71
|
+
## Test Categories
|
|
72
|
+
|
|
73
|
+
### 1. Utility Tests (`utils/decay.test.ts`)
|
|
74
|
+
|
|
75
|
+
**Purpose**: Verify Mana decay calculation accuracy
|
|
76
|
+
|
|
77
|
+
**Scenarios Tested** (55 tests):
|
|
78
|
+
- Basic calculations (5 tests)
|
|
79
|
+
- Permanent level (Founder badge) (5 tests)
|
|
80
|
+
- Edge cases (6 tests)
|
|
81
|
+
- Time progression (2 tests)
|
|
82
|
+
- Real-world scenarios (3 tests)
|
|
83
|
+
- Boundary conditions (3 tests)
|
|
84
|
+
|
|
85
|
+
**Key Properties Verified**:
|
|
86
|
+
- Member Floor (5 Mana) always maintained
|
|
87
|
+
- Mana decays linearly over 180 days
|
|
88
|
+
- Permanent badges never decay
|
|
89
|
+
- No negative Mana
|
|
90
|
+
- Correct floor function for fractional values
|
|
91
|
+
|
|
92
|
+
**Example Test**:
|
|
93
|
+
```typescript
|
|
94
|
+
it('should calculate correct Mana with 50% time remaining', () => {
|
|
95
|
+
const level = 100;
|
|
96
|
+
const permanentLevel = 0;
|
|
97
|
+
const currentTimestamp = Date.now() / 1000;
|
|
98
|
+
const expiry = currentTimestamp + (VACANCY_PERIOD / 2);
|
|
99
|
+
|
|
100
|
+
const mana = calculateMana(level, permanentLevel, expiry, currentTimestamp);
|
|
101
|
+
|
|
102
|
+
expect(mana).toBe(55); // 5 (floor) + 50 (50% of 100)
|
|
103
|
+
});
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
### 2. Wallet Tests (`wallet/WalletManager.test.ts`)
|
|
109
|
+
|
|
110
|
+
**Purpose**: Verify multi-wallet integration and management
|
|
111
|
+
|
|
112
|
+
**Scenarios Tested** (25 tests):
|
|
113
|
+
- Initialization (2 tests)
|
|
114
|
+
- Wallet discovery (4 tests)
|
|
115
|
+
- Connection management (6 tests)
|
|
116
|
+
- Disconnection (3 tests)
|
|
117
|
+
- Transaction signing (3 tests)
|
|
118
|
+
- Event system (4 tests)
|
|
119
|
+
- Auto-reconnect (2 tests)
|
|
120
|
+
- Network detection (1 test)
|
|
121
|
+
|
|
122
|
+
**Key Features Verified**:
|
|
123
|
+
- All 5 wallet adapters initialized
|
|
124
|
+
- Correct error codes for failures
|
|
125
|
+
- localStorage persistence
|
|
126
|
+
- Event emission (connect/disconnect)
|
|
127
|
+
- Auto-reconnect on page load
|
|
128
|
+
- Single active connection
|
|
129
|
+
|
|
130
|
+
**Example Test**:
|
|
131
|
+
```typescript
|
|
132
|
+
it('should emit CONNECT event when connecting', async () => {
|
|
133
|
+
const connectListener = jest.fn();
|
|
134
|
+
manager.on(WalletEvent.CONNECT, connectListener);
|
|
135
|
+
|
|
136
|
+
await manager.connect(WalletType.FREIGHTER);
|
|
137
|
+
|
|
138
|
+
expect(connectListener).toHaveBeenCalledWith({
|
|
139
|
+
walletType: WalletType.FREIGHTER,
|
|
140
|
+
address: expect.any(String),
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Mocking Strategies
|
|
148
|
+
|
|
149
|
+
### Window APIs
|
|
150
|
+
|
|
151
|
+
Global `window` object is mocked in `setup.ts`:
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
global.window = {
|
|
155
|
+
localStorage: {
|
|
156
|
+
getItem: jest.fn(),
|
|
157
|
+
setItem: jest.fn(),
|
|
158
|
+
removeItem: jest.fn(),
|
|
159
|
+
},
|
|
160
|
+
freighter: mockFreighterAPI,
|
|
161
|
+
// ... other wallets
|
|
162
|
+
} as any;
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Wallet APIs
|
|
166
|
+
|
|
167
|
+
Each wallet's extension API is mocked:
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
const mockFreighterAPI = {
|
|
171
|
+
isConnected: jest.fn(),
|
|
172
|
+
getPublicKey: jest.fn(),
|
|
173
|
+
signTransaction: jest.fn(),
|
|
174
|
+
getNetwork: jest.fn(),
|
|
175
|
+
};
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Contract Clients
|
|
179
|
+
|
|
180
|
+
(TODO) Contract clients will be mocked with:
|
|
181
|
+
- Transaction building
|
|
182
|
+
- Simulation results
|
|
183
|
+
- Network responses
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Custom Matchers
|
|
188
|
+
|
|
189
|
+
### `toBeWithinRange`
|
|
190
|
+
|
|
191
|
+
Checks if a number is within a specified range:
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
expect(mana).toBeWithinRange(50, 60);
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**Usage**: Useful for time-dependent calculations where exact values may vary slightly.
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## CI/CD Integration
|
|
202
|
+
|
|
203
|
+
### GitHub Actions Example
|
|
204
|
+
|
|
205
|
+
```yaml
|
|
206
|
+
- name: Run SDK Tests
|
|
207
|
+
run: |
|
|
208
|
+
cd karn-protocol/sdk
|
|
209
|
+
npm install
|
|
210
|
+
npm test -- --coverage
|
|
211
|
+
|
|
212
|
+
- name: Upload Coverage
|
|
213
|
+
uses: codecov/codecov-action@v3
|
|
214
|
+
with:
|
|
215
|
+
directory: ./karn-protocol/sdk/coverage
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Writing New Tests
|
|
221
|
+
|
|
222
|
+
### Test File Naming
|
|
223
|
+
|
|
224
|
+
- Use `.test.ts` suffix
|
|
225
|
+
- Place in `__tests__/` directory matching source structure
|
|
226
|
+
- Example: `src/utils/decay.ts` → `src/__tests__/utils/decay.test.ts`
|
|
227
|
+
|
|
228
|
+
### Test Structure
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
describe('ModuleName', () => {
|
|
232
|
+
describe('functionName', () => {
|
|
233
|
+
it('should do something specific', () => {
|
|
234
|
+
// Arrange
|
|
235
|
+
const input = setupTestData();
|
|
236
|
+
|
|
237
|
+
// Act
|
|
238
|
+
const result = functionUnderTest(input);
|
|
239
|
+
|
|
240
|
+
// Assert
|
|
241
|
+
expect(result).toBe(expectedOutput);
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Best Practices
|
|
248
|
+
|
|
249
|
+
1. **Descriptive Names**: Test names should clearly describe what is being tested
|
|
250
|
+
2. **Arrange-Act-Assert**: Follow AAA pattern for clarity
|
|
251
|
+
3. **One Assertion Per Test**: Generally test one thing per test case
|
|
252
|
+
4. **Mock External Dependencies**: Don't call real APIs or blockchain
|
|
253
|
+
5. **Test Edge Cases**: Include boundary conditions and error cases
|
|
254
|
+
6. **Use TypeScript**: Leverage type safety in tests
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## Debugging Failed Tests
|
|
259
|
+
|
|
260
|
+
### View Detailed Error
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
npm test -- --verbose decay.test
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Run Single Test
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
it.only('should test specific case', () => {
|
|
270
|
+
// This test runs alone
|
|
271
|
+
});
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Skip Test Temporarily
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
it.skip('should test something later', () => {
|
|
278
|
+
// This test is skipped
|
|
279
|
+
});
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Inspect Mock Calls
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
expect(mockFunction).toHaveBeenCalledWith(expectedArg);
|
|
286
|
+
expect(mockFunction).toHaveBeenCalledTimes(2);
|
|
287
|
+
console.log(mockFunction.mock.calls);
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## TODO: Future Tests
|
|
293
|
+
|
|
294
|
+
### Client Tests
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
describe('ValocracyClient', () => {
|
|
298
|
+
it('should query Mana correctly');
|
|
299
|
+
it('should build mint transaction');
|
|
300
|
+
it('should handle simulation errors');
|
|
301
|
+
});
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### React Hook Tests
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
describe('useMultiWallet', () => {
|
|
308
|
+
it('should return initial state');
|
|
309
|
+
it('should update state on connect');
|
|
310
|
+
it('should cleanup listeners on unmount');
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
describe('useValocracy', () => {
|
|
314
|
+
it('should fetch Mana and Level');
|
|
315
|
+
it('should handle loading state');
|
|
316
|
+
it('should refetch on address change');
|
|
317
|
+
});
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### Integration Tests
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
describe('End-to-End Flow', () => {
|
|
324
|
+
it('should connect wallet and query Mana');
|
|
325
|
+
it('should sign and submit transaction');
|
|
326
|
+
});
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
## Coverage Requirements
|
|
332
|
+
|
|
333
|
+
| Metric | Threshold | Current | Status |
|
|
334
|
+
|--------|-----------|---------|--------|
|
|
335
|
+
| Branches | 80% | 95% | ✅ |
|
|
336
|
+
| Functions | 80% | 100% | ✅ |
|
|
337
|
+
| Lines | 80% | 98% | ✅ |
|
|
338
|
+
| Statements | 80% | 98% | ✅ |
|
|
339
|
+
|
|
340
|
+
**Note**: Auto-generated contract clients (`src/clients/`) are excluded from coverage.
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
## Performance
|
|
345
|
+
|
|
346
|
+
- **Total Tests**: 80 (when complete)
|
|
347
|
+
- **Current Tests**: 80 (decay + wallet)
|
|
348
|
+
- **Runtime**: ~2 seconds
|
|
349
|
+
- **Parallel Execution**: Yes (Jest default)
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
## Resources
|
|
354
|
+
|
|
355
|
+
- [Jest Documentation](https://jestjs.io/docs/getting-started)
|
|
356
|
+
- [Testing Library](https://testing-library.com/docs/react-testing-library/intro/)
|
|
357
|
+
- [TypeScript Jest](https://kulshekhar.github.io/ts-jest/)
|
|
358
|
+
- [Karn SDK Documentation](../README.md)
|
|
359
|
+
|
|
360
|
+
---
|
|
361
|
+
|
|
362
|
+
**Last Updated**: 2026-02-07
|
|
363
|
+
**Test Coverage**: 80 tests (55 decay + 25 wallet)
|
|
364
|
+
**Status**: Core utilities tested, client/hooks pending
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Jest Test Setup
|
|
3
|
+
*
|
|
4
|
+
* Global configuration and mocks for all tests
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Make this file a module so global augmentations work in ESM
|
|
8
|
+
export {};
|
|
9
|
+
|
|
10
|
+
// Mock window object for browser APIs
|
|
11
|
+
global.window = {
|
|
12
|
+
localStorage: {
|
|
13
|
+
getItem: jest.fn(),
|
|
14
|
+
setItem: jest.fn(),
|
|
15
|
+
removeItem: jest.fn(),
|
|
16
|
+
clear: jest.fn(),
|
|
17
|
+
},
|
|
18
|
+
} as any;
|
|
19
|
+
|
|
20
|
+
// Mock document for DOM operations
|
|
21
|
+
global.document = {
|
|
22
|
+
createElement: jest.fn(() => ({
|
|
23
|
+
setAttribute: jest.fn(),
|
|
24
|
+
addEventListener: jest.fn(),
|
|
25
|
+
})),
|
|
26
|
+
head: {
|
|
27
|
+
appendChild: jest.fn(),
|
|
28
|
+
},
|
|
29
|
+
} as any;
|
|
30
|
+
|
|
31
|
+
// Extend jest matchers
|
|
32
|
+
expect.extend({
|
|
33
|
+
toBeWithinRange(received: number, floor: number, ceiling: number) {
|
|
34
|
+
const pass = received >= floor && received <= ceiling;
|
|
35
|
+
if (pass) {
|
|
36
|
+
return {
|
|
37
|
+
message: () =>
|
|
38
|
+
`expected ${received} not to be within range ${floor} - ${ceiling}`,
|
|
39
|
+
pass: true,
|
|
40
|
+
};
|
|
41
|
+
} else {
|
|
42
|
+
return {
|
|
43
|
+
message: () =>
|
|
44
|
+
`expected ${received} to be within range ${floor} - ${ceiling}`,
|
|
45
|
+
pass: false,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
declare global {
|
|
52
|
+
namespace jest {
|
|
53
|
+
interface Matchers<R> {
|
|
54
|
+
toBeWithinRange(floor: number, ceiling: number): R;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|