@kakarot-ci/core 0.6.6 → 0.7.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 +457 -2
- package/dist/cli/index.js +108 -34
- package/dist/cli/index.js.map +2 -2
- package/dist/index.cjs +108 -34
- package/dist/index.cjs.map +2 -2
- package/dist/index.js +108 -34
- package/dist/index.js.map +2 -2
- package/dist/src/github/client.d.ts.map +1 -1
- package/dist/src/types/config.d.ts +3 -0
- package/dist/src/types/config.d.ts.map +1 -1
- package/dist/src/utils/config-loader.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -21,6 +21,7 @@ var KakarotConfigSchema = z.object({
|
|
|
21
21
|
enableAutoCommit: z.boolean().default(true),
|
|
22
22
|
commitStrategy: z.enum(["direct", "branch-pr"]).default("direct"),
|
|
23
23
|
enablePRComments: z.boolean().default(true),
|
|
24
|
+
enableCoverage: z.boolean().default(false),
|
|
24
25
|
debug: z.boolean().default(false)
|
|
25
26
|
});
|
|
26
27
|
|
|
@@ -94,24 +95,11 @@ async function findProjectRoot(startPath) {
|
|
|
94
95
|
async function loadConfig() {
|
|
95
96
|
const explorer = cosmiconfig("kakarot", {
|
|
96
97
|
searchPlaces: [
|
|
97
|
-
"kakarot.config.ts",
|
|
98
98
|
"kakarot.config.js",
|
|
99
|
-
".kakarot-ci.config.ts",
|
|
100
99
|
".kakarot-ci.config.js",
|
|
101
100
|
".kakarot-ci.config.json",
|
|
102
101
|
"package.json"
|
|
103
|
-
]
|
|
104
|
-
loaders: {
|
|
105
|
-
".ts": async (filepath) => {
|
|
106
|
-
try {
|
|
107
|
-
const configModule = await import(filepath);
|
|
108
|
-
return configModule.default || configModule.config || null;
|
|
109
|
-
} catch (err) {
|
|
110
|
-
error(`Failed to load TypeScript config: ${err instanceof Error ? err.message : String(err)}`);
|
|
111
|
-
return null;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
102
|
+
]
|
|
115
103
|
});
|
|
116
104
|
try {
|
|
117
105
|
const result = await explorer.search();
|
|
@@ -148,7 +136,7 @@ async function loadConfig() {
|
|
|
148
136
|
} catch (err) {
|
|
149
137
|
if (err instanceof Error && err.message.includes("apiKey")) {
|
|
150
138
|
error(
|
|
151
|
-
"Missing required apiKey. Provide it via:\n - Config file (kakarot.config.
|
|
139
|
+
"Missing required apiKey. Provide it via:\n - Config file (kakarot.config.js, .kakarot-ci.config.js/json, or package.json)\n - Environment variable: KAKAROT_API_KEY"
|
|
152
140
|
);
|
|
153
141
|
}
|
|
154
142
|
throw err;
|
|
@@ -371,6 +359,7 @@ var GitHubClient = class {
|
|
|
371
359
|
async fileExists(ref, path) {
|
|
372
360
|
const originalError = console.error;
|
|
373
361
|
const originalWarn = console.warn;
|
|
362
|
+
const originalLog = console.log;
|
|
374
363
|
const suppress404 = (...args) => {
|
|
375
364
|
const message = String(args[0] || "");
|
|
376
365
|
if (message.includes("404") || message.includes("Not Found")) {
|
|
@@ -385,9 +374,17 @@ var GitHubClient = class {
|
|
|
385
374
|
}
|
|
386
375
|
originalWarn(...args);
|
|
387
376
|
};
|
|
377
|
+
const suppress404Log = (...args) => {
|
|
378
|
+
const message = String(args[0] || "");
|
|
379
|
+
if (message.includes("404") || message.includes("Not Found")) {
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
originalLog(...args);
|
|
383
|
+
};
|
|
388
384
|
try {
|
|
389
385
|
console.error = suppress404;
|
|
390
386
|
console.warn = suppress404Warn;
|
|
387
|
+
console.log = suppress404Log;
|
|
391
388
|
await this.octokit.rest.repos.getContent({
|
|
392
389
|
owner: this.owner,
|
|
393
390
|
repo: this.repo,
|
|
@@ -410,6 +407,7 @@ var GitHubClient = class {
|
|
|
410
407
|
} finally {
|
|
411
408
|
console.error = originalError;
|
|
412
409
|
console.warn = originalWarn;
|
|
410
|
+
console.log = originalLog;
|
|
413
411
|
}
|
|
414
412
|
}
|
|
415
413
|
/**
|
|
@@ -1081,15 +1079,49 @@ function buildSystemPrompt(framework) {
|
|
|
1081
1079
|
const importStatement = framework === "jest" ? "import { describe, it, expect } from 'jest';" : "import { describe, it, expect } from 'vitest';";
|
|
1082
1080
|
return `You are an expert ${frameworkName} test writer. Your task is to generate comprehensive unit tests for TypeScript/JavaScript functions.
|
|
1083
1081
|
|
|
1082
|
+
CRITICAL: Test the ACTUAL behavior of the code, not assumed behavior.
|
|
1083
|
+
|
|
1084
1084
|
Requirements:
|
|
1085
1085
|
1. Generate complete, runnable ${frameworkName} test code
|
|
1086
1086
|
2. Use ${frameworkName} syntax and best practices
|
|
1087
|
-
3.
|
|
1088
|
-
4.
|
|
1089
|
-
5.
|
|
1090
|
-
6.
|
|
1091
|
-
|
|
1092
|
-
|
|
1087
|
+
3. Analyze the function code to determine its ACTUAL runtime behavior before writing tests
|
|
1088
|
+
4. Test edge cases and normal operation based on what the code actually does
|
|
1089
|
+
5. Only test for errors/exceptions if the code actually throws them (check for try/catch, throw statements, or validation logic)
|
|
1090
|
+
6. Match JavaScript/TypeScript runtime semantics:
|
|
1091
|
+
- Arithmetic operations (+, -, *, /, %, **) do NOT throw errors for invalid inputs; they return NaN or Infinity
|
|
1092
|
+
- Division by zero returns Infinity (not an error)
|
|
1093
|
+
- Modulo by zero returns NaN (not an error)
|
|
1094
|
+
- Bitwise operations convert values to 32-bit integers
|
|
1095
|
+
- Operations with null/undefined may coerce to numbers or return NaN
|
|
1096
|
+
- TypeScript types are compile-time only; runtime behavior follows JavaScript rules
|
|
1097
|
+
7. For async functions:
|
|
1098
|
+
- Use async/await or .then()/.catch() appropriately
|
|
1099
|
+
- Test both resolved and rejected promises
|
|
1100
|
+
- Use resolves and rejects matchers when appropriate
|
|
1101
|
+
- Await async function calls in tests
|
|
1102
|
+
8. For functions with side effects or external dependencies:
|
|
1103
|
+
- Mock external dependencies (APIs, file system, databases, etc.)
|
|
1104
|
+
- Mock imported modules using ${framework === "jest" ? "jest.mock()" : "vi.mock()"}
|
|
1105
|
+
- Reset mocks between tests to ensure test isolation
|
|
1106
|
+
- Verify mock calls if the function's behavior depends on them
|
|
1107
|
+
9. For functions that modify state:
|
|
1108
|
+
- Test state before and after function calls
|
|
1109
|
+
- Reset state between tests if needed
|
|
1110
|
+
- Test state mutations, not just return values
|
|
1111
|
+
10. For error testing:
|
|
1112
|
+
- Only test for errors if the function actually throws them
|
|
1113
|
+
- Match actual error types and messages (use toThrow() with specific error types/messages)
|
|
1114
|
+
- For async errors, use rejects matcher
|
|
1115
|
+
11. Import handling:
|
|
1116
|
+
- Use the same import paths as the source file
|
|
1117
|
+
- Import types correctly (type imports for TypeScript types)
|
|
1118
|
+
- Mock dependencies at the module level, not the function level
|
|
1119
|
+
12. Test isolation:
|
|
1120
|
+
- Each test should be independent and not rely on other tests
|
|
1121
|
+
- Use beforeEach/afterEach for setup/teardown when needed
|
|
1122
|
+
- Don't share mutable state between tests
|
|
1123
|
+
13. Use descriptive test names that explain what is being tested
|
|
1124
|
+
14. Follow the existing test file structure if one exists
|
|
1093
1125
|
|
|
1094
1126
|
Output format:
|
|
1095
1127
|
- Return ONLY the test code, no explanations or markdown code blocks
|
|
@@ -1159,18 +1191,38 @@ ${existingTestFile}
|
|
|
1159
1191
|
|
|
1160
1192
|
`;
|
|
1161
1193
|
}
|
|
1162
|
-
prompt += `Generate comprehensive unit tests for ${target.functionName}.
|
|
1194
|
+
prompt += `Generate comprehensive unit tests for ${target.functionName}. IMPORTANT: Analyze the function code above to determine its ACTUAL behavior before writing tests.
|
|
1195
|
+
|
|
1196
|
+
`;
|
|
1197
|
+
prompt += `Include:
|
|
1163
1198
|
`;
|
|
1164
1199
|
prompt += `- Tests for normal operation with various inputs
|
|
1165
1200
|
`;
|
|
1166
|
-
prompt += `- Tests for edge cases (null, undefined, empty arrays, etc.)
|
|
1201
|
+
prompt += `- Tests for edge cases based on what the code actually does (null, undefined, empty arrays, etc.)
|
|
1167
1202
|
`;
|
|
1168
|
-
prompt += `- Tests for error conditions if
|
|
1203
|
+
prompt += `- Tests for error conditions ONLY if the code actually throws errors (check for throw statements, validation, or error handling)
|
|
1169
1204
|
`;
|
|
1170
1205
|
prompt += `- Tests for boundary conditions
|
|
1171
1206
|
`;
|
|
1172
1207
|
prompt += `- Proper mocking of dependencies if needed
|
|
1173
1208
|
|
|
1209
|
+
`;
|
|
1210
|
+
prompt += `Key considerations:
|
|
1211
|
+
`;
|
|
1212
|
+
prompt += `- If the function is async, use async/await in tests and test both success and error cases
|
|
1213
|
+
`;
|
|
1214
|
+
prompt += `- If the function uses external dependencies (imports), mock them appropriately
|
|
1215
|
+
`;
|
|
1216
|
+
prompt += `- If the function modifies state, test the state changes
|
|
1217
|
+
`;
|
|
1218
|
+
prompt += `- Match actual return types and values, not assumed types
|
|
1219
|
+
`;
|
|
1220
|
+
prompt += `- TypeScript types are compile-time only; test runtime behavior
|
|
1221
|
+
`;
|
|
1222
|
+
prompt += `- JavaScript/TypeScript arithmetic and bitwise operations do NOT throw errors for invalid inputs. They return NaN, Infinity, or perform type coercion. Only test for errors if the function code explicitly throws them.
|
|
1223
|
+
`;
|
|
1224
|
+
prompt += `- Use the same import paths as the source file for consistency
|
|
1225
|
+
|
|
1174
1226
|
`;
|
|
1175
1227
|
prompt += `Return ONLY the test code, no explanations or markdown formatting.`;
|
|
1176
1228
|
return prompt;
|
|
@@ -1195,13 +1247,34 @@ Context:
|
|
|
1195
1247
|
- The test code failed to run or produced incorrect results
|
|
1196
1248
|
- You need to analyze the error and fix the test code
|
|
1197
1249
|
|
|
1250
|
+
CRITICAL: Tests must match the ACTUAL behavior of the code being tested, not assumed behavior.
|
|
1251
|
+
|
|
1198
1252
|
Requirements:
|
|
1199
|
-
1.
|
|
1200
|
-
2.
|
|
1201
|
-
3.
|
|
1202
|
-
4.
|
|
1203
|
-
|
|
1204
|
-
|
|
1253
|
+
1. Analyze the original function code to understand its ACTUAL runtime behavior
|
|
1254
|
+
2. Fix the test code to match what the function actually does, not what it "should" do
|
|
1255
|
+
3. Only expect errors/exceptions if the function code actually throws them
|
|
1256
|
+
4. Match JavaScript/TypeScript runtime semantics:
|
|
1257
|
+
- Arithmetic operations do NOT throw errors; they return NaN or Infinity
|
|
1258
|
+
- Division by zero returns Infinity (not an error)
|
|
1259
|
+
- Modulo by zero returns NaN (not an error)
|
|
1260
|
+
- Bitwise operations convert values to 32-bit integers
|
|
1261
|
+
- TypeScript types are compile-time only; runtime behavior follows JavaScript rules
|
|
1262
|
+
5. For async functions:
|
|
1263
|
+
- Ensure tests properly await async calls
|
|
1264
|
+
- Use resolves/rejects matchers appropriately
|
|
1265
|
+
- Test both success and error cases for async functions
|
|
1266
|
+
6. For functions with dependencies:
|
|
1267
|
+
- Ensure mocks are properly set up
|
|
1268
|
+
- Verify import paths match the source file
|
|
1269
|
+
- Reset mocks if needed for test isolation
|
|
1270
|
+
7. For error testing:
|
|
1271
|
+
- Only expect errors if the function actually throws them
|
|
1272
|
+
- Match actual error types and messages
|
|
1273
|
+
- Use appropriate matchers (toThrow, rejects, etc.)
|
|
1274
|
+
8. Maintain the original test intent where possible, but prioritize correctness
|
|
1275
|
+
9. Use proper ${frameworkName} syntax
|
|
1276
|
+
10. Ensure all imports and dependencies are correct
|
|
1277
|
+
11. Fix any syntax errors, type errors, or logical errors
|
|
1205
1278
|
|
|
1206
1279
|
Output format:
|
|
1207
1280
|
- Return ONLY the fixed test code, no explanations or markdown code blocks
|
|
@@ -1934,7 +2007,7 @@ async function runPullRequest(context) {
|
|
|
1934
2007
|
})),
|
|
1935
2008
|
errors
|
|
1936
2009
|
};
|
|
1937
|
-
if (testFiles.size > 0) {
|
|
2010
|
+
if (config.enableCoverage && testFiles.size > 0) {
|
|
1938
2011
|
const testRunner = createTestRunner(framework);
|
|
1939
2012
|
const writtenPaths = Array.from(testFiles.keys());
|
|
1940
2013
|
try {
|
|
@@ -1952,12 +2025,12 @@ async function runPullRequest(context) {
|
|
|
1952
2025
|
summary.coverageReport = coverageReport;
|
|
1953
2026
|
summary.testResults = finalTestResults;
|
|
1954
2027
|
} else {
|
|
1955
|
-
|
|
2028
|
+
warn("Could not read coverage report (coverage package may be missing)");
|
|
1956
2029
|
}
|
|
1957
2030
|
} catch (err) {
|
|
1958
2031
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
1959
2032
|
if (errorMessage.includes("coverage") || errorMessage.includes("MISSING DEPENDENCY")) {
|
|
1960
|
-
|
|
2033
|
+
warn(`Coverage collection failed (coverage package may be missing): ${errorMessage.split("\n")[0]}`);
|
|
1961
2034
|
} else {
|
|
1962
2035
|
throw err;
|
|
1963
2036
|
}
|
|
@@ -2054,7 +2127,8 @@ async function commitTests(githubClient, pr, testFiles, config, summary) {
|
|
|
2054
2127
|
info(`Committing ${testFiles.length} test file(s)`);
|
|
2055
2128
|
try {
|
|
2056
2129
|
if (config.commitStrategy === "branch-pr") {
|
|
2057
|
-
const
|
|
2130
|
+
const timestamp = Date.now();
|
|
2131
|
+
const branchName = `kakarot-ci/tests-pr-${pr.number}-${timestamp}`;
|
|
2058
2132
|
const baseSha = await githubClient.createBranch(branchName, pr.head.ref);
|
|
2059
2133
|
await githubClient.commitFiles({
|
|
2060
2134
|
files: testFiles.map((file) => ({
|