@aiready/testability 0.6.21 → 0.6.23
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/.turbo/turbo-build.log +24 -23
- package/.turbo/turbo-test.log +20 -18
- package/coverage/analyzer.ts.html +54 -165
- package/coverage/clover.xml +38 -53
- package/coverage/coverage-final.json +3 -3
- package/coverage/index.html +30 -30
- package/coverage/provider.ts.html +29 -59
- package/coverage/scoring.ts.html +24 -135
- package/dist/chunk-CE46EON2.mjs +240 -0
- package/dist/chunk-CISO2RDG.mjs +198 -0
- package/dist/chunk-KYBNMI4K.mjs +237 -0
- package/dist/cli.js +33 -76
- package/dist/cli.mjs +9 -9
- package/dist/index.js +23 -66
- package/dist/index.mjs +1 -1
- package/package.json +2 -2
- package/src/__tests__/scoring.test.ts +31 -0
- package/src/analyzer.ts +25 -78
- package/src/cli.ts +8 -8
package/src/analyzer.ts
CHANGED
|
@@ -3,11 +3,12 @@ import {
|
|
|
3
3
|
calculateTestabilityIndex,
|
|
4
4
|
Severity,
|
|
5
5
|
IssueType,
|
|
6
|
-
|
|
6
|
+
runBatchAnalysis,
|
|
7
7
|
getParser,
|
|
8
|
+
isTestFile,
|
|
9
|
+
detectTestFramework,
|
|
8
10
|
} from '@aiready/core';
|
|
9
|
-
import { readFileSync
|
|
10
|
-
import { join } from 'path';
|
|
11
|
+
import { readFileSync } from 'fs';
|
|
11
12
|
import type {
|
|
12
13
|
TestabilityOptions,
|
|
13
14
|
TestabilityIssue,
|
|
@@ -89,62 +90,9 @@ async function analyzeFileTestability(filePath: string): Promise<FileAnalysis> {
|
|
|
89
90
|
return result;
|
|
90
91
|
}
|
|
91
92
|
|
|
92
|
-
// ---------------------------------------------------------------------------
|
|
93
|
-
// Test framework detection
|
|
94
|
-
// ---------------------------------------------------------------------------
|
|
95
|
-
|
|
96
|
-
function detectTestFramework(rootDir: string): boolean {
|
|
97
|
-
// Check common manifest files
|
|
98
|
-
const manifests = [
|
|
99
|
-
{
|
|
100
|
-
file: 'package.json',
|
|
101
|
-
deps: ['jest', 'vitest', 'mocha', 'mocha', 'jasmine', 'ava', 'tap'],
|
|
102
|
-
},
|
|
103
|
-
{ file: 'requirements.txt', deps: ['pytest', 'unittest', 'nose'] },
|
|
104
|
-
{ file: 'pyproject.toml', deps: ['pytest'] },
|
|
105
|
-
{ file: 'pom.xml', deps: ['junit', 'testng'] },
|
|
106
|
-
{ file: 'build.gradle', deps: ['junit', 'testng'] },
|
|
107
|
-
{ file: 'go.mod', deps: ['testing'] }, // go testing is built-in
|
|
108
|
-
];
|
|
109
|
-
|
|
110
|
-
for (const m of manifests) {
|
|
111
|
-
const p = join(rootDir, m.file);
|
|
112
|
-
if (existsSync(p)) {
|
|
113
|
-
if (m.file === 'go.mod') return true; // built-in
|
|
114
|
-
try {
|
|
115
|
-
const content = readFileSync(p, 'utf-8');
|
|
116
|
-
if (m.deps.some((d) => content.includes(d))) return true;
|
|
117
|
-
} catch {
|
|
118
|
-
// Ignore file read errors
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
return false;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// ---------------------------------------------------------------------------
|
|
126
93
|
// Main analyzer
|
|
127
94
|
// ---------------------------------------------------------------------------
|
|
128
95
|
|
|
129
|
-
const TEST_PATTERNS = [
|
|
130
|
-
/\.(test|spec)\.(ts|tsx|js|jsx)$/,
|
|
131
|
-
/_test\.go$/,
|
|
132
|
-
/test_.*\.py$/,
|
|
133
|
-
/.*_test\.py$/,
|
|
134
|
-
/.*Test\.java$/,
|
|
135
|
-
/.*Tests\.cs$/,
|
|
136
|
-
/__tests__\//,
|
|
137
|
-
/\/tests?\//,
|
|
138
|
-
/\/e2e\//,
|
|
139
|
-
/\/fixtures\//,
|
|
140
|
-
];
|
|
141
|
-
|
|
142
|
-
function isTestFile(filePath: string, extra?: string[]): boolean {
|
|
143
|
-
if (TEST_PATTERNS.some((p) => p.test(filePath))) return true;
|
|
144
|
-
if (extra) return extra.some((p) => filePath.includes(p));
|
|
145
|
-
return false;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
96
|
export async function analyzeTestability(
|
|
149
97
|
options: TestabilityOptions
|
|
150
98
|
): Promise<TestabilityReport> {
|
|
@@ -177,29 +125,28 @@ export async function analyzeTestability(
|
|
|
177
125
|
totalFunctions: number;
|
|
178
126
|
}> = [];
|
|
179
127
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
'testability',
|
|
187
|
-
'analyzing files',
|
|
188
|
-
options.onProgress
|
|
189
|
-
);
|
|
190
|
-
|
|
191
|
-
const a = await analyzeFileTestability(f);
|
|
192
|
-
for (const key of Object.keys(aggregated) as Array<keyof FileAnalysis>) {
|
|
193
|
-
aggregated[key] += a[key];
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// Collect file-level data
|
|
197
|
-
fileDetails.push({
|
|
128
|
+
await runBatchAnalysis(
|
|
129
|
+
sourceFiles,
|
|
130
|
+
'analyzing files',
|
|
131
|
+
'testability',
|
|
132
|
+
options.onProgress,
|
|
133
|
+
async (f: string) => ({
|
|
198
134
|
filePath: f,
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
})
|
|
202
|
-
|
|
135
|
+
analysis: await analyzeFileTestability(f),
|
|
136
|
+
}),
|
|
137
|
+
(result: { filePath: string; analysis: FileAnalysis }) => {
|
|
138
|
+
const a = result.analysis;
|
|
139
|
+
for (const key of Object.keys(aggregated) as Array<keyof FileAnalysis>) {
|
|
140
|
+
aggregated[key] += a[key];
|
|
141
|
+
}
|
|
142
|
+
// Collect file-level data
|
|
143
|
+
fileDetails.push({
|
|
144
|
+
filePath: result.filePath,
|
|
145
|
+
pureFunctions: a.pureFunctions,
|
|
146
|
+
totalFunctions: a.totalFunctions,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
);
|
|
203
150
|
|
|
204
151
|
const hasTestFramework = detectTestFramework(options.rootDir);
|
|
205
152
|
|
package/src/cli.ts
CHANGED
|
@@ -88,28 +88,28 @@ EXAMPLES:
|
|
|
88
88
|
} else {
|
|
89
89
|
displayStandardConsoleReport({
|
|
90
90
|
title: '🧪 Testability Analysis',
|
|
91
|
-
score: scoring.
|
|
92
|
-
rating: scoring.summary.rating,
|
|
91
|
+
score: scoring.score,
|
|
92
|
+
rating: scoring.rating || report.summary.rating,
|
|
93
93
|
dimensions: [
|
|
94
94
|
{
|
|
95
95
|
name: 'Test Coverage',
|
|
96
|
-
value:
|
|
96
|
+
value: report.summary.dimensions.testCoverageRatio,
|
|
97
97
|
},
|
|
98
98
|
{
|
|
99
99
|
name: 'Function Purity',
|
|
100
|
-
value:
|
|
100
|
+
value: report.summary.dimensions.purityScore,
|
|
101
101
|
},
|
|
102
102
|
{
|
|
103
103
|
name: 'Dependency Injection',
|
|
104
|
-
value:
|
|
104
|
+
value: report.summary.dimensions.dependencyInjectionScore,
|
|
105
105
|
},
|
|
106
106
|
{
|
|
107
107
|
name: 'Interface Focus',
|
|
108
|
-
value:
|
|
108
|
+
value: report.summary.dimensions.interfaceFocusScore,
|
|
109
109
|
},
|
|
110
110
|
{
|
|
111
111
|
name: 'Observability',
|
|
112
|
-
value:
|
|
112
|
+
value: report.summary.dimensions.observabilityScore,
|
|
113
113
|
},
|
|
114
114
|
],
|
|
115
115
|
stats: [
|
|
@@ -117,7 +117,7 @@ EXAMPLES:
|
|
|
117
117
|
{ label: 'Test Files', value: report.rawData.testFiles },
|
|
118
118
|
{
|
|
119
119
|
label: 'Coverage Ratio',
|
|
120
|
-
value: Math.round(
|
|
120
|
+
value: Math.round(report.summary.coverageRatio * 100) + '%',
|
|
121
121
|
},
|
|
122
122
|
],
|
|
123
123
|
issues: report.issues,
|