triniwiz / nativescript-stripe

Apache License 2.0
49 stars 34 forks source link

Error: Cannot read property 'toLowerCase' of undefined #121

Closed Stanteq closed 4 years ago

Stanteq commented 4 years ago

For a while I got this error when I try to access card information from a fresh created paymentMethod on Android

this.stripe.createPaymentMethod(cardView.card, (error, pm) => {
   if (error) return;
   console.log(pm.id) // -> OK
   console.log(pm.card) // Error:  Cannot read property 'toLowerCase' of undefined
    });

Full Error log:

JS: ERROR Error: Uncaught (in promise): TypeError: Cannot read property 'toLowerCase' of undefined
JS: TypeError: Cannot read property 'toLowerCase' of undefined
JS:     at toCardBrand (file: node_modules/nativescript-stripe/stripe.android.js:424:0)
JS:     at Function.push.../node_modules/nativescript-stripe/stripe.js.Card.fromNativePaymentMethod (file: node_modules/nativescript-stripe/stripe.android.js:243:0)
JS:     at PaymentMethod.get [as card] (file: node_modules/nativescript-stripe/stripe.android.js:538:26)
RobertGardner commented 4 years ago

I'm not able to reproduce this. I can see in the code where it's not checking for undefined but if I just do the check I may be hiding the root cause of the error.

Could you let me know what version of the plugin you are using and what credit card number you are providing? At this point in the code it is looking up the brand. Apparently the Stripe SDK is returning undefined for the brand. I'm not sure which credit cards it does that for. It doesn't do it for any of the ones I've tried.

Stanteq commented 4 years ago

@RobertGardner, I use the plugin very intensively so the error shows after updating to the latest version 6.6.1 (I tried with 4242424242424242 and 4000002500003155). After downgrading to previous one (forced to 6.6.0), it worked as expected.

p.s. I tested few times by switching the versions, it seems that the latest one has this problem. I see in changelog for 6.6.1 it was changed something about that.


Another question about paymentMethods (I will try to ask here and not creating another issue) On card creation I can't populate the billing_details.name (there is no such property). The only available one is just name

      const card: Card = cardView.card;
      card.name = "my name";

It's possible to add a billing_details property in the future? Thx.

RobertGardner commented 4 years ago

First, about Card billing details. There is no billing_details field on Stripe's Card object. The Android/iOS API Card is a representation of the Stripe API's Card (Stripe API is the communication protocol to the Stripe servers). (The plugin Card is just a wrapper around the Stripe Android/iOS Card.) All the address_ fields on Card are for the billing address. I guess Stripe assumes that the cardholder name will be the same as the billing address name. billing_details are stored on the PaymentMethod, so you may be able to store the name there instead. Alternatively, if you need it, I could expose the Stripe Card's metadata field, which was added recently, and you could store it there.


For the crash, since I can't reproduce it, you could stick with v6.6.0 until I get a diagnosis and fix in place. Stopping the crash is easy, but then it will return Unknown as the brand for all cards for you, unless I can figure out why it crashes for you and not for me. (To stop the crash, guard the switch statements in toCardBrand and fixupCardBrand with checks to if (brand).

Since I can't reproduce the crash, I could use your help. I'm developing on a Mac and use the Android simulator. I don't own a physical Android device. Stripe has started converting their entire Android SDK to Kotlin, and there are some bugs in {NS} support for Kotlin. (I filed this bug with NS but there has been no activity at all on it.)

The fact that you are having problems and I'm not makes me wonder if the Kotlin problems are only happening on the Mac Android simulator, or maybe my workaround behaves differently on the Mac simulator and other environments. I could use some help debugging that to provide more info to NS on the bug. If you are willing/able to help, please do the following:

Another piece of data that would be interesting is to know what the plugin's Card.brand returns in v6.6.0. I'm guessing it is undefined. It should be visa for the 4242... card. (In v6.6.1 I fixed it to return the correct value, Visa.)

Stanteq commented 4 years ago

@RobertGardner, Thx for the guiding. I debugged the code it's all fine except one thing:

when you populate the _brand you call this function: toCardBrand()

newCard._brand = toCardBrand(pmCard.component1());

After, inside the switch/case you have:

...
case com.stripe.android.model.Card.CardBrand.VISA.toLowerCase()
...

where: com.stripe.android.model.Card.CardBrand.VISA is undefined for me and it's crash which is very strange why I don't have access to the Card brands enums.

I use the same environment: Mac/Android simulator and device.


About billing_details yes you're right, I intended the property of paymentMethod which is creating like this:

this.stripe.createPaymentMethod(cardView.card, ...)

I wanted that paymentMethod ID which is returning in callback to contain (to have attached) already the billing_details.name (name on the card)

But I'm not sure If it's possible or this is a right question.

I ask because I observed after It's attached to the customer the payment method has billing_details property empty (so, I need to populate it manually in backend after I pass it).

RobertGardner commented 4 years ago

That's a very different problem than I thought it was. I have no idea why your environment would have those values undefined and mine does not. I assume you've tried deleting your platforms folder and rebuilding? That should force the Stripe SDK to be re-downloded.

The fix for this is pretty easy (I'll just hard-code the values that are in the SDK). Since it will work and won't introduce any other strangeness, I'll do that. I should have it deployed tomorrow.

I'm still suspicious that this is caused by bugs in {NS}'s Kotlin integration.

Stanteq commented 4 years ago

Yep, very strange. I can confirm that on version switch I delete node_modules and platform and download it again. On previous version (6.6.0) com.stripe.android.model.Card.CardBrand.VISA is undefined too but it's not called when card data is populated.

Maybe someone else at least can confirm the same problem with v.6.6.1 to be sure I'm not the only one ))

RobertGardner commented 4 years ago

Fixed in v6.6.2