How to get status of executed tests using afterEach in Jest? - node.js

When running tests in jest, I want to get the status of the 'it' whether they pass or fail, so far I was able to get the name of the running 'it' but I don't see a way to get its status.
// Expected value
let expectValue = 1;
// Test run
describe('Sample test', () => {
let statusTest = false;
afterEach(() => {
statusTest = false;
})
// This test passes
it('Value must be 1', () => {
expect(expectValue).toBe(1)
statusTest = true;
})
// This test fails
it('El valor debe ser 2', () => {
expect(expectValue).toBe(2)
statusTest = true;
})
beforeEach(() => {
/**
* At the moment it is being handled with a global variable to
* obtain the status of the test.
*
* Only the name and path are available in getState()
*/
if (!statusTest)
console.log(expect.getState().currentTestName)
})
})
At the time of passing the test I want to get its status either "passed" or "failed".
I tried to get the data inside expect or expect.getState(), but I don't see the value I require.
Similar questions:
Get the current test epec name in jest
Jest html reporters

Related

JEST Matcher error: received value must be a mock function

I am receiving "Matcher error: received value must be a mock function" trying to compare the result of the completed function. I do have 1 mock statement that mocks 2 methods from the utilities module for the index module to complete successfully when referencing those. I assume, though, that I do not need to mock index modules in order to pass the test. Here's the whole test that's not working:
import * as index from '../src/index';
jest.mock('../src/utils', () => {
const originalModule = jest.requireActual('../src/utils');
return {
__esModule: true,
...originalModule,
downloadModule: jest.fn(() => 'downloaded'),
compareChecksum: jest.fn(() => true)
}
});
describe('testing ingex file', () => {
test('testing case with mocked functions', async () => {
await expect(index.execute()).resolves.toHaveReturnedWith(undefined);
});
});
Utils is just a file with series of useful methods used in index. While the function called in index looks like this (Redacted):
//src/index
export async function execute() {
switch(type) { // comes from env vars
case 'file': {
await downloadModule(params); // mocked to succeed
if (await compareChecksum(otherParams)) {// mocked to succeed
console.log("Equal");
return;
}
...
}
...
}
}
The complete error I am getting:
expect(received).resolves.toHaveReturnedWith(expected)
Matcher error: received value must be a mock function
Received has value: undefined
So index module is dependent on utils and I mocked all necessary methods for it to pass successfully. Received value just cannot be a mock function ever, and it does receive the "undefined" result as expected but refuses to compare it properly. Not sure why the expected result is supposed to be a mock function in this case.
In case it matters this is typescript (not clearly visible from the code provided) and ts-jest is installed.

How to do callback in our component using react jest test cases

How can we do callback on success and failue cases for below lines of code for test coverage using jest
const handleService = () => {
window.domain.service("1321",'',onSuccess, onFailure)
}
const onSuccess = () => {
....update state values
}
const onFailure = () => {
....update state values
}
Something like this:
Spy on window.domain.service to gain access to the calls it receives. This will allow you to access the parameters of those calls which will be "1321",'',onSuccess, onFailure
Assign the function you wish to test to a variable
Invoke the function to execute the code in it (this will get you the coverage)
(Optional) assert that the callback functions behave correctly
Here is a snippet to help demonstrate
it('should run', () => {
// Some setup to create the function on the window, may not be needed if done elsewhere.
// Could be good to do this in a beforeEach and clean up in afterEach to avoid contaminating the window object
window.domain = {
service: () => {},
}
// Spy on the window.domain.service method.
// Provide a mock implementation if you don't want the real one to be called
const serviceSpy = jest.spyOn(window.domain, 'service');
executeYourCode();
// capture the arguments to the call
const [_arg1, _arg2, onSuccess, onFailure] = serviceSpy.mock.calls[0];
// execute the callbacks
onSuccess();
onFailure();
});

Why is the second Jest mock function never being called?

I am mocking navigator functions for simple clipboard functionality. Here is the relevant code:
// FUNCTION
/**
* Adds a click event to the button which will save a string to the navigator clipboard. Checks for
* clipboard permissions before copying.
*/
function loader(): void {
async function copyUrl(): Promise<void> {
const permission = await navigator.permissions.query({ name: "clipboard-write" });
if (permission.state == "granted" || permission.state == "prompt" ) {
await navigator.clipboard.writeText("the url");
} else {
console.error('Permission not supported');
}
}
const button = document.querySelector('button') as HTMLElement;
button.addEventListener('click', async () => {
await copyUrl();
});
}
// TEST
it('works', () => {
// mock navigator functions
Object.assign(navigator, {
permissions: {
query: jest.fn(async () => ({ state: "granted" }))
},
clipboard: {
writeText: jest.fn(async () => {})
}
});
// initialize DOM
document.body.innerHTML = '<button></button>';
loader(); // adds the event listener
// click the button!
const button = document.querySelector('button') as HTMLElement;
button.click();
expect(navigator.permissions.query).toHaveBeenCalledTimes(1);
expect(navigator.clipboard.writeText).toHaveBeenCalledWith('the url');
});
The test fails on expect(navigator.clipboard.writeText).toHaveBeenCalledWith('the url') with:
Expected: "the url" Number of calls: 0
Defeats the purpose of permissions, yes, but for the sake of debugging:
Try adding a clipboard call before permissions call like so?
// FUNCTION
// ...
async function copyUrl(): Promise<void> {
// add this
await navigator.clipboard.writeText('the url');
// keep the rest still
const permission = await navigator.permissions.query({ name: "clipboard-write" });
// ...
}
This fails on the first assertion now, expect(navigator.permissions.query).toHaveBeenCalledTimes(1) with
Expected number of calls: 1 Received number of calls: 0
With the addition above, I also changed the assertions to be:
expect(navigator.clipboard.writeText).toHaveBeenCalledWith('the url');
expect(navigator.clipboard.writeText).toHaveBeenCalledTimes(2);
expect(navigator.permissions.query).toHaveBeenCalledTimes(1);
... which failed on the second assertion because it expected 2 calls but only received 1.
I have been testing in a VSCode devcontainer and tried out the extension firsttris.vscode-jest-runner to debug the test. With breakpoints in the loader function, I'm able to see that every single line executes perfectly with my mockup but still fails at the end of debug.
I even changed the mock navigator.permissions.query function to return { state: 'denied' } instead. Both running and debugging, it did not satisfy the permission check and gave an error to the console as expected but the test still failed at expect(navigator.permissions.query).toHaveBeenCalledTimes(1) (with the added writeText call before it).
It seems to me that after the first call of a mock function, the others just don't work.
Am I missing something? Send help pls lol
EDITS
Using jest.spyOn as in this answer has the same issues.
Using an async test with an expect.assertions(n) assertion still produces the exact same issue.

If I am unit testing what happens inside an if-clause, should I mock everything up to the if-clause?

The scenario
I am writing unit tests for a module similar to the one below
service.js
const client = require("./../client");
let managedData = {};
function manageData(dataId) {
let users = client.retrieveUsers(); //Will return an array of strings. For example: a list of user names
let user = client.retrieveCurrentUser(); //Will return a string. For example: one user name
let userIsPresentInList = users.includes(user); //Check if the user is present in a broader user list
if(userIsPresentInList) {
managedData[dataId] = client.retrieveDataWithId(dataId);
}
}
function unmanageData(dataId) {
client.doSomethingToTheDataWithId(dataId)
delete managedData[dataId]
}
module.exports = {
manageData,
unmanageData
}
Some of my unit tests target what happens when the user is present in the list of users, i.e., what happens inside the if-clause
The questions is: if I am unit testing an if-clause, should I mock everything up to the clause (option 1 below)? Or should I create an way of "directly" ending up in the if-clause (option 2 below)?
The test
Option 1) Group the tests via describe blocks and mock in beforeEach/beforeAll:: Scenarios that concern what's inside the if-clause are grouped in a describe block and mocks are done for all statements up until the if-clause
Option 2) Mock intermediate functions inside module: service.js is refactored. The code that checks whether the user is in the list of users is extracted in a new function inside the module. This function then is mocked. In this way anything before the if-clause does not really matter and the test only concerns what is inside the if-clause is working
service.test.js
const service = require("./service");
const client = require("./../client");
jest.mock("./../client");
beforeEach(() => {
jest.clearAllMocks();
});
describe('Sucesful management', () => {
//OPTION 1
beforeEach(() => {
client.retrieveUsers = jest.fn(() => ["a", "b", "c"]);
client.retrieveCurrentUser = jest.fn(() => "a");
})
//OPTION 2
beforeEach(() => {
service.isUserPresentInUsersList = jest.fn(() => true);
})
afterEach(() => {
service.isUserPresentInUsersList.mockRestore();
})
it("Given the user belongs to the user list, should retrieve the data calleing manageData", async () => {
//Act
service.manageData("D");
//Assert
expect(client.retrieveDataWithId).toHaveBeenCalledWith("D");
});
it("Given the user belongs to the user list, should do something with the data when calling unmanageData", async () => {
//Act
service.manageData("D");
service.unmanageData("D");
//Assert
expect(client.doSomethingToTheDataWithId).toHaveBeenCalledWith("D");
});
})
Is there preferable one in this case? Is any of those approaches terrible?
An extended question would be: what are open source projects that have good testing practices that I can get inspiration from?

how to test a Module in NodeJs without function in it?

I have read and tried many ways to do this,I have a module like below .
//echo.js
module.exports = (services, request) => {
logger.debug('excecuting');
return true;
};
I want to write unit test for this module using sinon , what i did tried so far is.
describe('test', function() {
const echo1 = require('./echo');
var spy1 = sinon.spy(echo1);
beforeEach(() => {
spy1.resetHistory();
});
it('Is function echo called once - true ', done => {
echo1(testData.mockService, testData.stubRequest); //calling module
spy1.called.should.be.true;
done();
});
});
i get the below output which is failed, though i see my function being called in the output window
1) test
Is function echo called once - true :
AssertionError: expected false to be true
+ expected - actual
-false
+true
at Context.done (echo_unit.js:84:27)
could anyone tell me how to test modules in nodejs
It doesn't matter in this case whether it's a module or just a function.
A function that isn't called as a method can't be spied (also, describe function isn't a proper place to place var spy1 = sinon.spy(echo1)). This also isn't needed here because it's you who call the function, there's no need to test that it was called.
Since all that echo does is calls logger.debug and returns true, this needs to be tested:
it('Is function echo called once - true ', () => {
sinon.spy(logger, 'debug');
const result = echo1(testData.mockService, testData.stubRequest);
expect(logger.debug).to.have.been.calledWith("execute");
expect(result).to.be(true);
// the test is synchronous, no done() is needed
});

Resources