testeranto
Version:
the AI powered BDD test framework for typescript projects
186 lines (185 loc) • 8.6 kB
JavaScript
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-empty-object-type */
/* eslint-disable no-async-promise-executor */
/* eslint-disable @typescript-eslint/no-explicit-any */
import { defaultTestResourceRequirement, DefaultAdapter, } from "./index.js";
import { BaseGiven } from "./BaseGiven";
import { BaseWhen } from "./BaseWhen.js";
import { BaseThen } from "./BaseThen.js";
import { BaseSuite } from "./BaseSuite";
export default class Tiposkripto {
constructor(input, testSpecification, testImplementation, testResourceRequirement = defaultTestResourceRequirement, testAdapter = {}, uberCatcher = (cb) => cb()) {
this.artifacts = [];
const fullAdapter = DefaultAdapter(testAdapter);
// Create classy implementations
const classySuites = Object.entries(testImplementation.suites).reduce((a, [key], index) => {
a[key] = (somestring, givens) => {
return new (class extends BaseSuite {
afterAll(store, artifactory, pm) {
return fullAdapter.afterAll(store, pm);
}
assertThat(t) {
return fullAdapter.assertThis(t);
}
async setup(s, artifactory, tr, pm) {
var _a, _b;
return ((_b = (_a = fullAdapter.beforeAll) === null || _a === void 0 ? void 0 : _a.call(fullAdapter, s, tr, pm)) !== null && _b !== void 0 ? _b : s);
}
})(somestring, index, givens);
};
return a;
}, {});
const classyGivens = Object.entries(testImplementation.givens).reduce((a, [key, g]) => {
a[key] = (
// name: string,
features, whens, thens, gcb, initialValues) => {
// Debug the parameters being passed - check if features contains when-like objects
// console.log(`[Tiposkripto] Creating Given ${key} with:`);
// console.log(` name: ${name}`);
// console.log(` features:`, features);
// console.log(` whens:`, whens);
// console.log(` thens:`, thens);
// Ensure parameters are arrays and create copies to avoid reference issues
const safeFeatures = Array.isArray(features) ? [...features] : [];
const safeWhens = Array.isArray(whens) ? [...whens] : [];
const safeThens = Array.isArray(thens) ? [...thens] : [];
return new (class extends BaseGiven {
constructor() {
super(...arguments);
this.uberCatcher = uberCatcher;
}
async givenThat(subject, testResource, artifactory, initializer, initialValues, pm) {
return fullAdapter.beforeEach(subject, initializer, testResource, initialValues, pm);
}
afterEach(store, key, artifactory, pm) {
return Promise.resolve(fullAdapter.afterEach(store, key, pm));
}
})(
// name,
safeFeatures, safeWhens, safeThens, testImplementation.givens[key], initialValues);
};
return a;
}, {});
const classyWhens = Object.entries(testImplementation.whens).reduce((a, [key, whEn]) => {
a[key] = (...payload) => {
const whenInstance = new (class extends BaseWhen {
async andWhen(store, whenCB, testResource, pm) {
return await fullAdapter.andWhen(store, whenCB, testResource, pm);
}
})(`${key}: ${payload && payload.toString()}`, whEn(...payload));
// console.log(`[Tiposkripto] Created When ${key}:`, whenInstance.name);
return whenInstance;
};
return a;
}, {});
const classyThens = Object.entries(testImplementation.thens).reduce((a, [key, thEn]) => {
a[key] = (...args) => {
const thenInstance = new (class extends BaseThen {
async butThen(store, thenCB, testResource, pm) {
return await fullAdapter.butThen(store, thenCB, testResource, pm);
}
})(`${key}: ${args && args.toString()}`, thEn(...args));
// console.log(`[Tiposkripto] Created Then ${key}:`, thenInstance.name);
return thenInstance;
};
return a;
}, {});
// Set up the overrides
this.suitesOverrides = classySuites;
this.givenOverides = classyGivens;
this.whenOverides = classyWhens;
this.thenOverides = classyThens;
this.testResourceRequirement = testResourceRequirement;
this.testSpecification = testSpecification;
// Generate specs
this.specs = testSpecification(this.Suites(), this.Given(), this.When(), this.Then());
this.totalTests = this.calculateTotalTests();
this.testJobs = this.specs.map((suite) => {
const suiteRunner = (suite) => async (puppetMaster, tLog) => {
try {
const x = await suite.run(input, puppetMaster.testResourceConfiguration, (fPath, value) => puppetMaster.testArtiFactoryfileWriter(tLog, (p) => {
this.artifacts.push(p);
})(puppetMaster.testResourceConfiguration.fs + "/" + fPath, value), tLog, puppetMaster);
return x;
}
catch (e) {
console.error(e.stack);
throw e;
}
};
const runner = suiteRunner(suite);
return {
test: suite,
toObj: () => {
return suite.toObj();
},
runner,
receiveTestResourceConfig: async function (puppetMaster) {
const tLog = async (...l) => {
//
};
try {
const suiteDone = await runner(puppetMaster, tLog);
const fails = suiteDone.fails;
// Always use PM.writeFileSync to write tests.json, not direct filesystem access
await puppetMaster.writeFileSync(`tests.json`, JSON.stringify(this.toObj(), null, 2), "test");
return {
failed: fails > 0,
fails,
artifacts: this.artifacts || [],
features: suiteDone.features(),
tests: 0, // Keep existing field
runTimeTests: this.totalTests, // Add the total number of tests
};
}
catch (e) {
console.error(e.stack);
return {
failed: true,
fails: -1,
artifacts: this.artifacts || [],
features: [],
tests: 0, // Keep existing field
runTimeTests: -1, // Set to -1 on hard error
};
}
},
};
});
}
Specs() {
return this.specs;
}
Suites() {
return this.suitesOverrides;
}
Given() {
return this.givenOverides;
}
When() {
return this.whenOverides;
}
Then() {
return this.thenOverides;
}
// Add a method to access test jobs which can be used by receiveTestResourceConfig
getTestJobs() {
return this.testJobs;
}
calculateTotalTests() {
let total = 0;
for (const suite of this.specs) {
if (suite && typeof suite === "object") {
// Access the givens property which should be a record of test names to BaseGiven instances
// The givens property is typically on the suite instance
if ("givens" in suite) {
const givens = suite.givens;
if (givens && typeof givens === "object") {
total += Object.keys(givens).length;
}
}
}
}
return total;
}
}