@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/cli/index.js
CHANGED
|
@@ -276,6 +276,7 @@ var GitHubClient = class {
|
|
|
276
276
|
async fileExists(ref, path) {
|
|
277
277
|
const originalError = console.error;
|
|
278
278
|
const originalWarn = console.warn;
|
|
279
|
+
const originalLog = console.log;
|
|
279
280
|
const suppress404 = (...args) => {
|
|
280
281
|
const message = String(args[0] || "");
|
|
281
282
|
if (message.includes("404") || message.includes("Not Found")) {
|
|
@@ -290,9 +291,17 @@ var GitHubClient = class {
|
|
|
290
291
|
}
|
|
291
292
|
originalWarn(...args);
|
|
292
293
|
};
|
|
294
|
+
const suppress404Log = (...args) => {
|
|
295
|
+
const message = String(args[0] || "");
|
|
296
|
+
if (message.includes("404") || message.includes("Not Found")) {
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
originalLog(...args);
|
|
300
|
+
};
|
|
293
301
|
try {
|
|
294
302
|
console.error = suppress404;
|
|
295
303
|
console.warn = suppress404Warn;
|
|
304
|
+
console.log = suppress404Log;
|
|
296
305
|
await this.octokit.rest.repos.getContent({
|
|
297
306
|
owner: this.owner,
|
|
298
307
|
repo: this.repo,
|
|
@@ -315,6 +324,7 @@ var GitHubClient = class {
|
|
|
315
324
|
} finally {
|
|
316
325
|
console.error = originalError;
|
|
317
326
|
console.warn = originalWarn;
|
|
327
|
+
console.log = originalLog;
|
|
318
328
|
}
|
|
319
329
|
}
|
|
320
330
|
/**
|
|
@@ -356,6 +366,7 @@ var KakarotConfigSchema = z.object({
|
|
|
356
366
|
enableAutoCommit: z.boolean().default(true),
|
|
357
367
|
commitStrategy: z.enum(["direct", "branch-pr"]).default("direct"),
|
|
358
368
|
enablePRComments: z.boolean().default(true),
|
|
369
|
+
enableCoverage: z.boolean().default(false),
|
|
359
370
|
debug: z.boolean().default(false)
|
|
360
371
|
});
|
|
361
372
|
|
|
@@ -373,24 +384,11 @@ async function findProjectRoot(startPath) {
|
|
|
373
384
|
async function loadConfig() {
|
|
374
385
|
const explorer = cosmiconfig("kakarot", {
|
|
375
386
|
searchPlaces: [
|
|
376
|
-
"kakarot.config.ts",
|
|
377
387
|
"kakarot.config.js",
|
|
378
|
-
".kakarot-ci.config.ts",
|
|
379
388
|
".kakarot-ci.config.js",
|
|
380
389
|
".kakarot-ci.config.json",
|
|
381
390
|
"package.json"
|
|
382
|
-
]
|
|
383
|
-
loaders: {
|
|
384
|
-
".ts": async (filepath) => {
|
|
385
|
-
try {
|
|
386
|
-
const configModule = await import(filepath);
|
|
387
|
-
return configModule.default || configModule.config || null;
|
|
388
|
-
} catch (err) {
|
|
389
|
-
error(`Failed to load TypeScript config: ${err instanceof Error ? err.message : String(err)}`);
|
|
390
|
-
return null;
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
}
|
|
391
|
+
]
|
|
394
392
|
});
|
|
395
393
|
try {
|
|
396
394
|
const result = await explorer.search();
|
|
@@ -427,7 +425,7 @@ async function loadConfig() {
|
|
|
427
425
|
} catch (err) {
|
|
428
426
|
if (err instanceof Error && err.message.includes("apiKey")) {
|
|
429
427
|
error(
|
|
430
|
-
"Missing required apiKey. Provide it via:\n - Config file (kakarot.config.
|
|
428
|
+
"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"
|
|
431
429
|
);
|
|
432
430
|
}
|
|
433
431
|
throw err;
|
|
@@ -1067,15 +1065,49 @@ function buildSystemPrompt(framework) {
|
|
|
1067
1065
|
const importStatement = framework === "jest" ? "import { describe, it, expect } from 'jest';" : "import { describe, it, expect } from 'vitest';";
|
|
1068
1066
|
return `You are an expert ${frameworkName} test writer. Your task is to generate comprehensive unit tests for TypeScript/JavaScript functions.
|
|
1069
1067
|
|
|
1068
|
+
CRITICAL: Test the ACTUAL behavior of the code, not assumed behavior.
|
|
1069
|
+
|
|
1070
1070
|
Requirements:
|
|
1071
1071
|
1. Generate complete, runnable ${frameworkName} test code
|
|
1072
1072
|
2. Use ${frameworkName} syntax and best practices
|
|
1073
|
-
3.
|
|
1074
|
-
4.
|
|
1075
|
-
5.
|
|
1076
|
-
6.
|
|
1077
|
-
|
|
1078
|
-
|
|
1073
|
+
3. Analyze the function code to determine its ACTUAL runtime behavior before writing tests
|
|
1074
|
+
4. Test edge cases and normal operation based on what the code actually does
|
|
1075
|
+
5. Only test for errors/exceptions if the code actually throws them (check for try/catch, throw statements, or validation logic)
|
|
1076
|
+
6. Match JavaScript/TypeScript runtime semantics:
|
|
1077
|
+
- Arithmetic operations (+, -, *, /, %, **) do NOT throw errors for invalid inputs; they return NaN or Infinity
|
|
1078
|
+
- Division by zero returns Infinity (not an error)
|
|
1079
|
+
- Modulo by zero returns NaN (not an error)
|
|
1080
|
+
- Bitwise operations convert values to 32-bit integers
|
|
1081
|
+
- Operations with null/undefined may coerce to numbers or return NaN
|
|
1082
|
+
- TypeScript types are compile-time only; runtime behavior follows JavaScript rules
|
|
1083
|
+
7. For async functions:
|
|
1084
|
+
- Use async/await or .then()/.catch() appropriately
|
|
1085
|
+
- Test both resolved and rejected promises
|
|
1086
|
+
- Use resolves and rejects matchers when appropriate
|
|
1087
|
+
- Await async function calls in tests
|
|
1088
|
+
8. For functions with side effects or external dependencies:
|
|
1089
|
+
- Mock external dependencies (APIs, file system, databases, etc.)
|
|
1090
|
+
- Mock imported modules using ${framework === "jest" ? "jest.mock()" : "vi.mock()"}
|
|
1091
|
+
- Reset mocks between tests to ensure test isolation
|
|
1092
|
+
- Verify mock calls if the function's behavior depends on them
|
|
1093
|
+
9. For functions that modify state:
|
|
1094
|
+
- Test state before and after function calls
|
|
1095
|
+
- Reset state between tests if needed
|
|
1096
|
+
- Test state mutations, not just return values
|
|
1097
|
+
10. For error testing:
|
|
1098
|
+
- Only test for errors if the function actually throws them
|
|
1099
|
+
- Match actual error types and messages (use toThrow() with specific error types/messages)
|
|
1100
|
+
- For async errors, use rejects matcher
|
|
1101
|
+
11. Import handling:
|
|
1102
|
+
- Use the same import paths as the source file
|
|
1103
|
+
- Import types correctly (type imports for TypeScript types)
|
|
1104
|
+
- Mock dependencies at the module level, not the function level
|
|
1105
|
+
12. Test isolation:
|
|
1106
|
+
- Each test should be independent and not rely on other tests
|
|
1107
|
+
- Use beforeEach/afterEach for setup/teardown when needed
|
|
1108
|
+
- Don't share mutable state between tests
|
|
1109
|
+
13. Use descriptive test names that explain what is being tested
|
|
1110
|
+
14. Follow the existing test file structure if one exists
|
|
1079
1111
|
|
|
1080
1112
|
Output format:
|
|
1081
1113
|
- Return ONLY the test code, no explanations or markdown code blocks
|
|
@@ -1145,18 +1177,38 @@ ${existingTestFile}
|
|
|
1145
1177
|
|
|
1146
1178
|
`;
|
|
1147
1179
|
}
|
|
1148
|
-
prompt += `Generate comprehensive unit tests for ${target.functionName}.
|
|
1180
|
+
prompt += `Generate comprehensive unit tests for ${target.functionName}. IMPORTANT: Analyze the function code above to determine its ACTUAL behavior before writing tests.
|
|
1181
|
+
|
|
1182
|
+
`;
|
|
1183
|
+
prompt += `Include:
|
|
1149
1184
|
`;
|
|
1150
1185
|
prompt += `- Tests for normal operation with various inputs
|
|
1151
1186
|
`;
|
|
1152
|
-
prompt += `- Tests for edge cases (null, undefined, empty arrays, etc.)
|
|
1187
|
+
prompt += `- Tests for edge cases based on what the code actually does (null, undefined, empty arrays, etc.)
|
|
1153
1188
|
`;
|
|
1154
|
-
prompt += `- Tests for error conditions if
|
|
1189
|
+
prompt += `- Tests for error conditions ONLY if the code actually throws errors (check for throw statements, validation, or error handling)
|
|
1155
1190
|
`;
|
|
1156
1191
|
prompt += `- Tests for boundary conditions
|
|
1157
1192
|
`;
|
|
1158
1193
|
prompt += `- Proper mocking of dependencies if needed
|
|
1159
1194
|
|
|
1195
|
+
`;
|
|
1196
|
+
prompt += `Key considerations:
|
|
1197
|
+
`;
|
|
1198
|
+
prompt += `- If the function is async, use async/await in tests and test both success and error cases
|
|
1199
|
+
`;
|
|
1200
|
+
prompt += `- If the function uses external dependencies (imports), mock them appropriately
|
|
1201
|
+
`;
|
|
1202
|
+
prompt += `- If the function modifies state, test the state changes
|
|
1203
|
+
`;
|
|
1204
|
+
prompt += `- Match actual return types and values, not assumed types
|
|
1205
|
+
`;
|
|
1206
|
+
prompt += `- TypeScript types are compile-time only; test runtime behavior
|
|
1207
|
+
`;
|
|
1208
|
+
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.
|
|
1209
|
+
`;
|
|
1210
|
+
prompt += `- Use the same import paths as the source file for consistency
|
|
1211
|
+
|
|
1160
1212
|
`;
|
|
1161
1213
|
prompt += `Return ONLY the test code, no explanations or markdown formatting.`;
|
|
1162
1214
|
return prompt;
|
|
@@ -1181,13 +1233,34 @@ Context:
|
|
|
1181
1233
|
- The test code failed to run or produced incorrect results
|
|
1182
1234
|
- You need to analyze the error and fix the test code
|
|
1183
1235
|
|
|
1236
|
+
CRITICAL: Tests must match the ACTUAL behavior of the code being tested, not assumed behavior.
|
|
1237
|
+
|
|
1184
1238
|
Requirements:
|
|
1185
|
-
1.
|
|
1186
|
-
2.
|
|
1187
|
-
3.
|
|
1188
|
-
4.
|
|
1189
|
-
|
|
1190
|
-
|
|
1239
|
+
1. Analyze the original function code to understand its ACTUAL runtime behavior
|
|
1240
|
+
2. Fix the test code to match what the function actually does, not what it "should" do
|
|
1241
|
+
3. Only expect errors/exceptions if the function code actually throws them
|
|
1242
|
+
4. Match JavaScript/TypeScript runtime semantics:
|
|
1243
|
+
- Arithmetic operations do NOT throw errors; they return NaN or Infinity
|
|
1244
|
+
- Division by zero returns Infinity (not an error)
|
|
1245
|
+
- Modulo by zero returns NaN (not an error)
|
|
1246
|
+
- Bitwise operations convert values to 32-bit integers
|
|
1247
|
+
- TypeScript types are compile-time only; runtime behavior follows JavaScript rules
|
|
1248
|
+
5. For async functions:
|
|
1249
|
+
- Ensure tests properly await async calls
|
|
1250
|
+
- Use resolves/rejects matchers appropriately
|
|
1251
|
+
- Test both success and error cases for async functions
|
|
1252
|
+
6. For functions with dependencies:
|
|
1253
|
+
- Ensure mocks are properly set up
|
|
1254
|
+
- Verify import paths match the source file
|
|
1255
|
+
- Reset mocks if needed for test isolation
|
|
1256
|
+
7. For error testing:
|
|
1257
|
+
- Only expect errors if the function actually throws them
|
|
1258
|
+
- Match actual error types and messages
|
|
1259
|
+
- Use appropriate matchers (toThrow, rejects, etc.)
|
|
1260
|
+
8. Maintain the original test intent where possible, but prioritize correctness
|
|
1261
|
+
9. Use proper ${frameworkName} syntax
|
|
1262
|
+
10. Ensure all imports and dependencies are correct
|
|
1263
|
+
11. Fix any syntax errors, type errors, or logical errors
|
|
1191
1264
|
|
|
1192
1265
|
Output format:
|
|
1193
1266
|
- Return ONLY the fixed test code, no explanations or markdown code blocks
|
|
@@ -1944,7 +2017,7 @@ async function runPullRequest(context) {
|
|
|
1944
2017
|
})),
|
|
1945
2018
|
errors
|
|
1946
2019
|
};
|
|
1947
|
-
if (testFiles.size > 0) {
|
|
2020
|
+
if (config.enableCoverage && testFiles.size > 0) {
|
|
1948
2021
|
const testRunner = createTestRunner(framework);
|
|
1949
2022
|
const writtenPaths = Array.from(testFiles.keys());
|
|
1950
2023
|
try {
|
|
@@ -1962,12 +2035,12 @@ async function runPullRequest(context) {
|
|
|
1962
2035
|
summary.coverageReport = coverageReport;
|
|
1963
2036
|
summary.testResults = finalTestResults;
|
|
1964
2037
|
} else {
|
|
1965
|
-
|
|
2038
|
+
warn("Could not read coverage report (coverage package may be missing)");
|
|
1966
2039
|
}
|
|
1967
2040
|
} catch (err) {
|
|
1968
2041
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
1969
2042
|
if (errorMessage.includes("coverage") || errorMessage.includes("MISSING DEPENDENCY")) {
|
|
1970
|
-
|
|
2043
|
+
warn(`Coverage collection failed (coverage package may be missing): ${errorMessage.split("\n")[0]}`);
|
|
1971
2044
|
} else {
|
|
1972
2045
|
throw err;
|
|
1973
2046
|
}
|
|
@@ -2064,7 +2137,8 @@ async function commitTests(githubClient, pr, testFiles, config, summary) {
|
|
|
2064
2137
|
info(`Committing ${testFiles.length} test file(s)`);
|
|
2065
2138
|
try {
|
|
2066
2139
|
if (config.commitStrategy === "branch-pr") {
|
|
2067
|
-
const
|
|
2140
|
+
const timestamp = Date.now();
|
|
2141
|
+
const branchName = `kakarot-ci/tests-pr-${pr.number}-${timestamp}`;
|
|
2068
2142
|
const baseSha = await githubClient.createBranch(branchName, pr.head.ref);
|
|
2069
2143
|
await githubClient.commitFiles({
|
|
2070
2144
|
files: testFiles.map((file) => ({
|