@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.cjs
CHANGED
|
@@ -87,6 +87,7 @@ var KakarotConfigSchema = import_zod.z.object({
|
|
|
87
87
|
enableAutoCommit: import_zod.z.boolean().default(true),
|
|
88
88
|
commitStrategy: import_zod.z.enum(["direct", "branch-pr"]).default("direct"),
|
|
89
89
|
enablePRComments: import_zod.z.boolean().default(true),
|
|
90
|
+
enableCoverage: import_zod.z.boolean().default(false),
|
|
90
91
|
debug: import_zod.z.boolean().default(false)
|
|
91
92
|
});
|
|
92
93
|
|
|
@@ -160,24 +161,11 @@ async function findProjectRoot(startPath) {
|
|
|
160
161
|
async function loadConfig() {
|
|
161
162
|
const explorer = (0, import_cosmiconfig.cosmiconfig)("kakarot", {
|
|
162
163
|
searchPlaces: [
|
|
163
|
-
"kakarot.config.ts",
|
|
164
164
|
"kakarot.config.js",
|
|
165
|
-
".kakarot-ci.config.ts",
|
|
166
165
|
".kakarot-ci.config.js",
|
|
167
166
|
".kakarot-ci.config.json",
|
|
168
167
|
"package.json"
|
|
169
|
-
]
|
|
170
|
-
loaders: {
|
|
171
|
-
".ts": async (filepath) => {
|
|
172
|
-
try {
|
|
173
|
-
const configModule = await import(filepath);
|
|
174
|
-
return configModule.default || configModule.config || null;
|
|
175
|
-
} catch (err) {
|
|
176
|
-
error(`Failed to load TypeScript config: ${err instanceof Error ? err.message : String(err)}`);
|
|
177
|
-
return null;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
168
|
+
]
|
|
181
169
|
});
|
|
182
170
|
try {
|
|
183
171
|
const result = await explorer.search();
|
|
@@ -214,7 +202,7 @@ async function loadConfig() {
|
|
|
214
202
|
} catch (err) {
|
|
215
203
|
if (err instanceof Error && err.message.includes("apiKey")) {
|
|
216
204
|
error(
|
|
217
|
-
"Missing required apiKey. Provide it via:\n - Config file (kakarot.config.
|
|
205
|
+
"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"
|
|
218
206
|
);
|
|
219
207
|
}
|
|
220
208
|
throw err;
|
|
@@ -437,6 +425,7 @@ var GitHubClient = class {
|
|
|
437
425
|
async fileExists(ref, path) {
|
|
438
426
|
const originalError = console.error;
|
|
439
427
|
const originalWarn = console.warn;
|
|
428
|
+
const originalLog = console.log;
|
|
440
429
|
const suppress404 = (...args) => {
|
|
441
430
|
const message = String(args[0] || "");
|
|
442
431
|
if (message.includes("404") || message.includes("Not Found")) {
|
|
@@ -451,9 +440,17 @@ var GitHubClient = class {
|
|
|
451
440
|
}
|
|
452
441
|
originalWarn(...args);
|
|
453
442
|
};
|
|
443
|
+
const suppress404Log = (...args) => {
|
|
444
|
+
const message = String(args[0] || "");
|
|
445
|
+
if (message.includes("404") || message.includes("Not Found")) {
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
originalLog(...args);
|
|
449
|
+
};
|
|
454
450
|
try {
|
|
455
451
|
console.error = suppress404;
|
|
456
452
|
console.warn = suppress404Warn;
|
|
453
|
+
console.log = suppress404Log;
|
|
457
454
|
await this.octokit.rest.repos.getContent({
|
|
458
455
|
owner: this.owner,
|
|
459
456
|
repo: this.repo,
|
|
@@ -476,6 +473,7 @@ var GitHubClient = class {
|
|
|
476
473
|
} finally {
|
|
477
474
|
console.error = originalError;
|
|
478
475
|
console.warn = originalWarn;
|
|
476
|
+
console.log = originalLog;
|
|
479
477
|
}
|
|
480
478
|
}
|
|
481
479
|
/**
|
|
@@ -1147,15 +1145,49 @@ function buildSystemPrompt(framework) {
|
|
|
1147
1145
|
const importStatement = framework === "jest" ? "import { describe, it, expect } from 'jest';" : "import { describe, it, expect } from 'vitest';";
|
|
1148
1146
|
return `You are an expert ${frameworkName} test writer. Your task is to generate comprehensive unit tests for TypeScript/JavaScript functions.
|
|
1149
1147
|
|
|
1148
|
+
CRITICAL: Test the ACTUAL behavior of the code, not assumed behavior.
|
|
1149
|
+
|
|
1150
1150
|
Requirements:
|
|
1151
1151
|
1. Generate complete, runnable ${frameworkName} test code
|
|
1152
1152
|
2. Use ${frameworkName} syntax and best practices
|
|
1153
|
-
3.
|
|
1154
|
-
4.
|
|
1155
|
-
5.
|
|
1156
|
-
6.
|
|
1157
|
-
|
|
1158
|
-
|
|
1153
|
+
3. Analyze the function code to determine its ACTUAL runtime behavior before writing tests
|
|
1154
|
+
4. Test edge cases and normal operation based on what the code actually does
|
|
1155
|
+
5. Only test for errors/exceptions if the code actually throws them (check for try/catch, throw statements, or validation logic)
|
|
1156
|
+
6. Match JavaScript/TypeScript runtime semantics:
|
|
1157
|
+
- Arithmetic operations (+, -, *, /, %, **) do NOT throw errors for invalid inputs; they return NaN or Infinity
|
|
1158
|
+
- Division by zero returns Infinity (not an error)
|
|
1159
|
+
- Modulo by zero returns NaN (not an error)
|
|
1160
|
+
- Bitwise operations convert values to 32-bit integers
|
|
1161
|
+
- Operations with null/undefined may coerce to numbers or return NaN
|
|
1162
|
+
- TypeScript types are compile-time only; runtime behavior follows JavaScript rules
|
|
1163
|
+
7. For async functions:
|
|
1164
|
+
- Use async/await or .then()/.catch() appropriately
|
|
1165
|
+
- Test both resolved and rejected promises
|
|
1166
|
+
- Use resolves and rejects matchers when appropriate
|
|
1167
|
+
- Await async function calls in tests
|
|
1168
|
+
8. For functions with side effects or external dependencies:
|
|
1169
|
+
- Mock external dependencies (APIs, file system, databases, etc.)
|
|
1170
|
+
- Mock imported modules using ${framework === "jest" ? "jest.mock()" : "vi.mock()"}
|
|
1171
|
+
- Reset mocks between tests to ensure test isolation
|
|
1172
|
+
- Verify mock calls if the function's behavior depends on them
|
|
1173
|
+
9. For functions that modify state:
|
|
1174
|
+
- Test state before and after function calls
|
|
1175
|
+
- Reset state between tests if needed
|
|
1176
|
+
- Test state mutations, not just return values
|
|
1177
|
+
10. For error testing:
|
|
1178
|
+
- Only test for errors if the function actually throws them
|
|
1179
|
+
- Match actual error types and messages (use toThrow() with specific error types/messages)
|
|
1180
|
+
- For async errors, use rejects matcher
|
|
1181
|
+
11. Import handling:
|
|
1182
|
+
- Use the same import paths as the source file
|
|
1183
|
+
- Import types correctly (type imports for TypeScript types)
|
|
1184
|
+
- Mock dependencies at the module level, not the function level
|
|
1185
|
+
12. Test isolation:
|
|
1186
|
+
- Each test should be independent and not rely on other tests
|
|
1187
|
+
- Use beforeEach/afterEach for setup/teardown when needed
|
|
1188
|
+
- Don't share mutable state between tests
|
|
1189
|
+
13. Use descriptive test names that explain what is being tested
|
|
1190
|
+
14. Follow the existing test file structure if one exists
|
|
1159
1191
|
|
|
1160
1192
|
Output format:
|
|
1161
1193
|
- Return ONLY the test code, no explanations or markdown code blocks
|
|
@@ -1225,18 +1257,38 @@ ${existingTestFile}
|
|
|
1225
1257
|
|
|
1226
1258
|
`;
|
|
1227
1259
|
}
|
|
1228
|
-
prompt += `Generate comprehensive unit tests for ${target.functionName}.
|
|
1260
|
+
prompt += `Generate comprehensive unit tests for ${target.functionName}. IMPORTANT: Analyze the function code above to determine its ACTUAL behavior before writing tests.
|
|
1261
|
+
|
|
1262
|
+
`;
|
|
1263
|
+
prompt += `Include:
|
|
1229
1264
|
`;
|
|
1230
1265
|
prompt += `- Tests for normal operation with various inputs
|
|
1231
1266
|
`;
|
|
1232
|
-
prompt += `- Tests for edge cases (null, undefined, empty arrays, etc.)
|
|
1267
|
+
prompt += `- Tests for edge cases based on what the code actually does (null, undefined, empty arrays, etc.)
|
|
1233
1268
|
`;
|
|
1234
|
-
prompt += `- Tests for error conditions if
|
|
1269
|
+
prompt += `- Tests for error conditions ONLY if the code actually throws errors (check for throw statements, validation, or error handling)
|
|
1235
1270
|
`;
|
|
1236
1271
|
prompt += `- Tests for boundary conditions
|
|
1237
1272
|
`;
|
|
1238
1273
|
prompt += `- Proper mocking of dependencies if needed
|
|
1239
1274
|
|
|
1275
|
+
`;
|
|
1276
|
+
prompt += `Key considerations:
|
|
1277
|
+
`;
|
|
1278
|
+
prompt += `- If the function is async, use async/await in tests and test both success and error cases
|
|
1279
|
+
`;
|
|
1280
|
+
prompt += `- If the function uses external dependencies (imports), mock them appropriately
|
|
1281
|
+
`;
|
|
1282
|
+
prompt += `- If the function modifies state, test the state changes
|
|
1283
|
+
`;
|
|
1284
|
+
prompt += `- Match actual return types and values, not assumed types
|
|
1285
|
+
`;
|
|
1286
|
+
prompt += `- TypeScript types are compile-time only; test runtime behavior
|
|
1287
|
+
`;
|
|
1288
|
+
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.
|
|
1289
|
+
`;
|
|
1290
|
+
prompt += `- Use the same import paths as the source file for consistency
|
|
1291
|
+
|
|
1240
1292
|
`;
|
|
1241
1293
|
prompt += `Return ONLY the test code, no explanations or markdown formatting.`;
|
|
1242
1294
|
return prompt;
|
|
@@ -1261,13 +1313,34 @@ Context:
|
|
|
1261
1313
|
- The test code failed to run or produced incorrect results
|
|
1262
1314
|
- You need to analyze the error and fix the test code
|
|
1263
1315
|
|
|
1316
|
+
CRITICAL: Tests must match the ACTUAL behavior of the code being tested, not assumed behavior.
|
|
1317
|
+
|
|
1264
1318
|
Requirements:
|
|
1265
|
-
1.
|
|
1266
|
-
2.
|
|
1267
|
-
3.
|
|
1268
|
-
4.
|
|
1269
|
-
|
|
1270
|
-
|
|
1319
|
+
1. Analyze the original function code to understand its ACTUAL runtime behavior
|
|
1320
|
+
2. Fix the test code to match what the function actually does, not what it "should" do
|
|
1321
|
+
3. Only expect errors/exceptions if the function code actually throws them
|
|
1322
|
+
4. Match JavaScript/TypeScript runtime semantics:
|
|
1323
|
+
- Arithmetic operations do NOT throw errors; they return NaN or Infinity
|
|
1324
|
+
- Division by zero returns Infinity (not an error)
|
|
1325
|
+
- Modulo by zero returns NaN (not an error)
|
|
1326
|
+
- Bitwise operations convert values to 32-bit integers
|
|
1327
|
+
- TypeScript types are compile-time only; runtime behavior follows JavaScript rules
|
|
1328
|
+
5. For async functions:
|
|
1329
|
+
- Ensure tests properly await async calls
|
|
1330
|
+
- Use resolves/rejects matchers appropriately
|
|
1331
|
+
- Test both success and error cases for async functions
|
|
1332
|
+
6. For functions with dependencies:
|
|
1333
|
+
- Ensure mocks are properly set up
|
|
1334
|
+
- Verify import paths match the source file
|
|
1335
|
+
- Reset mocks if needed for test isolation
|
|
1336
|
+
7. For error testing:
|
|
1337
|
+
- Only expect errors if the function actually throws them
|
|
1338
|
+
- Match actual error types and messages
|
|
1339
|
+
- Use appropriate matchers (toThrow, rejects, etc.)
|
|
1340
|
+
8. Maintain the original test intent where possible, but prioritize correctness
|
|
1341
|
+
9. Use proper ${frameworkName} syntax
|
|
1342
|
+
10. Ensure all imports and dependencies are correct
|
|
1343
|
+
11. Fix any syntax errors, type errors, or logical errors
|
|
1271
1344
|
|
|
1272
1345
|
Output format:
|
|
1273
1346
|
- Return ONLY the fixed test code, no explanations or markdown code blocks
|
|
@@ -2000,7 +2073,7 @@ async function runPullRequest(context) {
|
|
|
2000
2073
|
})),
|
|
2001
2074
|
errors
|
|
2002
2075
|
};
|
|
2003
|
-
if (testFiles.size > 0) {
|
|
2076
|
+
if (config.enableCoverage && testFiles.size > 0) {
|
|
2004
2077
|
const testRunner = createTestRunner(framework);
|
|
2005
2078
|
const writtenPaths = Array.from(testFiles.keys());
|
|
2006
2079
|
try {
|
|
@@ -2018,12 +2091,12 @@ async function runPullRequest(context) {
|
|
|
2018
2091
|
summary.coverageReport = coverageReport;
|
|
2019
2092
|
summary.testResults = finalTestResults;
|
|
2020
2093
|
} else {
|
|
2021
|
-
|
|
2094
|
+
warn("Could not read coverage report (coverage package may be missing)");
|
|
2022
2095
|
}
|
|
2023
2096
|
} catch (err) {
|
|
2024
2097
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
2025
2098
|
if (errorMessage.includes("coverage") || errorMessage.includes("MISSING DEPENDENCY")) {
|
|
2026
|
-
|
|
2099
|
+
warn(`Coverage collection failed (coverage package may be missing): ${errorMessage.split("\n")[0]}`);
|
|
2027
2100
|
} else {
|
|
2028
2101
|
throw err;
|
|
2029
2102
|
}
|
|
@@ -2120,7 +2193,8 @@ async function commitTests(githubClient, pr, testFiles, config, summary) {
|
|
|
2120
2193
|
info(`Committing ${testFiles.length} test file(s)`);
|
|
2121
2194
|
try {
|
|
2122
2195
|
if (config.commitStrategy === "branch-pr") {
|
|
2123
|
-
const
|
|
2196
|
+
const timestamp = Date.now();
|
|
2197
|
+
const branchName = `kakarot-ci/tests-pr-${pr.number}-${timestamp}`;
|
|
2124
2198
|
const baseSha = await githubClient.createBranch(branchName, pr.head.ref);
|
|
2125
2199
|
await githubClient.commitFiles({
|
|
2126
2200
|
files: testFiles.map((file) => ({
|