Basic jest test on a 1 function file gets 0% coverage - jestjs

I have 2 files with 1 function in it. My test is just as simple, see below:
doc.js
export function createSynthId(doc) {
const synthId = `${doc.attachmentId}-${doc.materialId}-${doc.fileName}-${doc.title}-${doc.materialURL}`;
return synthId;
}
doc.test.js
import { createSynthId } from './doc';
describe('doc', () => {
it('create synthetic id', () => {
expect(createSynthId(global.doc)).toEqual('987654-123456-File Name.pptx-undefined-');
});
it('create synthetic id', () => {
expect(createSynthId({})).toEqual('undefined-undefined-undefined-undefined-undefined');
});
});
My second file is virtually the same, just a larger function. Both tests pass, but coverage is being reported at 0% for Statements, Functions, and Lines, but 100% for Branches. The coverage report is showing all the lines red as well.
We have many similar files and they all work. What am I missing here?
UPDATE
I added a temp function to doc.js
export const makeTestsHappy = () => {
console.log(CONFIG);
};
adding to doc.test.js
it('does more', () => {
makeTestsHappy();
});
and when I try to test that, I get the error TypeError: (0 , _doc.makeTestsHappy) is not a function

Dummy over here was mocking the file I was testing. I forgot to jest.unmock('/doc') It immediately started working when I unlocked. Thanks all for your patience :D

Try to rename your test file from doc.test.js to doc.spec.js. You are using the BDD syntax and the correct name should include spec.

Related

Jest extremely slow on failed tests

I have a jest test file that looks like this:
import Client from "socket.io-client"
describe("my awesome project", () => {
let clientSocket;
beforeAll((done) => {
clientSocket = new Client(`http://localhost:3000`);
clientSocket.on("connect", done);
});
afterAll(() => {
clientSocket.close();
});
it("should work", (done) => {
clientSocket.on("redacted", (message) => {
expect(2 + 2).toBe(56);
//expect(message === "foobar").toEqual(true);
done();
});
clientSocket.emit("redacted", "world");
});
});
This is a POC and this currently the entire implementation.
The jest.config looks like this:
export default {
// Automatically clear mock calls, instances, contexts and results before every test
clearMocks: true,
// Indicates whether the coverage information should be collected while executing the test
collectCoverage: true,
// The directory where Jest should output its coverage files
coverageDirectory: "coverage",
// Indicates which provider should be used to instrument code for coverage
coverageProvider: "v8",
// A preset that is used as a base for Jest's configuration
preset: "ts-jest",
};
Which is just the file the --intit command generated.
The core of my problem is that any expect I use that results in a failed test, no matter how trivial takes an absurd amount of time to complete. I accidentally left it running as above overnight and it eventually completed in 14 hours.
But with a passing test Jest is absolutely fine and completes rapidly.expect(2 + 2).toBe(4); for example runs perfectly. On the failed tests I see the data come back from the socket as expected in the time expected. Its only when the expect is hit that it stalls out. So I don't believe the problem is in the socket setup or some sort of communication problem.
I've tried the config based solutions I've found to no effect - eg Jest - Simple tests are slow
This is being run on my local windows machine from a terminal I'm fully starting and stopping for each test on my IDE.
OK so now I see the problem, I needed a try catch.
Can't quite believe none of the examples or docs I looked at as much as hinted this is necessary to handle something so basic.
test("should work", (done) => {
clientSocket.on("redacted", (message: string) => {
try {
expect(2 + 2).toBe(56);
//expect(message === "foobar").toEqual(true);
done();
} catch (err) {
done(err)
}
});
clientSocket.emit("redacted", "world");
});

Selenium Test Case not getting executed with Jest

I am working on setting up an automation test suite for an application using selenium and jest and it turns out that the console never reaches the inner body of the minimalist test case written below.
describe('When a user Opens Launchpad', () => {
test('It should be able to Navigate to Tasks Application without errors', async () => {
driver.get('http://localhost:4004/fiori.html').then(function () {
const temp = driver.findElement(By.xpath("li[#id='__tile11']"));
temp.then(function (element){
element.getAttribute("innerHTML");
expect(element.getText()).toBe("VT Dashboard");
})
});
}, 200000);
});
I looked online and tried multiple fixes like putting the driver.get() method above all these functions, making the test cases synchronous and using getText() instead of getAttribute() but none of them worked.
I either get an element not found error (The element actually exists when I check it on the chromium browser) or the test case executes successfully without reaching the expect statement in debug mode.
Bottomline is that driver.findElement() returns a promise instead of an element and would be great if I could get an element instead of promise.
Any help or correction here would be greatly appreciated.
If the function is async you should return the promise chain from that function or just use await keyword. So try following:
test('It should be able to Navigate to Tasks Application without errors', async () => {
await driver.get('http://localhost:4004/fiori.html');
const temp = await driver.findElement(By.xpath("li[#id='__tile11']"));
element.getAttribute("innerHTML");
expect(element.getText()).toBe("VT Dashboard");
}, 200000);
or
test('It should be able to Navigate to Tasks Application without errors', async () => {
return driver.get('http://localhost:4004/fiori.html').then(function () {
const temp = driver.findElement(By.xpath("li[#id='__tile11']"));
temp.then(function (element){
element.getAttribute("innerHTML");
expect(element.getText()).toBe("VT Dashboard");
})
});
}, 200000);

How to stop jest describe without throw all the test

I want to stop a whole describe of JEST without throwing an error or stoping the other describes.
Im writing e2e test for my app with JEST and PUPPETEER, I write the test in a way every DESCRIBE its a flow of the path and every IT its a step, inside a IT I want to stop the flow if the pages dont match some conditions.
describe('Book a Room', ()=> {
it ('enter on main page' async() => await mainPage.navigateToMainPage())
it('go to book room page', async() => await bookRoomPage.navigateToBookRoomPage())
// The function its inside the "bookRoomPage"
it('check if the user can book room', () => {
if (!page.userCanOpenARoom()) {
// DONT EXECUTE THE NEXT IT BUT CONTINUE WITH THE OTHER DESCRIBE
}
})
it('go to book preview...', async() => bookRoomPreviewPage.navigateToBookRoomPreviewPage());
// REMAINING FLOW
})
I already try with process.exit(0) but exit the whole process
You can try out what this blog says here its for sharing specs in your test suites which is pretty handy. But for your case specifically you could extract your page cases in separate suites and then dynamically include the test case on runtime if a condition is met.
Something like:
Include Spec function shared_specs/index.js
const includeSpec = (sharedExampleName, args) => {
require(`./${sharedExampleName}`)(args);
};
exports.includeSpec = includeSpec;
Test A shared_specs/test_a.js
describe('some_page', () => {
it...
})
Test B shared_specs/test_b.js
describe('some_other_page', () => {
it...
})
and then in your test case
// Something like this would be your path I guess
import {includeSpec} from '../shared_specs/includeSpec.js'
describe('Book a Room', async ()=> {
if (page.userCanOpenARoom()) {
includeSpec('test_a', page);
} else {
includeSpec('test_b', page); // Or dont do anything
}
});
Just make sure that you check the paths since
require(`./${sharedExampleName}`)(args);
will load it dynamically at runtime, and use includeSpec in your describe blocks not it blocks. You should be able to split up your test suites pretty nicely with this.

mocha test passing despite apparent stalling on a sync operation

Ok, this is kinda driving me batty. I am trying to run a mocha test on an app I'm writing that's supposed to select and copy a file based on project parameters (a dockerfile). The test is working for other cases, and in fact it's green for this case, except that it shouldn't be.
The test uses fs.readFileSync to store the file contents that should be there with the file contents that are actually there, to determine if the right file is copied.
Problem is, there's no file in the location being checked yet (as I haven't written the code to put it there, and I have validated by printing out the directories the test is using and then navigating there myself), but the test passes. Even more strange, as far as I can tell no code executes after the readFileSync operation. But it also doesn't time out...
Here's the test code in question:
it('should create a Dockerfile from ./data/dockerfiles/war.docker', () => {
let projectDocker = path.join(project, 'Dockerfile');
let warDocker = path.join(__dirname, '..', 'data','dockerfiles','war.docker');
select(project, (err, result) => {
let correct = fs.readFileSync(warDocker, 'utf-8');
console.log('projectDocker');
console.log('checking for projectDocker');
let prj = fs.readFileSync(projectDocker, 'utf-8');
console.log('Read file sync for project has completed'); // This line never fires
expect(prj).to.equal(correct);
expect(err).to.not.exist;
expect(result).to.exist;
expect(result).to.have.property('relPath', project);
expect(result).to.have.property('prepared', true);
});
});
select() looks suspiciously async, in which case your test should be async as well:
it('should create a Dockerfile from ./data/dockerfiles/war.docker', done => {
...
select(project, (err, result) => {
if (err) return done(err);
...
done();
});
});
Otherwise you run a big risk of exceptions being swallowed, as #Martin also suggests.

How can I build my test suite asynchronously?

I'm trying to create mocha tests for my controllers using a config that has to be loaded async. Below is my code. However, when the mocha test is run, it doesn't run any tests, displaying 0 passing. The console.logs are never even called. I tried doing before(next => config.build().then(next)) inside of the describe, but even though the tests run, before is never called. Is there a way to have the config be loaded one time before any tests are run?
'use strict';
const common = require('./common');
const config = require('../config');
config
.build()
.then(test);
function test() {
console.log(1);
describe('Unit Testing', () => {
console.log(2);
require('./auth');
});
}
You should run Mocha with the --delay option, and then use run() once you are done building your test suite. Here is an example derived from the code you show in the question:
'use strict';
function test() {
console.log(1);
describe('Unit Testing', () => {
console.log(2);
it("test", () => {
console.log(3);
});
});
// You must use --delay for `run()` to be available to you.
run();
}
setTimeout(test, 1000);
I'm using setTimeout to simulate an asynchronous operation. Using --delay and run() allows you to build a suite that is the result of an asynchronous computation. Note, however, that the suite must be built in one shot. (You cannot have an asynchronous process inside describe that will make calls to it. This won't work.)
One thing you should definitely not do is what rob3c suggests: calling describe or it (or both) from inside a hook. This is a mistake that every now and then people make so it is worth addressing in details. The problem is that it is just not supported by Mocha, and therefore there are no established semantics associated with calling describe or it from inside a hook. Oh, it is possible to write simple examples that work as one might expect but:
When the suite becomes more complex, the suite's behavior no longer corresponds to anything sensible.
Since there are no semantics associated with this approach, newer Mocha releases may handle the erroneous usage differently and break your suite.
Consider this simple example:
const assert = require("assert");
const p = Promise.resolve(["foo", "bar", "baz"]);
describe("top", () => {
let flag;
before(() => {
flag = true;
return p.then((names) => {
describe("embedded", () => {
for (const name of names) {
it(name, () => {
assert(flag);
});
}
});
});
});
after(() => {
flag = false;
});
it("regular test", () => {
assert(flag);
});
});
When we run it, we get:
top
✓ regular test
embedded
1) foo
2) bar
3) baz
1 passing (32ms)
3 failing
// [stack traces omitted for brevity]
What's going on here? Shouldn't all the tests pass? We set flag to true in the before hook for the top describe. All tests we create in it should see flag as true, no? The clue is in the output above: when we create tests inside a hook, Mocha will put the tests somewhere but it may not be in a location that reflects the structure of the describe blocks in the code. What happens in this case is that Mocha just appends the tests created in the hook the the very end of the suite, outside the top describe, so the after hook runs before the dynamically created tests, and we get a counter-intuitive result.
Using --delay and run(), we can write a suite that behaves in a way concordant with intuition:
const assert = require("assert");
const p = Promise.resolve(["foo", "bar", "baz"]).then((names) => {
describe("top", () => {
let flag;
before(() => {
flag = true;
});
after(() => {
flag = false;
});
describe("embedded", () => {
for (const name of names) {
it(name, () => {
assert(flag);
});
}
});
it("regular test", () => {
assert(flag);
});
});
run();
});
Output:
top
✓ regular test
embedded
✓ foo
✓ bar
✓ baz
4 passing (19ms)
In modern environments, you can use top-level await to fetch your data up front. This is a documented approach for mocha: https://mochajs.org/#dynamically-generating-tests
Slightly adapting the example from the mocha docs to show the general idea:
function fetchData() {
return new Promise((resolve) => setTimeout(resolve, 5000, [1, 2, 3]));
}
// top-level await: Node >= v14.8.0 with ESM test file
const data = await fetchData();
describe("dynamic tests", function () {
data.forEach((value) => {
it(`can use async data: ${value}`, function () {
// do something with data here
});
});
});
This is nice as it is on a per-file basis, and doesn't involve you taking on management responsibility of the test runner as you do with --delay.
The problem with using the --delay command line flag and run() callback that #Louis mentioned in his accepted answer, is that run() is a single global hook that delays the root test suite. Therefore, you have to build them all at once (as he mentioned), which can make organizing tests a hassle (to say the least).
However, I prefer to avoid magic flags whenever possible, and I certainly don't want to have to manage my entire test suite in a single global run() callback. Fortunately, there's a way to dynamically create the tests on a per-file basis, and it doesn't require any special flags, either :-)
To dynamically create It() tests in any test source file using data obtained asynchronously, you can (ab)use the before() hook with a placeholder It() test to ensure mocha waits until before() is run. Here's the example from my answer to a related question, for convenience:
before(function () {
console.log('Let the abuse begin...');
return promiseFn().
then(function (testSuite) {
describe('here are some dynamic It() tests', function () {
testSuite.specs.forEach(function (spec) {
it(spec.description, function () {
var actualResult = runMyTest(spec);
assert.equal(actualResult, spec.expectedResult);
});
});
});
});
});
it('This is a required placeholder to allow before() to work', function () {
console.log('Mocha should not require this hack IMHO');
});

Resources