@reliverse/rempts-test 2.3.1
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/README.md +264 -0
- package/dist/helpers.d.ts +53 -0
- package/dist/helpers.js +42 -0
- package/dist/matchers.d.ts +38 -0
- package/dist/matchers.js +62 -0
- package/dist/mod.d.ts +4 -0
- package/dist/mod.js +9 -0
- package/dist/test-command.d.ts +4 -0
- package/dist/test-command.js +360 -0
- package/dist/types.d.ts +65 -0
- package/dist/types.js +0 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
# rempts-test
|
|
2
|
+
|
|
3
|
+
Testing utilities for Rempts CLI applications.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add -d rempts-test
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- ๐งช Test individual commands or entire CLIs
|
|
14
|
+
- ๐ญ Mock user prompts and shell commands
|
|
15
|
+
- โ
Built-in test matchers for CLI output
|
|
16
|
+
- ๐ Support for validation and retry scenarios
|
|
17
|
+
- ๐ TypeScript support with full type inference
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
### Basic Command Testing
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { test, expect } from 'bun:test'
|
|
25
|
+
import { defineCommand } from '@reliverse/rempts-core'
|
|
26
|
+
import { testCommand, expectCommand } from '@reliverse/rempts-test'
|
|
27
|
+
|
|
28
|
+
const greetCommand = defineCommand({
|
|
29
|
+
name: 'greet',
|
|
30
|
+
description: 'Greet someone',
|
|
31
|
+
handler: async ({ colors }) => {
|
|
32
|
+
console.log(relico.green('Hello, world!'))
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
test('greet command', async () => {
|
|
37
|
+
const result = await testCommand(greetCommand)
|
|
38
|
+
|
|
39
|
+
expectCommand(result).toHaveSucceeded()
|
|
40
|
+
expectCommand(result).toContainInStdout('[green]Hello, world![/green]')
|
|
41
|
+
})
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Testing with Flags
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
const deployCommand = defineCommand({
|
|
48
|
+
name: 'deploy',
|
|
49
|
+
options: {
|
|
50
|
+
env: option(z.enum(['dev', 'prod'])),
|
|
51
|
+
force: option(z.boolean().default(false))
|
|
52
|
+
},
|
|
53
|
+
handler: async ({ flags }) => {
|
|
54
|
+
console.log(`Deploying to ${flags.env}${flags.force ? ' (forced)' : ''}`)
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
test('deploy with flags', async () => {
|
|
59
|
+
const result = await testCommand(deployCommand, {
|
|
60
|
+
flags: { env: 'prod', force: true }
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
expect(result.stdout).toContain('Deploying to prod (forced)')
|
|
64
|
+
})
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Mocking User Prompts
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
import { mockPromptResponses } from '@reliverse/rempts-test'
|
|
71
|
+
|
|
72
|
+
const setupCommand = defineCommand({
|
|
73
|
+
name: 'setup',
|
|
74
|
+
handler: async ({ prompt }) => {
|
|
75
|
+
const name = await prompt('Project name:')
|
|
76
|
+
const useTs = await prompt.confirm('Use TypeScript?')
|
|
77
|
+
console.log(`Creating ${name} with${useTs ? '' : 'out'} TypeScript`)
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
test('interactive setup', async () => {
|
|
82
|
+
const result = await testCommand(setupCommand, mockPromptResponses({
|
|
83
|
+
'Project name:': 'my-app',
|
|
84
|
+
'Use TypeScript?': 'y'
|
|
85
|
+
}))
|
|
86
|
+
|
|
87
|
+
expect(result.stdout).toContain('Creating my-app with TypeScript')
|
|
88
|
+
})
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Mocking Shell Commands
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
import { mockShellCommands } from '@reliverse/rempts-test'
|
|
95
|
+
|
|
96
|
+
const statusCommand = defineCommand({
|
|
97
|
+
name: 'status',
|
|
98
|
+
handler: async ({ shell }) => {
|
|
99
|
+
const branch = await shell`git branch --show-current`.text()
|
|
100
|
+
const status = await shell`git status --porcelain`.text()
|
|
101
|
+
console.log(`On branch: ${branch.trim()}`)
|
|
102
|
+
console.log(`Clean: ${status.trim() === ''}`)
|
|
103
|
+
}
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
test('git status', async () => {
|
|
107
|
+
const result = await testCommand(statusCommand, mockShellCommands({
|
|
108
|
+
'git branch --show-current': 'feature/awesome\n',
|
|
109
|
+
'git status --porcelain': ''
|
|
110
|
+
}))
|
|
111
|
+
|
|
112
|
+
expect(result.stdout).toContain('On branch: feature/awesome')
|
|
113
|
+
expect(result.stdout).toContain('Clean: true')
|
|
114
|
+
})
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Testing Validation with Retries
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
const emailCommand = defineCommand({
|
|
121
|
+
name: 'register',
|
|
122
|
+
handler: async ({ prompt }) => {
|
|
123
|
+
const email = await prompt('Enter email:', {
|
|
124
|
+
schema: z.string().email()
|
|
125
|
+
})
|
|
126
|
+
console.log(`Registered: ${email}`)
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
test('email validation', async () => {
|
|
131
|
+
const result = await testCommand(emailCommand, mockPromptResponses({
|
|
132
|
+
'Enter email:': ['invalid', 'still-bad', 'valid@email.com']
|
|
133
|
+
}))
|
|
134
|
+
|
|
135
|
+
// First two attempts fail validation
|
|
136
|
+
expect(result.stderr).toContain('Invalid email')
|
|
137
|
+
// Third attempt succeeds
|
|
138
|
+
expect(result.stdout).toContain('Registered: valid@email.com')
|
|
139
|
+
})
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Testing Complete CLIs
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
import { createCLI } from '@reliverse/rempts-core'
|
|
146
|
+
import { testCLI } from '@reliverse/rempts-test'
|
|
147
|
+
|
|
148
|
+
test('CLI help', async () => {
|
|
149
|
+
const result = await testCLI(
|
|
150
|
+
(cli) => {
|
|
151
|
+
cli.command('hello', {
|
|
152
|
+
description: 'Say hello',
|
|
153
|
+
handler: async () => console.log('Hello!')
|
|
154
|
+
})
|
|
155
|
+
},
|
|
156
|
+
['--help']
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
expectCommand(result).toContainInStdout('Say hello')
|
|
160
|
+
})
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Using Helper Functions
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
import { mockInteractive, mergeTestOptions } from '@reliverse/rempts-test'
|
|
167
|
+
|
|
168
|
+
test('complex interaction', async () => {
|
|
169
|
+
const result = await testCommand(myCommand, mockInteractive(
|
|
170
|
+
{
|
|
171
|
+
'Name:': 'Alice',
|
|
172
|
+
'Continue?': 'y'
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
'npm --version': '10.0.0\n'
|
|
176
|
+
}
|
|
177
|
+
))
|
|
178
|
+
|
|
179
|
+
// Or merge multiple option sets
|
|
180
|
+
const result2 = await testCommand(myCommand, mergeTestOptions(
|
|
181
|
+
{ flags: { verbose: true } },
|
|
182
|
+
mockPromptResponses({ 'Name:': 'Bob' }),
|
|
183
|
+
{ env: { NODE_ENV: 'test' } }
|
|
184
|
+
))
|
|
185
|
+
})
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Test Matchers
|
|
189
|
+
|
|
190
|
+
The `expectCommand` function provides CLI-specific test matchers:
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
// Exit code assertions
|
|
194
|
+
expectCommand(result).toHaveExitCode(0)
|
|
195
|
+
expectCommand(result).toHaveSucceeded() // exit code 0
|
|
196
|
+
expectCommand(result).toHaveFailed() // exit code !== 0
|
|
197
|
+
|
|
198
|
+
// Output assertions
|
|
199
|
+
expectCommand(result).toContainInStdout('success')
|
|
200
|
+
expectCommand(result).toContainInStderr('error')
|
|
201
|
+
expectCommand(result).toMatchStdout(/pattern/)
|
|
202
|
+
expectCommand(result).toMatchStderr(/error.*occurred/)
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## API Reference
|
|
206
|
+
|
|
207
|
+
### `testCommand(command, options?)`
|
|
208
|
+
|
|
209
|
+
Test a single command.
|
|
210
|
+
|
|
211
|
+
**Parameters:**
|
|
212
|
+
|
|
213
|
+
- `command`: Command to test
|
|
214
|
+
- `options`: Test options
|
|
215
|
+
- `flags`: Command flags
|
|
216
|
+
- `args`: Positional arguments
|
|
217
|
+
- `env`: Environment variables
|
|
218
|
+
- `cwd`: Working directory
|
|
219
|
+
- `stdin`: Input lines (string or array)
|
|
220
|
+
- `mockPrompts`: Map of prompt messages to responses
|
|
221
|
+
- `mockShellCommands`: Map of shell commands to outputs
|
|
222
|
+
- `exitCode`: Expected exit code
|
|
223
|
+
|
|
224
|
+
**Returns:** `TestResult` with stdout, stderr, exitCode, duration, and error
|
|
225
|
+
|
|
226
|
+
### `testCLI(setupFn, argv, options?)`
|
|
227
|
+
|
|
228
|
+
Test a complete CLI with multiple commands.
|
|
229
|
+
|
|
230
|
+
**Parameters:**
|
|
231
|
+
|
|
232
|
+
- `setupFn`: Function to configure the CLI
|
|
233
|
+
- `argv`: Command line arguments
|
|
234
|
+
- `options`: Test options (same as testCommand)
|
|
235
|
+
|
|
236
|
+
### Helper Functions
|
|
237
|
+
|
|
238
|
+
- `mockPromptResponses(responses)`: Create options with mock prompt responses
|
|
239
|
+
- `mockShellCommands(commands)`: Create options with mock shell outputs
|
|
240
|
+
- `mockInteractive(prompts, commands?)`: Combine prompt and shell mocks
|
|
241
|
+
- `mockValidationAttempts(attempts)`: Create stdin for validation testing
|
|
242
|
+
- `mergeTestOptions(...options)`: Merge multiple test option objects
|
|
243
|
+
|
|
244
|
+
## Tips
|
|
245
|
+
|
|
246
|
+
1. **Colors in Output**: The test utilities preserve color codes as tags (e.g., `[green]text[/green]`) for easier assertion
|
|
247
|
+
|
|
248
|
+
2. **Multiple Attempts**: For validation scenarios, provide arrays of responses:
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
mockPromptResponses({
|
|
252
|
+
'Enter age:': ['abc', '-5', '25'] // Tries each until valid
|
|
253
|
+
})
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
3. **Default Mocks**: Common commands have default mock responses:
|
|
257
|
+
- `git branch --show-current`: Returns `main\n`
|
|
258
|
+
- `git status`: Returns `nothing to commit, working tree clean\n`
|
|
259
|
+
|
|
260
|
+
4. **Schema Validation**: The mock prompt automatically handles Standard Schema validation and retry logic
|
|
261
|
+
|
|
262
|
+
## License
|
|
263
|
+
|
|
264
|
+
MIT
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { TestOptions } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Helper to create test options with mock prompt responses
|
|
4
|
+
* @param responses - Map of prompt messages to responses
|
|
5
|
+
* @example
|
|
6
|
+
* mockPromptResponses({
|
|
7
|
+
* 'Enter name:': 'Alice',
|
|
8
|
+
* 'Enter age:': ['invalid', '25'], // Multiple attempts for validation
|
|
9
|
+
* 'Continue?': 'y'
|
|
10
|
+
* })
|
|
11
|
+
*/
|
|
12
|
+
export declare function mockPromptResponses(responses: Record<string, string | string[]>): Pick<TestOptions, "mockPrompts">;
|
|
13
|
+
/**
|
|
14
|
+
* Helper to create test options with mock shell command outputs
|
|
15
|
+
* @param commands - Map of shell commands to their outputs
|
|
16
|
+
* @example
|
|
17
|
+
* mockShellCommands({
|
|
18
|
+
* 'git status': 'On branch main\nnothing to commit',
|
|
19
|
+
* 'npm --version': '10.2.0',
|
|
20
|
+
* 'node --version': 'v20.10.0'
|
|
21
|
+
* })
|
|
22
|
+
*/
|
|
23
|
+
export declare function mockShellCommands(commands: Record<string, string>): Pick<TestOptions, "mockShellCommands">;
|
|
24
|
+
/**
|
|
25
|
+
* Helper to create test options for interactive commands
|
|
26
|
+
* @param prompts - Prompt responses
|
|
27
|
+
* @param commands - Shell command outputs
|
|
28
|
+
* @example
|
|
29
|
+
* mockInteractive(
|
|
30
|
+
* { 'Name:': 'Alice', 'Continue?': 'y' },
|
|
31
|
+
* { 'git status': 'clean' }
|
|
32
|
+
* )
|
|
33
|
+
*/
|
|
34
|
+
export declare function mockInteractive(prompts: Record<string, string | string[]>, commands?: Record<string, string>): TestOptions;
|
|
35
|
+
/**
|
|
36
|
+
* Helper to create stdin input for validation testing
|
|
37
|
+
* Useful for testing retry behavior with invalid inputs
|
|
38
|
+
* @param attempts - Array of input attempts
|
|
39
|
+
* @example
|
|
40
|
+
* mockValidationAttempts(['invalid-email', 'still-bad', 'valid@email.com'])
|
|
41
|
+
*/
|
|
42
|
+
export declare function mockValidationAttempts(attempts: string[]): Pick<TestOptions, "stdin">;
|
|
43
|
+
/**
|
|
44
|
+
* Helper to combine multiple test option objects
|
|
45
|
+
* @param options - Test option objects to merge
|
|
46
|
+
* @example
|
|
47
|
+
* mergeTestOptions(
|
|
48
|
+
* { flags: { verbose: true } },
|
|
49
|
+
* mockPromptResponses({ 'Name:': 'Alice' }),
|
|
50
|
+
* { env: { NODE_ENV: 'test' } }
|
|
51
|
+
* )
|
|
52
|
+
*/
|
|
53
|
+
export declare function mergeTestOptions(...options: Partial<TestOptions>[]): TestOptions;
|
package/dist/helpers.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export function mockPromptResponses(responses) {
|
|
2
|
+
return { mockPrompts: responses };
|
|
3
|
+
}
|
|
4
|
+
export function mockShellCommands(commands) {
|
|
5
|
+
return { mockShellCommands: commands };
|
|
6
|
+
}
|
|
7
|
+
export function mockInteractive(prompts, commands) {
|
|
8
|
+
return {
|
|
9
|
+
...mockPromptResponses(prompts),
|
|
10
|
+
...commands ? mockShellCommands(commands) : {}
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export function mockValidationAttempts(attempts) {
|
|
14
|
+
return { stdin: attempts };
|
|
15
|
+
}
|
|
16
|
+
export function mergeTestOptions(...options) {
|
|
17
|
+
const merged = {};
|
|
18
|
+
for (const opt of options) {
|
|
19
|
+
if (opt.stdin || opt.mockPrompts) {
|
|
20
|
+
const stdinArray = [];
|
|
21
|
+
if (merged.stdin) {
|
|
22
|
+
if (Array.isArray(merged.stdin)) {
|
|
23
|
+
stdinArray.push(...merged.stdin);
|
|
24
|
+
} else {
|
|
25
|
+
stdinArray.push(merged.stdin);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (opt.stdin) {
|
|
29
|
+
if (Array.isArray(opt.stdin)) {
|
|
30
|
+
stdinArray.push(...opt.stdin);
|
|
31
|
+
} else {
|
|
32
|
+
stdinArray.push(opt.stdin);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (stdinArray.length > 0) {
|
|
36
|
+
merged.stdin = stdinArray;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
Object.assign(merged, opt);
|
|
40
|
+
}
|
|
41
|
+
return merged;
|
|
42
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { TestResult } from "./types.js";
|
|
2
|
+
export interface Matchers {
|
|
3
|
+
toHaveExitCode(code: number): void;
|
|
4
|
+
toHaveSucceeded(): void;
|
|
5
|
+
toHaveFailed(): void;
|
|
6
|
+
toContainInStdout(text: string): void;
|
|
7
|
+
toContainInStderr(text: string): void;
|
|
8
|
+
toMatchStdout(pattern: RegExp): void;
|
|
9
|
+
toMatchStderr(pattern: RegExp): void;
|
|
10
|
+
}
|
|
11
|
+
export declare function createMatchers(result: TestResult): Matchers;
|
|
12
|
+
declare global {
|
|
13
|
+
namespace jest {
|
|
14
|
+
interface Matchers<R> {
|
|
15
|
+
toHaveExitCode(code: number): R;
|
|
16
|
+
toHaveSucceeded(): R;
|
|
17
|
+
toHaveFailed(): R;
|
|
18
|
+
toContainInStdout(text: string): R;
|
|
19
|
+
toContainInStderr(text: string): R;
|
|
20
|
+
toMatchStdout(pattern: RegExp): R;
|
|
21
|
+
toMatchStderr(pattern: RegExp): R;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export declare function expectCommand(result: TestResult): {
|
|
26
|
+
toHaveExitCode(code: number): void;
|
|
27
|
+
toHaveSucceeded(): void;
|
|
28
|
+
toHaveFailed(): void;
|
|
29
|
+
toContainInStdout(text: string): void;
|
|
30
|
+
toContainInStderr(text: string): void;
|
|
31
|
+
toMatchStdout(pattern: RegExp): void;
|
|
32
|
+
toMatchStderr(pattern: RegExp): void;
|
|
33
|
+
stdout: string;
|
|
34
|
+
stderr: string;
|
|
35
|
+
exitCode: number;
|
|
36
|
+
duration: number;
|
|
37
|
+
error?: Error;
|
|
38
|
+
};
|
package/dist/matchers.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export function createMatchers(result) {
|
|
2
|
+
return {
|
|
3
|
+
toHaveExitCode(code) {
|
|
4
|
+
if (result.exitCode !== code) {
|
|
5
|
+
throw new Error(
|
|
6
|
+
`Expected exit code ${code}, but got ${result.exitCode}
|
|
7
|
+
stdout: ${result.stdout}
|
|
8
|
+
stderr: ${result.stderr}`
|
|
9
|
+
);
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
toHaveSucceeded() {
|
|
13
|
+
if (result.exitCode !== 0) {
|
|
14
|
+
throw new Error(
|
|
15
|
+
`Expected command to succeed (exit code 0), but got ${result.exitCode}
|
|
16
|
+
stdout: ${result.stdout}
|
|
17
|
+
stderr: ${result.stderr}
|
|
18
|
+
` + (result.error ? `error: ${result.error.message}` : "")
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
toHaveFailed() {
|
|
23
|
+
if (result.exitCode === 0) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
`Expected command to fail (non-zero exit code), but it succeeded
|
|
26
|
+
stdout: ${result.stdout}`
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
toContainInStdout(text) {
|
|
31
|
+
if (!result.stdout.includes(text)) {
|
|
32
|
+
throw new Error(`Expected stdout to contain "${text}"
|
|
33
|
+
stdout: ${result.stdout}`);
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
toContainInStderr(text) {
|
|
37
|
+
if (!result.stderr.includes(text)) {
|
|
38
|
+
throw new Error(`Expected stderr to contain "${text}"
|
|
39
|
+
stderr: ${result.stderr}`);
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
toMatchStdout(pattern) {
|
|
43
|
+
if (!pattern.test(result.stdout)) {
|
|
44
|
+
throw new Error(`Expected stdout to match ${pattern}
|
|
45
|
+
stdout: ${result.stdout}`);
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
toMatchStderr(pattern) {
|
|
49
|
+
if (!pattern.test(result.stderr)) {
|
|
50
|
+
throw new Error(`Expected stderr to match ${pattern}
|
|
51
|
+
stderr: ${result.stderr}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export function expectCommand(result) {
|
|
57
|
+
const matchers = createMatchers(result);
|
|
58
|
+
return {
|
|
59
|
+
...result,
|
|
60
|
+
...matchers
|
|
61
|
+
};
|
|
62
|
+
}
|
package/dist/mod.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { mergeTestOptions, mockInteractive, mockPromptResponses, mockShellCommands, mockValidationAttempts, } from "./helpers.js";
|
|
2
|
+
export { createMatchers, expectCommand } from "./matchers.js";
|
|
3
|
+
export { testCLI, testCommand } from "./test-command.js";
|
|
4
|
+
export type { Matchers, MockHandlerArgs, MockShell, ShellPromise, TestOptions, TestResult, } from "./types.js";
|
package/dist/mod.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export {
|
|
2
|
+
mergeTestOptions,
|
|
3
|
+
mockInteractive,
|
|
4
|
+
mockPromptResponses,
|
|
5
|
+
mockShellCommands,
|
|
6
|
+
mockValidationAttempts
|
|
7
|
+
} from "./helpers.js";
|
|
8
|
+
export { createMatchers, expectCommand } from "./matchers.js";
|
|
9
|
+
export { testCLI, testCommand } from "./test-command.js";
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CLI, Command } from "@reliverse/rempts-core";
|
|
2
|
+
import type { TestOptions, TestResult } from "./types.js";
|
|
3
|
+
export declare function testCommand(command: Command<any>, options?: TestOptions): Promise<TestResult>;
|
|
4
|
+
export declare function testCLI(setupCLI: (cli: CLI) => void, argv: string[], _options?: Omit<TestOptions, "args">): Promise<TestResult>;
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
import { createCLI } from "@reliverse/rempts-core";
|
|
2
|
+
export async function testCommand(command, options = {}) {
|
|
3
|
+
const startTime = performance.now();
|
|
4
|
+
const stdout = [];
|
|
5
|
+
const stderr = [];
|
|
6
|
+
let exitCode = 0;
|
|
7
|
+
let error;
|
|
8
|
+
const stdinLines = Array.isArray(options.stdin) ? [...options.stdin] : options.stdin ? [options.stdin] : [];
|
|
9
|
+
const mockPromptsMap = options.mockPrompts || {};
|
|
10
|
+
const promptResponsesUsed = /* @__PURE__ */ new Map();
|
|
11
|
+
const mockPrompt = Object.assign(
|
|
12
|
+
async (message, options2) => {
|
|
13
|
+
stdout.push(message);
|
|
14
|
+
let response;
|
|
15
|
+
if (mockPromptsMap[message]) {
|
|
16
|
+
const responses = mockPromptsMap[message];
|
|
17
|
+
const usedCount = promptResponsesUsed.get(message) || 0;
|
|
18
|
+
if (Array.isArray(responses)) {
|
|
19
|
+
response = responses[usedCount] ?? responses.at(-1) ?? "";
|
|
20
|
+
promptResponsesUsed.set(message, usedCount + 1);
|
|
21
|
+
} else {
|
|
22
|
+
response = responses ?? "";
|
|
23
|
+
}
|
|
24
|
+
} else {
|
|
25
|
+
response = stdinLines.shift() || "";
|
|
26
|
+
}
|
|
27
|
+
stdout.push(response);
|
|
28
|
+
if (options2?.schema) {
|
|
29
|
+
const result = await options2.schema["~standard"].validate(response);
|
|
30
|
+
if (result.issues) {
|
|
31
|
+
stderr.push("[red]Invalid input:[/red]");
|
|
32
|
+
for (const issue of result.issues) {
|
|
33
|
+
stderr.push(`[dim] \u2022 ${issue.message}[/dim]`);
|
|
34
|
+
}
|
|
35
|
+
const hasMoreMockResponses = mockPromptsMap[message] && Array.isArray(mockPromptsMap[message]) && (promptResponsesUsed.get(message) || 0) < mockPromptsMap[message].length;
|
|
36
|
+
const hasMoreStdin = stdinLines.length > 0;
|
|
37
|
+
if (hasMoreMockResponses || hasMoreStdin) {
|
|
38
|
+
return mockPrompt(message, options2);
|
|
39
|
+
}
|
|
40
|
+
return void 0;
|
|
41
|
+
}
|
|
42
|
+
return result.value;
|
|
43
|
+
}
|
|
44
|
+
if (options2?.validate) {
|
|
45
|
+
const validationResult = options2.validate(response);
|
|
46
|
+
if (validationResult !== true) {
|
|
47
|
+
const errorMsg = typeof validationResult === "string" ? validationResult : "Invalid input";
|
|
48
|
+
stderr.push(`\u2717 ${errorMsg}`);
|
|
49
|
+
if (stdinLines.length > 0) {
|
|
50
|
+
return mockPrompt(message, options2);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return response;
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
confirm: async (message, opts) => {
|
|
58
|
+
stdout.push(message);
|
|
59
|
+
let response;
|
|
60
|
+
if (mockPromptsMap[message]) {
|
|
61
|
+
const responses = mockPromptsMap[message];
|
|
62
|
+
const usedCount = promptResponsesUsed.get(message) || 0;
|
|
63
|
+
if (Array.isArray(responses)) {
|
|
64
|
+
response = responses[usedCount] ?? responses.at(-1) ?? "";
|
|
65
|
+
promptResponsesUsed.set(message, usedCount + 1);
|
|
66
|
+
} else {
|
|
67
|
+
response = responses ?? "";
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
response = stdinLines.shift() || "";
|
|
71
|
+
}
|
|
72
|
+
stdout.push(response);
|
|
73
|
+
const normalized = response.toLowerCase().trim();
|
|
74
|
+
return normalized === "y" || normalized === "yes" || opts?.default && normalized === "";
|
|
75
|
+
},
|
|
76
|
+
select: async (message, selectOptions) => {
|
|
77
|
+
stdout.push(message);
|
|
78
|
+
selectOptions.options.forEach((choice2, i) => {
|
|
79
|
+
const label = typeof choice2 === "object" ? choice2.label : choice2;
|
|
80
|
+
stdout.push(` ${i + 1}. ${label}`);
|
|
81
|
+
});
|
|
82
|
+
let response;
|
|
83
|
+
if (mockPromptsMap[message]) {
|
|
84
|
+
const responses = mockPromptsMap[message];
|
|
85
|
+
const usedCount = promptResponsesUsed.get(message) || 0;
|
|
86
|
+
if (Array.isArray(responses)) {
|
|
87
|
+
response = responses[usedCount] ?? responses.at(-1) ?? "";
|
|
88
|
+
promptResponsesUsed.set(message, usedCount + 1);
|
|
89
|
+
} else {
|
|
90
|
+
response = responses ?? "";
|
|
91
|
+
}
|
|
92
|
+
} else {
|
|
93
|
+
response = stdinLines.shift() || "1";
|
|
94
|
+
}
|
|
95
|
+
stdout.push(`> ${response}`);
|
|
96
|
+
const index = Number.parseInt(response, 10) - 1;
|
|
97
|
+
const choice = selectOptions.options[index] || selectOptions.options[0];
|
|
98
|
+
return typeof choice === "object" ? choice.value : choice;
|
|
99
|
+
},
|
|
100
|
+
password: async (message, options2) => {
|
|
101
|
+
stdout.push(message);
|
|
102
|
+
let response;
|
|
103
|
+
if (mockPromptsMap[message]) {
|
|
104
|
+
const responses = mockPromptsMap[message];
|
|
105
|
+
const usedCount = promptResponsesUsed.get(message) || 0;
|
|
106
|
+
if (Array.isArray(responses)) {
|
|
107
|
+
response = responses[usedCount] ?? responses.at(-1) ?? "";
|
|
108
|
+
promptResponsesUsed.set(message, usedCount + 1);
|
|
109
|
+
} else {
|
|
110
|
+
response = responses ?? "";
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
response = stdinLines.shift() || "";
|
|
114
|
+
}
|
|
115
|
+
stdout.push("*".repeat(response.length));
|
|
116
|
+
if (options2?.schema) {
|
|
117
|
+
const result = await options2.schema["~standard"].validate(response);
|
|
118
|
+
if (result.issues) {
|
|
119
|
+
stderr.push("[red]Invalid input:[/red]");
|
|
120
|
+
for (const issue of result.issues) {
|
|
121
|
+
stderr.push(`[dim] \u2022 ${issue.message}[/dim]`);
|
|
122
|
+
}
|
|
123
|
+
const hasMoreMockResponses = mockPromptsMap[message] && Array.isArray(mockPromptsMap[message]) && (promptResponsesUsed.get(message) || 0) < mockPromptsMap[message].length;
|
|
124
|
+
const hasMoreStdin = stdinLines.length > 0;
|
|
125
|
+
if (hasMoreMockResponses || hasMoreStdin) {
|
|
126
|
+
return mockPrompt.password(message, options2);
|
|
127
|
+
}
|
|
128
|
+
return void 0;
|
|
129
|
+
}
|
|
130
|
+
return result.value;
|
|
131
|
+
}
|
|
132
|
+
return response;
|
|
133
|
+
},
|
|
134
|
+
multiselect: async (message, selectOptions) => {
|
|
135
|
+
stdout.push(message);
|
|
136
|
+
selectOptions.options.forEach((choice, i) => {
|
|
137
|
+
const label = typeof choice === "object" ? choice.label : choice;
|
|
138
|
+
stdout.push(` [ ] ${i + 1}. ${label}`);
|
|
139
|
+
});
|
|
140
|
+
let response;
|
|
141
|
+
if (mockPromptsMap[message]) {
|
|
142
|
+
const responses = mockPromptsMap[message];
|
|
143
|
+
const usedCount = promptResponsesUsed.get(message) || 0;
|
|
144
|
+
if (Array.isArray(responses)) {
|
|
145
|
+
response = responses[usedCount] ?? responses.at(-1) ?? "";
|
|
146
|
+
promptResponsesUsed.set(message, usedCount + 1);
|
|
147
|
+
} else {
|
|
148
|
+
response = responses ?? "";
|
|
149
|
+
}
|
|
150
|
+
} else {
|
|
151
|
+
response = stdinLines.shift() || "";
|
|
152
|
+
}
|
|
153
|
+
stdout.push(`> ${response}`);
|
|
154
|
+
const indices = response.split(",").map((s) => Number.parseInt(s.trim(), 10) - 1);
|
|
155
|
+
return indices.filter((i) => i >= 0 && i < selectOptions.options.length).map((i) => {
|
|
156
|
+
const choice = selectOptions.options[i];
|
|
157
|
+
return typeof choice === "object" ? choice.value : choice;
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
);
|
|
162
|
+
const mockSpinner = (text) => {
|
|
163
|
+
if (text) {
|
|
164
|
+
stdout.push(`\u280B ${text}`);
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
start: (text2) => {
|
|
168
|
+
if (text2) {
|
|
169
|
+
stdout.push(`\u280B ${text2}`);
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
stop: (text2) => {
|
|
173
|
+
if (text2) {
|
|
174
|
+
stdout.push(text2);
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
succeed: (text2) => {
|
|
178
|
+
stdout.push(`\u2705 ${text2 || "Done"}`);
|
|
179
|
+
},
|
|
180
|
+
fail: (text2) => {
|
|
181
|
+
stdout.push(`\u274C ${text2 || "Failed"}`);
|
|
182
|
+
},
|
|
183
|
+
warn: (text2) => {
|
|
184
|
+
stdout.push(`\u26A0\uFE0F ${text2 || "Warning"}`);
|
|
185
|
+
},
|
|
186
|
+
info: (text2) => {
|
|
187
|
+
stdout.push(`\u2139\uFE0F ${text2 || "Info"}`);
|
|
188
|
+
},
|
|
189
|
+
update: (text2) => {
|
|
190
|
+
stdout.push(`\u280B ${text2}`);
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
};
|
|
194
|
+
const mockShellCommands = options.mockShellCommands || {};
|
|
195
|
+
const mockShell = (strings, ...values) => {
|
|
196
|
+
const command2 = strings.reduce((acc, str, i) => {
|
|
197
|
+
return acc + str + (values[i] || "");
|
|
198
|
+
}, "").trim();
|
|
199
|
+
stdout.push(`$ ${command2}`);
|
|
200
|
+
const promise = Promise.resolve();
|
|
201
|
+
promise.text = async () => {
|
|
202
|
+
if (mockShellCommands[command2]) {
|
|
203
|
+
return mockShellCommands[command2];
|
|
204
|
+
}
|
|
205
|
+
if (command2.includes("git branch --show-current")) {
|
|
206
|
+
return "main\n";
|
|
207
|
+
}
|
|
208
|
+
if (command2.includes("git status")) {
|
|
209
|
+
return "nothing to commit, working tree clean\n";
|
|
210
|
+
}
|
|
211
|
+
return "";
|
|
212
|
+
};
|
|
213
|
+
promise.json = async () => {
|
|
214
|
+
if (mockShellCommands[command2]) {
|
|
215
|
+
try {
|
|
216
|
+
return JSON.parse(mockShellCommands[command2]);
|
|
217
|
+
} catch {
|
|
218
|
+
return {};
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return {};
|
|
222
|
+
};
|
|
223
|
+
promise.quiet = () => promise;
|
|
224
|
+
return promise;
|
|
225
|
+
};
|
|
226
|
+
const mockColors = {
|
|
227
|
+
red: (text) => `[red]${text}[/red]`,
|
|
228
|
+
green: (text) => `[green]${text}[/green]`,
|
|
229
|
+
blue: (text) => `[blue]${text}[/blue]`,
|
|
230
|
+
yellow: (text) => `[yellow]${text}[/yellow]`,
|
|
231
|
+
cyan: (text) => `[cyan]${text}[/cyan]`,
|
|
232
|
+
magenta: (text) => `[magenta]${text}[/magenta]`,
|
|
233
|
+
gray: (text) => `[gray]${text}[/gray]`,
|
|
234
|
+
dim: (text) => `[dim]${text}[/dim]`,
|
|
235
|
+
bold: (text) => `[bold]${text}[/bold]`,
|
|
236
|
+
italic: (text) => `[italic]${text}[/italic]`,
|
|
237
|
+
underline: (text) => `[underline]${text}[/underline]`,
|
|
238
|
+
strikethrough: (text) => `[strikethrough]${text}[/strikethrough]`,
|
|
239
|
+
bgRed: (text) => `[bgRed]${text}[/bgRed]`,
|
|
240
|
+
bgGreen: (text) => `[bgGreen]${text}[/bgGreen]`,
|
|
241
|
+
bgBlue: (text) => `[bgBlue]${text}[/bgBlue]`,
|
|
242
|
+
bgYellow: (text) => `[bgYellow]${text}[/bgYellow]`,
|
|
243
|
+
bgCyan: (text) => `[bgCyan]${text}[/bgCyan]`,
|
|
244
|
+
bgMagenta: (text) => `[bgMagenta]${text}[/bgMagenta]`,
|
|
245
|
+
bgGray: (text) => `[bgGray]${text}[/bgGray]`,
|
|
246
|
+
black: (text) => `[black]${text}[/black]`,
|
|
247
|
+
white: (text) => `[white]${text}[/white]`,
|
|
248
|
+
bgBlack: (text) => `[bgBlack]${text}[/bgBlack]`,
|
|
249
|
+
bgWhite: (text) => `[bgWhite]${text}[/bgWhite]`,
|
|
250
|
+
// Add missing bright colors
|
|
251
|
+
brightRed: (text) => `[brightRed]${text}[/brightRed]`,
|
|
252
|
+
brightGreen: (text) => `[brightGreen]${text}[/brightGreen]`,
|
|
253
|
+
brightYellow: (text) => `[brightYellow]${text}[/brightYellow]`,
|
|
254
|
+
brightBlue: (text) => `[brightBlue]${text}[/brightBlue]`,
|
|
255
|
+
brightCyan: (text) => `[brightCyan]${text}[/brightCyan]`,
|
|
256
|
+
brightMagenta: (text) => `[brightMagenta]${text}[/brightMagenta]`,
|
|
257
|
+
brightWhite: (text) => `[brightWhite]${text}[/brightWhite]`,
|
|
258
|
+
reset: (text) => `[reset]${text}[/reset]`,
|
|
259
|
+
strip: (text) => text.replace(/\[[^\]]+\]/g, "")
|
|
260
|
+
};
|
|
261
|
+
const originalLog = console.log;
|
|
262
|
+
const originalError = console.error;
|
|
263
|
+
console.log = (...args) => {
|
|
264
|
+
stdout.push(args.join(" "));
|
|
265
|
+
};
|
|
266
|
+
console.error = (...args) => {
|
|
267
|
+
stderr.push(args.join(" "));
|
|
268
|
+
};
|
|
269
|
+
try {
|
|
270
|
+
const handlerArgs = {
|
|
271
|
+
flags: options.flags || {},
|
|
272
|
+
positional: options.args || [],
|
|
273
|
+
env: { ...process.env, ...options.env },
|
|
274
|
+
cwd: options.cwd || process.cwd(),
|
|
275
|
+
prompt: mockPrompt,
|
|
276
|
+
spinner: mockSpinner,
|
|
277
|
+
shell: mockShell,
|
|
278
|
+
colors: mockColors,
|
|
279
|
+
terminal: {
|
|
280
|
+
width: 80,
|
|
281
|
+
height: 24,
|
|
282
|
+
isInteractive: false,
|
|
283
|
+
isCI: true,
|
|
284
|
+
supportsColor: false,
|
|
285
|
+
supportsMouse: false
|
|
286
|
+
},
|
|
287
|
+
runtime: {
|
|
288
|
+
startTime: Date.now(),
|
|
289
|
+
args: options.args || [],
|
|
290
|
+
command: command.description
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
if (command.handler) {
|
|
294
|
+
await command.handler(handlerArgs);
|
|
295
|
+
}
|
|
296
|
+
exitCode = options.exitCode || 0;
|
|
297
|
+
} catch (err) {
|
|
298
|
+
error = err;
|
|
299
|
+
exitCode = 1;
|
|
300
|
+
stderr.push(error.message);
|
|
301
|
+
} finally {
|
|
302
|
+
console.log = originalLog;
|
|
303
|
+
console.error = originalError;
|
|
304
|
+
}
|
|
305
|
+
const duration = performance.now() - startTime;
|
|
306
|
+
return {
|
|
307
|
+
stdout: stdout.join("\n"),
|
|
308
|
+
stderr: stderr.join("\n"),
|
|
309
|
+
exitCode,
|
|
310
|
+
duration,
|
|
311
|
+
error
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
export async function testCLI(setupCLI, argv, _options = {}) {
|
|
315
|
+
const startTime = performance.now();
|
|
316
|
+
const stdout = [];
|
|
317
|
+
const stderr = [];
|
|
318
|
+
let exitCode = 0;
|
|
319
|
+
let error;
|
|
320
|
+
const originalLog = console.log;
|
|
321
|
+
const originalError = console.error;
|
|
322
|
+
const originalExit = process.exit;
|
|
323
|
+
console.log = (...args) => {
|
|
324
|
+
stdout.push(args.join(" "));
|
|
325
|
+
};
|
|
326
|
+
console.error = (...args) => {
|
|
327
|
+
stderr.push(args.join(" "));
|
|
328
|
+
};
|
|
329
|
+
process.exit = (code) => {
|
|
330
|
+
exitCode = code || 0;
|
|
331
|
+
throw new Error(`Process exited with code ${exitCode}`);
|
|
332
|
+
};
|
|
333
|
+
try {
|
|
334
|
+
const cli = await createCLI({
|
|
335
|
+
name: "test-cli",
|
|
336
|
+
version: "1.0.0",
|
|
337
|
+
description: "Test CLI"
|
|
338
|
+
});
|
|
339
|
+
setupCLI(cli);
|
|
340
|
+
await cli.run(argv);
|
|
341
|
+
} catch (err) {
|
|
342
|
+
if (!err.message.startsWith("Process exited with code")) {
|
|
343
|
+
error = err;
|
|
344
|
+
exitCode = 1;
|
|
345
|
+
stderr.push(error?.message || "Unknown error");
|
|
346
|
+
}
|
|
347
|
+
} finally {
|
|
348
|
+
console.log = originalLog;
|
|
349
|
+
console.error = originalError;
|
|
350
|
+
process.exit = originalExit;
|
|
351
|
+
}
|
|
352
|
+
const duration = performance.now() - startTime;
|
|
353
|
+
return {
|
|
354
|
+
stdout: stdout.join("\n"),
|
|
355
|
+
stderr: stderr.join("\n"),
|
|
356
|
+
exitCode,
|
|
357
|
+
duration,
|
|
358
|
+
error
|
|
359
|
+
};
|
|
360
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { HandlerArgs } from "@reliverse/rempts-core";
|
|
2
|
+
export interface TestOptions {
|
|
3
|
+
/** Command flags to pass */
|
|
4
|
+
flags?: Record<string, unknown>;
|
|
5
|
+
/** Positional arguments */
|
|
6
|
+
args?: string[];
|
|
7
|
+
/** Environment variables */
|
|
8
|
+
env?: Record<string, string>;
|
|
9
|
+
/** Current working directory */
|
|
10
|
+
cwd?: string;
|
|
11
|
+
/** Input for prompts (line by line) */
|
|
12
|
+
stdin?: string | string[];
|
|
13
|
+
/** Mock prompt responses mapped by prompt message */
|
|
14
|
+
mockPrompts?: Record<string, string | string[]>;
|
|
15
|
+
/** Mock shell command outputs */
|
|
16
|
+
mockShellCommands?: Record<string, string>;
|
|
17
|
+
/** Exit code to expect */
|
|
18
|
+
exitCode?: number;
|
|
19
|
+
}
|
|
20
|
+
export interface TestResult {
|
|
21
|
+
/** Captured stdout */
|
|
22
|
+
stdout: string;
|
|
23
|
+
/** Captured stderr */
|
|
24
|
+
stderr: string;
|
|
25
|
+
/** Exit code */
|
|
26
|
+
exitCode: number;
|
|
27
|
+
/** Execution time in ms */
|
|
28
|
+
duration: number;
|
|
29
|
+
/** Any error thrown */
|
|
30
|
+
error?: Error;
|
|
31
|
+
}
|
|
32
|
+
export interface MockHandlerArgs extends Omit<HandlerArgs, "prompt" | "spinner" | "shell"> {
|
|
33
|
+
prompt: {
|
|
34
|
+
(message: string, options?: any): Promise<string>;
|
|
35
|
+
confirm: (message: string, options?: any) => Promise<boolean>;
|
|
36
|
+
select: <T = string>(message: string, options: any) => Promise<T>;
|
|
37
|
+
password: (message: string, options?: any) => Promise<string>;
|
|
38
|
+
multiselect: <T = string>(message: string, options: any) => Promise<T[]>;
|
|
39
|
+
};
|
|
40
|
+
spinner: (text?: string) => {
|
|
41
|
+
start: (text?: string) => void;
|
|
42
|
+
stop: (text?: string) => void;
|
|
43
|
+
succeed: (text?: string) => void;
|
|
44
|
+
fail: (text?: string) => void;
|
|
45
|
+
warn: (text?: string) => void;
|
|
46
|
+
info: (text?: string) => void;
|
|
47
|
+
update: (text: string) => void;
|
|
48
|
+
};
|
|
49
|
+
shell: MockShell;
|
|
50
|
+
}
|
|
51
|
+
export interface Matchers {
|
|
52
|
+
toHaveExitCode(code: number): void;
|
|
53
|
+
toHaveSucceeded(): void;
|
|
54
|
+
toHaveFailed(): void;
|
|
55
|
+
toContainInStdout(text: string): void;
|
|
56
|
+
toContainInStderr(text: string): void;
|
|
57
|
+
toMatchStdout(pattern: RegExp): void;
|
|
58
|
+
toMatchStderr(pattern: RegExp): void;
|
|
59
|
+
}
|
|
60
|
+
export type MockShell = (strings: TemplateStringsArray, ...values: any[]) => ShellPromise;
|
|
61
|
+
export interface ShellPromise extends Promise<void> {
|
|
62
|
+
text(): Promise<string>;
|
|
63
|
+
json<T = any>(): Promise<T>;
|
|
64
|
+
quiet(): ShellPromise;
|
|
65
|
+
}
|
package/dist/types.js
ADDED
|
File without changes
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@reliverse/rempts-test",
|
|
3
|
+
"version": "2.3.1",
|
|
4
|
+
"description": "Testing utilities for Rempts CLI applications",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"assertions",
|
|
7
|
+
"bun",
|
|
8
|
+
"cli",
|
|
9
|
+
"matchers",
|
|
10
|
+
"rempts",
|
|
11
|
+
"test",
|
|
12
|
+
"testing",
|
|
13
|
+
"typescript"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://github.com/reliverse/dler#readme",
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/reliverse/dler/issues"
|
|
18
|
+
},
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"author": "blefnk",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/reliverse/dler.git",
|
|
24
|
+
"directory": "packages/test"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist"
|
|
28
|
+
],
|
|
29
|
+
"type": "module",
|
|
30
|
+
"module": "./src/mod.ts",
|
|
31
|
+
"types": "./src/mod.ts",
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"types": "./dist/mod.d.ts",
|
|
35
|
+
"import": "./dist/mod.js"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@reliverse/relico": "2.3.1",
|
|
43
|
+
"@reliverse/rempts-core": "2.3.1",
|
|
44
|
+
"arktype": "^2.1.29",
|
|
45
|
+
"arkregex": "^0.0.5"
|
|
46
|
+
}
|
|
47
|
+
}
|