Skip to content

Commit ad3e9e7

Browse files
committed
Test cli wrapper return code/out/err, match entire result in toMatchSnapshot()
1 parent 4d73911 commit ad3e9e7

21 files changed

Lines changed: 290 additions & 204 deletions

src/commands/reset.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
import { Command } from 'commander';
22
import { CliOptions } from '../types/options.js';
33
import { ManagerLocal } from '@open-audio-stack/core';
4+
import { output, OutputType } from '../utils.js';
45

56
export function reset(command: Command, manager: ManagerLocal) {
67
command
78
.command('reset')
89
.option('-l, --log', 'Enable logging')
910
.description('Reset the synced package cache')
1011
.action((options: CliOptions) => {
11-
if (options.log) manager.logEnable();
12-
else manager.logDisable();
13-
manager.reset();
14-
console.log(`${manager.type} cache has been reset`);
12+
const message = `Reset ${manager.type}`;
13+
output(OutputType.START, message, options, manager);
14+
try {
15+
manager.reset();
16+
const payload =
17+
options && options.json ? { type: manager.type, status: 'reset' } : `Reset complete ${manager.type}`;
18+
output(OutputType.SUCCESS, payload, options, manager);
19+
} catch (err: any) {
20+
output(OutputType.ERROR, err, options, manager);
21+
process.exit(1);
22+
}
1523
});
1624
}

src/utils.ts

Lines changed: 25 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { Base, Package } from '@open-audio-stack/core';
1+
import { Base, isTests, Package } from '@open-audio-stack/core';
22
import CliTable3 from 'cli-table3';
3-
import ora from 'ora';
3+
import ora, { Ora } from 'ora';
44
import type { CliOptions } from './types/options.js';
55

66
export function formatOutput(result: Package[] | Package | undefined, versions?: string[], json?: boolean): string {
@@ -62,96 +62,46 @@ export function truncateString(str: string, num: number) {
6262
}
6363
}
6464

65-
// Simple spinner registry for the `output` API so callers can start/stop spinners
66-
const _spinners: Map<string, ReturnType<typeof ora>> = new Map();
67-
6865
export enum OutputType {
6966
START = 'start',
7067
SUCCESS = 'success',
7168
ERROR = 'error',
7269
}
7370

74-
/**
75-
* Low level output API that callers can use to mark start, success, and error
76-
* states for long-running operations. This provides clear control over when
77-
* spinners start/stop and when textual/json output is emitted.
78-
*/
79-
export function output(type: OutputType, payload: any, options?: CliOptions, base?: Base) {
80-
const useJson = Boolean(options && options.json);
81-
const isTest = Boolean(process.env.VITEST || process.env.NODE_ENV === 'test');
82-
const key = String(typeof payload === 'string' ? payload : (payload && payload.message) || payload || '');
83-
84-
if (type === OutputType.START) {
85-
// configure base logging at start
86-
if (base) {
87-
if (options && options.log) base.logEnable();
88-
else base.logDisable();
89-
}
90-
91-
if (useJson) {
92-
console.log(JSON.stringify({ status: 'inprogress', message: key }, null, 2));
93-
return;
94-
}
71+
let spinner: Ora | undefined;
9572

96-
if (isTest) {
97-
console.log(key);
98-
return;
99-
}
100-
101-
// interactive run: create and start a spinner for this key
102-
const s = ora(key).start();
103-
_spinners.set(key, s);
104-
return;
105-
}
106-
107-
if (type === OutputType.SUCCESS) {
108-
// If JSON requested and payload is an object, print it
109-
if (useJson && typeof payload === 'object') {
110-
console.log(JSON.stringify(payload, null, 2));
111-
return;
112-
}
113-
114-
// For non-json modes we expect payload to be a string (commands should pass a string)
115-
const messageOut = String(payload);
116-
117-
if (isTest) {
118-
// In test mode only print the final payload (no start/checkmark).
119-
console.log(messageOut);
120-
return;
121-
}
122-
123-
const s = _spinners.get(key);
124-
if (s) {
125-
s.succeed(key);
126-
if (messageOut && messageOut !== key) console.log(messageOut);
127-
_spinners.delete(key);
128-
return;
129-
}
73+
export function output(type: OutputType, message: any, options?: CliOptions, base?: Base) {
74+
// console.log('\n output', type, message, options);
75+
const useJson = Boolean(options && options.json);
76+
if (message.message) message = message.message;
13077

131-
// fallback
132-
console.log(key);
133-
if (messageOut && messageOut !== key) console.log(messageOut);
134-
return;
78+
// If logging, ensure core package logging is enabled.
79+
if (base) {
80+
if (options && options.log) base.logEnable();
81+
else base.logDisable();
13582
}
13683

137-
// ERROR
138-
const errMsg = payload instanceof Error ? payload.message : String(payload);
84+
// If json, output json only.
13985
if (useJson) {
140-
console.log(JSON.stringify({ error: errMsg }, null, 2));
86+
console.log(JSON.stringify({ type, message }, null, 2));
14187
return;
14288
}
14389

144-
if (isTest) {
145-
console.error(errMsg);
90+
// If test, output text only.
91+
if (isTests()) {
92+
console.log(message);
14693
return;
14794
}
14895

149-
const s2 = _spinners.get(key);
150-
if (s2) {
151-
s2.fail(errMsg);
152-
_spinners.delete(key);
96+
// If interactive run, use spinners.
97+
if (type === OutputType.START) {
98+
spinner = ora(message).start();
99+
return;
100+
} else if (type === OutputType.SUCCESS) {
101+
spinner?.succeed(message);
102+
return;
103+
} else {
104+
spinner?.fail(message);
153105
return;
154106
}
155-
156-
console.error(errMsg);
157107
}

tests/__snapshots__/index.test.ts.snap

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
22

33
exports[`Root command 1`] = `
4-
Usage: index [options] [command]
4+
{
5+
code: 1,
6+
err: Usage: index [options] [command]
57
68
Options:
79
-V, --version output the version number
@@ -13,11 +15,15 @@ Commands:
1315
plugins
1416
presets
1517
projects
16-
help [command] display help for command
18+
help [command] display help for command,
19+
out: ,
20+
}
1721
`;
1822

1923
exports[`Root command plugins 1`] = `
20-
Usage: index plugins [options] [command]
24+
{
25+
code: 1,
26+
err: Usage: index plugins [options] [command]
2127
2228
Options:
2329
-h, --help display help for command
@@ -36,11 +42,15 @@ Commands:
3642
sync [options] Sync remote packages into cache
3743
uninstall [options] <input> Uninstall a package locally by
3844
slug/version
39-
help [command] display help for command
45+
help [command] display help for command,
46+
out: ,
47+
}
4048
`;
4149
4250
exports[`Root command presets 1`] = `
43-
Usage: index presets [options] [command]
51+
{
52+
code: 1,
53+
err: Usage: index presets [options] [command]
4454
4555
Options:
4656
-h, --help display help for command
@@ -59,11 +69,15 @@ Commands:
5969
sync [options] Sync remote packages into cache
6070
uninstall [options] <input> Uninstall a package locally by
6171
slug/version
62-
help [command] display help for command
72+
help [command] display help for command,
73+
out: ,
74+
}
6375
`;
6476
6577
exports[`Root command projects 1`] = `
66-
Usage: index projects [options] [command]
78+
{
79+
code: 1,
80+
err: Usage: index projects [options] [command]
6781
6882
Options:
6983
-h, --help display help for command
@@ -82,5 +96,7 @@ Commands:
8296
sync [options] Sync remote packages into cache
8397
uninstall [options] <input> Uninstall a package locally by
8498
slug/version
85-
help [command] display help for command
99+
help [command] display help for command,
100+
out: ,
101+
}
86102
`;
Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,73 @@
11
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
22

33
exports[`Config get 1`] = `
4-
Get config appDir
5-
test2
4+
{
5+
code: 0,
6+
err: ,
7+
out: Get config appDir
8+
test,
9+
}
610
`;
711

812
exports[`Config get 2`] = `
9-
Get config pluginsDir
10-
test/installed/plugins
13+
{
14+
code: 0,
15+
err: ,
16+
out: Get config pluginsDir
17+
test/installed/plugins,
18+
}
1119
`;
1220

1321
exports[`Config get 3`] = `
14-
Get config presetsDir
15-
test/installed/presets
22+
{
23+
code: 0,
24+
err: ,
25+
out: Get config presetsDir
26+
test/installed/presets,
27+
}
1628
`;
1729

1830
exports[`Config get 4`] = `
19-
Get config projectsDir
20-
test/installed/projects
31+
{
32+
code: 0,
33+
err: ,
34+
out: Get config projectsDir
35+
test/installed/projects,
36+
}
2137
`;
2238

2339
exports[`Config get 5`] = `
24-
Get config registries
25-
[object Object]
40+
{
41+
code: 0,
42+
err: ,
43+
out: Get config registries
44+
[object Object],
45+
}
2646
`;
2747

2848
exports[`Config get 6`] = `
29-
Get config version
30-
1.0.0
49+
{
50+
code: 0,
51+
err: ,
52+
out: Get config version
53+
1.0.0,
54+
}
3155
`;
3256

3357
exports[`Config set 1`] = `
34-
Get config appDir
35-
test2
58+
{
59+
code: 0,
60+
err: ,
61+
out: Get config appDir
62+
test2,
63+
}
3664
`;
3765

3866
exports[`Config set 2`] = `
39-
Get config appDir
40-
test
67+
{
68+
code: 0,
69+
err: ,
70+
out: Get config appDir
71+
test,
72+
}
4173
`;
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
22

33
exports[`Create package 1`] = `
4-
User force closed the prompt with 0 null
5-
Create package
4+
{
5+
code: 1,
6+
err: ,
7+
out: Create package
68
? Org id (org-name)
7-
9+
User force closed the prompt with 0 null,
10+
}
811
`;

tests/commands/__snapshots__/filter.test.ts.snap

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,32 @@
11
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
22

33
exports[`Filter packages 1`] = `
4-
Filter plugins by name=Surge XT
4+
{
5+
code: 0,
6+
err: ,
7+
out: Filter plugins by name=Surge XT
58
┌─────────────────────────┬──────────┬─────────┬───────────┬────────────┬─────────┬───────────────────────────────┐
69
IdNameVersionInstalledDateLicenseTags
710
├─────────────────────────┼──────────┼─────────┼───────────┼────────────┼─────────┼───────────────────────────────┤
8-
│ surge-synthesizer/surge │ Surge XT │ 1.3.4 │ ✓ │ 2024-08-11 │ gpl-3.0 │ Instrument, Synth, Modulation │
9-
└─────────────────────────┴──────────┴─────────┴───────────┴────────────┴─────────┴───────────────────────────────┘
11+
surge-synthesizer/surgeSurge XT1.3.4-2024-08-11gpl-3.0Instrument, Synth, Modulation
12+
└─────────────────────────┴──────────┴─────────┴───────────┴────────────┴─────────┴───────────────────────────────┘,
13+
}
1014
`;
1115

1216
exports[`Filter packages 2`] = `
13-
Filter plugins by name=Surge XU
14-
No results found
17+
{
18+
code: 0,
19+
err: ,
20+
out: Filter plugins by name=Surge XU
21+
No results found,
22+
}
1523
`;
1624

1725
exports[`Filter packages 3`] = `
18-
Filter plugins by license=cc0-1.0
26+
{
27+
code: 0,
28+
err: ,
29+
out: Filter plugins by license=cc0-1.0
1930
┌────────────────────────────────────────┬──────────────────────────┬─────────┬───────────┬────────────┬─────────┬───────────────────────────────────┐
2031
IdNameVersionInstalledDateLicenseTags
2132
├────────────────────────────────────────┼──────────────────────────┼─────────┼───────────┼────────────┼─────────┼───────────────────────────────────┤
@@ -42,5 +53,6 @@ Filter plugins by license=cc0-1.0
4253
freepats/hang-d-minorHang D Minor1.0.0-2022-03-30cc0-1.0Instrument, Orchestra, Hang, s...
4354
├────────────────────────────────────────┼──────────────────────────┼─────────┼───────────┼────────────┼─────────┼───────────────────────────────────┤
4455
freepats/glasses-of-waterGlasses Of Water1.0.0-2019-12-27cc0-1.0Instrument, Orchestra, Glass, ...
45-
└────────────────────────────────────────┴──────────────────────────┴─────────┴───────────┴────────────┴─────────┴───────────────────────────────────┘
56+
└────────────────────────────────────────┴──────────────────────────┴─────────┴───────────┴────────────┴─────────┴───────────────────────────────────┘,
57+
}
4658
`;

0 commit comments

Comments
 (0)