jest-decorated
jest-decorated copied to clipboard
Is there some way to using jest-decorated API to return some info?
is there some way that can be used so I can extract some info from test spec files, like name of the test suites, test case titles...etc without executing any test?
Yes, there are some ways, but they are poorly documented and should be improved (refactored a bit). I'm planning to do this, probably by the end of this week (docs/readme update & example & misc refactor for simplifying the API).
Currently, you can use the @RunWith decorator and implement your own TestRunner
. Here is it's interface to implement:
interface ITestRunner {
registerMocks(describeRunner: IDescribeRunner, parentDescribeRunner?: IDescribeRunner): void;
registerAutoCleared(describeRunner: IDescribeRunner, parentDescribeRunner?: IDescribeRunner): void;
registerLazyModules(describeRunner: IDescribeRunner, parentDescribeRunner?: IDescribeRunner): void;
registerMockFnsAndSpies(describeRunner: IDescribeRunner, parentDescribeRunner?: IDescribeRunner): void;
registerHooks(describeRunner: IDescribeRunner, parentDescribeRunner?: IDescribeRunner): void;
registerTestsInJest(describeRunner: IDescribeRunner, parentDescribeRunner?: IDescribeRunner): void;
}
ATM, you must implement ALL of the methods, and add more functionality after. So, the initial implementation will look like this:
class MyTestRunner implements ITestRunner {
public constructor(protected readonly defaultTestsRunner: ITestRunner) {}
public registerMocks(describeRunner: IDescribeRunner, parentDescribeRunner?: IDescribeRunner): void {
this.defaultTestsRunner.registerMocks(describeRunner, parentDescribeRunner);
}
public registerAutoCleared(describeRunner: IDescribeRunner, parentDescribeRunner?: IDescribeRunner): void {
this.defaultTestsRunner.registerAutoCleared(describeRunner, parentDescribeRunner);
}
public registerLazyModules(describeRunner: IDescribeRunner, parentDescribeRunner?: IDescribeRunner): void {
this.defaultTestsRunner.registerLazyModules(describeRunner, parentDescribeRunner);
}
public registerMockFnsAndSpies(describeRunner: IDescribeRunner, parentDescribeRunner?: IDescribeRunner): void {
this.defaultTestsRunner.registerMockFnsAndSpies(describeRunner, parentDescribeRunner);
}
public registerHooks(describeRunner: IDescribeRunner, parentDescribeRunner?: IDescribeRunner): void {
this.defaultTestsRunner.registerHooks(describeRunner, parentDescribeRunner);
}
public registerTestsInJest(describeRunner: IDescribeRunner, parentDescribeRunner?: IDescribeRunner): void {
this.defaultTestsRunner.registerTestsInJest(describeRunner, parentDescribeRunner);
}
}
And then, you can starting doing your own things:
class MyTestRunner implements ITestRunner {
// ...
public registerTestsInJest(describeRunner: IDescribeRunner, parentDescribeRunner?: IDescribeRunner): void {
this.processTests(describeRunner); // this line is executed before tests are passed to jest
this.defaultTestsRunner.registerTestsInJest(describeRunner, parentDescribeRunner); // this line is registering tests in jest
}
protected processTests(describeRunner: IDescribeRunner): void {
const testsService = describeRunner.getTestsService();
// log info about tests, set your own metadata, change anything, etc.
for (const testEntity of testsService.getTests()) {
console.log(testEntity); // TestEntity { name, description, timeout, metadata, dataProviders, testType }
testEntity.description += " my label"; // modify test's description
testEntity.setMetadata("myKey", { myVal: "foo" }); // add some custom data to test entity
testEntity.setTestType("skip"); // or skip test at all, if you want
}
testsService.registerPreProcessor(
// callback to be executed for each test (during the jest tests execution), before running the test itself
(preProcessorData: PreProcessorData) => {
// here you can do any side effects, but you shouldn't change any info about the test itself (name, description, type)
const { testEntity, args, clazzInstance } = preProcessorData;
// you can also override this data, by returning the same object
return preProcessorData;
},
// order of the callback in the callbacks chain, if it matters
1_000,
);
testsService.registerPostProcessor(
// callback to be executed for each test (during the jest tests execution), after running the test itself
(preProcessorResult: unknown, testError?: Error) => {
// preProcessorResult is an entity, returned by your test-method (usually test returns nothing, and the value is undefined)
console.log(preProcessorResult);
// testError is a test error; regardless of the post-processor result, this function error will be thrown (test has failed)
console.log(testError);
},
// order of the callback in the callbacks chain, if it matters
1_000,
);
}
}
When you're ready - start using your runner:
@Describe()
@RunWith(MyTestRunner)
class MyTest {
// ...
}
Typings can be found in the @jest-decorated/shared
package:
import type { ITestRunner, PreProcessorData, IDescribeRunner, TestEntity } from "@jest-decorated/shared";
@vitalishapovalov thanks for sharing this, but could you provide a sample for a snippet on how exactly I can run one single test that will run in dry mode and get a list of names of specific annotation values such as @Test/@Describe...etc values for other existing tests
I'm not 100% sure that I've understood the issue, maybe you can provide some more details or examples of what exactly you want to achieve? Regarding the Dry mode - you mean, bypass all of the additional functionality and simply execute existing tests/hooks?