JEST - Yellow lines on the coverage report for async methods - javascript

I have the following case on Vue JS, in a method inside a component:
The method loadProducts is async, when I run the JEST tests, shows me I don't cover line 320, but all other lines and inside the function are covered.
If I tried to await and evaluate the result of this function I will receive the result of line 339 and 343:
const {success} = await wrapper.vm.loadProducts();
A simplified test that I wrote:
describe('loadProducts', () => {
it('should return false', async () => {
const {success} = await wrapper.vm.loadProducts();
expect(success).toEqual(false);
});
);
How can I avoid the coverage report shows me this warning?

Just a guess - maybe you should render the component that is using that function and make it run that function. I cannot tell when that function is called, maybe on some button click? Then render the component and click the button in the test.
You can always check the coverage report which should be under the ./coverage/lcov-report/index.html. You can find there sometimes some additional information.
BTW: Your then returns success in Pascalcase and the catch in lowercase.

Related

How can we skip the .after steps in TestCafe if the test itself fails?

In our project, we use .beforeEach, .before, .afterEach, and .after in most of our tests and test files.
If a test step fails, we'd like to have the ability to skip the .afterEach and .after of the tests since most likely, we wouldn't be able to execute those steps successfully after a failure.
Does TestCafe have this ability built-in?
Thanks,
You can use test context or fixture context. Set a special value in the context after all steps and check this value in the after hook. If the value is acceptable, execute the remaining part of the hook; else skip it. For example:
fixture`Fixture`
.page`https://example.com/`
.after((ctx) => {
if (!ctx.success)
return;
console.log('After fixture');
//other code
});
test('Test', async (t) => {
await t.click('non-existed-element');
t.fixtureCtx = { success: true }
})

It seems that the beforeEach hook is executing for another test class (Mocha testing framework)

I am not sure what is happening.
I am using the Mocha testing framework to learn writing tests for solidity classes.
I met a strange behaviour, that I never met before. I have some previous experience with Mocha (with Cypress), but never saw this strange behaviour.
What is the problem:
I have two testing classes.
The first class:
//01. Call library modules.
const assert = require('assert'); // Declare an assertion library module.
const { beforeEach } = require('mocha');
//02. Create an example class with some logic inside.
class exampleClass {
func1() {
return 'random value 1';
}
func2() {
return 'random_value_2';
}
}
//03. Declare global variables.
let exam;
//04. Declare the "beforeEach" function. This function will be executed before every "it" test.
beforeEach(() => {
exam = new exampleClass(); // Declare a constructor for exampleClass.
});
//05. Create a test suite using "describe" function.
describe('name of the describe', () => {
//06. Add tests using "it" function.
it('This example shows how the assert will pass', () => {
assert.equal(exam.func1(), 'random value 1'); // Make an assertion to verify that the two values are equal.
});
xit('This example shows how the assert will fail, but the test will be skipped because the "X" symbol is added like a prefix for "it".', () => {
assert.equal(exam.func1(), 'random value'); // Make an assertion to verify that the two values are equal.
});
it('This example shows how the assert will pass', () => {
assert.equal(exam.func2(), 'random_value_2'); // Make an assertion to verify that the two values are equal.
});
});
The first class is a basic example of using the Mocha testing framework.
The second class:
//01. Call library modules.
const ganache = require('ganache'); // Declare a ganache library module.
const Web3 = require('web3'); // Declare a web3 library module.
//02. Create an instances.
const web3 = new Web3(ganache.provider()); // Declare an instance for Web3 including ganache.
//03. Declare the "beforeEach" function. This function will be executed before every "it" test.
beforeEach(() => {
// Get a list of all accounts.
web3.eth.getAccounts()
.then(fetchedAccounts => { // Get an access to all of the accounts. We use then, because "getAccounts()" function is returning a promise.
console.log(fetchedAccounts);
});
});
//04. Create a test suite using "describe" function.
describe('Generate fake eth accounts example 1', () => {
//05. Add tests using "it" function.
it('A0.1. example 1', () => {
});
});
The second class is an example of the generation of fake data (fake eth accounts).
If I execute the classes separately - everything is working as expected.
But if I execute all tests (both classes) - it seems that the "beforeEach" hook from class 2 is applying to class 1 for some reason.
As result, the console printed fake generated accounts three times. Three because 3 tests were passed. I am not sure why this is happening.

Create React App changes behaviour of jest.fn() when mocking async function

I am confused about the below behaviour of jest.fn() when run from a clean CRA project created using npx create-react-app jest-fn-behaviour.
Example:
describe("jest.fn behaviour", () => {
const getFunc = async () => {
return new Promise((res) => {
setTimeout(() => {
res("some-response");
}, 500)
});;
}
const getFuncOuterMock = jest.fn(getFunc);
test("works fine", async () => {
const getFuncInnerMock = jest.fn(getFunc);
const result = await getFuncInnerMock();
expect(result).toBe("some-response"); // passes
})
test("does not work", async () => {
const result = await getFuncOuterMock();
expect(result).toBe("some-response"); // fails - Received: undefined
})
});
The above test will work as expected in a clean JavaScript project but not in a CRA project.
Can someone please explain why the second test fails? It appears to me that when mocking an async function jest.fn() will not work as expected when called within a non-async function (e.g. describe above). It will work only when called within an async function (test above). But why would CRA alter the behaviour in such a way?
The reason for this is, as I mentioned in another answer, that CRA's default Jest setup includes the following line:
resetMocks: true,
Per the Jest docs, that means (emphasis mine):
Automatically reset mock state before every test. Equivalent to
calling jest.resetAllMocks() before each test. This will lead to
any mocks having their fake implementations removed but does not
restore their initial implementation.
As I pointed out in the comments, your mock is created at test discovery time, when Jest is locating all of the specs and calling the describe (but not it/test) callbacks, not at execution time, when it calls the spec callbacks. Therefore its mock implementation is pointless, as it's cleared before any test gets to run.
Instead, you have three options:
As you've seen, creating the mock inside the test itself works. Reconfiguring an existing mock inside the test would also work, e.g. getFuncOuterMock.mockImplementation(getFunc) (or just getFuncOuterMock.mockResolvedValue("some-response")).
You could move the mock creation and/or configuration into a beforeEach callback; these are executed after all the mocks get reset:
describe("jest.fn behaviour", () => {
let getFuncOuterMock;
// or `const getFuncOuterMock = jest.fn();`
beforeEach(() => {
getFuncOuterMock = jest.fn(getFunc);
// or `getFuncOuterMock.mockImplementation(getFunc);`
});
...
});
resetMocks is one of CRA's supported keys for overriding Jest configuration, so you could add:
"jest": {
"resetMocks": false
},
into your package.json.
However, note that this can lead to false positive tests where you expect(someMock).toHaveBeenCalledWith(some, args) and it passes due to an interaction with the mock in a different test. If you're going to disable the automatic resetting, you should also change the implementation to create the mock in beforeEach (i.e. the let getFuncOuterMock; example in option 2) to avoid state leaking between tests.
Note that this is nothing to do with sync vs. async, or anything other than mock lifecycle; you'd see the same behaviour with the following example in a CRA project (or a vanilla JS project with the resetMocks: true Jest configuration):
describe("the problem", () => {
const mock = jest.fn(() => "foo");
it("got reset before I was executed", () => {
expect(mock()).toEqual("foo");
});
});
● the problem › got reset before I was executed
expect(received).toEqual(expected) // deep equality
Expected: "foo"
Received: undefined

How to get/set out-of-scope variables when testing a function with dependency on these (jest)?

I'm trying to have full test coverage on some helper functions in my project. My first tests for either of the functions checks whether 2 out-of-scope variables are declared or not, which run successfully.
What I want to do is, jest to set/mock wrapper and layer variables declared out-of-scope of the functions to be tested, but can't seem to have it right no matter how hard I tried.
Thankful and appreciate any kind of help in this direction as I'm fairly rookie in terms of writing tests in general not to mention tests for jest.
I have tried jest.mock by mocking by default my imported module and then did jest.requireActual on 2 functions.
I have tried jest.doMock with a module factory which sets these 2 variables and then returns in an object.
Module: helpers/index.js
let wrapper; // Is created on runtime ergo initially undefined.
const layer = document.createElement('div');
layer.classList.add('layer');
const isElement = elm => {
if (!(elm instanceof Element)) {
throw new Error('Given element is not of type Element or is undefined!');
}
}
export const someFn = async () => {
wrapper = document.querySelector('.wrapper');
isElement(wrapper);
isElement(layer);
// Code that needs to be tested
// but cannot since when testing this function
// 'wrapper' and 'layer' are always undefined.
}
Test: helpers/index.test.js
// Helpers
import {someFn} from 'helpers';
describe('Method: someFn', () => {
test('should NOT throw', async () => {
await expect(someFn()).resolves.not.toThrow(); // but it does!
});
});
Actual result: Received promise rejected instead of resolved
Expected result: Not to throw, considering these out-of-scope variables that this function relies on, can somehow be set/mocked while testing it.

Is there a way to run particular Protractor test depending on the result of the other test?

This kind of question has been asked before but most of this question has pretty complicated background.
The scenario is simple. Let's say we are testing our favorite TODO app.
Test cases are next:
TC00 - 'User should be able to add a TODO item to the TODO list'
TC01 - 'User should be able to rename TODO item'
TC02 - 'User should be able to remove TODO item'
I don't want to run the TC01 and TC02 if TC00 fails (the TODO item is not added so I have nothing to remove or rename)
So I've been researching on this question for the past 3 days and the most common answers fro this question are:
• Your tests should not depend on each other
• Protractor/Jasmine does not have feature to dynamically turn on/off tests ('it' blocks)
There reason why I'm asking this question here is because it looks like a very widespread case and still no clear suggestion to handle this (I mean I could not find any)
My javascript skills are poor but I understand that I need to play around, let's say' passing 'done' or adding the if with the test inside...
it('should add a todo' ()=> {
todoInput.sendKeys('test')
addButton.click();
let item = element(by.cssContainingText('.list-item','test')
expect(item.isPresent()).toBe(true)
}
In my case there are like 15 tests ('it' blocks) after adding the item to the list. And I want to skip SOME OF THE tests if the 'parent' test failed.
PLEASE NOTE:
There is a solution out there which allows to skip ALL remaining test if one fails. This does not suit my needs
Man, I spent good couple of weeks researching this, and yes there was NO clear answers, until I realized how protractor works in details. If you understand this too you'll figure out the best option for you.
SOLUTION IS BELOW AFTER SHORT THEORY
1) If you try to pass async function to describe you see it'll fail, because it only accepts synchronous function
What it means for you, is that whatever condition you want to pass to it block, it can't be Promise based (Promise == resolves somewhen, but not immediately). What you're trying to do essentially IS a Promise (open page, do something and wait to see if the condition satisfies your criteria)
if (conditionIsTrue) { // can't be Promise
it('name', () => {
})
}
Thats first thing to consider...
2) When you run protractor, it picks up spec files specified in config and builds the queue of describe/it AND beforeAll/afterAll blocks. IMPORTANT DETAIL HERE IS THAT IT HAPPENS BEFORE THE BROWSER EVEN STARTED.
Look at this example
let conditionIsTrue; // undefined
it('name', () => {
conditionIsTrue = true;
})
if (conditionIsTrue) { // still undefined
it('name', () => {
})
}
By the time Protractor reaches if() statement, the value of conditionIsTrue is still undefined. And it maybe overwritten inside of it block, when browser starts, later on, but not when it builds the queue. So it skips it.
In other words, protractor knows which describe blocks it'll run before it even opens the browser, and this queue can NOT be modified during execution
POSSIBLE SOLUTION
1.1 Define a global variable outside of describe
let conditionIsTrue; // undefined
describe("describe", () => {
it('name1', async () => {
conditionIsTrue = await element.isPresent(); // NOW IT'S TRUE if element is present
})
it('name2', async () => {
if (conditionIsTrue) {
//do whatever you want if the element is present
} else {
console.log("Skipping 'name2' test")
}
})
})
So you won't skip the it block itself, however you can skip anything inside of it
1.2 The same approach can be used for skipping it blocks across different specs, using environment variable. Example:
spec_1.js
describe(`Suite: 1`, () => {
it("element is present", async () => {
if (await element.isPresent()) {
process.env.FLAG = true
} else {
process.env.FLAG = false
}
});
});
spec_2.js
describe(`Suite: 2`, () => {
it("element is present", async () => {
if (process.env.FLAG) {
// do element specific actions
}
});
});
Another possibility I found out, but never had a chance to check is to use Grunt task runner, which may help you implement the following scenario
Run protractor to execute one spec
Check a desired condition
Export this condition to environment variable
Exit protractor
In your Grunt task implement a conditional logic for executing the rests of conditional specs, by starting protractor again
But honestly, I don't see why you'd want to go this time consuming route, which requires a lot of code... But just as an FYI
There is one way provided by Protractor which might achieve what you want to achieve.
In protractor config file you can have onPrepare function. It is actually a callback function called once protractor is ready and available, and before the specs are executed. If multiple capabilities are being run, this will run once per capability.
Now as i understand you need to do a test or we can say execute a parent function and then based on its output you want to run some tests and do not want to run other tests.
onPrepare function in protractor config file will look like this :
onPrepare: async () => {
await browser.manage().window().maximize();
await browser.driver.get('url')
// continue your parent test steps for adding an item and at the last of function you can assign a global variable say global.itemAdded = true/false based on the result of above test steps. Note that you need to use 'global.' here to make it a global variable which will then be available in all specs
}
Now in you specs file you can run tests (it()) based on global.itemAdded variable value
if(global.itemAdded === true) {
it('This test should be running' () => {
})
}
if(global.itemAdded === false) {
it('This test should not be running' () => {
})
}

Categories

Resources