Expo React Native watchPositionAsync fires multiple times - reactjs

I am using watchPositionAsync to get the location of the user and update the state, this works fine but when the app is in the background and re-opened, it seems to fire multiple times causing my screen to refresh, it also ignored the 10 second interval.
Is there any way to fix this? It seems to be a problem on Android and iOS
async componentDidMount() {
this._getlocation();
}
_getlocation = async () => {
const { status } = await Permissions.askAsync(Permissions.LOCATION)
this.watchLocation = await Location.watchPositionAsync(
{
distanceInterval: 15,
accuracy:6,
timeInterval: 10000
},
location => {
let coords = location.coords;
this.setState({userLocation: location})
this.fetchItems();
},
error => console.log(error)
);
}

Try to add "isRunning: false" to the component state and try to use the following edition:
async componentDidMount() {
if(this.state.isRunning === false) { // <----- ADDED ------------------------
this._getlocation();
}
}
_getlocation = async () => {
const { status } = await Permissions.askAsync(Permissions.LOCATION);
this.setState({ isRunning: true }); // <----- ADDED ------------------------
this.watchLocation = await Location.watchPositionAsync(
{
distanceInterval: 15,
accuracy:6,
timeInterval: 10000
},
location => {
let coords = location.coords;
this.setState({userLocation: location})
this.fetchItems();
},
error => console.log(error)
);
}

Related

Wrong value of state displayed after refreshing a page from useEffect()

I have a problem with my page that fetch data from a server and displays it for the user. I am using the hook useEffect for it.
My problem is that the first time I visit a page the correct data are displayed (so from /home I go to /product1 I get correct information). But after manually refreshing my page /product1 even though the server is getting the correct information again, my state object of my page will not update again. Is there a way to fix this? Code below:
const [productInfo, setProductInfo] = useState({
saleStarted : null,
quantityPerSize : []
})
useEffect(() => {
const fetchdata = async () => {
setLoading(true);
const query = new db.Query('Products');
query.equalTo('productId', params.productId);
await query.find()
.then(async (response) => {
setdata(response[0].attributes);
})
.catch((err) => {
setError(err);
console.log(err);
})
.finally(() => {
setLoading(false);
});
}
if(isInitialized){
fetchdata();
}
}, [isInitialized]);
useEffect(() => {
const saleStartedInfo = async() => {
const options = {
link : url + params.contractId,
}
try{
let started = await db.find(options)
console.log(started); //returns true
setProductInfo({...productInfo, saleStarted : started});
}catch(e){
console.log(e);
}
}
const quantitySize = async() => {
let _quantityBySize = [];
for(let k = 0 ;k<data.numberOfSize;k++) {
let options = {
address : url + params.contractId,
}
try{
let quantitySize = await db.find(options);
_quantityBySize.push(quantitySize)
} catch(err) {
console.log(err);
}
}
console.log(_quantityBySize); // let's say returns [5,4,10] if product has 3 size
setContractInfo({...contractInfo, quantityPerSize : _quantityBySize})
}
if(isInitialized && data){
saleStartedInfo();
quantityMinted();
}
}, [data])
So after rendering this page the first time it will show sale started, and quantity 5, 4 and 10. After refresh it will show sale not started and quantity === [] (empty array)

Can't seem to get test coverage for a setTimeout action dispatched inside of an useEffect

I'm having an issue getting test coverage for a react action dispatch with window.setTimeout() the test passes with done() but it doesn't actually provide any coverage for the istanbul coverage. I tried a few things but nothing has worked so far. Anyone familiar with testing this? I've also tried using lolex instead to mock the time instead of using window.setTimeout() but it fails saying getBrSeoData was never called.
This is my code
useEffect(() => {
if (!Config.ui.isBot) {
window.setTimeout(() => {
getBrSeoData(productType, productId, productName, productStatus);
}, BR_DELAY);
}
}, [getBrSeoData, productType, productId, productName, productStatus]);
This is the test
it("should make the blooomreach api call if !Config.ui.isBot", done => {
const BR_DELAY = 6000;
const response = {
status: "SUCCESS",
payload: {
"related-item": bloomreachState["related-item"],
"related-category": [],
"more-results": []
}
};
props = {
relatedSearches: bloomreachState["related-item"],
relatedCategories: bloomreachState["related-category"],
relatedProducts: bloomreachState["more-results"],
getBrSeoData: sinon.spy(() => new Promise(resolve => resolve({ response })))
};
Config.ui.isBot = false;
component = render(<BloomreachSeo {...props} />);
window.setTimeout(() => {
expect(props.getBrSeoData).to.have.been.calledOnce;
}, BR_DELAY);
done();
});
Istanbul showing no coverage for the line
I was able to get it working by using the npm package lolex. If anyone has issues with it using react testing library along with testing a window.setTimeout()
let clock;
beforeEach(() => {
clock = lolex.install({ now: 4476701471000, toFake: ["setTimeout"] });
});
afterEach(() => {
clock.uninstall();
});
it("should make the bloomreach api call if !Config.ui.isBot", () => {
const BR_DELAY = 5000;
const response = {
status: "SUCCESS",
payload: {
"related-item": bloomreachState["related-item"],
"related-category": [],
"more-results": []
}
};
props = {
relatedSearches: bloomreachState["related-item"],
relatedCategories: bloomreachState["related-category"],
relatedProducts: bloomreachState["more-results"],
getBrSeoData: sinon.spy(() => new Promise(resolve => resolve({ response })))
};
Config.ui.isBot = false;
component = render(<BloomreachSeo {...props} />);
clock.tick(BR_DELAY);
clock.setTimeout(() => {
expect(props.getBrSeoData).to.have.been.called;
}, BR_DELAY);
});

this discord.js event doesn't work needs adaptation

I was wanting to adapt this code to work within my discord.js bot project.
As an event, it starts as soon as the bot comes online, but this way it isn't coming online, not even a console.log returns a log about that event.
this code below would have to run inside this event code.
and all my events start from a:
client.on("ready", () => { // event of my project starts like this
// code
});
module.exports = class {
constructor(client) {
this.client = client;
}
async run() {
this.client.on("ready", async () => {
await this.VipFilter();
});
}
async VipFilter() {
setInterval(async () => {
const list_vips = await require("mongoose")
.connection.collection("users")
.find({ "vip.date": { $gt: 1 } })
.toArray();
const filter_members = Object.entries(list_vips).filter(
([, x]) => x.vip.date <= Date.now()
);
const VIPS = filter_members.map(([, x]) => x.idU);
await this.VipRemove(VIPS);
}, 60000);
}
async VipRemove(VIPS) {
let totalPessoas = VIPS.length;
let size = 0;
const interval = setInterval(async () => {
if (totalPessoas <= 0) clearInterval(interval);
else {
let members = VIPS[size++];
const user = await this.client.users.fetch(members);
await this.client.database.users.findOneAndUpdate(
{ idU: user.id },
{ $set: { "vip.date": 0, "vip.hasVip": false } }
);
}
totalPessoas--;
}, 5000);
}
}; ```

UseEffect not returning response onMount

I am running a test on page load and refresh. It is working well but the test is returning 0;
below is my code;
useEffect(() => {
setLoading(true);
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(getPosition);
} else {
setError("Your browser doesn't support geolocation");
}
const fetchLocations = async () => {
if(currentPos.latitude!==undefined && currentPos.longitude!==undefined) {
try {
const response = await instance
.get("/explore", {
params: {
ll: `${currentPos.latitude},${currentPos.longitude}`
}
})
console.log(response.data.response.groups[0].items);
setLocations(response.data.response.groups[0].items);
setError('')
setLoading(false)
} catch (error) {
setError('Error getting data');
setLoading(false)
}
}
}
fetchLocations()
}, [currentPos.latitude, currentPos.longitude]);
and my test:
What is happening here is on first mount loading... is available. On fetching data from the API is expected toHaveBeenCalledTimes to be 1 instead of returning 0.
it("renders location venues on currentlocation ", async () => {
const {getByText, container} = render(<Venues />);
getByText('Loading...')
await axiosMock.get.mockResolvedValueOnce(() =>
Promise.resolve({ data: {response } })
)
expect(axiosMock.get).toHaveBeenCalledTimes(0)
await waitForElement(() =>
container,
expect(axiosMock.get).toHaveBeenCalledTimes(1)
);
});
How can I fix this test and make it work properly?

How to cover Promise.all(...) statement with unit test

I cannot write a test that covers Promise.all() statement within a asynchronous function (loadMessages()) that is ran in setTimeout() block of componentDidMount method.
In componentDidMount there is this.loadMessages() function that is called within setTimeout callback, in order for me to complete my test i need loadMessages() executed.
componentDidMount() {
const { conversationId } = this.state
const POLLING_INTERVAL = 3000
if (conversationId) {
setTimeout(() => this.loadMessages(), 0)
this.timer = setInterval(() => this.loadMessages(), POLLING_INTERVAL)
} else {
this.setState({ loading: false })
}
}
I resolved setTimeout callback with
await new Promise(resolve =>
setTimeout(() => {
resolve()
}, 3000)
)
and that solves a function call, but when start executing a function the report coverage is saying that Promise.all is not covered and function itself looks like:
async loadMessages() {
const { messages, conversationId, errors } = this.state
let messagesWithAuthors
// initial load
if (messages.length === 0) {
try {
let initialMessages = await runtime.dais.communication.auto.getMessagesByConversationId(
conversationId
)
const messageAuthors = await Promise.all(
initialMessages.map(async message =>
//runtime.dais.orgService.auto.getPersonById(message.sender.id)
runtime.dais.organization.auto.getPersonById(message.sender.id)
)
)
messagesWithAuthors = initialMessages.map((message, i) => ({
...message,
author: messageAuthors[i],
}))
this.setState({
messages: messagesWithAuthors,
messageAuthors,
loading: false,
})
} catch (error) {
this.setState({ errors: [...errors, error], hasErrors: true, modalOpen: true })
}
} else {
let updatedMessages = await runtime.dais.communication.auto.getMessagesByConversationId(
conversationId
)
this.checkIfNeedUpdate(updatedMessages)
}
}
is there some way to mock a values that are returned from Promise.all() into messageAuthors variable?
I am testing using #testing-library/react and my test looks like this
it('ensure that we have chat window shown if we have conversation as a prop', async () => {
const queries = render(
<CommWidget runtime={runtime} conversationId="fe3d52fc-ffb3-482a-aedf-79000645ca70" />
)
await new Promise(resolve =>
setTimeout(() => {
resolve()
}, 3000)
)
const commWidget = queries.container.querySelector(
'.ui-comm-widget .ui.segments.comm-widget #chat-window'
)
expect(commWidget).toBeInstanceOf(HTMLDivElement)
})
Please don't put a timeout in your tests that's an anti-pattern. What happens after the promise resolves? Is the page going to change? If so wait for the change to appear. See this article for an introduction on testing async methods.

Resources