Is it possible to do something only if a Jasmine test fails? Juxtaposed with afterEach()
which executes after an it()
regardless of outcome, I\'m l
I wanted to do something similar on jasmine 2.5.2 (having custom logger object which would print out only when test fails, without having to do it manually).
Struggled quite a bit to make it work generically through beforeEach/afterEach, finally I caved in to an uglier solution
// logger print on fail
function collectSpecs(suite: jasmine.Suite): jasmine.Spec[] {
const result: jasmine.Spec[] = [];
const process = [suite];
while (process.length) {
const suite = process.pop();
const children = suite.children; // wrong jasmine typing
children.forEach(item => {
switch (item.constructor.name) {
case "Suite":
process.push(item);
break;
case "Spec":
result.push(item);
break;
}
});
}
return result;
}
function findSpec(specId: string): jasmine.Spec {
const rootSuite: jasmine.Suite = jasmine.getEnv()["topSuite"]();
return collectSpecs(rootSuite)
.filter(s => `${s.id}` === specId)[0]; // wrong jasmine typing on id
}
const loggerSpecProperty = "logger";
function createReporter(): jasmine.CustomReporter {
return {
specDone: (result: jasmine.CustomReporterResult) => {
const spec = findSpec(result.id);
if (result.failedExpectations.length) {
const logger: modLog.MemoryLogger = spec[loggerSpecProperty];
if (logger) {
console.log(`\nfailed spec logger:\n${logger.lines.join("\n")}`);
}
}
delete spec[loggerSpecProperty];
}
};
}
export function registerReporter(): void {
jasmine.getEnv().addReporter(createReporter());
}
function createLogger(): modLog.MemoryLogger {
return new modLog.MemoryLogger(modLog.LogLevel.debug);
}
interface IItCallback {
(done?: Function): void;
}
interface IItFunctionTyping {
(name: string, callback: IItCallback): void;
}
interface IItFunction {
(name: string, callback: IItCallback): jasmine.Spec;
}
// bad typings on it/xit/fit, actually returns Spec but is typed as void
export function lit(fnIt: IItFunctionTyping, name: string, callback: IItCallback): jasmine.Spec {
function inner(spec: jasmine.Spec, done?: Function) {
const log = createLogger();
this.log = log;
spec[loggerSpecProperty] = log;
callback.call(this, done);
}
const itFunc = (fnIt || it);
if (callback.length) {
const spec = itFunc(name, function (done) {
inner.call(this, spec, done);
});
return spec;
} else {
const spec = itFunc(name, function () {
inner.call(this, spec);
});
return spec;
}
}
some unneccessary type mumbo jumbo there due to @types/jasmine obscuring some details of the actual implementation (I suppose it's on purpose, typing version matches the jasmine package version), but I also wanted to practice my TypeScript
passing "it" function to still allow for xit/fit when needed modLog is my logger module, override this to suite your needs
usage:
instead of
it("should do something", function (done) {
done();
});
use
lit(it, "should do something", function (done) {
this.log.debug("test");
fail("test output");
done();
});
(not very well documented but I think you can get the picture)
it would be much nicer if there was a way for customReporter to access the spec context
(then again this all is basically only for debugging purposes, you could as well add console.log to specific test when it fails and you're struggling with the details, but it was interesting excercise in getting to know jasmine a bit more)