@craftapit/tester
Version:
A focused, LLM-powered testing framework for natural language test scenarios
133 lines (132 loc) • 4.79 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.loadConfig = loadConfig;
const fs = __importStar(require("fs/promises"));
const path = __importStar(require("path"));
async function loadConfig(configPath, cliOptions) {
// Default configuration
let config = {
browser: {
headless: false
},
llm: {
provider: 'openai',
model: 'gpt-4'
},
logging: {
level: 'info',
screenshots: true
}
};
// Load from config file if provided
if (configPath) {
try {
const configFile = await fs.readFile(path.resolve(configPath), 'utf-8');
const fileConfig = JSON.parse(configFile);
config = mergeConfigs(config, fileConfig);
}
catch (error) {
console.warn(`Warning: Could not load config file: ${configPath}`);
}
}
else {
// Try to load from default locations
const defaultLocations = [
'./craft-a-tester.json',
'./craftatester.json',
'./config/craft-a-tester.json',
'./.craft-a-tester.json'
];
for (const location of defaultLocations) {
try {
const configFile = await fs.readFile(path.resolve(location), 'utf-8');
const fileConfig = JSON.parse(configFile);
config = mergeConfigs(config, fileConfig);
break;
}
catch (error) {
// Ignore errors, just try the next location
}
}
}
// Override with CLI options
if (cliOptions) {
if (cliOptions.headless !== undefined) {
config.browser = { ...config.browser, headless: cliOptions.headless };
}
if (cliOptions.model || cliOptions.provider || cliOptions.apiKey) {
config.llm = {
...config.llm,
...(cliOptions.model && { model: cliOptions.model }),
...(cliOptions.provider && { provider: cliOptions.provider }),
...(cliOptions.apiKey && { apiKey: cliOptions.apiKey })
};
}
}
// Load API keys from environment if not provided
if (config.llm && !config.llm.apiKey) {
if (config.llm.provider === 'openai') {
config.llm.apiKey = process.env.OPENAI_API_KEY;
}
else if (config.llm.provider === 'anthropic') {
config.llm.apiKey = process.env.ANTHROPIC_API_KEY;
}
}
return config;
}
/**
* Helper function to merge configs with proper handling of nested properties
*/
function mergeConfigs(baseConfig, overrideConfig) {
const result = { ...baseConfig };
for (const [key, value] of Object.entries(overrideConfig)) {
// If the override has a property that's an object and not null, and the base has the same property as an object
if (value !== null &&
typeof value === 'object' &&
!Array.isArray(value) &&
result[key] !== null &&
typeof result[key] === 'object' &&
!Array.isArray(result[key])) {
// Recursively merge the nested objects
result[key] = mergeConfigs(result[key], value);
}
else {
// Otherwise just override the value
result[key] = value;
}
}
return result;
}