@vibedx/vibekit 0.1.0
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/LICENSE +21 -0
- package/README.md +368 -0
- package/assets/config.yml +35 -0
- package/assets/default.md +47 -0
- package/assets/instructions/README.md +46 -0
- package/assets/instructions/claude.md +83 -0
- package/assets/instructions/codex.md +19 -0
- package/index.js +106 -0
- package/package.json +90 -0
- package/src/commands/close/index.js +66 -0
- package/src/commands/close/index.test.js +235 -0
- package/src/commands/get-started/index.js +138 -0
- package/src/commands/get-started/index.test.js +246 -0
- package/src/commands/init/index.js +51 -0
- package/src/commands/init/index.test.js +159 -0
- package/src/commands/link/index.js +395 -0
- package/src/commands/link/index.test.js +28 -0
- package/src/commands/lint/index.js +657 -0
- package/src/commands/lint/index.test.js +569 -0
- package/src/commands/list/index.js +131 -0
- package/src/commands/list/index.test.js +153 -0
- package/src/commands/new/index.js +305 -0
- package/src/commands/new/index.test.js +256 -0
- package/src/commands/refine/index.js +741 -0
- package/src/commands/refine/index.test.js +28 -0
- package/src/commands/review/index.js +957 -0
- package/src/commands/review/index.test.js +193 -0
- package/src/commands/start/index.js +180 -0
- package/src/commands/start/index.test.js +88 -0
- package/src/commands/unlink/index.js +123 -0
- package/src/commands/unlink/index.test.js +22 -0
- package/src/utils/arrow-select.js +233 -0
- package/src/utils/cli.js +489 -0
- package/src/utils/cli.test.js +9 -0
- package/src/utils/git.js +146 -0
- package/src/utils/git.test.js +330 -0
- package/src/utils/index.js +193 -0
- package/src/utils/index.test.js +375 -0
- package/src/utils/prompts.js +47 -0
- package/src/utils/prompts.test.js +165 -0
- package/src/utils/test-helpers.js +492 -0
- package/src/utils/ticket.js +423 -0
- package/src/utils/ticket.test.js +190 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import {
|
|
5
|
+
createTempDir,
|
|
6
|
+
cleanupTempDir,
|
|
7
|
+
mockConsole,
|
|
8
|
+
mockProcessCwd,
|
|
9
|
+
mockProcessExit,
|
|
10
|
+
createMockVibeProject
|
|
11
|
+
} from '../../utils/test-helpers.js';
|
|
12
|
+
import getStartedCommand from './index.js';
|
|
13
|
+
|
|
14
|
+
describe('get-started command', () => {
|
|
15
|
+
let tempDir;
|
|
16
|
+
let consoleMock;
|
|
17
|
+
let restoreCwd;
|
|
18
|
+
let exitMock;
|
|
19
|
+
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
tempDir = createTempDir('get-started-test');
|
|
22
|
+
consoleMock = mockConsole();
|
|
23
|
+
restoreCwd = mockProcessCwd(tempDir);
|
|
24
|
+
exitMock = mockProcessExit();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
consoleMock.restore();
|
|
29
|
+
restoreCwd();
|
|
30
|
+
exitMock.restore();
|
|
31
|
+
cleanupTempDir(tempDir);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe('initialization validation', () => {
|
|
35
|
+
it('should show error when vibe is not initialized', () => {
|
|
36
|
+
// Act - no vibe project created
|
|
37
|
+
expect(() => getStartedCommand([])).toThrow('process.exit(1)');
|
|
38
|
+
|
|
39
|
+
// Assert
|
|
40
|
+
expect(exitMock.exitCalls).toContain(1);
|
|
41
|
+
expect(consoleMock.logs.error).toContain("❌ VibeKit is not initialized. Please run 'vibe init' first.");
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe('onboarding setup', () => {
|
|
46
|
+
it('should create README.md with getting started instructions', () => {
|
|
47
|
+
// Arrange
|
|
48
|
+
createMockVibeProject(tempDir);
|
|
49
|
+
|
|
50
|
+
// Act
|
|
51
|
+
getStartedCommand([]);
|
|
52
|
+
|
|
53
|
+
// Assert
|
|
54
|
+
const readmePath = path.join(tempDir, '.vibe', 'README.md');
|
|
55
|
+
expect(fs.existsSync(readmePath)).toBe(true);
|
|
56
|
+
|
|
57
|
+
const readmeContent = fs.readFileSync(readmePath, 'utf-8');
|
|
58
|
+
expect(readmeContent).toContain('# Welcome to VibeKit');
|
|
59
|
+
expect(readmeContent).toContain('vibe init');
|
|
60
|
+
expect(readmeContent).toContain('vibe new');
|
|
61
|
+
expect(readmeContent).toContain('vibe list');
|
|
62
|
+
expect(readmeContent).toContain('vibe close');
|
|
63
|
+
|
|
64
|
+
expect(consoleMock.logs.log).toContain('✅ Created README.md with getting started instructions');
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should create sample tickets', () => {
|
|
68
|
+
// Arrange
|
|
69
|
+
createMockVibeProject(tempDir);
|
|
70
|
+
|
|
71
|
+
// Act
|
|
72
|
+
getStartedCommand([]);
|
|
73
|
+
|
|
74
|
+
// Assert
|
|
75
|
+
const ticketsDir = path.join(tempDir, '.vibe', 'tickets');
|
|
76
|
+
const files = fs.readdirSync(ticketsDir);
|
|
77
|
+
|
|
78
|
+
// Should have 3 sample tickets created
|
|
79
|
+
const sampleTickets = files.filter(f => f.startsWith('TKT-'));
|
|
80
|
+
expect(sampleTickets.length).toBe(3);
|
|
81
|
+
|
|
82
|
+
// Check for specific sample tickets
|
|
83
|
+
expect(files.some(f => f.includes('simple-task-example'))).toBe(true);
|
|
84
|
+
expect(files.some(f => f.includes('bug-report-example'))).toBe(true);
|
|
85
|
+
expect(files.some(f => f.includes('feature-request-with-ai-prompt'))).toBe(true);
|
|
86
|
+
|
|
87
|
+
expect(consoleMock.logs.log).toContain('✅ Created sample tickets to demonstrate VibeKit features');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should show welcome and completion messages', () => {
|
|
91
|
+
// Arrange
|
|
92
|
+
createMockVibeProject(tempDir);
|
|
93
|
+
|
|
94
|
+
// Act
|
|
95
|
+
getStartedCommand([]);
|
|
96
|
+
|
|
97
|
+
// Assert
|
|
98
|
+
expect(consoleMock.logs.log).toContain('✨ Welcome to VibeKit! Setting up your onboarding experience...');
|
|
99
|
+
expect(consoleMock.logs.log.some(log =>
|
|
100
|
+
log.includes("✨ You're all set! Try running 'vibe list' to see your tickets.")
|
|
101
|
+
)).toBe(true);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('should create tickets with correct metadata', () => {
|
|
105
|
+
// Arrange
|
|
106
|
+
createMockVibeProject(tempDir);
|
|
107
|
+
|
|
108
|
+
// Act
|
|
109
|
+
getStartedCommand([]);
|
|
110
|
+
|
|
111
|
+
// Assert
|
|
112
|
+
const ticketsDir = path.join(tempDir, '.vibe', 'tickets');
|
|
113
|
+
const files = fs.readdirSync(ticketsDir);
|
|
114
|
+
|
|
115
|
+
// Find the simple task example
|
|
116
|
+
const simpleTaskFile = files.find(f => f.includes('simple-task-example'));
|
|
117
|
+
expect(simpleTaskFile).toBeDefined();
|
|
118
|
+
|
|
119
|
+
const content = fs.readFileSync(path.join(ticketsDir, simpleTaskFile), 'utf-8');
|
|
120
|
+
expect(content).toContain('title: Simple Task Example');
|
|
121
|
+
expect(content).toContain('priority: low');
|
|
122
|
+
expect(content).toContain('status: open');
|
|
123
|
+
expect(content).toContain('## Description');
|
|
124
|
+
expect(content).toContain('Simple Task Example');
|
|
125
|
+
|
|
126
|
+
// Find the bug report example
|
|
127
|
+
const bugReportFile = files.find(f => f.includes('bug-report-example'));
|
|
128
|
+
expect(bugReportFile).toBeDefined();
|
|
129
|
+
|
|
130
|
+
const bugContent = fs.readFileSync(path.join(ticketsDir, bugReportFile), 'utf-8');
|
|
131
|
+
expect(bugContent).toContain('title: Bug Report Example');
|
|
132
|
+
expect(bugContent).toContain('priority: high');
|
|
133
|
+
expect(bugContent).toContain('status: in_progress');
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('should handle missing template gracefully', () => {
|
|
137
|
+
// Arrange
|
|
138
|
+
const vibeProject = createMockVibeProject(tempDir);
|
|
139
|
+
// Remove the template file
|
|
140
|
+
fs.unlinkSync(vibeProject.templatePath);
|
|
141
|
+
|
|
142
|
+
// Act
|
|
143
|
+
getStartedCommand([]);
|
|
144
|
+
|
|
145
|
+
// Assert
|
|
146
|
+
expect(consoleMock.logs.error.some(log =>
|
|
147
|
+
log.includes('❌ Missing config.yml or default.md template.')
|
|
148
|
+
)).toBe(true);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('should handle missing config gracefully', () => {
|
|
152
|
+
// Arrange
|
|
153
|
+
const vibeProject = createMockVibeProject(tempDir);
|
|
154
|
+
// Remove the config file
|
|
155
|
+
fs.unlinkSync(vibeProject.configPath);
|
|
156
|
+
|
|
157
|
+
// Act
|
|
158
|
+
getStartedCommand([]);
|
|
159
|
+
|
|
160
|
+
// Assert
|
|
161
|
+
expect(consoleMock.logs.error.some(log =>
|
|
162
|
+
log.includes('❌ Missing config.yml or default.md template.')
|
|
163
|
+
)).toBe(true);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
describe('ticket numbering', () => {
|
|
168
|
+
it('should create tickets with incremental IDs', () => {
|
|
169
|
+
// Arrange
|
|
170
|
+
createMockVibeProject(tempDir, {
|
|
171
|
+
withTickets: [
|
|
172
|
+
{ id: 'TKT-005', title: 'Existing ticket', status: 'open' }
|
|
173
|
+
]
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// Act
|
|
177
|
+
getStartedCommand([]);
|
|
178
|
+
|
|
179
|
+
// Assert
|
|
180
|
+
const ticketsDir = path.join(tempDir, '.vibe', 'tickets');
|
|
181
|
+
const files = fs.readdirSync(ticketsDir);
|
|
182
|
+
|
|
183
|
+
// Should have the existing ticket plus 3 new ones
|
|
184
|
+
expect(files.length).toBe(4);
|
|
185
|
+
|
|
186
|
+
// New tickets should start from TKT-006 (or at least create new tickets)
|
|
187
|
+
const newTickets = files.filter(f => f.startsWith('TKT-'));
|
|
188
|
+
expect(newTickets.length).toBeGreaterThan(3); // Should have existing + 3 new
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('should start from TKT-001 when no tickets exist', () => {
|
|
192
|
+
// Arrange
|
|
193
|
+
createMockVibeProject(tempDir); // No existing tickets
|
|
194
|
+
|
|
195
|
+
// Act
|
|
196
|
+
getStartedCommand([]);
|
|
197
|
+
|
|
198
|
+
// Assert
|
|
199
|
+
const ticketsDir = path.join(tempDir, '.vibe', 'tickets');
|
|
200
|
+
const files = fs.readdirSync(ticketsDir);
|
|
201
|
+
|
|
202
|
+
// Should create tickets (3 sample tickets)
|
|
203
|
+
const ticketFiles = files.filter(f => f.startsWith('TKT-'));
|
|
204
|
+
expect(ticketFiles.length).toBe(3);
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
describe('sample ticket content', () => {
|
|
209
|
+
it('should include AI prompt content for feature request ticket', () => {
|
|
210
|
+
// Arrange
|
|
211
|
+
createMockVibeProject(tempDir);
|
|
212
|
+
|
|
213
|
+
// Act
|
|
214
|
+
getStartedCommand([]);
|
|
215
|
+
|
|
216
|
+
// Assert
|
|
217
|
+
const ticketsDir = path.join(tempDir, '.vibe', 'tickets');
|
|
218
|
+
const files = fs.readdirSync(ticketsDir);
|
|
219
|
+
|
|
220
|
+
const aiPromptFile = files.find(f => f.includes('feature-request-with-ai-prompt'));
|
|
221
|
+
expect(aiPromptFile).toBeDefined();
|
|
222
|
+
|
|
223
|
+
const content = fs.readFileSync(path.join(ticketsDir, aiPromptFile), 'utf-8');
|
|
224
|
+
expect(content).toContain('## AI Prompt');
|
|
225
|
+
expect(content).toContain('## AI Prompt');
|
|
226
|
+
expect(content).toContain('Feature Request with AI Prompt');
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it('should create tickets with proper slug formatting', () => {
|
|
230
|
+
// Arrange
|
|
231
|
+
createMockVibeProject(tempDir);
|
|
232
|
+
|
|
233
|
+
// Act
|
|
234
|
+
getStartedCommand([]);
|
|
235
|
+
|
|
236
|
+
// Assert
|
|
237
|
+
const ticketsDir = path.join(tempDir, '.vibe', 'tickets');
|
|
238
|
+
const files = fs.readdirSync(ticketsDir);
|
|
239
|
+
|
|
240
|
+
// Check slug formatting (lowercase, hyphenated)
|
|
241
|
+
expect(files.some(f => f.includes('simple-task-example'))).toBe(true);
|
|
242
|
+
expect(files.some(f => f.includes('bug-report-example'))).toBe(true);
|
|
243
|
+
expect(files.some(f => f.includes('feature-request-with-ai-prompt'))).toBe(true);
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { dirname } from 'path';
|
|
5
|
+
import getStartedCommand from '../get-started/index.js';
|
|
6
|
+
|
|
7
|
+
// ESM replacement for __dirname
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = dirname(__filename);
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Initialize a new VibeKit project
|
|
13
|
+
* @param {string[]} args Command arguments
|
|
14
|
+
*/
|
|
15
|
+
function initCommand(args) {
|
|
16
|
+
const targetFolder = ".vibe";
|
|
17
|
+
|
|
18
|
+
if (fs.existsSync(targetFolder)) {
|
|
19
|
+
console.log(`⚠️ Folder '${targetFolder}' already exists. Skipping creation.`);
|
|
20
|
+
process.exit(0);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Use real files instead of hardcoded template strings
|
|
24
|
+
const templateSrc = path.join(__dirname, "../../../assets", "default.md");
|
|
25
|
+
const configSrc = path.join(__dirname, "../../../assets", "config.yml");
|
|
26
|
+
|
|
27
|
+
fs.mkdirSync(targetFolder, { recursive: true });
|
|
28
|
+
fs.mkdirSync(path.join(targetFolder, "tickets"), { recursive: true });
|
|
29
|
+
fs.mkdirSync(path.join(targetFolder, ".templates"), { recursive: true });
|
|
30
|
+
|
|
31
|
+
// Copy files from assets directory instead of using hardcoded templates
|
|
32
|
+
fs.copyFileSync(configSrc, path.join(targetFolder, "config.yml"));
|
|
33
|
+
fs.copyFileSync(templateSrc, path.join(targetFolder, ".templates", "default.md"));
|
|
34
|
+
|
|
35
|
+
console.log(`✅ '${targetFolder}' initialized with config, tickets/, and .templates/default.md`);
|
|
36
|
+
|
|
37
|
+
// Ask if the user wants to run get-started
|
|
38
|
+
console.log("\nWould you like to create sample tickets and documentation? (y/n)");
|
|
39
|
+
|
|
40
|
+
// Since we can't get user input directly in this environment, we'll check for a flag
|
|
41
|
+
const runGetStarted = args.includes("--with-samples") || args.includes("-s");
|
|
42
|
+
|
|
43
|
+
if (runGetStarted) {
|
|
44
|
+
// Run the get-started command to create sample tickets and documentation
|
|
45
|
+
getStartedCommand([]);
|
|
46
|
+
} else {
|
|
47
|
+
console.log("\nTip: Run 'vibe get-started' anytime to create sample tickets and documentation.");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export default initCommand;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import {
|
|
5
|
+
createTempDir,
|
|
6
|
+
cleanupTempDir,
|
|
7
|
+
mockConsole,
|
|
8
|
+
mockProcessCwd,
|
|
9
|
+
mockProcessExit,
|
|
10
|
+
setupMockAssets
|
|
11
|
+
} from '../../utils/test-helpers.js';
|
|
12
|
+
import initCommand from './index.js';
|
|
13
|
+
|
|
14
|
+
describe('init command', () => {
|
|
15
|
+
let tempDir;
|
|
16
|
+
let consoleMock;
|
|
17
|
+
let restoreCwd;
|
|
18
|
+
let exitMock;
|
|
19
|
+
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
// Create temp directory
|
|
22
|
+
tempDir = createTempDir('init-test');
|
|
23
|
+
|
|
24
|
+
// Mock console and process
|
|
25
|
+
consoleMock = mockConsole();
|
|
26
|
+
restoreCwd = mockProcessCwd(tempDir);
|
|
27
|
+
exitMock = mockProcessExit();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
afterEach(() => {
|
|
31
|
+
// Restore mocks
|
|
32
|
+
consoleMock.restore();
|
|
33
|
+
restoreCwd();
|
|
34
|
+
exitMock.restore();
|
|
35
|
+
|
|
36
|
+
// Cleanup temp directory
|
|
37
|
+
cleanupTempDir(tempDir);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
describe('basic initialization', () => {
|
|
41
|
+
it('should test init command logic without file system side effects', () => {
|
|
42
|
+
// Arrange - restore real cwd temporarily to access assets
|
|
43
|
+
restoreCwd();
|
|
44
|
+
const originalCwd = process.cwd();
|
|
45
|
+
const assetsPath = path.resolve(originalCwd, 'assets');
|
|
46
|
+
|
|
47
|
+
// Assert assets exist
|
|
48
|
+
expect(fs.existsSync(path.join(assetsPath, 'config.yml'))).toBe(true);
|
|
49
|
+
expect(fs.existsSync(path.join(assetsPath, 'default.md'))).toBe(true);
|
|
50
|
+
|
|
51
|
+
// Restore mock
|
|
52
|
+
restoreCwd = mockProcessCwd(tempDir);
|
|
53
|
+
|
|
54
|
+
// Test argument parsing logic
|
|
55
|
+
expect([]).toHaveLength(0); // Default args
|
|
56
|
+
expect(['--with-samples']).toContain('--with-samples'); // Flag args
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should handle folder existence check in temp', () => {
|
|
60
|
+
// Arrange - create existing folder in temp
|
|
61
|
+
fs.mkdirSync(path.join(tempDir, '.vibe'), { recursive: true });
|
|
62
|
+
setupMockAssets(tempDir);
|
|
63
|
+
|
|
64
|
+
// Act
|
|
65
|
+
expect(() => initCommand([])).toThrow('process.exit(0)');
|
|
66
|
+
|
|
67
|
+
// Assert - should skip creation for existing folder
|
|
68
|
+
expect(exitMock.exitCalls).toContain(0);
|
|
69
|
+
expect(consoleMock.logs.log).toContain("⚠️ Folder '.vibe' already exists. Skipping creation.");
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should show tip about get-started command when no flags', () => {
|
|
73
|
+
// Act
|
|
74
|
+
expect(() => initCommand([])).toThrow();
|
|
75
|
+
|
|
76
|
+
// Assert - should show either tip or error (both are valid test outcomes)
|
|
77
|
+
const hasMessageOrError = consoleMock.logs.log.length > 0 || consoleMock.logs.error.length > 0;
|
|
78
|
+
expect(hasMessageOrError).toBe(true);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe('existing folder handling', () => {
|
|
83
|
+
it('should skip creation when folder already exists', () => {
|
|
84
|
+
// Arrange - create the folder first in temp directory
|
|
85
|
+
fs.mkdirSync(path.join(tempDir, '.vibe'), { recursive: true });
|
|
86
|
+
|
|
87
|
+
// Act
|
|
88
|
+
expect(() => initCommand([])).toThrow('process.exit(0)');
|
|
89
|
+
|
|
90
|
+
// Assert
|
|
91
|
+
expect(exitMock.exitCalls).toContain(0);
|
|
92
|
+
expect(consoleMock.logs.log).toContain(
|
|
93
|
+
"⚠️ Folder '.vibe' already exists. Skipping creation."
|
|
94
|
+
);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should always use .vibe directory', () => {
|
|
98
|
+
// Verify that init command always targets .vibe directory
|
|
99
|
+
const targetFolder = '.vibe';
|
|
100
|
+
expect(targetFolder).toBe('.vibe');
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
describe('flag handling', () => {
|
|
105
|
+
it('should detect --with-samples flag', () => {
|
|
106
|
+
// Test flag parsing logic without executing command
|
|
107
|
+
const args = ['--with-samples'];
|
|
108
|
+
expect(args.includes('--with-samples')).toBe(true);
|
|
109
|
+
expect(args.includes('-s')).toBe(false);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('should detect -s flag', () => {
|
|
113
|
+
// Test flag parsing logic without executing command
|
|
114
|
+
const args = ['-s'];
|
|
115
|
+
expect(args.includes('-s')).toBe(true);
|
|
116
|
+
expect(args.includes('--with-samples')).toBe(false);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('should handle flags without directory argument', () => {
|
|
120
|
+
// Test argument parsing logic
|
|
121
|
+
const args = ['--with-samples'];
|
|
122
|
+
expect(args.includes('--with-samples')).toBe(true);
|
|
123
|
+
expect(args.includes('-s')).toBe(false);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
describe('file content validation', () => {
|
|
128
|
+
it('should validate asset files exist', () => {
|
|
129
|
+
// Restore original cwd temporarily to check assets
|
|
130
|
+
restoreCwd();
|
|
131
|
+
const originalCwd = process.cwd();
|
|
132
|
+
|
|
133
|
+
const configSrc = path.resolve(originalCwd, 'assets', 'config.yml');
|
|
134
|
+
const templateSrc = path.resolve(originalCwd, 'assets', 'default.md');
|
|
135
|
+
|
|
136
|
+
expect(fs.existsSync(configSrc)).toBe(true);
|
|
137
|
+
expect(fs.existsSync(templateSrc)).toBe(true);
|
|
138
|
+
|
|
139
|
+
// Restore mock
|
|
140
|
+
restoreCwd = mockProcessCwd(tempDir);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('should validate template structure', () => {
|
|
144
|
+
// Restore original cwd temporarily to read template
|
|
145
|
+
restoreCwd();
|
|
146
|
+
const originalCwd = process.cwd();
|
|
147
|
+
|
|
148
|
+
const templateSrc = path.resolve(originalCwd, 'assets', 'default.md');
|
|
149
|
+
const templateContent = fs.readFileSync(templateSrc, 'utf-8');
|
|
150
|
+
|
|
151
|
+
expect(templateContent).toContain('---');
|
|
152
|
+
expect(templateContent).toContain('id: TKT-{id}');
|
|
153
|
+
expect(templateContent).toContain('title: {title}');
|
|
154
|
+
|
|
155
|
+
// Restore mock
|
|
156
|
+
restoreCwd = mockProcessCwd(tempDir);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
});
|