Skip to content

Commit acb45be

Browse files
committed
update unit tests
1 parent cdc0325 commit acb45be

3 files changed

Lines changed: 226 additions & 60 deletions

File tree

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { input, select } from '@inquirer/prompts';
2-
import chalk from 'chalk';
3-
import { isDirectoryValid, readJsonFile, writeFile } from '../utils';
2+
import { isDirectoryValid, readJsonFile, writeFile } from '../../utils';
43
import { issuer, RawVerifiableCredential, signW3C } from '@trustvc/trustvc';
5-
import { SignInput } from '../types';
4+
import { SignInput } from '../../types';
5+
import signale from 'signale';
66

77
export const command = 'w3c-sign';
88
export const describe = 'Sign a verifiable credential using a did key-pair file';
@@ -14,7 +14,7 @@ export const handler = async () => {
1414

1515
await sign(answers);
1616
} catch (err: unknown) {
17-
console.error(chalk.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
17+
signale.error(`${err instanceof Error ? err.message : String(err)}`);
1818
}
1919
};
2020

@@ -80,11 +80,9 @@ export const sign = async ({
8080
if (signedVC?.signed) {
8181
const signedVCPath = `${pathToSignedVC}/signed_vc.json`;
8282
writeFile(signedVCPath, signedVC.signed);
83-
console.log(''); // blank line for spacing
84-
// signale.success(chalk.green('Signed verifiable credential saved to: ' + pathToSignedVC));
83+
signale.success('\nSigned verifiable credential saved to: ' + pathToSignedVC);
8584
}
8685
else {
87-
console.log(''); // blank line for spacing
88-
// signale.error(chalk.red(signedVC.error));
86+
signale.error('\n' + signedVC.error);
8987
}
9088
};
Lines changed: 96 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,29 @@
11
import * as prompts from '@inquirer/prompts';
22
import { issuer } from '@trustvc/trustvc';
33
import { beforeEach, describe, expect, it, MockedFunction, vi } from 'vitest';
4-
import { promptForInputs, sign } from '../../src/commands/sign';
5-
import { SignInput } from '../../src/types';
4+
import { promptForInputs, sign } from '../../../src/commands/w3c/sign';
5+
import { SignInput } from '../../../src/types';
66

77

88
vi.mock('@inquirer/prompts');
99

10-
vi.mock('../../src/utils', async () => {
11-
const actual = await vi.importActual<typeof import('../../src/utils')>('../../src/utils');
10+
vi.mock('signale', () => ({
11+
default: {
12+
success: vi.fn(),
13+
error: vi.fn(),
14+
warn: vi.fn(),
15+
info: vi.fn(),
16+
},
17+
Signale: vi.fn().mockImplementation(() => ({
18+
await: vi.fn(),
19+
success: vi.fn(),
20+
})),
21+
}));
22+
23+
vi.mock('../../../src/utils', async () => {
24+
const actual = await vi.importActual<typeof import('../../../src/utils')>(
25+
'../../../src/utils',
26+
);
1227
return {
1328
...actual,
1429
readJsonFile: vi.fn(),
@@ -25,39 +40,6 @@ vi.mock('@trustvc/trustvc', async () => {
2540
};
2641
});
2742

28-
29-
const mockPromptFlow = (
30-
algorithm: 'ecdsa-sd-2023' | 'bbs-2023' = 'ecdsa-sd-2023',
31-
) => {
32-
(prompts.input as any)
33-
.mockResolvedValueOnce('./did-keypair.json')
34-
.mockResolvedValueOnce('./credential.json')
35-
.mockResolvedValueOnce('.');
36-
37-
(prompts.select as any).mockResolvedValueOnce(algorithm);
38-
};
39-
40-
const mockUtilsHappyPath = async (
41-
keyPairData = { domain: 'https://example.com' },
42-
credential = { id: 'urn:uuid:123' },
43-
) => {
44-
const utils = await import('../../src/utils');
45-
46-
(utils.readJsonFile as MockedFunction<any>)
47-
.mockReturnValueOnce(keyPairData)
48-
.mockReturnValueOnce(credential);
49-
50-
(utils.isDirectoryValid as MockedFunction<any>).mockReturnValue(true);
51-
52-
return utils;
53-
};
54-
55-
const mockSignSuccess = async (signed: any) => {
56-
const trustvc = await import('@trustvc/trustvc');
57-
(trustvc.signW3C as MockedFunction<any>).mockResolvedValue({ signed });
58-
};
59-
60-
6143
describe('w3c-sign', () => {
6244
beforeEach(() => {
6345
vi.clearAllMocks();
@@ -66,8 +48,17 @@ describe('w3c-sign', () => {
6648

6749
describe('promptForInputs', () => {
6850
it('returns parsed inputs when algorithm is ecdsa-sd-2023', async () => {
69-
mockPromptFlow('ecdsa-sd-2023');
70-
await mockUtilsHappyPath();
51+
(prompts.input as any)
52+
.mockResolvedValueOnce('./did-keypair.json')
53+
.mockResolvedValueOnce('./credential.json')
54+
.mockResolvedValueOnce('.');
55+
(prompts.select as any).mockResolvedValueOnce('ecdsa-sd-2023');
56+
57+
const utils = await import('../../../src/utils');
58+
(utils.readJsonFile as MockedFunction<any>)
59+
.mockReturnValueOnce({ domain: 'https://example.com' })
60+
.mockReturnValueOnce({ id: 'urn:uuid:123' });
61+
(utils.isDirectoryValid as MockedFunction<any>).mockReturnValue(true);
7162

7263
const result = await promptForInputs();
7364

@@ -80,8 +71,17 @@ describe('w3c-sign', () => {
8071
});
8172

8273
it('returns parsed inputs when algorithm is bbs-2023', async () => {
83-
mockPromptFlow('bbs-2023');
84-
await mockUtilsHappyPath();
74+
(prompts.input as any)
75+
.mockResolvedValueOnce('./did-keypair.json')
76+
.mockResolvedValueOnce('./credential.json')
77+
.mockResolvedValueOnce('.');
78+
(prompts.select as any).mockResolvedValueOnce('bbs-2023');
79+
80+
const utils = await import('../../../src/utils');
81+
(utils.readJsonFile as MockedFunction<any>)
82+
.mockReturnValueOnce({ domain: 'https://example.com' })
83+
.mockReturnValueOnce({ id: 'urn:uuid:123' });
84+
(utils.isDirectoryValid as MockedFunction<any>).mockReturnValue(true);
8585

8686
const result = await promptForInputs();
8787

@@ -94,8 +94,17 @@ describe('w3c-sign', () => {
9494
});
9595

9696
it('provides required validation rules for inputs', async () => {
97-
mockPromptFlow('bbs-2023');
98-
await mockUtilsHappyPath();
97+
(prompts.input as any)
98+
.mockResolvedValueOnce('./did-keypair.json')
99+
.mockResolvedValueOnce('./credential.json')
100+
.mockResolvedValueOnce('.');
101+
(prompts.select as any).mockResolvedValueOnce('bbs-2023');
102+
103+
const utils = await import('../../../src/utils');
104+
(utils.readJsonFile as MockedFunction<any>)
105+
.mockReturnValueOnce({ domain: 'https://example.com' })
106+
.mockReturnValueOnce({ id: 'urn:uuid:123' });
107+
(utils.isDirectoryValid as MockedFunction<any>).mockReturnValue(true);
99108

100109
await promptForInputs();
101110

@@ -117,8 +126,17 @@ describe('w3c-sign', () => {
117126
});
118127

119128
it('prompts for encryption algorithm with supported choices', async () => {
120-
mockPromptFlow();
121-
await mockUtilsHappyPath();
129+
(prompts.input as any)
130+
.mockResolvedValueOnce('./did-keypair.json')
131+
.mockResolvedValueOnce('./credential.json')
132+
.mockResolvedValueOnce('.');
133+
(prompts.select as any).mockResolvedValueOnce('ecdsa-sd-2023');
134+
135+
const utils = await import('../../../src/utils');
136+
(utils.readJsonFile as MockedFunction<any>)
137+
.mockReturnValueOnce({ domain: 'https://example.com' })
138+
.mockReturnValueOnce({ id: 'urn:uuid:123' });
139+
(utils.isDirectoryValid as MockedFunction<any>).mockReturnValue(true);
122140

123141
await promptForInputs();
124142

@@ -134,8 +152,8 @@ describe('w3c-sign', () => {
134152
});
135153

136154
it('throws when given an invalid did key-pair file path (readJsonFile fails)', async () => {
137-
mockPromptFlow('ecdsa-sd-2023');
138-
const utils = await import('../../src/utils');
155+
(prompts.input as any).mockResolvedValueOnce('./did-keypair.json');
156+
const utils = await import('../../../src/utils');
139157

140158
(utils.readJsonFile as MockedFunction<any>).mockImplementation(() => {
141159
throw new Error('Invalid key pair file path: ./did-keypair.json');
@@ -147,8 +165,10 @@ describe('w3c-sign', () => {
147165
});
148166

149167
it('throws when given an invalid credential file path (readJsonFile fails)', async () => {
150-
mockPromptFlow('ecdsa-sd-2023');
151-
const utils = await import('../../src/utils');
168+
(prompts.input as any)
169+
.mockResolvedValueOnce('./did-keypair.json')
170+
.mockResolvedValueOnce('./credential.json');
171+
const utils = await import('../../../src/utils');
152172

153173
(utils.readJsonFile as MockedFunction<any>)
154174
.mockReturnValueOnce({ domain: 'https://example.com' })
@@ -163,8 +183,16 @@ describe('w3c-sign', () => {
163183
});
164184

165185
it('throws when output path is not a valid directory', async () => {
166-
mockPromptFlow('ecdsa-sd-2023');
167-
const utils = await mockUtilsHappyPath();
186+
(prompts.input as any)
187+
.mockResolvedValueOnce('./did-keypair.json')
188+
.mockResolvedValueOnce('./credential.json')
189+
.mockResolvedValueOnce('./invalid-dir');
190+
(prompts.select as any).mockResolvedValueOnce('ecdsa-sd-2023');
191+
192+
const utils = await import('../../../src/utils');
193+
(utils.readJsonFile as MockedFunction<any>)
194+
.mockReturnValueOnce({ domain: 'https://example.com' })
195+
.mockReturnValueOnce({ id: 'urn:uuid:123' });
168196
(utils.isDirectoryValid as MockedFunction<any>).mockReturnValue(false);
169197

170198
await expect(promptForInputs()).rejects.toThrow('Output path is not valid');
@@ -175,6 +203,8 @@ describe('w3c-sign', () => {
175203
describe('sign', () => {
176204
let writeFileMock: MockedFunction<any>;
177205
let signW3CMock: MockedFunction<any>;
206+
let signaleSuccessMock: MockedFunction<any>;
207+
let signaleErrorMock: MockedFunction<any>;
178208

179209
const input: SignInput = {
180210
keyPairData: { domain: 'https://example.com' } as typeof issuer.IssuedDIDOption,
@@ -184,11 +214,15 @@ describe('w3c-sign', () => {
184214
};
185215

186216
beforeEach(async () => {
187-
const utils = await import('../../src/utils');
217+
const utils = await import('../../../src/utils');
188218
writeFileMock = utils.writeFile as MockedFunction<any>;
189219

190220
const trustvc = await import('@trustvc/trustvc');
191221
signW3CMock = trustvc.signW3C as MockedFunction<any>;
222+
223+
const signale = await import('signale');
224+
signaleSuccessMock = (signale.default as any).success;
225+
signaleErrorMock = (signale.default as any).error;
192226
});
193227

194228
it('signs with ecdsa-sd-2023 and writes to default output path', async () => {
@@ -202,6 +236,10 @@ describe('w3c-sign', () => {
202236
'ecdsa-sd-2023',
203237
);
204238
expect(writeFileMock).toHaveBeenCalledWith('./signed_vc.json', { proof: 'ok' });
239+
expect(signaleSuccessMock).toHaveBeenCalledWith(
240+
expect.stringContaining('Signed verifiable credential saved to: .'),
241+
);
242+
expect(signaleErrorMock).not.toHaveBeenCalled();
205243
});
206244

207245
it('signs with bbs-2023 and writes to a custom output directory', async () => {
@@ -219,6 +257,10 @@ describe('w3c-sign', () => {
219257
'bbs-2023',
220258
);
221259
expect(writeFileMock).toHaveBeenCalledWith('./out/signed_vc.json', { proof: 'ok' });
260+
expect(signaleSuccessMock).toHaveBeenCalledWith(
261+
expect.stringContaining('Signed verifiable credential saved to: ./out'),
262+
);
263+
expect(signaleErrorMock).not.toHaveBeenCalled();
222264
});
223265

224266
it('does not write file when signing fails', async () => {
@@ -227,6 +269,8 @@ describe('w3c-sign', () => {
227269
await sign(input);
228270

229271
expect(writeFileMock).not.toHaveBeenCalled();
272+
expect(signaleSuccessMock).not.toHaveBeenCalled();
273+
expect(signaleErrorMock).toHaveBeenCalledWith(expect.stringContaining('Failed to sign'));
230274
});
231275

232276
it('throws when writing signed VC fails', async () => {

0 commit comments

Comments
 (0)