I planned updating some Promise.all to Promise.allSettled in my React Native - Expo Project but the function does not Exist. i checked all Versions and everything fits but i still cant use the function.
node -v: 14.15.4
expo SDK -v version: ^40.0.1
expo uses react native -v 0.63 in their SDK version. This should not be the problem. This is the error message:
Promise.allSettled is not a function
Does anybody knows a solution to this? Thank you for your help!
For anyone coming across this issue, apparently this was fixed in v64:
https://github.com/facebook/react-native/issues/30236#issuecomment-939286987
For older versions, you can use a simple polyfill:
Promise.allSettled = Promise.allSettled || ((promises) => Promise.all(
promises.map(p => p
.then(value => ({
status: "fulfilled",
value
}))
.catch(reason => ({
status: "rejected",
reason
}))
)
));
React Native uses https://github.com/then/promise for Promises and only in version 8.2.0 it was added with allSettled.
React Ntaive team updated to this version only in 0.70.6 (here list of changes including promise version bumping to 8.3.0 https://github.com/facebook/react-native/releases/tag/v0.70.6)
export const PromiseHelperAllSettled = (promises) => {
return Promise.all(promises.map(function (promise) {
return promise.then(function (value) {
return { state: 'fulfilled', value: value };
}).catch(function (reason) {
return { state: 'rejected', reason: reason };
});
}));
};
import { PromiseHelperAllSettled } from './PromiseHelperAllSettled';
useEffect(() => {
if (Promise && !Promise.allSettled) {
Promise.allSettled = PromiseHelperAllSettled;
}
},[]);
Related
I want to configure a custom login command in which I have to make a signIn call which returns a promise.
commands.js:
Cypress.Commands.add("login", () => {
AuthLib.signIn(username, password).then((data) => {
cy.setLocalStorage("accessToken", data.accessToken);
});
AuthLib.signIn() returns a promise.
Then I want to use this command in an before block:
before(() => {
cy.login();
cy.saveLocalStorage();
});
I notice that the promise is not resolved.
A 'hacky' fix would be to add cy.wait(4000) between login() and saveLocalStorage().
But that makes my test depend on the loading time of the auth server
I found this 'related' issue: Cypress.io How to handle async code where https://www.npmjs.com/package/cypress-promise is referred. But this library cannot be used in before or beforeEach
How can I await the promise returned from login() / make sure the promise from login() is resolved before doing cy.saveLocalStorage()?
Update
I added the examples of what works and does not work in : https://github.com/Nxtra/Cypress-Amplify-Auth-Example/blob/main/cypress/support/commands.js
A solution would be to start with cy.then():
Cypress.Commands.add("login", () => {
cy.then(() => AuthLib.signIn(username, password)).then((data) => {
cy.setLocalStorage("accessToken", data.accessToken);
});
Make sure that you return that promise inside Cypress.Commands.add callback.
It's a bit confusing to deal with promises in Cypress context, since a lot of async behavior is magically handled within cy. commands.
Cypress.Commands.add("login", () => {
return AuthLib.signIn(username, password).then((data) => {
cy.setLocalStorage("accessToken", data.accessToken);
});
});
Other solution:
Cypress.Commands.add("login", () => {
return AuthLib.signIn(username, password);
});
before(() => {
cy.login();
cy.setLocalStorage("accessToken", data.accessToken);
});
I have an action that uses Promise.allSettled to return multiple stat objects from an API.
When I run the tests with mocking I get the error
Promise.allSettled is not a function
I have a get endpoint to returns different types of stats.
myapi.com/get_stats/:type
I have an action for this API as follows
const types = ['seo', 'referrers', 'clicks', 'posts', 'videos'];
const promises = [];
types.forEach(type =>
promises.push(
api().stats.getStats(type),
),
);
Promise.allSettled(promises).then(res => {
const { statData, statErrors } = mapData(res); // Data manipulation
dispatch({ type: FETCH_STATS_RESOLVED, payload: { statData, statErrors } });
});
My Test set up
jest.mock('api-file.js', () => ({
api: () => ({
stats: {
getStats: type => {
switch (type) {
case: 'seo':
return mockSeoStats;
}
}
}
})
}));
in beforeEach()
mockSeoStats.mockImplementation(() => Promise.resolve({ value: {data: myData} }));
I can see that the Action is receiving these mocked values, but Promise.allSettled is complaining
I assume it's having a hard time with the jest mock structure
So, how can i mock Promise.allSettled to just return what I expect it to, instead of looking at my mocked functions?
A similar question was asked at Execute batch of promise with Promise.allSettled()
Promise.allSettled is available from Node version 12.0 +
You can update node using Node's version manager
nvm ls
# Look for a 12.17.0 version (latest)
nvm install 12.17.0
# Automatically switches to new version
npm run test
# Should properly run your Promise.all
Hope that helped.
Try wrapping Promise.allSettled in try-catch block if you don't want to update node js.
Example:
try {
Promise.allSettled([
// your code
]).finally(() => {
// your code`enter code here`
});
} catch (e) {
console.log('promise.allSettled', e);
}
As mentioned in my previous question about mocking, I am new to Jest and testing and I seem to be getting some curveballs.
This time around I am having trouble mocking shelljs in my CLI application.
Automocking jest.mock('shelljs'); didn't work and errored as:[TypeError: shell.exec is not a function]
So I went ahead and tried to use mockImplementation()
jest.mock('shelljs', () => {
return jest.fn().mockImplementation(() => {
return {
exec: () => {}
};
});
});
To my surprise I am still getting the same error message
Any pointers would be much apprecieted.
UPDATE 08/04/2020:
As per Teneff's reply below, the mocking works fine with:
jest.mock('shelljs', () => {
return {
exec: jest.fn()
};
});
Now I'm getting timeouts as my call of shell.exec() is async and have a callback that resolves my promise.
My goal is to mock shell.exec() to just resolve the promise, but it goes into waiting around and Jest times out.
Taking onboard Teneff's answer I realised that the timeout happens, because I mocked shell.exec successfully however I have used it's async version exec(command [, options] [, callback]) so I tried first logging out the arguments and it worked.
All was left to do to call the callback and voila, my test works.
jest.mock('shelljs', () => {
return {
exec: jest.fn((_, __, callback) => callback())
};
});
As you're using shell as an object with .exec property your jest.mock factory function should return an object with exec property
jest.mock('shelljs', () => {
return { exec: jest.fn() }
});
Teneff answer worked for me.
But as I wanted to mock different shell responses I improved it like that :
const shelljs = require('shelljs');
jest.mock('shelljs');
describe('Run the test suite', () => {
test('it should ...', async () => {
shelljs.exec = jest.fn().mockImplementation(() => ({ code: 0 }));
...
expect(...);
});
test('it should ...', async () => {
shelljs.exec = jest.fn().mockImplementation(() => ({ code: 1 }));
...
expect(...);
});
});
I have a problem that I can't understand and I was hoping that someone could help me with.
This is my test: state.messages is an empty array and api.botReply is called 0 times when it is in the function to be ran.
state.typing is set to true so I know I run the function.
test('test to resolve data from botReply', done => {
const wrapper = shallow(<Bot />);
api.botReply = jest.fn(() =>
Promise.resolve(wrapper.setState({ typing: false }))
);
wrapper.instance().sendReply();
setImmediate(() => {
wrapper.update();
console.log(wrapper.state('typing'));
console.log(wrapper.state('messages'));
expect(api.botReply).toHaveBeenCalledTimes(1);
done();
});
});
And this is the function that is run:
sendReply = () => {
this.setState({ typing: true });
api.botReply()
.then(reply => {
this.setState({ messages: [...this.state.messages, reply], typing: false });
})
};
Discarding promise chains and using random delays can lead to race conditions like this one.
Since a promise is provided in tests, it should be chained to maintain correct control flow. It's not a good practice to assign Jest spies as methods because they won't be cleaned up afterwards. A promise is supposed to resolve with reply, not set state.
It should be something like:
test('test to resolve data from botReply', async () => {
const wrapper = shallow(<Bot />);
const promise = Promise.resolve('reply')'
jest.spyOn(api, 'botReply').mockImplementation(() => promise);
wrapper.instance().sendReply();
expect(wrapper.state('typing')).toBe(true);
await promise;
expect(api.botReply).toHaveBeenCalledTimes(1);
expect(wrapper.state('typing')).toBe(false);
});
I'm trying to use node-geocoder npm package to get latitude and longitude of position some objects.
Could you help me please to understand JavaScript promises.
Here is an example code:
import nodeGeocoder from 'node-geocoder'
function getLocation (str) {
// Selecting Google as provider
const geocoder = nodeGeocoder({
provider: 'google',
})
return geocoder.geocode(str)
.then(response => {
// I want to return latitude an longitude
return [response[0].latitude, response[0].longitude]
})
.catch(error => {
console.log(`Geocoder Error: ${ error }`)
})
}
export default getLocation
So. This is a test (Jest framework):
import getLocation from './index'
test('Checking', () => {
expect(getLocation('29 champs elysée paris')).toEqual([48.8698679, 2.3072976])
})
When I'm trying to use this test I just get promise status {"fulfillmentValue": undefined, "isFulfilled": false, "isRejected": false, "rejectionReason": undefined}.
But I need to get just promise resolved result. How can I do it?
I don't want to edit test
For testing, most test suites offer an async callback for all your promise based tests. I would expect it (pun intended) to work like this:
import getLocation from './index'
test('Checking', (done) => {
getLocation('29 champs elysée paris').then(geoData => {
expect(geoData).toEqual([48.8698679, 2.3072976]);
done();
}).catch(error => {
done(error)
});
});
Depending on the testing framework you might be using, the way you call the resolver callback (i.e: done()) can change. However, the pattern should more or less be the same.