React Native: RNIap.getPurchaseHistory().then runs infinately - ios

The project is at this Github Repository. The file with the code is at components/Soundboard.js
This code was working previously, but now it looks like the promise is running forever. It looks like neither the resolve function, nor the reject function are executing because if I uncomment all the commented lines below and call the function askForPurchase() the only things printed to the console are
an object that looks like "_40": 0, "_55": {"_40": 0, "_55": null, "_65": 0, "_72": null}, "_65": 3, "_72": null} for the line console.log(RNIap.getPurchaseHistory())
and then the word end.
The buyProduct() function also is no longer initializing an IAP.
const buyProduct = function(){
RNIap.requestPurchase("1985162691", false).then(purchase => {
store.dispatch(setPurchases(purchase))
await RNIap.finishTransaction(purchase, false) //developerPayloadAndroid?: string Should I use this argument? I don't get how to use it
}).catch((error) => {
console.log(error.message);
})
}
const askForPurchase = function(){
if (!store.getState().purchase){
//console.log(RNIap.getPurchaseHistory())
RNIap.getPurchaseHistory().then(purchase => {
//console.log(`test1`)
store.dispatch(setPurchases(purchase))
if (purchase.length == 0){
//console.log(`test if`)
buyProduct()
}else{
//console.log(`test else`)
RNIap.getAvailablePurchases()
}
}, reason => {
console.log(reason)
})
//console.log(`end`)
}
}
EXTRA
This code was working a few months ago and I even pulled a commit(1b9cb81f229680e173ce910892dddedc632c1651, comment: "Made the seal pic more cartoony") from that time to test out. After pulling this commit, I deleted my node_modules and pods, and cleaned my build folder, but the askForPurchase() and buyProduct() functions no longer work in that commit either.
I am testing this on a real iPhone SE running ios 13.6.1
I created a sandbox tester if you need to test it out, but I don't think you'll need it
email: rniapsandbox#gmail.com
pw: Somepassword1

hello #Sam problem is async await problem they are not able to get value because they are not waiting to get data before getting data its firing without data and it was returning promise so you have to use async function
so your code be like
const buyProduct = async()=>{
await RNIap.requestPurchase("1985162691", false).then(purchase => {
store.dispatch(setPurchases(purchase))
await RNIap.finishTransaction(purchase, false) //developerPayloadAndroid?: string Should I use this argument? I don't get how to use it
}).catch((error) => {
console.log(error.message);
})}
const askForPurchase = async()=>{
if (!store.getState().purchase){
//console.log(await RNIap.getPurchaseHistory())
await RNIap.getPurchaseHistory().then(purchase => {
//console.log(`test1`)
store.dispatch(setPurchases(purchase))
if (purchase.length == 0){
//console.log(`test if`)
buyProduct()
}else{
//console.log(`test else`)
RNIap.getAvailablePurchases()
}
}, reason => {
console.log(reason)
})
//console.log(`end`)
}}

You will need to change from
console.log(RNIap.getPurchaseHistory())
to
console.log(await RNIap.getPurchaseHistory())

Related

Cypress: Is it possible to complete a test after failure

Overview
I want to automatically test all 200 pages of our website every week after the update to see if the update broke any of them
The test case
Login and go to the sitemap
Get the URLs and check each for their HTTP status
The code
it('check HTTP status', () => {
cy.visit(Cypress.config('siteMapUrl'))
cy.get('.portlet-separator').should('contain', 'Available Links')
cy.get('.inputwrapper>a')
.each(($el, index, $list) => {
if($list){
cy.get($el)
.invoke('attr', 'href')
.then(href => {
cy.request(Cypress.config('url')+href)
.should('have.property', 'status', 200)
})
}
})
What happens:
Once an URL returns anything else than status 200 the test fails.
What I would like:
I would like Cypress to iterate through the complete list of URLs before returning the URLs that failed.
Why?
If more than one URL in the list is broken, I will not find the 2nd broken URL with this test until our devs have fixed the first one. Yet I need to produce a list with all broken URLs at the beginning of the week
I have already seen this answer but I would like to know if there is a different solution before I try to implement this
You should not use .should() after each URL - that will fail immediately, even if setting failOnStatus: false.
Instead save the results and check at the end.
const failed = []
cy.get(".inputwrapper>a").each(($el, index, $list) => {
cy.get($el)
.invoke("attr", "href")
.then((href) => {
cy.request({
url: Cypress.config("url") + href,
failOnStatusCode: false,
})
.its('status')
.then(status => {
if (status !== 200) {
failed.push(href)
}
})
})
}
})
.then(() => {
// check inside then to ensure loop has finished
cy.log(`Failed links: `${failed.join(', ')`)
expect(failed.length).to.eq(0)
})

trying to store image as base64 and using it

I have a block of code that I found online and it seems to be working and not working at the same time. I think its probably my lack of understanding but I cant seem to get it to work the way I want it.
selectPicture() {
let context = imagepicker.create({
mode: "single" // use "multiple" for multiple selection
});
var imageBase64
context
.authorize()
.then(function() {
return context.present();
})
.then(function(selection) {
selection.forEach(function(selected) {
imageSourceModule.fromAsset(selected).then((imageSource) => {
imageBase64 = imageSource.toBase64String("jpg",60);
console.log("Image saved successfully!")
console.log(imageBase64)
console.log("test test") //runs fine
this.image = "~/assets/images/account/camera.png" //cant seem to run
console.log("test test 2")
}).catch(function (e) {
// process error
console.log("got error 1")
});
})
}).catch(function (e) {
// process error
console.log("got error 2")
});
},
Within the imageSourceModule.fromAsset(selected).then((imageSource), I was trying to save the base64 info in another variable but cant seem to do anything within other than console log a string. When I run this.image = "~/assets/images/account/camera.png" (just a placeholder, even calling a method does not work too) for example it catches an error.
What could the problem be? thank you!
UPDATE
I changed console.log("got error 1") to log the actual update and what i got was:
undefined is not an object (evaluating 'this.image = "~/assets/images/account/camera.png"')*
I now think that theres a problem with my understanding calling variable outside. My variable 'image' is within the script at
data() {
return {
image : ""
}
}
first of all check what this variable is, because you do not use es6 arrow functions, so this is probably not the vue instance.
the second thing: when you change vue-variables asynchronously use the $set method, like: this.$set(this, 'image', '~/assets/images/account/camera.png')

Fetch not working on react native when run on Expo from iphone

So it's actually been on and off the past few days, the fetch function for POST method (for login purposes) on my app would suddenly stop working when I'm not even making any changes to the code.
I spent hrs tracking down the bug the first time this happened but realized that the code is still running fine on Android simulator that I run from Android studio.
This problem only happens on my iphone device when I run the code via expo.
is there any sort of convention on how to tackle this issue?
I've been googling for a few days now but no one forum actually agreed on a solution, some works but says it's unstable and some just doesn't work.
I'm pretty new to expo, react native, and everything in general, so please enlighten me using "english" lol
EDIT: since I was asked about the code, here it is, I hope it helps:
export function login(user, callback){
var endpoint = "oauth/token";
const { username, password } = user;
//from https://scotch.io/tutorials/how-to-encode-and-decode-strings-with-base64-in-javascript
var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(e){var t="";var n,r,i,s,o,u,a;var f=0;e=Base64._utf8_encode(e);while(f<e.length){n=e.charCodeAt(f++);r=e.charCodeAt(f++);i=e.charCodeAt(f++);s=n>>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+this._keyStr.charAt(s)+this._keyStr.charAt(o)+this._keyStr.charAt(u)+this._keyStr.charAt(a)}return t},decode:function(e){var t="";var n,r,i;var s,o,u,a;var f=0;e=e.replace(/[^A-Za-z0-9+/=]/g,"");while(f<e.length){s=this._keyStr.indexOf(e.charAt(f++));o=this._keyStr.indexOf(e.charAt(f++));u=this._keyStr.indexOf(e.charAt(f++));a=this._keyStr.indexOf(e.charAt(f++));n=s<<2|o>>4;r=(o&15)<<4|u>>2;i=(u&3)<<6|a;t=t+String.fromCharCode(n);if(u!=64){t=t+String.fromCharCode(r)}if(a!=64){t=t+String.fromCharCode(i)}}t=Base64._utf8_decode(t);return t},_utf8_encode:function(e){e=e.replace(/\r\n/g,"\n");var t="";for(var n=0;n<e.length;n++){var r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r)}else if(r>127&&r<2048){t+=String.fromCharCode(r>>6|192);t+=String.fromCharCode(r&63|128)}else{t+=String.fromCharCode(r>>12|224);t+=String.fromCharCode(r>>6&63|128);t+=String.fromCharCode(r&63|128)}}return t},_utf8_decode:function(e){var t="";var n=0;var r=c1=c2=0;while(n<e.length){r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r);n++}else if(r>191&&r<224){c2=e.charCodeAt(n+1);t+=String.fromCharCode((r&31)<<6|c2&63);n+=2}else{c2=e.charCodeAt(n+1);c3=e.charCodeAt(n+2);t+=String.fromCharCode((r&15)<<12|(c2&63)<<6|c3&63);n+=3}}return t}};
let header = {
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": ("Basic " + Base64.encode(username+":"+password))
};
let userData = {
"grant_type": "password",
"username": username,
"password": password
};
return fetchAPI(endpoint,'POST', header, userData)
.then((tokenJson) => {
alert("\nAccess Token:\n\n" + tokenJson.access_token + "");
callback(true, {exists : true, token : tokenJson.access_token}, null);
})
.catch((error) => {
alert(error);
callback(false, null, error);
});
}
And here's the fetchAPI function (a generic fetch function) called from that function:
export function fetchAPI(endpoint, method, header, data) {
let url = 'http://10.64.2.149:8081/' + endpoint;
let options = {
method: method,
headers: header,
body: stringify(data) //from qs-stringify package
};
return fetch(url, options)
.then(response => {
return response.json()
.then((json) => { ...//not relevant from this point on
The fetch 'POST' seems to always get stuck at response.json(), it just never resolves until it returns "network request failed". But as I said only happens sometimes when I run it on iphone via expo. It is fine on Android sim.
Thanks! :)

Atomic update of Realtime Database from Google Cloud Functions

I use Google Cloud Functions to create an API endpoint for my users to interact with the Realtime Database.
The problem I have is that I'm not sure how the code works. I have a helper function doSomething that I need to call only once, but I have a suspicion that there are cases where it can be called twice or possibly more (when multiple users call the API at the same time and the update operation hasn't been processed by the DB yet). Is it possible? Does it mean I need to use a transaction method? Thank you!
DB structure
{
somePath: {
someSubPath: null
}
}
Google Cloud Functions code
const functions = require('firebase-functions')
const admin = require('firebase-admin')
const cors = require('cors')({origin: true});
admin.initializeApp(functions.config().firebase)
// API ENDPOINT
exports.test = functions.https.onRequest((req, res) => {
cors(req, res, () => {
admin.database().ref('/somePath/someSubPath').once('value')
.then(snapshot => {
const value = snapshot.val()
if (value) return res.status(400).send({ message: 'doSomethingAlreadyCalled' })
doSomething()
const updates = { '/somePath/someSubPath': true }
return admin.database().ref().update(updates)
.then(() => res.status(200).send({ message: 'OK' }))
})
.catch(error => res.status(400).send({ message: 'updateError' }))
})
})
// HELPERS
const doSomething = () => {
// needs to be called only once
}
I believe you were downvoted due to the above pseudocode not making complete sense and there being no log or output of what your code is actually doing in your question. Not having a complete picture makes it hard for us to help you.
Just Going from your structure in the question, your actual code could be calling twice due to function hoisting. Whenever I have this issue, I’ll go back to the api documentation and try to restructure my code from rereading.
HTH

Wait for future to complete

I use my postgres database query to determine my next action. And I need to wait for the results before I can execute the next line of code. Now my conn.query returns a Future but I can't manage to get it async when I place my code in another function.
main() {
// get the database connection string from the settings.ini in the project root folder
db = getdb();
geturl().then((String url) => print(url));
}
Future geturl() {
connect(db).then((conn) {
conn.query("select trim(url) from crawler.crawls where content IS NULL").toList()
.then((result) { return result[0].toString(); })
.catchError((err) => print('Query error: $err'))
.whenComplete(() {
conn.close();
});
});
}
I just want geturl() to wait for the returned value but whatever I do; it fires immediately. Can anyone point me a of a piece of the docs that explains what I am missing here?
You're not actually returning a Future in geturl currently. You have to actually return the Futures that you use:
Future geturl() {
return connect(db).then((conn) {
return conn.query("select trim(url) from crawler.crawls where content IS NULL").toList()
.then((result) { return result[0].toString(); })
.catchError((err) => print('Query error: $err'))
.whenComplete(() {
conn.close();
});
});
}
To elaborate on John's comment, here's how you'd implement this using async/await. (The async/await feature was added in Dart 1.9)
main() async {
try {
var url = await getUrl();
print(url);
} on Exception catch (ex) {
print('Query error: $ex');
}
}
Future getUrl() async {
// get the database connection string from the settings.ini in the project root folder
db = getdb();
var conn = await connect(db);
try {
var sql = "select trim(url) from crawler.crawls where content IS NULL";
var result = await conn.query(sql).toList();
return result[0].toString();
} finally {
conn.close();
}
}
I prefer, in scenarios with multiple-chained futures (hopefully soon a thing of the past once await comes out), to use a Completer. It works like this:
Future geturl() {
final c = new Completer(); // declare a completer.
connect(db).then((conn) {
conn.query("select trim(url) from crawler.crawls where content IS NULL").toList()
.then((result) {
c.complete(result[0].toString()); // use the completer to return the result instead
})
.catchError((err) => print('Query error: $err'))
.whenComplete(() {
conn.close();
});
});
return c.future; // return the future to the completer instead
}
To answer your 'where are the docs' question: https://www.dartlang.org/docs/tutorials/futures/
You said that you were trying to get your geturl() function to 'wait for the returned value'. A function that returns a Future (as in the example in the previous answer) will execute and return immediately, it will not wait. In fact that is precisely what Futures are for, to avoid code doing nothing or 'blocking' while waiting for data to arrive or an external process to finish.
The key thing to understand is that when the interpreter gets to a call to then() or 'catchError()' on a Future, it does not execute the code inside, it puts it aside to be executed later when the future 'completes', and then just keeps right on executing any following code.
In other words, when using Futures in Dart you are setting up chunks of code that will be executed non-linearly.

Resources