Is there a way to get the current spec name from within the running test?
Basically I want to save a file, eg. using a function saveFile()
, with the name of the file being the spec name. Without having to manually retype the name of the test.
There's been a 2+-year old issue in the Jest repo to make the test name available, with no official solution as of Feb 2021. One core maintainer said none would be available any time soon.
The community has provided workarounds, however:
expect.getState().currentTestName
This will return the full path to the test, from the outermost describe to the test itself, separated with ' '
(not the best separator), e.g. static methods toString
. You can't easily tell which one was the describe
name, and which one was the test
name.
The same GitHub issue has this alternative method, which makes the test name accessible directly in the test via jasmine['currentTest'].fullName
, no extend
needed. Note though that Jasmine will no longer be the default test reported starting in Jest 27.
module.exports = {
setupFilesAfterEnv: ['./jest.setup.js'],
.................
};
// Patch tests to include their own name
jasmine.getEnv().addReporter({
specStarted: result => jasmine.currentTest = result,
specDone: result => jasmine.currentTest = result,
});
describe('Test description', () => {
beforeEach(() => console.log('Before test', jasmine['currentTest'].fullName));
test(...);
});
This worked for me
console.log(expect.getState().currentTestName);
I found that the only possible way was through the use of expect()
, which contains the spec name in its this
. doing something like
expect.extend({
async toSaveFile(data) {
fs.writeFileSync(`${this.currentTestName}.txt`, data)
return { pass: true };
},
});
allows to then do
expect().toSaveFile('contents of the file');
it's definitely a hack, but it's the only way I could find to get a reference to the spec name. there is also this.testPath
that indicates the test file
expect.getState().currentTestName
The issue with expect.getState().currentTestName
is that it provides a concatenated string.
So e.g. in case of sum.test.js
test file:
import { sum } from "./sum";
import { sleep } from "./util/sleep";
describe("testing sum", () => {
describe("middle", () => {
test('adds 1 + 1 to equal 2', async () => {
console.log("TESTNAME", expect.getState().currentTestName)
await sleep(1000)
expect(sum(1, 1)).toBe(2);
});
})
})
It prints out TESTNAME testing sum middle adds 1 + 1 to equal 2
where you cannot tell which belongs to which.
To get the name of each test separated, this is what you can do:
Create custom environment. This listens to events and sets up the variable:
Note that instead of
NodeEnvironment
, you can usePuppeteerEnvironment
if you are usingjest-puppeteer
:const PuppeteerEnvironment = require("jest-environment-puppeteer")
const NodeEnvironment = require('jest-environment-node');
class CustomEnvironment extends NodeEnvironment {
constructor(config, context) {
super(config, context);
this.testPath = context.testPath;
this.docblockPragmas = context.docblockPragmas;
}
getNames(parent) {
if (!parent) {
return [];
}
if (parent.name === 'ROOT_DESCRIBE_BLOCK') {
return [];
}
const parentName = this.getNames(parent.parent);
return [
...parentName,
parent.name
]
}
async handleTestEvent(event, state) {
const {name} = event;
if (["test_start", "test_fn_start"].includes(name)) {
this.global.testNames = this.getNames(event.test)
}
}
}
module.exports = CustomEnvironment;
Register the file in jest.config.js
:
export default {
// ...
// location of the file above
testEnvironment: "./src/my-custom-environment.js",
}
TypeScript
)Create global.d.ts
file:
declare const testNames: string[]
Use it in your tests:
import { sum } from "./sum";
import { sleep } from "./util/sleep";
describe("testing sum", () => {
describe("middle", () => {
test('adds 1 + 1 to equal 2', async () => {
console.log("TEST NAMES", testNames)
await sleep(1000)
expect(sum(1, 1)).toBe(2);
});
})
})
Output:
TEST NAMES [ 'testing sum', 'middle', 'adds 1 + 1 to equal 2' ]
Credits goes to: