Skip to content

Commit 3bff6cc

Browse files
feat(express): add supertest for createAddress
2 parents 5693e9d + cae56ab commit 3bff6cc

File tree

2 files changed

+146
-0
lines changed

2 files changed

+146
-0
lines changed

modules/express/test/lib/testutil.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
/**
22
* Utility functions for testing
33
*/
4+
import * as request from 'supertest';
5+
import { app as expressApp } from '../../src/expressApp';
46

57
// helper function to unlock a token for a specified time
68
export function unlockToken(agent, accessToken, seconds) {
@@ -12,3 +14,14 @@ export function unlockToken(agent, accessToken, seconds) {
1214
res.statusCode.should.equal(200);
1315
});
1416
}
17+
18+
export function setupAgent(): request.SuperAgentTest {
19+
const args: any = {
20+
debug: false,
21+
env: 'test',
22+
logfile: '/dev/null',
23+
};
24+
25+
const app = expressApp(args);
26+
return request.agent(app);
27+
}

modules/express/test/unit/typedRoutes/createAddress.ts

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ import {
66
PostCreateAddress,
77
} from '../../../src/typedRoutes/api/v2/createAddress';
88
import { assertDecode } from './common';
9+
import 'should';
10+
import 'should-http';
11+
import 'should-sinon';
12+
import * as sinon from 'sinon';
13+
import { BitGo } from 'bitgo';
14+
import { setupAgent } from '../../lib/testutil';
915

1016
/**
1117
* Helper function to extract path parameter names from a route path
@@ -26,6 +32,133 @@ function getCodecParamNames(paramsCodec: Record<string, any>): string[] {
2632
}
2733

2834
describe('CreateAddress codec tests', function () {
35+
describe('createAddress', function () {
36+
const agent = setupAgent();
37+
38+
const walletId = '68c02f96aa757d9212bd1a536f123456';
39+
const coin = 'tbtc';
40+
41+
const mockResponse = {
42+
id: '68ed4dbfe664aa98d171ac0f524ef111',
43+
address: '2N632etYgykMhGrScEN7RpAthg64ACsTL6v',
44+
chain: 0,
45+
index: 1,
46+
coin: 'tbtc',
47+
wallet: '68c02f96aa757d9212bd1a536f123456',
48+
label: 'My new address',
49+
coinSpecific: {
50+
redeemScript:
51+
'522103ebc10ae7ca49f55228fd29dd32eadfcd289fb43082fabb8e0f3bcee9ab09853721039b1a9b93a2e8114d6627753fc37f115e721609b35187d74dc32e5adfa97992402102a704615d8eedaf2e0ff37f7e503615fb6765b8b147a97ac1d930b37e709755dc53ae',
52+
},
53+
addressType: 'p2sh',
54+
keychains: [
55+
{
56+
id: '68c02f94aa757d9212bd19b783deb065',
57+
pub: 'xpub661MyMwAqRbcGCSB6BrtvtRzb4Pebi5RLaC8dqZ8Zt2sJsWZ8dj7pXrLRfiGjYAD5PMV23dAxNQww8kggwKZUZtEhcjH1vPDhu4dUihbv2T',
58+
ethAddress: '0x23f7b80a5f5dce2bfb9e09d40e37794cc8e2a3be',
59+
source: 'user',
60+
type: 'independent',
61+
encryptedPrv:
62+
'{"iv":"abc123xyz456==","v":1,"iter":10000,"ks":256,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"def789ghi012=","ct":"mockEncryptedPrivateKeyData1234567890"}',
63+
},
64+
{
65+
id: '68c02f94a36d5167fa49878f9553f40e',
66+
pub: 'xpub661MyMwAqRbcFUMUdma6ot9QPBcBDiyJSo3CsyE53hjcZ9RgAH2oxcNViRTv9bUJrHeEiDhL2sLDa9kXgjSwL33Bca3ApQaG7nBJJc5enLr',
67+
ethAddress: '0xfb1d696334a2632952ae25aead77be781df91e18',
68+
source: 'backup',
69+
type: 'independent',
70+
encryptedPrv:
71+
'{"iv":"uvw345qrs678==","v":1,"iter":10000,"ks":256,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"jkl901mno234=","ct":"mockEncryptedPrivateKeyDataBackup567890"}',
72+
},
73+
{
74+
id: '68c02f95aa757d9212bd19e7ee0744e4',
75+
pub: 'xpub661MyMwAqRbcFZ1e1eeAuFnu8gBAM1Yd7bJUSEL7TRX3QQ6vbY6B5Uugf8E93eTfvcKRHHZUiqq7WLLerZdFkp2guAVG1Mkuqp6ZZqbQ53u',
76+
ethAddress: '0xfad325e7f4b57549ff68395e0d42378046208a71',
77+
source: 'bitgo',
78+
type: 'independent',
79+
isBitGo: true,
80+
isTrust: false,
81+
hsmType: 'institutional',
82+
},
83+
],
84+
};
85+
86+
afterEach(function () {
87+
sinon.restore();
88+
});
89+
90+
it('should successfully create a new wallet address', async function () {
91+
const requestBody = {
92+
label: 'My new address',
93+
chain: 0,
94+
allowSkipVerifyAddress: true,
95+
};
96+
97+
// Create mock wallet with createAddress method
98+
const mockWallet = {
99+
createAddress: sinon.stub().resolves(mockResponse),
100+
};
101+
102+
// Stub the wallets().get() chain
103+
const walletsGetStub = sinon.stub().resolves(mockWallet);
104+
105+
const mockWallets = {
106+
get: walletsGetStub,
107+
};
108+
109+
const mockCoin = {
110+
wallets: sinon.stub().returns(mockWallets),
111+
};
112+
113+
// Stub BitGo.prototype.coin to return our mock coin
114+
const coinStub = sinon.stub(BitGo.prototype, 'coin').returns(mockCoin as any);
115+
116+
// Make the request to Express
117+
const result = await agent
118+
.post(`/api/v2/${coin}/wallet/${walletId}/address`)
119+
.set('Authorization', 'Bearer test_access_token_12345')
120+
.set('Content-Type', 'application/json')
121+
.send(requestBody);
122+
123+
// Verify the response
124+
assert.strictEqual(result.status, 200);
125+
result.body.should.have.property('id', '68ed4dbfe664aa98d171ac0f524ef111');
126+
result.body.should.have.property('address', '2N632etYgykMhGrScEN7RpAthg64ACsTL6v');
127+
result.body.should.have.property('chain', 0);
128+
result.body.should.have.property('index', 1);
129+
result.body.should.have.property('coin', 'tbtc');
130+
result.body.should.have.property('wallet', walletId);
131+
result.body.should.have.property('label', 'My new address');
132+
result.body.should.have.property('addressType', 'p2sh');
133+
result.body.should.have.property('keychains');
134+
result.body.keychains.should.be.Array();
135+
result.body.keychains.should.have.length(3);
136+
137+
// Verify the keychain structure
138+
result.body.keychains[0].should.have.property('source', 'user');
139+
result.body.keychains[1].should.have.property('source', 'backup');
140+
result.body.keychains[2].should.have.property('source', 'bitgo');
141+
result.body.keychains[2].should.have.property('isBitGo', true);
142+
143+
// Verify that the correct BitGoJS methods were called
144+
assert.strictEqual(coinStub.calledOnceWith(coin), true);
145+
assert.strictEqual(mockCoin.wallets.calledOnce, true);
146+
assert.strictEqual(walletsGetStub.calledOnceWith({ id: walletId }), true);
147+
assert.strictEqual(
148+
mockWallet.createAddress.calledOnceWith(
149+
sinon.match({
150+
coin: coin,
151+
id: walletId,
152+
label: 'My new address',
153+
chain: 0,
154+
allowSkipVerifyAddress: true,
155+
})
156+
),
157+
true
158+
);
159+
});
160+
});
161+
29162
describe('CreateAddressParams', function () {
30163
it('should validate params with required coin and id', function () {
31164
const validParams = {

0 commit comments

Comments
 (0)