Use variable expressions in test.each Jest - jestjs

Below is my code snippet:
describe('Upper Describe,()=>{
let value;
beforeEach(()=>{
value=require('testModule').value;
});
it.each([
`${value}`,
])('test something',(value)=>{
console.log(value);
});
});
Here the value comes to be undefined.
My guess is it is because as the describe blocks get loaded at the starting so are the values for it.each. Can anyone please help me with a workaround to get the variable values inside it.each array?
Thanks in advance!!

Instead of passing the value itself to it.each pass a function that returns the value.
This will delay evaluation of the value so beforeEach can modify what gets returned:
describe('Upper Describe', () => {
let value;
beforeEach(() => {
value = require('testModule').value;
});
it.each([
() => `${value}`, // pass a function that returns the value
])('test something', (func) => {
console.log(func()); // SUCCESS: prints value export from testModule
});
});

Related

Jest: Mock a nested function which returns key/value pairs multiple times

I am writing a test for an API which calls a nested api multiple times to get a key value pair. The value will always be a boolean and I am trying to mock this service aka KeyValueService in the code below. These and other more booleans are used in the PhotoService and I would like to mock these values so I can change the test to match these values.
I have mocked the booleans and also tried setting mockResolveValuetwice to true twice thinking that it may apply true for both variables valueA and valueB, but it did not work. I will be using this nested service multiple times and not just twice. So far none of the solutions worked. How can I get a desired value for each key value pair? TIA!
jest.mock('../../service/keyValue.service', () => ({
valueA: false,
valueB: false
}));
describe('PhotosService', () => {
let service: PhotosService;
let keyValueService: KeyValueService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [PhotosService],
}).compile();
service = module.get<PhotosService>(PhotosService);
keyValueService.get.mockResolveValue(() => true);
});
it('should be defined', () => {
expect(service).toBeDefined();
valueA.mockResolveValue(() => true);
});
});
But the values doesnt change. I also tried the following,
it('should be defined', () => {
keyValueService.get.mockResolveValue(true);
keyValueService.get.mockResolveValue(true);
expect(service).toBeDefined();
valueA.mockResolveValue(() => true);
});
Alright one thing that worked for me was to set keyValueService.get again in my test or it block to jest.fn() again which worked for me to resolve this issue.
keyValueService.get = jest.fn()...;
Upto to use what you want. Either mockImplementation if need be or mockReturnValue etc. My guess is that it just reassigns the get function to a new mock value for that particular it/test block.

how to get [chrome.instanceID.getID] , [chrome.storage.sync.get] by async & await?

How do you get the information for the Chrome extension by using async and await?
[chrome.instanceID.getID]
[chrome.storage.sync.get]
We tried this code:
async function test()
{
let _r = await chrome.instanceID.getID();
return _r;
}
let _pc_id = test();
but _pc_id returns a promise. We find no way to get the value in it. How should we do this?
You can get the instanceID like this, but can't store it in a variable to use it out of scope of the promise, AFAIK. You may want to read this: saving data from promise in a variable
If you want to use the returned value of Promise you need to do it in the promise or in .then()s after the promise, at least that is how I do it.
chrome.instanceID.getID example:
chrome.instanceID.getID((instance_id) => {
console.log(instance_id);
// Execute your other related code here
});
or
var promise = chrome.instanceID.getID();
promise.then((instance_id) => {
console.log(instance_id);
// Execute your other related code here
});
or
chrome.instanceID.getID()
.then((instance_id) => {
console.log(instance_id);
// Execute your other related code here
});
chrome.storage.sync.get example:
chrome.storage.sync.get('myKey', function(items) {
var key = items.myKey;
// Below code is an example, change it to your needs
if (key) {
console.log(key)
} else {
key = createKey(); // a custom function that generates keys
chrome.storage.sync.set({myKey: key}, function () {
console.log(key);
});
}
};

How to fix - Promise { <pending> } in Node.js and use it as variable anywhere

I'm accessing google API for converting coordinates into detailed objects using node-geocoder library from npmjs. Everything went well and I'm getting the expected object from geocoder API. The problem started the moment when I thought of using the data outside the promise function. I want to use the values outside the promise/async-await function.
Below is the code I've tried, Pls take a look and help me. TIA...
function goecoderPromiseFunction() {
return new Promise(function (resolve, reject) {
geocoder.reverse({ lat: 45.767, lon: 4.833 })
.then(data => {
cityName = data[0].city;
resolve(cityName);
})
.catch(err => {
console.log(err);
});
});
}
async function app() {
var a = await goecoderPromiseFunction();
return a;
}
var a = app();
console.log("a->", a);
I expect the variable "a" should print the city name "Lyon", but it prints
a-> Promise { < pending > }
The promise returned by the app function is never consumed, that is why it remains in a pending state.
Call then on the app function to get the result :
app().then(a => console.log("a->", a));
You can also use async/await :
(async function() {
var a = await app();
console.log("a->", a);
})();
An asynchronous function actually returns a promise that 'resolves' to the function's return value. You are therefore assigning a promise to the value of a. If you are in the global scope, you obviously cannot use async/await so you need to use either a self-executing async function or you need to run
a.then(data => console.log('a->', data));
to get what you are looking for.
Find out more about async functions here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
It prints because console.log("a->", a); runs while promise haven't returned answer for a variable "a"
Note: you haven't used reject function, if there is an error you wont notice and may be that error was the required answer to be carried by variable "a" that's why it still pending i.e still waiting.
For more idea try to use reject function inside the catch block example reject(err)
instead of console it out as you've done

Get the value of a promise and assign to variable

utility.fetchInfo() returns a Promise object. I need to be able to get the value of this Promise object and assign the value of it to a variable that I can then use later on in my code.
At the moment, I can happily print the value of result to the console, but I need to be able to assign this value to myVal. So far, I've tried a lot of things and nothing has worked.
var myVal = utility.fetchInfo().then(result => console.log(result));
Thanks
What #dhilt said but do your stuff inside the promise callback function:
utility.fetchInfo().then(result => {
doSomethingWith(result);
});
Or use async/await if you are using a recent version of Node or Babel:
async function myFunction () {
var myVal = await utility.fetchInfo();
}
Just do an assignment within the callback's body
utility.fetchInfo().then(result => { myVal = result; });
Depends on the situation, for example, if there's a big piece of async logic, it may be better to extract it in a separate function:
let myVal; // undefined until myAsyncFunc is called
const myAsyncFunc = (result) => {
console.log(result);
myVal = result;
// ...
};
utility.fetchInfo().then(myAsyncFunc); // async call of myAsyncFunc
When you return the value to another file/function and you are getting undefined because another function where you are using that value is not waiting for the value to be assigned to the variable. For example there are two function
function1(){
var x=desired_value
}
function2(){
var y = x
}
now function1 might take some time to assign desire value to var x and java script ll not wait for this, it ll start running function2 and when you read the value of y you will get undefined.
To solve this problem we can use java script promise/await/async, return value from async function as resolve. refer below example
async function1(){ //function1 should be async here for this to work
return new Promise(function(resolve,reject){
resolve(desired_value)
});
}
or above function can be writtern as
async function1(){ //function1 should be async here for this to work
return Promise.resolve(desired_value)
}
Now we can use this value in another function by calling the function1 and use await keyword
function2(){
var y = await function1();
}
now it ll wait for function1 to complete before assigning its value to y.
I think what you are looking for is some fancy ES7 syntax:
var myVal = (async () => {
var data = await utility.fetchInfo();
return data;
})();
(async () => {
console.log(await myVal);
})();
Keep in mind console.log(myVal) will end up with Promise { <pending> }, So instead you would use
(async () => {
console.log(await myVal);
})();
which would return your desired output.

How to get `this` in jest mock function

I have the below code, which mocks a function fetchAge of Person. I need to conditionally return a value based on the value of this, but this is an empty object in the function. Is there any way to do this in Jest?
jest.unmock('Person');
const Person = require('Person');
Query.prototype.fetchAge = jest.fn(() => {
console.log(this); // this returns an empty object
if(this.name === 'Bob') return 21;
if(this.name === 'Joe') return 19;
});
test('verify correct ages', function() {
const bob = new Person('Bob');
expect(bob.fetchAge).toEqual(21);
});
If you don't need to assert anything on the mocked fetchAge method (like fetchAge.mock.calls.length for example) you could simply assign the fetchAge method to a new function without using jest.fn.
E.g.
Query.prototype.fetchAge = () => {
console.log(this); // this returns an empty object
if(this.name === 'Bob') return 21;
if(this.name === 'Joe') return 19;
};
I think that way this will relate to the correct object (here bob).

Resources