@lbruton/specflow 3.4.1 → 3.5.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/dist/core/__tests__/config-loader.test.d.ts +2 -0
- package/dist/core/__tests__/config-loader.test.d.ts.map +1 -0
- package/dist/core/__tests__/config-loader.test.js +184 -0
- package/dist/core/__tests__/config-loader.test.js.map +1 -0
- package/dist/core/__tests__/index-updater.test.d.ts +2 -0
- package/dist/core/__tests__/index-updater.test.d.ts.map +1 -0
- package/dist/core/__tests__/index-updater.test.js +122 -0
- package/dist/core/__tests__/index-updater.test.js.map +1 -0
- package/dist/core/__tests__/migration.test.d.ts +2 -0
- package/dist/core/__tests__/migration.test.d.ts.map +1 -0
- package/dist/core/__tests__/migration.test.js +151 -0
- package/dist/core/__tests__/migration.test.js.map +1 -0
- package/dist/core/__tests__/path-utils.test.js +101 -12
- package/dist/core/__tests__/path-utils.test.js.map +1 -1
- package/dist/core/archive-service.d.ts.map +1 -1
- package/dist/core/archive-service.js +22 -0
- package/dist/core/archive-service.js.map +1 -1
- package/dist/core/config-loader.d.ts +31 -0
- package/dist/core/config-loader.d.ts.map +1 -0
- package/dist/core/config-loader.js +162 -0
- package/dist/core/config-loader.js.map +1 -0
- package/dist/core/index-updater.d.ts +17 -0
- package/dist/core/index-updater.d.ts.map +1 -0
- package/dist/core/index-updater.js +86 -0
- package/dist/core/index-updater.js.map +1 -0
- package/dist/core/migration.d.ts +30 -0
- package/dist/core/migration.d.ts.map +1 -0
- package/dist/core/migration.js +109 -0
- package/dist/core/migration.js.map +1 -0
- package/dist/core/path-utils.d.ts +7 -0
- package/dist/core/path-utils.d.ts.map +1 -1
- package/dist/core/path-utils.js +22 -10
- package/dist/core/path-utils.js.map +1 -1
- package/dist/core/template-generator.d.ts.map +1 -1
- package/dist/core/template-generator.js +32 -11
- package/dist/core/template-generator.js.map +1 -1
- package/dist/core/workspace-initializer.d.ts +6 -1
- package/dist/core/workspace-initializer.d.ts.map +1 -1
- package/dist/core/workspace-initializer.js +69 -9
- package/dist/core/workspace-initializer.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +15 -2
- package/dist/server.js.map +1 -1
- package/dist/tools/approvals.d.ts.map +1 -1
- package/dist/tools/approvals.js +14 -0
- package/dist/tools/approvals.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-loader.test.d.ts","sourceRoot":"","sources":["../../../src/core/__tests__/config-loader.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { describe, it, expect, afterEach } from 'vitest';
|
|
2
|
+
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'fs';
|
|
3
|
+
import { join, resolve } from 'path';
|
|
4
|
+
import { tmpdir } from 'os';
|
|
5
|
+
import { loadConfig, createDefaultConfig, loadOrCreateConfig, } from '../config-loader.js';
|
|
6
|
+
describe('loadConfig', () => {
|
|
7
|
+
let tempDir;
|
|
8
|
+
afterEach(() => {
|
|
9
|
+
if (tempDir) {
|
|
10
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
function setupProject(config, opts) {
|
|
14
|
+
tempDir = mkdtempSync(join(tmpdir(), 'specflow-cfg-'));
|
|
15
|
+
const specflowDir = join(tempDir, '.specflow');
|
|
16
|
+
mkdirSync(specflowDir, { recursive: true });
|
|
17
|
+
writeFileSync(join(specflowDir, 'config.json'), JSON.stringify(config, null, 2));
|
|
18
|
+
if (opts?.createDocVault !== false) {
|
|
19
|
+
// Create the DocVault directory that the config points to
|
|
20
|
+
const dvPath = config.docvault;
|
|
21
|
+
const abs = resolve(tempDir, dvPath);
|
|
22
|
+
mkdirSync(abs, { recursive: true });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
it('returns correct ResolvedConfig with valid config.json', async () => {
|
|
26
|
+
setupProject({
|
|
27
|
+
project: 'MyProject',
|
|
28
|
+
docvault: '../DocVault',
|
|
29
|
+
issue_prefix: 'MP',
|
|
30
|
+
});
|
|
31
|
+
const result = await loadConfig(tempDir);
|
|
32
|
+
expect(result.project).toBe('MyProject');
|
|
33
|
+
expect(result.docvault).toBe('../DocVault');
|
|
34
|
+
expect(result.issue_prefix).toBe('MP');
|
|
35
|
+
expect(result.docvaultAbsolute).toBe(resolve(tempDir, '../DocVault'));
|
|
36
|
+
expect(result.specflowRoot).toBe(join(resolve(tempDir, '../DocVault'), 'specflow', 'MyProject'));
|
|
37
|
+
expect(result.globalTemplatesPath).toBe(join(resolve(tempDir, '../DocVault'), 'specflow', 'templates'));
|
|
38
|
+
});
|
|
39
|
+
it('resolves relative docvault path against projectPath', async () => {
|
|
40
|
+
setupProject({
|
|
41
|
+
project: 'TestApp',
|
|
42
|
+
docvault: '../DocVault',
|
|
43
|
+
issue_prefix: 'TA',
|
|
44
|
+
});
|
|
45
|
+
const result = await loadConfig(tempDir);
|
|
46
|
+
expect(result.docvaultAbsolute).toBe(resolve(tempDir, '../DocVault'));
|
|
47
|
+
});
|
|
48
|
+
it('resolves absolute docvault path as-is', async () => {
|
|
49
|
+
tempDir = mkdtempSync(join(tmpdir(), 'specflow-cfg-'));
|
|
50
|
+
const absDocVault = mkdtempSync(join(tmpdir(), 'specflow-dv-'));
|
|
51
|
+
const specflowDir = join(tempDir, '.specflow');
|
|
52
|
+
mkdirSync(specflowDir, { recursive: true });
|
|
53
|
+
writeFileSync(join(specflowDir, 'config.json'), JSON.stringify({
|
|
54
|
+
project: 'AbsTest',
|
|
55
|
+
docvault: absDocVault,
|
|
56
|
+
issue_prefix: 'AT',
|
|
57
|
+
}));
|
|
58
|
+
const result = await loadConfig(tempDir);
|
|
59
|
+
expect(result.docvaultAbsolute).toBe(absDocVault);
|
|
60
|
+
// Clean up extra temp dir
|
|
61
|
+
rmSync(absDocVault, { recursive: true, force: true });
|
|
62
|
+
});
|
|
63
|
+
it('throws on missing config.json (ENOENT)', async () => {
|
|
64
|
+
tempDir = mkdtempSync(join(tmpdir(), 'specflow-cfg-'));
|
|
65
|
+
// No .specflow/ directory at all
|
|
66
|
+
await expect(loadConfig(tempDir)).rejects.toThrow();
|
|
67
|
+
});
|
|
68
|
+
it('throws on invalid project name', async () => {
|
|
69
|
+
setupProject({
|
|
70
|
+
project: 'My Project!',
|
|
71
|
+
docvault: '../DocVault',
|
|
72
|
+
issue_prefix: 'MP',
|
|
73
|
+
});
|
|
74
|
+
await expect(loadConfig(tempDir)).rejects.toThrow(/Invalid project name/);
|
|
75
|
+
});
|
|
76
|
+
it('throws on empty project field', async () => {
|
|
77
|
+
setupProject({
|
|
78
|
+
project: '',
|
|
79
|
+
docvault: '../DocVault',
|
|
80
|
+
issue_prefix: 'MP',
|
|
81
|
+
});
|
|
82
|
+
await expect(loadConfig(tempDir)).rejects.toThrow(/Invalid project name/);
|
|
83
|
+
});
|
|
84
|
+
it('throws on empty docvault field', async () => {
|
|
85
|
+
setupProject({
|
|
86
|
+
project: 'TestApp',
|
|
87
|
+
docvault: '',
|
|
88
|
+
issue_prefix: 'TA',
|
|
89
|
+
});
|
|
90
|
+
await expect(loadConfig(tempDir)).rejects.toThrow(/docvault path must be a non-empty string/);
|
|
91
|
+
});
|
|
92
|
+
it('throws on empty issue_prefix field', async () => {
|
|
93
|
+
setupProject({
|
|
94
|
+
project: 'TestApp',
|
|
95
|
+
docvault: '../DocVault',
|
|
96
|
+
issue_prefix: '',
|
|
97
|
+
});
|
|
98
|
+
await expect(loadConfig(tempDir)).rejects.toThrow(/Invalid issue_prefix/);
|
|
99
|
+
});
|
|
100
|
+
it('throws on inaccessible docvault path', async () => {
|
|
101
|
+
setupProject({
|
|
102
|
+
project: 'TestApp',
|
|
103
|
+
docvault: '../NonExistent',
|
|
104
|
+
issue_prefix: 'TA',
|
|
105
|
+
}, { createDocVault: false });
|
|
106
|
+
await expect(loadConfig(tempDir)).rejects.toThrow(/DocVault path does not exist/);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
describe('createDefaultConfig', () => {
|
|
110
|
+
let tempDir;
|
|
111
|
+
let parentDir;
|
|
112
|
+
afterEach(() => {
|
|
113
|
+
if (parentDir) {
|
|
114
|
+
rmSync(parentDir, { recursive: true, force: true });
|
|
115
|
+
}
|
|
116
|
+
else if (tempDir) {
|
|
117
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
it('auto-detects project name from dirname', async () => {
|
|
121
|
+
parentDir = mkdtempSync(join(tmpdir(), 'specflow-parent-'));
|
|
122
|
+
const projectDir = join(parentDir, 'MyProject');
|
|
123
|
+
const docVaultDir = join(parentDir, 'DocVault');
|
|
124
|
+
mkdirSync(projectDir, { recursive: true });
|
|
125
|
+
mkdirSync(docVaultDir, { recursive: true });
|
|
126
|
+
tempDir = projectDir;
|
|
127
|
+
const result = await createDefaultConfig(projectDir);
|
|
128
|
+
expect(result.project).toBe('MyProject');
|
|
129
|
+
});
|
|
130
|
+
it('detects ../DocVault sibling', async () => {
|
|
131
|
+
parentDir = mkdtempSync(join(tmpdir(), 'specflow-parent-'));
|
|
132
|
+
const projectDir = join(parentDir, 'TestApp');
|
|
133
|
+
const docVaultDir = join(parentDir, 'DocVault');
|
|
134
|
+
mkdirSync(projectDir, { recursive: true });
|
|
135
|
+
mkdirSync(docVaultDir, { recursive: true });
|
|
136
|
+
tempDir = projectDir;
|
|
137
|
+
const result = await createDefaultConfig(projectDir);
|
|
138
|
+
expect(result.docvault).toBe('../DocVault');
|
|
139
|
+
expect(result.docvaultAbsolute).toBe(resolve(projectDir, '../DocVault'));
|
|
140
|
+
});
|
|
141
|
+
it('throws when no DocVault found', async () => {
|
|
142
|
+
parentDir = mkdtempSync(join(tmpdir(), 'specflow-parent-'));
|
|
143
|
+
const projectDir = join(parentDir, 'Lonely');
|
|
144
|
+
mkdirSync(projectDir, { recursive: true });
|
|
145
|
+
tempDir = projectDir;
|
|
146
|
+
await expect(createDefaultConfig(projectDir)).rejects.toThrow(/Could not auto-detect DocVault/);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
describe('loadOrCreateConfig', () => {
|
|
150
|
+
let parentDir;
|
|
151
|
+
afterEach(() => {
|
|
152
|
+
if (parentDir) {
|
|
153
|
+
rmSync(parentDir, { recursive: true, force: true });
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
it('loads existing config', async () => {
|
|
157
|
+
parentDir = mkdtempSync(join(tmpdir(), 'specflow-parent-'));
|
|
158
|
+
const projectDir = join(parentDir, 'ExistingProject');
|
|
159
|
+
const docVaultDir = join(parentDir, 'DocVault');
|
|
160
|
+
mkdirSync(projectDir, { recursive: true });
|
|
161
|
+
mkdirSync(docVaultDir, { recursive: true });
|
|
162
|
+
const specflowDir = join(projectDir, '.specflow');
|
|
163
|
+
mkdirSync(specflowDir, { recursive: true });
|
|
164
|
+
writeFileSync(join(specflowDir, 'config.json'), JSON.stringify({
|
|
165
|
+
project: 'ExistingProject',
|
|
166
|
+
docvault: '../DocVault',
|
|
167
|
+
issue_prefix: 'EP',
|
|
168
|
+
}));
|
|
169
|
+
const result = await loadOrCreateConfig(projectDir);
|
|
170
|
+
expect(result.project).toBe('ExistingProject');
|
|
171
|
+
expect(result.issue_prefix).toBe('EP');
|
|
172
|
+
});
|
|
173
|
+
it('creates config when none exists', async () => {
|
|
174
|
+
parentDir = mkdtempSync(join(tmpdir(), 'specflow-parent-'));
|
|
175
|
+
const projectDir = join(parentDir, 'NewProject');
|
|
176
|
+
const docVaultDir = join(parentDir, 'DocVault');
|
|
177
|
+
mkdirSync(projectDir, { recursive: true });
|
|
178
|
+
mkdirSync(docVaultDir, { recursive: true });
|
|
179
|
+
const result = await loadOrCreateConfig(projectDir);
|
|
180
|
+
expect(result.project).toBe('NewProject');
|
|
181
|
+
expect(result.docvault).toBe('../DocVault');
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
//# sourceMappingURL=config-loader.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-loader.test.js","sourceRoot":"","sources":["../../../src/core/__tests__/config-loader.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-updater.test.d.ts","sourceRoot":"","sources":["../../../src/core/__tests__/index-updater.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { describe, it, expect, afterEach } from 'vitest';
|
|
2
|
+
import { mkdtempSync, mkdirSync, writeFileSync, rmSync, readFileSync, existsSync, } from 'fs';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { tmpdir } from 'os';
|
|
5
|
+
import { ensureIndexExists, addSpecToIndex, removeSpecFromIndex, } from '../index-updater.js';
|
|
6
|
+
function makeConfig(specflowRoot) {
|
|
7
|
+
return {
|
|
8
|
+
project: 'TestProject',
|
|
9
|
+
docvault: '../DocVault',
|
|
10
|
+
issue_prefix: 'TP',
|
|
11
|
+
docvaultAbsolute: join(specflowRoot, '..', '..'),
|
|
12
|
+
specflowRoot,
|
|
13
|
+
globalTemplatesPath: join(specflowRoot, '..', 'templates'),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
describe('ensureIndexExists', () => {
|
|
17
|
+
let tempDir;
|
|
18
|
+
afterEach(() => {
|
|
19
|
+
if (tempDir) {
|
|
20
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
it('creates _Index.md with heading and table', async () => {
|
|
24
|
+
tempDir = mkdtempSync(join(tmpdir(), 'specflow-idx-'));
|
|
25
|
+
const dir = join(tempDir, 'specs');
|
|
26
|
+
await ensureIndexExists(dir, 'Specs');
|
|
27
|
+
const content = readFileSync(join(dir, '_Index.md'), 'utf-8');
|
|
28
|
+
expect(content).toContain('# Specs');
|
|
29
|
+
expect(content).toContain('| Page | Description |');
|
|
30
|
+
expect(content).toContain('|------|-------------|');
|
|
31
|
+
});
|
|
32
|
+
it('is idempotent — does not overwrite existing', async () => {
|
|
33
|
+
tempDir = mkdtempSync(join(tmpdir(), 'specflow-idx-'));
|
|
34
|
+
const dir = join(tempDir, 'specs');
|
|
35
|
+
mkdirSync(dir, { recursive: true });
|
|
36
|
+
writeFileSync(join(dir, '_Index.md'), '# Custom Content\n');
|
|
37
|
+
await ensureIndexExists(dir, 'Specs');
|
|
38
|
+
const content = readFileSync(join(dir, '_Index.md'), 'utf-8');
|
|
39
|
+
expect(content).toBe('# Custom Content\n');
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
describe('addSpecToIndex', () => {
|
|
43
|
+
let tempDir;
|
|
44
|
+
afterEach(() => {
|
|
45
|
+
if (tempDir) {
|
|
46
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
it('adds table row with wikilink', async () => {
|
|
50
|
+
tempDir = mkdtempSync(join(tmpdir(), 'specflow-idx-'));
|
|
51
|
+
const specflowRoot = join(tempDir, 'specflow', 'TestProject');
|
|
52
|
+
const specsDir = join(specflowRoot, 'specs');
|
|
53
|
+
mkdirSync(specsDir, { recursive: true });
|
|
54
|
+
writeFileSync(join(specsDir, '_Index.md'), '# Specs\n\n| Page | Description |\n|------|-------------|\n');
|
|
55
|
+
const config = makeConfig(specflowRoot);
|
|
56
|
+
await addSpecToIndex(config, 'SWF-1-auth', 'Authentication feature');
|
|
57
|
+
const content = readFileSync(join(specsDir, '_Index.md'), 'utf-8');
|
|
58
|
+
expect(content).toContain('| [[SWF-1-auth]] | Authentication feature |');
|
|
59
|
+
});
|
|
60
|
+
it('does not duplicate existing entries', async () => {
|
|
61
|
+
tempDir = mkdtempSync(join(tmpdir(), 'specflow-idx-'));
|
|
62
|
+
const specflowRoot = join(tempDir, 'specflow', 'TestProject');
|
|
63
|
+
const specsDir = join(specflowRoot, 'specs');
|
|
64
|
+
mkdirSync(specsDir, { recursive: true });
|
|
65
|
+
writeFileSync(join(specsDir, '_Index.md'), '# Specs\n\n| Page | Description |\n|------|-------------|\n| [[SWF-1-auth]] | Auth |\n');
|
|
66
|
+
const config = makeConfig(specflowRoot);
|
|
67
|
+
await addSpecToIndex(config, 'SWF-1-auth', 'Updated description');
|
|
68
|
+
const content = readFileSync(join(specsDir, '_Index.md'), 'utf-8');
|
|
69
|
+
const matches = content.match(/\[\[SWF-1-auth\]\]/g);
|
|
70
|
+
expect(matches).toHaveLength(1);
|
|
71
|
+
});
|
|
72
|
+
it('creates index if missing', async () => {
|
|
73
|
+
tempDir = mkdtempSync(join(tmpdir(), 'specflow-idx-'));
|
|
74
|
+
const specflowRoot = join(tempDir, 'specflow', 'TestProject');
|
|
75
|
+
const config = makeConfig(specflowRoot);
|
|
76
|
+
await addSpecToIndex(config, 'SWF-2-dashboard', 'Dashboard feature');
|
|
77
|
+
const specsDir = join(specflowRoot, 'specs');
|
|
78
|
+
expect(existsSync(join(specsDir, '_Index.md'))).toBe(true);
|
|
79
|
+
const content = readFileSync(join(specsDir, '_Index.md'), 'utf-8');
|
|
80
|
+
expect(content).toContain('[[SWF-2-dashboard]]');
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
describe('removeSpecFromIndex', () => {
|
|
84
|
+
let tempDir;
|
|
85
|
+
afterEach(() => {
|
|
86
|
+
if (tempDir) {
|
|
87
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
it('removes the correct entry', async () => {
|
|
91
|
+
tempDir = mkdtempSync(join(tmpdir(), 'specflow-idx-'));
|
|
92
|
+
const specflowRoot = join(tempDir, 'specflow', 'TestProject');
|
|
93
|
+
const specsDir = join(specflowRoot, 'specs');
|
|
94
|
+
mkdirSync(specsDir, { recursive: true });
|
|
95
|
+
writeFileSync(join(specsDir, '_Index.md'), '# Specs\n\n| Page | Description |\n|------|-------------|\n| [[SWF-1-auth]] | Auth |\n| [[SWF-2-dash]] | Dashboard |\n');
|
|
96
|
+
const config = makeConfig(specflowRoot);
|
|
97
|
+
await removeSpecFromIndex(config, 'SWF-1-auth');
|
|
98
|
+
const content = readFileSync(join(specsDir, '_Index.md'), 'utf-8');
|
|
99
|
+
expect(content).not.toContain('[[SWF-1-auth]]');
|
|
100
|
+
expect(content).toContain('[[SWF-2-dash]]');
|
|
101
|
+
});
|
|
102
|
+
it('is a no-op when spec not found', async () => {
|
|
103
|
+
tempDir = mkdtempSync(join(tmpdir(), 'specflow-idx-'));
|
|
104
|
+
const specflowRoot = join(tempDir, 'specflow', 'TestProject');
|
|
105
|
+
const specsDir = join(specflowRoot, 'specs');
|
|
106
|
+
mkdirSync(specsDir, { recursive: true });
|
|
107
|
+
const original = '# Specs\n\n| Page | Description |\n|------|-------------|\n| [[SWF-1-auth]] | Auth |\n';
|
|
108
|
+
writeFileSync(join(specsDir, '_Index.md'), original);
|
|
109
|
+
const config = makeConfig(specflowRoot);
|
|
110
|
+
await removeSpecFromIndex(config, 'SWF-99-missing');
|
|
111
|
+
const content = readFileSync(join(specsDir, '_Index.md'), 'utf-8');
|
|
112
|
+
expect(content).toBe(original);
|
|
113
|
+
});
|
|
114
|
+
it('is a no-op when file does not exist', async () => {
|
|
115
|
+
tempDir = mkdtempSync(join(tmpdir(), 'specflow-idx-'));
|
|
116
|
+
const specflowRoot = join(tempDir, 'specflow', 'TestProject');
|
|
117
|
+
const config = makeConfig(specflowRoot);
|
|
118
|
+
// Should not throw
|
|
119
|
+
await expect(removeSpecFromIndex(config, 'SWF-1-auth')).resolves.toBeUndefined();
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
//# sourceMappingURL=index-updater.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-updater.test.js","sourceRoot":"","sources":["../../../src/core/__tests__/index-updater.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration.test.d.ts","sourceRoot":"","sources":["../../../src/core/__tests__/migration.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { describe, it, expect, afterEach } from 'vitest';
|
|
2
|
+
import { mkdtempSync, mkdirSync, writeFileSync, rmSync, existsSync, readFileSync, } from 'fs';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { tmpdir } from 'os';
|
|
5
|
+
import { needsMigration, migrateToDocVault } from '../migration.js';
|
|
6
|
+
function makeConfig(tempDir, specflowRoot) {
|
|
7
|
+
return {
|
|
8
|
+
project: 'TestProject',
|
|
9
|
+
docvault: '../DocVault',
|
|
10
|
+
issue_prefix: 'TP',
|
|
11
|
+
docvaultAbsolute: join(tempDir, 'DocVault'),
|
|
12
|
+
specflowRoot,
|
|
13
|
+
globalTemplatesPath: join(tempDir, 'DocVault', 'specflow', 'templates'),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
describe('needsMigration', () => {
|
|
17
|
+
let tempDir;
|
|
18
|
+
afterEach(() => {
|
|
19
|
+
if (tempDir) {
|
|
20
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
it('returns true when .specflow/ has specs/', async () => {
|
|
24
|
+
tempDir = mkdtempSync(join(tmpdir(), 'specflow-mig-'));
|
|
25
|
+
const specsDir = join(tempDir, '.specflow', 'specs');
|
|
26
|
+
mkdirSync(specsDir, { recursive: true });
|
|
27
|
+
writeFileSync(join(specsDir, 'some-spec.md'), '# Spec');
|
|
28
|
+
const config = makeConfig(tempDir, join(tempDir, 'DocVault', 'specflow', 'TestProject'));
|
|
29
|
+
expect(await needsMigration(tempDir, config)).toBe(true);
|
|
30
|
+
});
|
|
31
|
+
it('returns true when .specflow/ has steering/', async () => {
|
|
32
|
+
tempDir = mkdtempSync(join(tmpdir(), 'specflow-mig-'));
|
|
33
|
+
const steeringDir = join(tempDir, '.specflow', 'steering');
|
|
34
|
+
mkdirSync(steeringDir, { recursive: true });
|
|
35
|
+
writeFileSync(join(steeringDir, 'product.md'), '# Product');
|
|
36
|
+
const config = makeConfig(tempDir, join(tempDir, 'DocVault', 'specflow', 'TestProject'));
|
|
37
|
+
expect(await needsMigration(tempDir, config)).toBe(true);
|
|
38
|
+
});
|
|
39
|
+
it('returns false when .specflow/ is empty (only config.json)', async () => {
|
|
40
|
+
tempDir = mkdtempSync(join(tmpdir(), 'specflow-mig-'));
|
|
41
|
+
const specflowDir = join(tempDir, '.specflow');
|
|
42
|
+
mkdirSync(specflowDir, { recursive: true });
|
|
43
|
+
writeFileSync(join(specflowDir, 'config.json'), '{}');
|
|
44
|
+
const config = makeConfig(tempDir, join(tempDir, 'DocVault', 'specflow', 'TestProject'));
|
|
45
|
+
expect(await needsMigration(tempDir, config)).toBe(false);
|
|
46
|
+
});
|
|
47
|
+
it('returns false when .specflow/ does not exist', async () => {
|
|
48
|
+
tempDir = mkdtempSync(join(tmpdir(), 'specflow-mig-'));
|
|
49
|
+
const config = makeConfig(tempDir, join(tempDir, 'DocVault', 'specflow', 'TestProject'));
|
|
50
|
+
expect(await needsMigration(tempDir, config)).toBe(false);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
describe('migrateToDocVault', () => {
|
|
54
|
+
let tempDir;
|
|
55
|
+
afterEach(() => {
|
|
56
|
+
if (tempDir) {
|
|
57
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
function setupLocalSpecflow(dirs) {
|
|
61
|
+
for (const [dirName, files] of Object.entries(dirs)) {
|
|
62
|
+
const dirPath = join(tempDir, '.specflow', dirName);
|
|
63
|
+
mkdirSync(dirPath, { recursive: true });
|
|
64
|
+
for (const [fileName, content] of Object.entries(files)) {
|
|
65
|
+
writeFileSync(join(dirPath, fileName), content);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
it('copies all 5 directories correctly', async () => {
|
|
70
|
+
tempDir = mkdtempSync(join(tmpdir(), 'specflow-mig-'));
|
|
71
|
+
const specflowRoot = join(tempDir, 'DocVault', 'specflow', 'TestProject');
|
|
72
|
+
setupLocalSpecflow({
|
|
73
|
+
steering: { 'product.md': '# Product' },
|
|
74
|
+
specs: { 'spec-1.md': '# Spec 1' },
|
|
75
|
+
'user-templates': { 'tmpl.md': '# Template' },
|
|
76
|
+
approvals: { 'approval.md': '# Approval' },
|
|
77
|
+
archive: { 'old.md': '# Old' },
|
|
78
|
+
});
|
|
79
|
+
const config = makeConfig(tempDir, specflowRoot);
|
|
80
|
+
const result = await migrateToDocVault(tempDir, config);
|
|
81
|
+
expect(result.migratedDirs).toContain('steering');
|
|
82
|
+
expect(result.migratedDirs).toContain('specs');
|
|
83
|
+
expect(result.migratedDirs).toContain('user-templates');
|
|
84
|
+
expect(result.migratedDirs).toContain('approvals');
|
|
85
|
+
expect(result.migratedDirs).toContain('archive');
|
|
86
|
+
expect(result.errors).toHaveLength(0);
|
|
87
|
+
// Verify files were actually copied
|
|
88
|
+
expect(readFileSync(join(specflowRoot, 'steering', 'product.md'), 'utf-8')).toBe('# Product');
|
|
89
|
+
expect(readFileSync(join(specflowRoot, 'specs', 'spec-1.md'), 'utf-8')).toBe('# Spec 1');
|
|
90
|
+
expect(readFileSync(join(specflowRoot, 'approvals', 'approval.md'), 'utf-8')).toBe('# Approval');
|
|
91
|
+
expect(readFileSync(join(specflowRoot, 'archive', 'old.md'), 'utf-8')).toBe('# Old');
|
|
92
|
+
});
|
|
93
|
+
it('renames user-templates/ to templates/ in destination', async () => {
|
|
94
|
+
tempDir = mkdtempSync(join(tmpdir(), 'specflow-mig-'));
|
|
95
|
+
const specflowRoot = join(tempDir, 'DocVault', 'specflow', 'TestProject');
|
|
96
|
+
setupLocalSpecflow({
|
|
97
|
+
'user-templates': { 'custom.md': '# Custom Template' },
|
|
98
|
+
});
|
|
99
|
+
const config = makeConfig(tempDir, specflowRoot);
|
|
100
|
+
await migrateToDocVault(tempDir, config);
|
|
101
|
+
// Should be at templates/, not user-templates/
|
|
102
|
+
expect(readFileSync(join(specflowRoot, 'templates', 'custom.md'), 'utf-8')).toBe('# Custom Template');
|
|
103
|
+
expect(existsSync(join(specflowRoot, 'user-templates'))).toBe(false);
|
|
104
|
+
});
|
|
105
|
+
it('skips destinations that already have content', async () => {
|
|
106
|
+
tempDir = mkdtempSync(join(tmpdir(), 'specflow-mig-'));
|
|
107
|
+
const specflowRoot = join(tempDir, 'DocVault', 'specflow', 'TestProject');
|
|
108
|
+
// Create existing content at destination
|
|
109
|
+
const destSpecs = join(specflowRoot, 'specs');
|
|
110
|
+
mkdirSync(destSpecs, { recursive: true });
|
|
111
|
+
writeFileSync(join(destSpecs, 'existing.md'), '# Existing');
|
|
112
|
+
setupLocalSpecflow({
|
|
113
|
+
specs: { 'new-spec.md': '# New Spec' },
|
|
114
|
+
});
|
|
115
|
+
const config = makeConfig(tempDir, specflowRoot);
|
|
116
|
+
const result = await migrateToDocVault(tempDir, config);
|
|
117
|
+
expect(result.skippedDirs).toContain('specs');
|
|
118
|
+
expect(result.migratedDirs).not.toContain('specs');
|
|
119
|
+
// Original destination content should be preserved
|
|
120
|
+
expect(readFileSync(join(destSpecs, 'existing.md'), 'utf-8')).toBe('# Existing');
|
|
121
|
+
});
|
|
122
|
+
it('handles missing source dirs gracefully', async () => {
|
|
123
|
+
tempDir = mkdtempSync(join(tmpdir(), 'specflow-mig-'));
|
|
124
|
+
const specflowRoot = join(tempDir, 'DocVault', 'specflow', 'TestProject');
|
|
125
|
+
mkdirSync(join(tempDir, '.specflow'), { recursive: true });
|
|
126
|
+
const config = makeConfig(tempDir, specflowRoot);
|
|
127
|
+
const result = await migrateToDocVault(tempDir, config);
|
|
128
|
+
// Nothing to migrate, nothing should error
|
|
129
|
+
expect(result.migratedDirs).toHaveLength(0);
|
|
130
|
+
expect(result.skippedDirs).toHaveLength(0);
|
|
131
|
+
expect(result.errors).toHaveLength(0);
|
|
132
|
+
});
|
|
133
|
+
it('returns accurate MigrationResult', async () => {
|
|
134
|
+
tempDir = mkdtempSync(join(tmpdir(), 'specflow-mig-'));
|
|
135
|
+
const specflowRoot = join(tempDir, 'DocVault', 'specflow', 'TestProject');
|
|
136
|
+
// Pre-populate one destination
|
|
137
|
+
const destSteering = join(specflowRoot, 'steering');
|
|
138
|
+
mkdirSync(destSteering, { recursive: true });
|
|
139
|
+
writeFileSync(join(destSteering, 'existing.md'), '# Existing');
|
|
140
|
+
setupLocalSpecflow({
|
|
141
|
+
steering: { 'product.md': '# Product' },
|
|
142
|
+
specs: { 'spec.md': '# Spec' },
|
|
143
|
+
});
|
|
144
|
+
const config = makeConfig(tempDir, specflowRoot);
|
|
145
|
+
const result = await migrateToDocVault(tempDir, config);
|
|
146
|
+
expect(result.migratedDirs).toEqual(['specs']);
|
|
147
|
+
expect(result.skippedDirs).toEqual(['steering']);
|
|
148
|
+
expect(result.errors).toHaveLength(0);
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
//# sourceMappingURL=migration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration.test.js","sourceRoot":"","sources":["../../../src/core/__tests__/migration.test.ts"],"names":[],"mappings":"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"}
|