jest-test-lineage-reporter 2.1.0 ā 2.1.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/README.md +40 -11
- package/package.json +1 -1
- package/src/cli/commands/init.js +254 -0
- package/src/cli/index.js +10 -0
package/README.md
CHANGED
|
@@ -20,29 +20,58 @@ A comprehensive test analytics platform that provides line-by-line test coverage
|
|
|
20
20
|
|
|
21
21
|
## š CLI Usage (New!)
|
|
22
22
|
|
|
23
|
-
Jest Test Lineage Reporter now includes a powerful CLI tool!
|
|
23
|
+
Jest Test Lineage Reporter now includes a powerful CLI tool with automatic configuration!
|
|
24
24
|
|
|
25
25
|
### Quick Start with CLI
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
#
|
|
29
|
-
jest-lineage
|
|
28
|
+
# 1. Install the package
|
|
29
|
+
npm install --save-dev jest-test-lineage-reporter jest babel-jest @babel/core @babel/preset-env
|
|
30
30
|
|
|
31
|
-
#
|
|
32
|
-
jest-lineage
|
|
31
|
+
# 2. Initialize configuration (creates jest.config.js and babel.config.js)
|
|
32
|
+
npx jest-lineage init
|
|
33
33
|
|
|
34
|
-
#
|
|
35
|
-
jest-lineage
|
|
34
|
+
# 3. Run tests with lineage tracking
|
|
35
|
+
npx jest-lineage test
|
|
36
36
|
|
|
37
|
-
#
|
|
38
|
-
jest-lineage
|
|
37
|
+
# 4. Generate HTML report
|
|
38
|
+
npx jest-lineage report --open
|
|
39
39
|
|
|
40
|
-
#
|
|
41
|
-
jest-lineage
|
|
40
|
+
# 5. Run mutation testing
|
|
41
|
+
npx jest-lineage mutate --threshold 85
|
|
42
|
+
|
|
43
|
+
# 6. Query which tests cover a specific line
|
|
44
|
+
npx jest-lineage query src/calculator.ts 42
|
|
45
|
+
|
|
46
|
+
# 7. Full analysis workflow (test + mutate + report)
|
|
47
|
+
npx jest-lineage analyze --open
|
|
42
48
|
```
|
|
43
49
|
|
|
44
50
|
### CLI Commands
|
|
45
51
|
|
|
52
|
+
#### `jest-lineage init` ā NEW
|
|
53
|
+
Initialize project configuration automatically.
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
# Create jest.config.js and babel.config.js with all required settings
|
|
57
|
+
npx jest-lineage init
|
|
58
|
+
|
|
59
|
+
# Force overwrite existing config files
|
|
60
|
+
npx jest-lineage init --force
|
|
61
|
+
|
|
62
|
+
# Configure for TypeScript project
|
|
63
|
+
npx jest-lineage init --typescript
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**What it does:**
|
|
67
|
+
- ā
Checks for required dependencies
|
|
68
|
+
- ā
Creates `jest.config.js` with lineage reporter configured
|
|
69
|
+
- ā
Creates `babel.config.js` with instrumentation plugin
|
|
70
|
+
- ā
Detects TypeScript and configures accordingly
|
|
71
|
+
- ā
Shows clear next steps
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
46
75
|
#### `jest-lineage test [jest-args...]`
|
|
47
76
|
Run Jest tests with lineage tracking enabled.
|
|
48
77
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Init Command
|
|
3
|
+
* Initialize jest-test-lineage-reporter in a project
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const { success, error, info, warning } = require('../utils/output-formatter');
|
|
9
|
+
|
|
10
|
+
async function initCommand(options) {
|
|
11
|
+
try {
|
|
12
|
+
const cwd = process.cwd();
|
|
13
|
+
const jestConfigPath = path.join(cwd, 'jest.config.js');
|
|
14
|
+
const babelConfigPath = path.join(cwd, 'babel.config.js');
|
|
15
|
+
const packageJsonPath = path.join(cwd, 'package.json');
|
|
16
|
+
|
|
17
|
+
console.log('\nš Initializing jest-test-lineage-reporter...\n');
|
|
18
|
+
|
|
19
|
+
// Check if package.json exists
|
|
20
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
21
|
+
error('No package.json found. Please run "npm init" first.');
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Detect if jest-test-lineage-reporter is installed locally or globally
|
|
26
|
+
const isLocalInstall = isInstalledLocally(cwd);
|
|
27
|
+
|
|
28
|
+
if (!isLocalInstall) {
|
|
29
|
+
warning('jest-test-lineage-reporter is installed globally.');
|
|
30
|
+
warning('For best results, install it locally in your project:\n');
|
|
31
|
+
console.log(' npm install --save-dev jest-test-lineage-reporter\n');
|
|
32
|
+
|
|
33
|
+
if (!options.force) {
|
|
34
|
+
error('Global installation detected. Use --force to continue with absolute paths.');
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Read package.json to check dependencies
|
|
40
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
41
|
+
const allDeps = {
|
|
42
|
+
...(packageJson.dependencies || {}),
|
|
43
|
+
...(packageJson.devDependencies || {}),
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// Check for required dependencies
|
|
47
|
+
const requiredDeps = ['jest', 'babel-jest', '@babel/core', '@babel/preset-env'];
|
|
48
|
+
const missingDeps = requiredDeps.filter(dep => !allDeps[dep]);
|
|
49
|
+
|
|
50
|
+
if (missingDeps.length > 0) {
|
|
51
|
+
warning('Missing required dependencies:');
|
|
52
|
+
missingDeps.forEach(dep => console.log(` - ${dep}`));
|
|
53
|
+
console.log('\nš” Install them with:');
|
|
54
|
+
console.log(` npm install --save-dev ${missingDeps.join(' ')}\n`);
|
|
55
|
+
|
|
56
|
+
if (!options.force) {
|
|
57
|
+
error('Please install missing dependencies first, or use --force to continue anyway.');
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Create or update Jest config
|
|
63
|
+
let jestConfigCreated = false;
|
|
64
|
+
if (fs.existsSync(jestConfigPath)) {
|
|
65
|
+
if (!options.force) {
|
|
66
|
+
warning(`jest.config.js already exists. Use --force to overwrite.`);
|
|
67
|
+
info('Please manually add the following to your jest.config.js:');
|
|
68
|
+
const setupPath = isLocalInstall
|
|
69
|
+
? 'jest-test-lineage-reporter/src/testSetup.js'
|
|
70
|
+
: getGlobalPackagePath('testSetup.js');
|
|
71
|
+
console.log(`
|
|
72
|
+
setupFilesAfterEnv: ['${setupPath}'],
|
|
73
|
+
|
|
74
|
+
reporters: [
|
|
75
|
+
'default',
|
|
76
|
+
['jest-test-lineage-reporter', {
|
|
77
|
+
outputFile: '.jest-lineage-data.json',
|
|
78
|
+
enableMutationTesting: false,
|
|
79
|
+
}]
|
|
80
|
+
],
|
|
81
|
+
|
|
82
|
+
collectCoverage: true,
|
|
83
|
+
collectCoverageFrom: ['src/**/*.{js,ts}', '!src/**/*.test.{js,ts}'],
|
|
84
|
+
|
|
85
|
+
transform: {
|
|
86
|
+
'^.+\\\\.(js|jsx|ts|tsx)$': 'babel-jest',
|
|
87
|
+
},
|
|
88
|
+
`);
|
|
89
|
+
} else {
|
|
90
|
+
createJestConfig(jestConfigPath, options, isLocalInstall);
|
|
91
|
+
jestConfigCreated = true;
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
createJestConfig(jestConfigPath, options, isLocalInstall);
|
|
95
|
+
jestConfigCreated = true;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Create or update Babel config
|
|
99
|
+
let babelConfigCreated = false;
|
|
100
|
+
if (fs.existsSync(babelConfigPath)) {
|
|
101
|
+
if (!options.force) {
|
|
102
|
+
warning(`babel.config.js already exists. Use --force to overwrite.`);
|
|
103
|
+
info('Please manually add the lineage tracker plugin to your babel.config.js:');
|
|
104
|
+
const pluginPath = isLocalInstall
|
|
105
|
+
? 'jest-test-lineage-reporter/src/babel-plugin-lineage-tracker.js'
|
|
106
|
+
: getGlobalPackagePath('babel-plugin-lineage-tracker.js');
|
|
107
|
+
console.log(`
|
|
108
|
+
plugins: [
|
|
109
|
+
'${pluginPath}',
|
|
110
|
+
],
|
|
111
|
+
`);
|
|
112
|
+
} else {
|
|
113
|
+
createBabelConfig(babelConfigPath, options, isLocalInstall);
|
|
114
|
+
babelConfigCreated = true;
|
|
115
|
+
}
|
|
116
|
+
} else {
|
|
117
|
+
createBabelConfig(babelConfigPath, options, isLocalInstall);
|
|
118
|
+
babelConfigCreated = true;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Summary
|
|
122
|
+
console.log('\n' + 'ā'.repeat(50));
|
|
123
|
+
if (jestConfigCreated && babelConfigCreated) {
|
|
124
|
+
success('Configuration complete! āØ\n');
|
|
125
|
+
console.log('ā
Created jest.config.js');
|
|
126
|
+
console.log('ā
Created babel.config.js\n');
|
|
127
|
+
} else if (!jestConfigCreated && !babelConfigCreated) {
|
|
128
|
+
info('Configuration files already exist.');
|
|
129
|
+
info('Use --force to overwrite, or manually update the files.\n');
|
|
130
|
+
} else {
|
|
131
|
+
info('Partial configuration completed.');
|
|
132
|
+
if (jestConfigCreated) console.log('ā
Created jest.config.js');
|
|
133
|
+
if (babelConfigCreated) console.log('ā
Created babel.config.js');
|
|
134
|
+
console.log('');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Show next steps
|
|
138
|
+
console.log('š Next steps:\n');
|
|
139
|
+
if (missingDeps.length > 0) {
|
|
140
|
+
console.log('1. Install missing dependencies:');
|
|
141
|
+
console.log(` npm install --save-dev ${missingDeps.join(' ')}\n`);
|
|
142
|
+
}
|
|
143
|
+
console.log(`${missingDeps.length > 0 ? '2' : '1'}. Run your tests with lineage tracking:`);
|
|
144
|
+
console.log(' npx jest-lineage test\n');
|
|
145
|
+
console.log(`${missingDeps.length > 0 ? '3' : '2'}. Query coverage data:`);
|
|
146
|
+
console.log(' npx jest-lineage query src/yourfile.js\n');
|
|
147
|
+
console.log(`${missingDeps.length > 0 ? '4' : '3'}. Generate HTML report:`);
|
|
148
|
+
console.log(' npx jest-lineage report --open\n');
|
|
149
|
+
console.log('ā'.repeat(50) + '\n');
|
|
150
|
+
|
|
151
|
+
} catch (err) {
|
|
152
|
+
error(`Failed to initialize: ${err.message}`);
|
|
153
|
+
if (options.verbose) {
|
|
154
|
+
console.error(err.stack);
|
|
155
|
+
}
|
|
156
|
+
process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function createJestConfig(filePath, options, isLocalInstall) {
|
|
161
|
+
const isTypeScript = options.typescript || hasTypeScriptFiles();
|
|
162
|
+
const setupPath = isLocalInstall
|
|
163
|
+
? 'jest-test-lineage-reporter/src/testSetup.js'
|
|
164
|
+
: getGlobalPackagePath('testSetup.js');
|
|
165
|
+
|
|
166
|
+
const config = `module.exports = {
|
|
167
|
+
testEnvironment: 'node',
|
|
168
|
+
|
|
169
|
+
// Required: Setup file for lineage tracking
|
|
170
|
+
setupFilesAfterEnv: ['${setupPath}'],
|
|
171
|
+
|
|
172
|
+
// Add the lineage reporter
|
|
173
|
+
reporters: [
|
|
174
|
+
'default',
|
|
175
|
+
[
|
|
176
|
+
'jest-test-lineage-reporter',
|
|
177
|
+
{
|
|
178
|
+
outputFile: '.jest-lineage-data.json',
|
|
179
|
+
enableMutationTesting: false,
|
|
180
|
+
}
|
|
181
|
+
]
|
|
182
|
+
],
|
|
183
|
+
|
|
184
|
+
// Enable coverage
|
|
185
|
+
collectCoverage: true,
|
|
186
|
+
collectCoverageFrom: [
|
|
187
|
+
'src/**/*.{js${isTypeScript ? ',ts' : ''}}',
|
|
188
|
+
'!src/**/*.test.{js${isTypeScript ? ',ts' : ''}}',
|
|
189
|
+
'!src/**/*.d.ts',
|
|
190
|
+
],
|
|
191
|
+
|
|
192
|
+
// Use babel-jest for transformation
|
|
193
|
+
transform: {
|
|
194
|
+
'^.+\\\\.(js|jsx${isTypeScript ? '|ts|tsx' : ''})$': 'babel-jest',
|
|
195
|
+
},
|
|
196
|
+
|
|
197
|
+
// File extensions
|
|
198
|
+
moduleFileExtensions: ['js', 'jsx'${isTypeScript ? ", 'ts', 'tsx'" : ''}, 'json'],
|
|
199
|
+
};
|
|
200
|
+
`;
|
|
201
|
+
|
|
202
|
+
fs.writeFileSync(filePath, config, 'utf8');
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function createBabelConfig(filePath, options, isLocalInstall) {
|
|
206
|
+
const isTypeScript = options.typescript || hasTypeScriptFiles();
|
|
207
|
+
const pluginPath = isLocalInstall
|
|
208
|
+
? 'jest-test-lineage-reporter/src/babel-plugin-lineage-tracker.js'
|
|
209
|
+
: getGlobalPackagePath('babel-plugin-lineage-tracker.js');
|
|
210
|
+
|
|
211
|
+
const config = `module.exports = {
|
|
212
|
+
presets: [
|
|
213
|
+
['@babel/preset-env', { targets: { node: 'current' } }],${isTypeScript ? `
|
|
214
|
+
'@babel/preset-typescript',` : ''}
|
|
215
|
+
],
|
|
216
|
+
plugins: [
|
|
217
|
+
// Required: Lineage tracker plugin for instrumentation
|
|
218
|
+
'${pluginPath}',
|
|
219
|
+
],
|
|
220
|
+
};
|
|
221
|
+
`;
|
|
222
|
+
|
|
223
|
+
fs.writeFileSync(filePath, config, 'utf8');
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function hasTypeScriptFiles() {
|
|
227
|
+
const cwd = process.cwd();
|
|
228
|
+
const srcDir = path.join(cwd, 'src');
|
|
229
|
+
|
|
230
|
+
if (!fs.existsSync(srcDir)) return false;
|
|
231
|
+
|
|
232
|
+
try {
|
|
233
|
+
const files = fs.readdirSync(srcDir);
|
|
234
|
+
return files.some(file => file.endsWith('.ts') || file.endsWith('.tsx'));
|
|
235
|
+
} catch {
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function isInstalledLocally(cwd) {
|
|
241
|
+
const localPath = path.join(cwd, 'node_modules', 'jest-test-lineage-reporter');
|
|
242
|
+
return fs.existsSync(localPath);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function getGlobalPackagePath(filename) {
|
|
246
|
+
// Get the directory where this script is running from
|
|
247
|
+
const scriptDir = path.dirname(path.dirname(path.dirname(__dirname)));
|
|
248
|
+
const srcPath = path.join(scriptDir, 'src', filename);
|
|
249
|
+
|
|
250
|
+
// Return absolute path
|
|
251
|
+
return srcPath;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
module.exports = initCommand;
|
package/src/cli/index.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
const { Command } = require('commander');
|
|
7
|
+
const initCommand = require('./commands/init');
|
|
7
8
|
const testCommand = require('./commands/test');
|
|
8
9
|
const mutateCommand = require('./commands/mutate');
|
|
9
10
|
const reportCommand = require('./commands/report');
|
|
@@ -19,6 +20,15 @@ async function run(argv) {
|
|
|
19
20
|
.description('Comprehensive test analytics with lineage tracking and mutation testing')
|
|
20
21
|
.version(pkg.version, '-v, --version', 'Display version number');
|
|
21
22
|
|
|
23
|
+
// Init command - Initialize project configuration
|
|
24
|
+
program
|
|
25
|
+
.command('init')
|
|
26
|
+
.description('Initialize jest-test-lineage-reporter configuration')
|
|
27
|
+
.option('--force', 'Overwrite existing configuration files')
|
|
28
|
+
.option('--typescript', 'Configure for TypeScript project')
|
|
29
|
+
.option('--verbose', 'Show detailed error messages')
|
|
30
|
+
.action(initCommand);
|
|
31
|
+
|
|
22
32
|
// Test command - Run Jest with lineage tracking
|
|
23
33
|
program
|
|
24
34
|
.command('test [jest-args...]')
|