@nexical/cli 0.11.0 → 0.11.2
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/.github/workflows/deploy.yml +1 -1
- package/.husky/pre-commit +1 -0
- package/.prettierignore +8 -0
- package/.prettierrc +7 -0
- package/GEMINI.md +36 -30
- package/README.md +85 -56
- package/dist/chunk-AC4B3HPJ.js +93 -0
- package/dist/chunk-AC4B3HPJ.js.map +1 -0
- package/dist/{chunk-JYASTIIW.js → chunk-PJIOCW2A.js} +1 -1
- package/dist/chunk-PJIOCW2A.js.map +1 -0
- package/dist/{chunk-WKERTCM6.js → chunk-Q7YLW5HJ.js} +5 -2
- package/dist/chunk-Q7YLW5HJ.js.map +1 -0
- package/dist/index.js +41 -12
- package/dist/index.js.map +1 -1
- package/dist/src/commands/init.d.ts +4 -1
- package/dist/src/commands/init.js +8 -4
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/module/add.d.ts +3 -1
- package/dist/src/commands/module/add.js +24 -13
- package/dist/src/commands/module/add.js.map +1 -1
- package/dist/src/commands/module/list.js +9 -5
- package/dist/src/commands/module/list.js.map +1 -1
- package/dist/src/commands/module/remove.d.ts +3 -1
- package/dist/src/commands/module/remove.js +13 -7
- package/dist/src/commands/module/remove.js.map +1 -1
- package/dist/src/commands/module/update.d.ts +3 -1
- package/dist/src/commands/module/update.js +7 -5
- package/dist/src/commands/module/update.js.map +1 -1
- package/dist/src/commands/run.d.ts +4 -1
- package/dist/src/commands/run.js +10 -2
- package/dist/src/commands/run.js.map +1 -1
- package/dist/src/commands/setup.js +9 -4
- package/dist/src/commands/setup.js.map +1 -1
- package/dist/src/utils/discovery.js +1 -1
- package/dist/src/utils/git.js +1 -1
- package/dist/src/utils/url-resolver.js +1 -1
- package/eslint.config.mjs +67 -0
- package/index.ts +34 -20
- package/package.json +56 -32
- package/src/commands/init.ts +79 -76
- package/src/commands/module/add.ts +158 -148
- package/src/commands/module/list.ts +61 -50
- package/src/commands/module/remove.ts +59 -54
- package/src/commands/module/update.ts +44 -42
- package/src/commands/run.ts +89 -81
- package/src/commands/setup.ts +70 -60
- package/src/utils/discovery.ts +98 -113
- package/src/utils/git.ts +35 -28
- package/src/utils/url-resolver.ts +50 -45
- package/test/e2e/lifecycle.e2e.test.ts +139 -131
- package/test/integration/commands/init.integration.test.ts +64 -64
- package/test/integration/commands/module.integration.test.ts +122 -122
- package/test/integration/commands/run.integration.test.ts +70 -63
- package/test/integration/utils/command-loading.integration.test.ts +40 -53
- package/test/unit/commands/init.test.ts +163 -128
- package/test/unit/commands/module/add.test.ts +312 -245
- package/test/unit/commands/module/list.test.ts +108 -91
- package/test/unit/commands/module/remove.test.ts +74 -67
- package/test/unit/commands/module/update.test.ts +74 -70
- package/test/unit/commands/run.test.ts +253 -201
- package/test/unit/commands/setup.test.ts +138 -128
- package/test/unit/utils/command-discovery.test.ts +138 -125
- package/test/unit/utils/git.test.ts +135 -117
- package/test/unit/utils/integration-helpers.test.ts +59 -49
- package/test/unit/utils/url-resolver.test.ts +46 -34
- package/test/utils/integration-helpers.ts +36 -29
- package/tsconfig.json +15 -25
- package/tsup.config.ts +14 -14
- package/vitest.config.ts +10 -10
- package/vitest.e2e.config.ts +6 -6
- package/vitest.integration.config.ts +17 -17
- package/dist/chunk-JYASTIIW.js.map +0 -1
- package/dist/chunk-OKXOCNXP.js +0 -105
- package/dist/chunk-OKXOCNXP.js.map +0 -1
- package/dist/chunk-WKERTCM6.js.map +0 -1
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { logger } from '@nexical/cli-core';
|
|
2
1
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
3
2
|
import RunCommand from '../../../src/commands/run.js';
|
|
4
3
|
import fs from 'fs-extra';
|
|
@@ -7,246 +6,299 @@ import EventEmitter from 'events';
|
|
|
7
6
|
import process from 'node:process';
|
|
8
7
|
|
|
9
8
|
vi.mock('@nexical/cli-core', async (importOriginal) => {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
const mod = await importOriginal<typeof import('@nexical/cli-core')>();
|
|
10
|
+
return {
|
|
11
|
+
...mod,
|
|
12
|
+
logger: {
|
|
13
|
+
code: vi.fn(),
|
|
14
|
+
debug: vi.fn(),
|
|
15
|
+
error: vi.fn(),
|
|
16
|
+
success: vi.fn(),
|
|
17
|
+
info: vi.fn(),
|
|
18
|
+
warn: vi.fn(),
|
|
19
|
+
},
|
|
20
|
+
};
|
|
15
21
|
});
|
|
16
22
|
vi.mock('fs-extra');
|
|
17
23
|
vi.mock('child_process');
|
|
18
24
|
vi.mock('child_process');
|
|
19
25
|
|
|
20
26
|
describe('RunCommand', () => {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
vi.spyOn(process, 'on').mockImplementation((event: string | symbol, listener: any) => {
|
|
50
|
-
return process;
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
await command.init();
|
|
54
|
-
mockExit = vi.spyOn(process, 'exit').mockImplementation((() => { }) as any);
|
|
27
|
+
let command: RunCommand;
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
29
|
+
let mockChild: any;
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
31
|
+
let mockExit: any;
|
|
32
|
+
|
|
33
|
+
beforeEach(async () => {
|
|
34
|
+
vi.clearAllMocks();
|
|
35
|
+
command = new RunCommand({}, { rootDir: '/mock/root' });
|
|
36
|
+
|
|
37
|
+
mockChild = new EventEmitter();
|
|
38
|
+
mockChild.kill = vi.fn();
|
|
39
|
+
mockChild.stdout = new EventEmitter();
|
|
40
|
+
mockChild.stderr = new EventEmitter();
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
42
|
+
vi.mocked(cp.spawn).mockReturnValue(mockChild as any);
|
|
43
|
+
|
|
44
|
+
vi.spyOn(command, 'error').mockImplementation(() => {});
|
|
45
|
+
vi.spyOn(command, 'info').mockImplementation(() => {});
|
|
46
|
+
vi.spyOn(command, 'success').mockImplementation(() => {});
|
|
47
|
+
vi.spyOn(command, 'warn').mockImplementation(() => {});
|
|
48
|
+
|
|
49
|
+
// Defaultfs mocks
|
|
50
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
51
|
+
vi.mocked(fs.pathExists).mockImplementation(async (p: any) => {
|
|
52
|
+
if (p.includes('package.json')) return true;
|
|
53
|
+
return false;
|
|
55
54
|
});
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
56
|
+
vi.mocked(fs.readJson).mockImplementation(async (p: any) => {
|
|
57
|
+
return { scripts: { test: 'echo test', sc: 'echo sc' } };
|
|
59
58
|
});
|
|
60
59
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
expect(RunCommand.requiresProject).toBe(true);
|
|
65
|
-
expect(RunCommand.args).toBeDefined();
|
|
60
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
61
|
+
vi.spyOn(process, 'on').mockImplementation((event: string | symbol, listener: any) => {
|
|
62
|
+
return process;
|
|
66
63
|
});
|
|
67
64
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
65
|
+
await command.init();
|
|
66
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
67
|
+
mockExit = vi.spyOn(process, 'exit').mockImplementation((() => {}) as any);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
afterEach(() => {
|
|
71
|
+
vi.resetAllMocks();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('should have correct static properties', () => {
|
|
75
|
+
// expect(RunCommand.paths).toEqual([['run']]); // run is default? Check base command implementation if needed, but 'usage' covers it.
|
|
76
|
+
expect(RunCommand.usage).toBe('run <script> [args...]');
|
|
77
|
+
expect(RunCommand.requiresProject).toBe(true);
|
|
78
|
+
expect(RunCommand.args).toBeDefined();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should error if project root is missing', async () => {
|
|
82
|
+
command = new RunCommand({}, { rootDir: undefined });
|
|
83
|
+
vi.spyOn(command, 'init').mockImplementation(async () => {});
|
|
84
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
85
|
+
vi.spyOn(command, 'error').mockImplementation((() => {}) as any);
|
|
86
|
+
|
|
87
|
+
await command.runInit({ script: 'script', args: [] });
|
|
88
|
+
expect(command.error).toHaveBeenCalledWith(
|
|
89
|
+
expect.stringContaining('requires to be run within an app project'),
|
|
90
|
+
1,
|
|
91
|
+
);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('should error if script is missing', async () => {
|
|
95
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
96
|
+
await command.run({} as any);
|
|
97
|
+
expect(command.error).toHaveBeenCalledWith('Please specify a script to run.');
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('should run core script via npm', async () => {
|
|
101
|
+
setTimeout(() => {
|
|
102
|
+
mockChild.emit('close', 0);
|
|
103
|
+
}, 10);
|
|
104
|
+
|
|
105
|
+
// run(options)
|
|
106
|
+
await command.run({ script: 'test', args: [] });
|
|
107
|
+
|
|
108
|
+
expect(cp.spawn).toHaveBeenCalledWith(
|
|
109
|
+
'npm',
|
|
110
|
+
['run', 'test', '--'],
|
|
111
|
+
expect.objectContaining({
|
|
112
|
+
cwd: '/mock/root',
|
|
113
|
+
}),
|
|
114
|
+
);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('should run module script if resolved', async () => {
|
|
118
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
119
|
+
vi.mocked(fs.pathExists).mockImplementation(async (p: any) => {
|
|
120
|
+
return p.includes('stripe/package.json') || p.includes('stripe') || p.includes('core');
|
|
75
121
|
});
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
122
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
123
|
+
vi.mocked(fs.readJson).mockImplementation(async (p: any) => {
|
|
124
|
+
if (p.includes('stripe')) {
|
|
125
|
+
return { scripts: { sync: 'node scripts/sync.js' } };
|
|
126
|
+
}
|
|
127
|
+
return { scripts: { test: 'echo test' } };
|
|
80
128
|
});
|
|
81
129
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
130
|
+
setTimeout(() => {
|
|
131
|
+
mockChild.emit('close', 0);
|
|
132
|
+
}, 10);
|
|
133
|
+
|
|
134
|
+
await command.run({ script: 'stripe:sync', args: ['--flag'] });
|
|
135
|
+
|
|
136
|
+
// Expect shell execution of raw command
|
|
137
|
+
// Expect npm run <scriptName>
|
|
138
|
+
expect(cp.spawn).toHaveBeenCalledWith(
|
|
139
|
+
'npm',
|
|
140
|
+
expect.arrayContaining(['run', 'sync', '--', '--flag']),
|
|
141
|
+
expect.objectContaining({
|
|
142
|
+
cwd: expect.stringContaining('/modules/stripe'),
|
|
143
|
+
}),
|
|
144
|
+
);
|
|
145
|
+
expect(cp.spawn).toHaveBeenCalledWith(
|
|
146
|
+
'npm',
|
|
147
|
+
expect.arrayContaining(['run', 'sync', '--', '--flag']),
|
|
148
|
+
expect.objectContaining({
|
|
149
|
+
cwd: expect.stringContaining('/modules/stripe'),
|
|
150
|
+
}),
|
|
151
|
+
);
|
|
152
|
+
// strict run.ts does not log "Running module script..." in new revision
|
|
153
|
+
// expect(command.info).toHaveBeenCalledWith(expect.stringContaining('Running module script'));
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('should handle module script read error', async () => {
|
|
157
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
158
|
+
vi.mocked(fs.pathExists).mockImplementation(async (p: any) => {
|
|
159
|
+
return p.includes('stripe'); // module exists
|
|
93
160
|
});
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
if (p.includes('stripe')) {
|
|
101
|
-
return { scripts: { sync: 'node scripts/sync.js' } };
|
|
102
|
-
}
|
|
103
|
-
return { scripts: { test: 'echo test' } };
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
setTimeout(() => {
|
|
107
|
-
mockChild.emit('close', 0);
|
|
108
|
-
}, 10);
|
|
109
|
-
|
|
110
|
-
await command.run({ script: 'stripe:sync', args: ['--flag'] });
|
|
111
|
-
|
|
112
|
-
// Expect shell execution of raw command
|
|
113
|
-
// Expect npm run <scriptName>
|
|
114
|
-
expect(cp.spawn).toHaveBeenCalledWith('npm', expect.arrayContaining([
|
|
115
|
-
'run', 'sync', '--', '--flag'
|
|
116
|
-
]), expect.objectContaining({
|
|
117
|
-
cwd: expect.stringContaining('/modules/stripe')
|
|
118
|
-
}));
|
|
119
|
-
expect(cp.spawn).toHaveBeenCalledWith('npm', expect.arrayContaining([
|
|
120
|
-
'run', 'sync', '--', '--flag'
|
|
121
|
-
]), expect.objectContaining({
|
|
122
|
-
cwd: expect.stringContaining('/modules/stripe')
|
|
123
|
-
}));
|
|
124
|
-
// strict run.ts does not log "Running module script..." in new revision
|
|
125
|
-
// expect(command.info).toHaveBeenCalledWith(expect.stringContaining('Running module script'));
|
|
161
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
162
|
+
vi.mocked(fs.readJson).mockImplementation(async (p: any) => {
|
|
163
|
+
if (p.includes('stripe')) {
|
|
164
|
+
throw new Error('Read failed');
|
|
165
|
+
}
|
|
166
|
+
return { scripts: {} };
|
|
126
167
|
});
|
|
127
168
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
});
|
|
132
|
-
vi.mocked(fs.readJson).mockImplementation(async (p: any) => {
|
|
133
|
-
if (p.includes('stripe')) {
|
|
134
|
-
throw new Error('Read failed');
|
|
135
|
-
}
|
|
136
|
-
return { scripts: {} };
|
|
137
|
-
});
|
|
169
|
+
setTimeout(() => {
|
|
170
|
+
mockChild.emit('close', 0);
|
|
171
|
+
}, 10);
|
|
138
172
|
|
|
139
|
-
|
|
140
|
-
mockChild.emit('close', 0);
|
|
141
|
-
}, 10);
|
|
173
|
+
await command.run({ script: 'stripe:sync', args: [] });
|
|
142
174
|
|
|
143
|
-
|
|
175
|
+
expect(command.error).toHaveBeenCalledWith(
|
|
176
|
+
expect.stringContaining('Failed to read package.json'),
|
|
177
|
+
);
|
|
178
|
+
});
|
|
144
179
|
|
|
145
|
-
|
|
180
|
+
it('should ignore module script if package.json missing', async () => {
|
|
181
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
182
|
+
vi.mocked(fs.pathExists).mockImplementation(async (p: any) => {
|
|
183
|
+
return p.includes('stripe') && !p.includes('package.json');
|
|
146
184
|
});
|
|
147
185
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
});
|
|
186
|
+
vi.mocked(fs.readJson).mockResolvedValue({
|
|
187
|
+
scripts: { 'stripe:sync': 'fallback' },
|
|
188
|
+
});
|
|
152
189
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
190
|
+
setTimeout(() => {
|
|
191
|
+
mockChild.emit('close', 0);
|
|
192
|
+
}, 10);
|
|
193
|
+
await command.run({ script: 'stripe:sync', args: [] });
|
|
194
|
+
|
|
195
|
+
// Should error strict
|
|
196
|
+
expect(command.error).toHaveBeenCalledWith(
|
|
197
|
+
expect.stringContaining('Failed to find package.json'),
|
|
198
|
+
);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('should handle cleanup signals', async () => {
|
|
202
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
203
|
+
const listeners: Record<string, Function> = {};
|
|
204
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
205
|
+
vi.spyOn(process, 'on').mockImplementation((event: string | symbol, listener: any) => {
|
|
206
|
+
listeners[event.toString()] = listener;
|
|
207
|
+
return process;
|
|
208
|
+
});
|
|
156
209
|
|
|
157
|
-
|
|
158
|
-
|
|
210
|
+
const runPromise = command.run({ script: 'test', args: [] });
|
|
211
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
159
212
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
213
|
+
// Simulate signal by calling listener directly
|
|
214
|
+
if (listeners['SIGINT']) listeners['SIGINT']();
|
|
215
|
+
mockChild.emit('close', 0);
|
|
163
216
|
|
|
164
|
-
|
|
165
|
-
const listeners: Record<string, Function> = {};
|
|
166
|
-
vi.spyOn(process, 'on').mockImplementation((event: string | symbol, listener: any) => {
|
|
167
|
-
listeners[event.toString()] = listener;
|
|
168
|
-
return process;
|
|
169
|
-
});
|
|
217
|
+
await runPromise;
|
|
170
218
|
|
|
171
|
-
|
|
172
|
-
|
|
219
|
+
expect(mockExit).toHaveBeenCalled();
|
|
220
|
+
});
|
|
173
221
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
222
|
+
it('should handle non-zero exit code', async () => {
|
|
223
|
+
setTimeout(() => {
|
|
224
|
+
mockChild.emit('close');
|
|
225
|
+
}, 10);
|
|
226
|
+
await command.run({ script: 'test', args: [] });
|
|
227
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
228
|
+
expect(mockExit).toHaveBeenCalledWith(1);
|
|
229
|
+
});
|
|
177
230
|
|
|
178
|
-
|
|
231
|
+
it('should use cmd on windows for module scripts', async () => {
|
|
232
|
+
const originalPlatform = process.platform;
|
|
233
|
+
Object.defineProperty(process, 'platform', { value: 'win32' });
|
|
179
234
|
|
|
180
|
-
|
|
235
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
236
|
+
vi.mocked(fs.pathExists).mockImplementation(async (p: any) => {
|
|
237
|
+
return p.includes('stripe');
|
|
181
238
|
});
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
189
|
-
expect(mockExit).toHaveBeenCalledWith(1);
|
|
239
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
240
|
+
vi.mocked(fs.readJson).mockImplementation(async (p: any) => {
|
|
241
|
+
if (p.includes('stripe')) {
|
|
242
|
+
return { scripts: { sync: 'node scripts/sync.js' } };
|
|
243
|
+
}
|
|
244
|
+
return { scripts: {} };
|
|
190
245
|
});
|
|
191
246
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
expect(cp.spawn).toHaveBeenCalledWith('npm', expect.arrayContaining([
|
|
210
|
-
'run', 'sync'
|
|
211
|
-
]), expect.anything());
|
|
212
|
-
|
|
213
|
-
Object.defineProperty(process, 'platform', { value: originalPlatform });
|
|
247
|
+
setTimeout(() => {
|
|
248
|
+
mockChild.emit('close', 0);
|
|
249
|
+
}, 10);
|
|
250
|
+
await command.run({ script: 'stripe:sync', args: [] });
|
|
251
|
+
|
|
252
|
+
expect(cp.spawn).toHaveBeenCalledWith(
|
|
253
|
+
'npm',
|
|
254
|
+
expect.arrayContaining(['run', 'sync']),
|
|
255
|
+
expect.anything(),
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
Object.defineProperty(process, 'platform', { value: originalPlatform });
|
|
259
|
+
});
|
|
260
|
+
it('should fall back to default behavior if script not found in module', async () => {
|
|
261
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
262
|
+
vi.mocked(fs.pathExists).mockImplementation(async (p: any) => {
|
|
263
|
+
return p.includes('src/modules/mymod') || p.includes('package.json');
|
|
214
264
|
});
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
});
|
|
219
|
-
vi.mocked(fs.readJson).mockResolvedValue({
|
|
220
|
-
name: 'mymod',
|
|
221
|
-
scripts: { other: 'command' }
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
setTimeout(() => { mockChild.emit('close', 0); }, 10);
|
|
225
|
-
await command.run({ script: 'mymod:missing', args: [] });
|
|
226
|
-
|
|
227
|
-
// Should error strict
|
|
228
|
-
expect(command.error).toHaveBeenCalledWith(expect.stringContaining('does not exist in module mymod'));
|
|
229
|
-
expect(cp.spawn).not.toHaveBeenCalled();
|
|
265
|
+
vi.mocked(fs.readJson).mockResolvedValue({
|
|
266
|
+
name: 'mymod',
|
|
267
|
+
scripts: { other: 'command' },
|
|
230
268
|
});
|
|
231
269
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
270
|
+
setTimeout(() => {
|
|
271
|
+
mockChild.emit('close', 0);
|
|
272
|
+
}, 10);
|
|
273
|
+
await command.run({ script: 'mymod:missing', args: [] });
|
|
236
274
|
|
|
237
|
-
|
|
238
|
-
|
|
275
|
+
// Should error strict
|
|
276
|
+
expect(command.error).toHaveBeenCalledWith(
|
|
277
|
+
expect.stringContaining('does not exist in module mymod'),
|
|
278
|
+
);
|
|
279
|
+
expect(cp.spawn).not.toHaveBeenCalled();
|
|
280
|
+
});
|
|
239
281
|
|
|
240
|
-
|
|
241
|
-
|
|
282
|
+
it('should handle null exit code', async () => {
|
|
283
|
+
setTimeout(() => {
|
|
284
|
+
mockChild.emit('close'); // emit undefined
|
|
285
|
+
}, 10);
|
|
242
286
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
scripts: { test: 'echo test' }
|
|
246
|
-
});
|
|
287
|
+
await command.run({ script: 'test', args: [] });
|
|
288
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
247
289
|
|
|
248
|
-
|
|
290
|
+
expect(mockExit).toHaveBeenCalledWith(1);
|
|
291
|
+
});
|
|
249
292
|
|
|
250
|
-
|
|
293
|
+
it('should error if script not found in core', async () => {
|
|
294
|
+
vi.mocked(fs.readJson).mockResolvedValue({
|
|
295
|
+
scripts: { test: 'echo test' },
|
|
251
296
|
});
|
|
297
|
+
|
|
298
|
+
await command.run({ script: 'missing-script', args: [] });
|
|
299
|
+
|
|
300
|
+
expect(command.error).toHaveBeenCalledWith(
|
|
301
|
+
expect.stringContaining('does not exist in Nexical core'),
|
|
302
|
+
);
|
|
303
|
+
});
|
|
252
304
|
});
|