cypress-load-balancer
Version:
A simple load balancer for Cypress tests.
93 lines (92 loc) • 4 kB
JavaScript
import path from "path";
import fs from "node:fs";
class Utils {
getPath(...pathNames) {
return path.join(process.cwd(), ".cypress_load_balancer", ...pathNames);
}
//eslint-disable-next-line @typescript-eslint/no-explicit-any
DEBUG(...args) {
if (process.env.CYPRESS_LOAD_BALANCER_DEBUG == "true") {
console.debug("cypress-load-balancer", ...args);
}
}
get CLB_DIRECTORY() {
return this.getPath();
}
get MAIN_LOAD_BALANCING_MAP_FILE_PATH() {
return this.getPath("spec-map.json");
}
get MAX_DURATIONS_ALLOWED() {
return Number(Number(process.env.CYPRESS_LOAD_BALANCER_MAX_DURATIONS_ALLOWED || 10));
}
get TESTING_TYPES() {
return ["e2e", "component"];
}
/**
* Adds a new filepath entry to the load balancing map
* @param loadBalancingMap {LoadBalancingMap}
* @param testingType {TestingType}
* @param filePath {FilePath}
* @param [opts={}]
* @param [opts.force=] {boolean} If true, will re-create the entry even if one already exists
*/
createNewEntry(loadBalancingMap, testingType, filePath, opts = {}) {
if (loadBalancingMap[testingType][filePath] == null || opts.force === true) {
loadBalancingMap[testingType][filePath] = { stats: { durations: [], average: 0 } };
this.DEBUG(`Added new entry for file in load balancer object for "${testingType}" type tests:`, filePath);
}
else {
this.DEBUG(`File already exists in load balancer for "${testingType}" type tests:`, filePath);
}
}
calculateAverageDuration(durations) {
return Math.ceil(durations.reduce((acc, t) => acc + Math.abs(t), 0) / (durations.length || 1));
}
saveMapFile(loadBalancingMap, fileName) {
const file = fileName != null
? this.getPath(fileName.replace(/.json/g, ``) + ".json")
: this.MAIN_LOAD_BALANCING_MAP_FILE_PATH;
fs.writeFileSync(file, JSON.stringify(loadBalancingMap));
this.DEBUG("Saved load balancing map file");
}
shrinkToFit(arr) {
if (arr.length > this.MAX_DURATIONS_ALLOWED) {
arr.splice(0, arr.length - this.MAX_DURATIONS_ALLOWED);
}
return arr;
}
initializeLoadBalancingFiles(opts = {}) {
let [isDirectoryCreated, isFileCreated] = [false, false];
const dir = this.CLB_DIRECTORY;
if (!fs.existsSync(dir) || opts.forceCreateMainDirectory === true) {
fs.mkdirSync(dir);
this.DEBUG("Created directory for `/.cypress_load_balancer", `Force initialization?`, opts.forceCreateMainDirectory);
isDirectoryCreated = true;
}
if (!fs.existsSync(this.MAIN_LOAD_BALANCING_MAP_FILE_PATH) || opts.forceCreateMainLoadBalancingMap === true) {
this.saveMapFile({ e2e: {}, component: {} });
this.DEBUG("Cypress load balancing file initialized", `Force initialization?`, opts.forceCreateMainLoadBalancingMap);
isFileCreated = true;
}
return [isDirectoryCreated, isFileCreated];
}
/**
* Updates file status:
* Optional:
* adds a new duration;
* Always:
* Removes oldest durations if maximum length has been reached;
* Calculates the average duration.
* @param loadBalancingMap {LoadBalancingMap}
* @param testingType {TestingType}
* @param fileName {string}
* @param [duration=] {number} Only adds new duration if provided
*/
updateFileStats(loadBalancingMap, testingType, fileName, duration) {
if (duration != null)
loadBalancingMap[testingType][fileName].stats.durations.push(duration);
this.shrinkToFit(loadBalancingMap[testingType][fileName].stats.durations);
loadBalancingMap[testingType][fileName].stats.average = this.calculateAverageDuration(loadBalancingMap[testingType][fileName].stats.durations);
}
}
export default new Utils();