Skip to content

Commit 8d928e9

Browse files
committed
refactor: added unit tests that test encoding and decoding from end to end
also fixed other minor errors TICKET: WP-5444
1 parent f14ae3f commit 8d928e9

File tree

3 files changed

+149
-5
lines changed

3 files changed

+149
-5
lines changed

modules/express/src/typedRoutes/api/v2/lightningInitWallet.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ import { BitgoExpressError } from '../../schemas/error';
44

55
/**
66
* Path parameters for initializing a Lightning wallet
7-
* @property {string} coin - A lightning coin name (e.g, lnbtc).
7+
* @property {string} coin - A lightning coin name (e.g, lnbtc, tlnbtc).
88
* @property {string} walletId - The ID of the wallet.
99
*/
1010
export const LightningInitWalletParams = {
1111
coin: t.string,
1212
walletId: t.string,
13-
};
13+
} as const;
1414

1515
/**
1616
* Request body for initializing a Lightning wallet
@@ -19,7 +19,17 @@ export const LightningInitWalletParams = {
1919
export const LightningInitWalletBody = {
2020
passphrase: t.string,
2121
expressHost: optional(t.string),
22-
};
22+
} as const;
23+
24+
/**
25+
* Response
26+
* - 200: Returns the updated wallet. On success, the wallet's `coinSpecific` will include the encrypted admin macaroon for the Lightning signer node.
27+
* - 400: BitGo Express error payload when initialization cannot proceed (for example: invalid coin, unsupported environment, wallet not in an initializable state).
28+
*/
29+
export const LightningInitWalletResponse = {
30+
200: t.unknown,
31+
400: BitgoExpressError,
32+
} as const;
2333

2434
/**
2535
* Lightning - This is only used for self-custody lightning. Initialize a newly created Lightning Network Daemon (LND) for the first time.
@@ -33,7 +43,7 @@ export const PostLightningInitWallet = httpRoute({
3343
path: '/api/v2/:coin/wallet/:walletId/initwallet',
3444
method: 'POST',
3545
request: httpRequest({ params: LightningInitWalletParams, body: LightningInitWalletBody }),
36-
response: { 200: t.unknown, 400: BitgoExpressError },
46+
response: LightningInitWalletResponse,
3747
});
3848

3949
export type PostLightningInitWallet = typeof PostLightningInitWallet;

modules/express/test/unit/clientRoutes/lightning/lightningSignerRoutes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ describe('Lightning signer routes', () => {
8080
passphrase: apiData.initWalletRequestBody.passphrase,
8181
...(includingOptionalFields ? { expressHost: apiData.initWalletRequestBody.expressHost } : {}),
8282
},
83-
} as unknown as express.Request & { decoded: any };
83+
} as unknown as ExpressApiRouteRequest<'express.lightning.initWallet'>;
8484

8585
await handleInitLightningWallet(req);
8686

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

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ import {
99
LightningInitWalletBody,
1010
LightningInitWalletParams,
1111
} from '../../../src/typedRoutes/api/v2/lightningInitWallet';
12+
import { agent as supertest } from 'supertest';
13+
import nock from 'nock';
14+
import { DefaultConfig } from '../../../src/config';
15+
import { app as expressApp } from '../../../src/expressApp';
16+
import * as sinon from 'sinon';
17+
import { BitGo } from 'bitgo';
1218

1319
export function assertDecode<T>(codec: t.Type<T, unknown>, input: unknown): T {
1420
const result = codec.decode(input);
@@ -123,3 +129,131 @@ describe('io-ts decode tests', function () {
123129
assertDecode(t.type(LightningInitWalletBody), { passphrase: 'p', expressHost: 'host.example' });
124130
});
125131
});
132+
133+
describe('e2e tests for io-ts routes', function () {
134+
let agent;
135+
let authenticateStub: sinon.SinonStub;
136+
let walletsStub: sinon.SinonStub;
137+
let decryptStub: sinon.SinonStub;
138+
let encryptStub: sinon.SinonStub;
139+
let verifyAddressStub: sinon.SinonStub;
140+
before(function () {
141+
nock.restore();
142+
143+
const args = {
144+
...DefaultConfig,
145+
debug: false,
146+
env: 'test' as const,
147+
logfile: '/dev/null',
148+
};
149+
150+
const app = expressApp(args);
151+
agent = supertest(app);
152+
153+
authenticateStub = sinon.stub(BitGo.prototype, 'authenticate').callsFake(async (body: any) => {
154+
return {
155+
email: `${body.username}@example.com`,
156+
password: body.password,
157+
forceSMS: false,
158+
} as any;
159+
});
160+
encryptStub = sinon.stub(BitGo.prototype, 'encrypt').callsFake((params: any) => `enc:${params.input}`);
161+
decryptStub = sinon.stub(BitGo.prototype, 'decrypt').callsFake((params: any) => {
162+
const inputStr = String(params.input);
163+
return inputStr.startsWith('enc:') ? inputStr.substring(4) : inputStr;
164+
});
165+
verifyAddressStub = sinon.stub(BitGo.prototype, 'verifyAddress').callsFake((_params: any) => true);
166+
walletsStub = sinon.stub(BitGo.prototype, 'wallets').callsFake(() => {
167+
return {
168+
createWalletWithKeychains: async () => ({
169+
wallet: 'wallet-id-123',
170+
userKeychain: 'user-keychain',
171+
backupKeychain: 'backup-keychain',
172+
}),
173+
};
174+
});
175+
});
176+
beforeEach(function () {
177+
authenticateStub.resetHistory();
178+
walletsStub.resetHistory();
179+
decryptStub.resetHistory();
180+
encryptStub.resetHistory();
181+
verifyAddressStub.resetHistory();
182+
});
183+
after(function () {
184+
authenticateStub.restore();
185+
walletsStub.restore();
186+
decryptStub.restore();
187+
encryptStub.restore();
188+
verifyAddressStub.restore();
189+
});
190+
191+
it('POST /api/v2/user/login success', async function () {
192+
const res = await agent.post('/api/v2/user/login').send({ username: 'alice', password: 'pw' });
193+
res.status.should.equal(200);
194+
res.body.email.should.equal('[email protected]');
195+
res.body.password.should.equal('pw');
196+
sinon.assert.calledOnce(authenticateStub);
197+
sinon.assert.calledWithMatch(authenticateStub, { username: 'alice', password: 'pw' });
198+
});
199+
200+
it('POST /api/v2/user/login decode failure', async function () {
201+
const res = await agent.post('/api/v2/user/login').send({ username: 'alice' });
202+
res.status.should.equal(400);
203+
sinon.assert.notCalled(authenticateStub);
204+
});
205+
206+
it('POST /api/v2/encrypt success', async function () {
207+
const res = await agent.post('/api/v2/encrypt').send({ input: 'hello' });
208+
res.status.should.equal(200);
209+
res.body.encrypted.should.equal('enc:hello');
210+
sinon.assert.calledOnce(encryptStub);
211+
sinon.assert.calledWithMatch(encryptStub, { input: 'hello' });
212+
});
213+
214+
it('POST /api/v2/encrypt decode failure', async function () {
215+
const res = await agent.post('/api/v2/encrypt').send({ input: 123 });
216+
res.status.should.equal(400);
217+
sinon.assert.notCalled(encryptStub);
218+
});
219+
220+
it('POST /api/v2/decrypt success', async function () {
221+
const res = await agent.post('/api/v2/decrypt').send({ input: 'enc:secret', password: 'pw' });
222+
res.status.should.equal(200);
223+
res.body.decrypted.should.equal('secret');
224+
sinon.assert.calledOnce(decryptStub);
225+
sinon.assert.calledWithMatch(decryptStub, { input: 'enc:secret', password: 'pw' });
226+
});
227+
228+
it('POST /api/v2/decrypt decode failure', async function () {
229+
const res = await agent.post('/api/v2/decrypt').send({ password: 'pw' });
230+
res.status.should.equal(400);
231+
sinon.assert.notCalled(decryptStub);
232+
});
233+
234+
it('POST /api/v2/verifyaddress success', async function () {
235+
const res = await agent.post('/api/v2/verifyaddress').send({ address: 'addr1' });
236+
res.status.should.equal(200);
237+
res.body.should.have.property('verified', true);
238+
sinon.assert.calledOnce(verifyAddressStub);
239+
});
240+
241+
it('POST /api/v2/verifyaddress decode failure - invalid address', async function () {
242+
const res = await agent.post('/api/v2/verifyaddress').send({ address: 42 });
243+
res.status.should.equal(400);
244+
sinon.assert.notCalled(verifyAddressStub);
245+
});
246+
247+
it('POST /api/v1/wallets/simplecreate success', async function () {
248+
const res = await agent.post('/api/v1/wallets/simplecreate').send({ passphrase: 'pass' });
249+
res.status.should.equal(200);
250+
res.body.wallet.should.equal('wallet-id-123');
251+
sinon.assert.calledOnce(walletsStub);
252+
});
253+
254+
it('POST /api/v1/wallets/simplecreate decode - missing passphrase', async function () {
255+
const res = await agent.post('/api/v1/wallets/simplecreate').send({});
256+
res.status.should.equal(400);
257+
sinon.assert.notCalled(walletsStub);
258+
});
259+
});

0 commit comments

Comments
 (0)