From c5cd4fbc6f15a13aba084d165383d2dacb61fb30 Mon Sep 17 00:00:00 2001 From: Dan Jackson Date: Wed, 8 Nov 2017 10:27:19 -0800 Subject: [PATCH 1/6] Adding STPAddress `containsContent...ForFields:` methods to check for any useful data These are like an `isEmpty` check for the address, but they check the fields needed for a particular billing or shipping address setting. This addresses #831, which was introduced when `STPShippingAddressViewController.billingAddress` started receiving an empty STPAddress from STPCard instead of a nil one. I had trouble deciding on the semantics of `containsContentForFields: .None` (should it return true or false?). I chose to always return NO. If the question is "Does this address have useful data for me, and I'm interested in none of the data from this address?", then false/NO makes sense. It also parallels with the behavior when messaging nil. Unit tests to come, and I'm not in love with the method names. --- Stripe/PublicHeaders/STPAddress.h | 34 ++++++++++++++++++++++ Stripe/STPAddCardViewController.m | 7 +++-- Stripe/STPAddress.m | 35 +++++++++++++++++++++++ Stripe/STPShippingAddressViewController.m | 7 +++-- 4 files changed, 79 insertions(+), 4 deletions(-) diff --git a/Stripe/PublicHeaders/STPAddress.h b/Stripe/PublicHeaders/STPAddress.h index d62193db919..3d7c3163f3a 100644 --- a/Stripe/PublicHeaders/STPAddress.h +++ b/Stripe/PublicHeaders/STPAddress.h @@ -166,6 +166,24 @@ typedef NS_ENUM(NSUInteger, STPBillingAddressFields) { */ - (BOOL)containsRequiredFields:(STPBillingAddressFields)requiredFields; +/** + Checks if this STPAddress has any content (possibly invalid) in any of the + desired billing address fields. + + Where `containsRequiredFields:` validates that this STPAddress contains valid data in + all of the required fields, this method checks for the existence of *any* data. + + For example, if `desiredFields` is `STPBillingAddressFieldsZip`, this will check + if the postalCode is empty. + + Note: When `desiredFields == STPBillingAddressFieldsNone`, this method always returns + NO. + + @parameter desiredFields The billing address information the caller is interested in. + @return YES if there is any data in this STPAddress that's relevant for those fields. + */ +- (BOOL)containsContentForFields:(STPBillingAddressFields)desiredFields; + /** Checks if this STPAddress has the level of valid address information required by the passed in setting. @@ -177,6 +195,22 @@ typedef NS_ENUM(NSUInteger, STPBillingAddressFields) { */ - (BOOL)containsRequiredShippingAddressFields:(PKAddressField)requiredFields; +/** + Checks if this STPAddress has any content (possibly invalid) in any of the + desired shipping address fields. + + Where `containsRequiredShippingAddressFields:` validates that this STPAddress + contains valid data in all of the required fields, this method checks for the + existence of *any* data. + + Note: When `desiredFields == PKAddressFieldNone`, this method always returns + NO. + + @parameter desiredFields The shipping address information the caller is interested in. + @return YES if there is any data in this STPAddress that's relevant for those fields. + */ +- (BOOL)containsContentForShippingAddressFields:(PKAddressField)desiredFields; + /** Converts an STPBillingAddressFields enum value into the closest equivalent representation of PKAddressField options diff --git a/Stripe/STPAddCardViewController.m b/Stripe/STPAddCardViewController.m index a54b3175c8b..e8ea9b189d3 100644 --- a/Stripe/STPAddCardViewController.m +++ b/Stripe/STPAddCardViewController.m @@ -145,8 +145,11 @@ - (void)createAndSetupViews { } [addressHeaderView.button addTarget:self action:@selector(useShippingAddress:) forControlEvents:UIControlEventTouchUpInside]; - BOOL needsAddress = self.configuration.requiredBillingAddressFields != STPBillingAddressFieldsNone && !self.addressViewModel.isValid; - BOOL buttonVisible = (needsAddress && self.shippingAddress != nil && !self.hasUsedShippingAddress); + BOOL requiredFields = self.configuration.requiredBillingAddressFields; + BOOL needsAddress = requiredFields != STPBillingAddressFieldsNone && !self.addressViewModel.isValid; + BOOL buttonVisible = (needsAddress && + [self.shippingAddress containsContentForFields:requiredFields] + && !self.hasUsedShippingAddress); addressHeaderView.buttonHidden = !buttonVisible; [addressHeaderView setNeedsLayout]; _addressHeaderView = addressHeaderView; diff --git a/Stripe/STPAddress.m b/Stripe/STPAddress.m index fc723c8c9ff..a978984c8f6 100644 --- a/Stripe/STPAddress.m +++ b/Stripe/STPAddress.m @@ -275,6 +275,19 @@ - (BOOL)containsRequiredFields:(STPBillingAddressFields)requiredFields { return containsFields; } +- (BOOL)containsContentForFields:(STPBillingAddressFields)desiredFields { + switch (desiredFields) { + case STPBillingAddressFieldsNone: + return NO; + case STPBillingAddressFieldsZip: + return self.postalCode.length > 0; + case STPBillingAddressFieldsFull: + return [self hasPartialPostalAddress]; + } + + return NO; +} + - (BOOL)containsRequiredShippingAddressFields:(PKAddressField)requiredFields { BOOL containsFields = YES; if (requiredFields & PKAddressFieldName) { @@ -292,6 +305,13 @@ - (BOOL)containsRequiredShippingAddressFields:(PKAddressField)requiredFields { return containsFields; } +- (BOOL)containsContentForShippingAddressFields:(PKAddressField)desiredFields { + return (((desiredFields & PKAddressFieldName) && self.name.length > 0) + || ((desiredFields & PKAddressFieldEmail) && self.email.length > 0) + || ((desiredFields & PKAddressFieldPhone) && self.phone.length > 0) + || ((desiredFields & PKAddressFieldPostalAddress) && [self hasPartialPostalAddress])); +} + - (BOOL)hasValidPostalAddress { return (self.line1.length > 0 && self.city.length > 0 @@ -301,6 +321,21 @@ - (BOOL)hasValidPostalAddress { countryCode:self.country] == STPCardValidationStateValid)); } +/** + Does this STPAddress contain any data in the postal address fields? + + If they are all empty or nil, returns NO. Even a single character in a + single field will return YES. + */ +- (BOOL)hasPartialPostalAddress { + return (self.line1.length > 0 + || self.line2.length > 0 + || self.city.length > 0 + || self.country.length > 0 + || self.state.length > 0 + || self.postalCode.length > 0); +} + + (PKAddressField)applePayAddressFieldsFromBillingAddressFields:(STPBillingAddressFields)billingAddressFields { FAUXPAS_IGNORED_IN_METHOD(APIAvailability); switch (billingAddressFields) { diff --git a/Stripe/STPShippingAddressViewController.m b/Stripe/STPShippingAddressViewController.m index a6fe42f3b9b..04aed567ae9 100644 --- a/Stripe/STPShippingAddressViewController.m +++ b/Stripe/STPShippingAddressViewController.m @@ -137,8 +137,11 @@ - (void)createAndSetupViews { forState:UIControlStateNormal]; [headerView.button addTarget:self action:@selector(useBillingAddress:) forControlEvents:UIControlEventTouchUpInside]; - BOOL needsAddress = self.configuration.requiredShippingAddressFields & PKAddressFieldPostalAddress && !self.addressViewModel.isValid; - BOOL buttonVisible = (needsAddress && self.billingAddress != nil && !self.hasUsedBillingAddress); + PKAddressField requiredFields = self.configuration.requiredShippingAddressFields; + BOOL needsAddress = requiredFields & PKAddressFieldPostalAddress && !self.addressViewModel.isValid; + BOOL buttonVisible = (needsAddress + && [self.billingAddress containsContentForShippingAddressFields:requiredFields] + && !self.hasUsedBillingAddress); headerView.button.alpha = buttonVisible ? 1 : 0; [headerView setNeedsLayout]; _addressHeaderView = headerView; From 2b0014f1b680a83bf1c60352a7fefae06bc4f3d6 Mon Sep 17 00:00:00 2001 From: Dan Jackson Date: Wed, 8 Nov 2017 13:27:38 -0800 Subject: [PATCH 2/6] Rename containsContentForFields: -> containsContentForBillingAddressFields: --- Stripe/PublicHeaders/STPAddress.h | 2 +- Stripe/STPAddCardViewController.m | 2 +- Stripe/STPAddress.m | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Stripe/PublicHeaders/STPAddress.h b/Stripe/PublicHeaders/STPAddress.h index 3d7c3163f3a..0e720efb473 100644 --- a/Stripe/PublicHeaders/STPAddress.h +++ b/Stripe/PublicHeaders/STPAddress.h @@ -182,7 +182,7 @@ typedef NS_ENUM(NSUInteger, STPBillingAddressFields) { @parameter desiredFields The billing address information the caller is interested in. @return YES if there is any data in this STPAddress that's relevant for those fields. */ -- (BOOL)containsContentForFields:(STPBillingAddressFields)desiredFields; +- (BOOL)containsContentForBillingAddressFields:(STPBillingAddressFields)desiredFields; /** Checks if this STPAddress has the level of valid address information diff --git a/Stripe/STPAddCardViewController.m b/Stripe/STPAddCardViewController.m index e8ea9b189d3..6d674ee1c4c 100644 --- a/Stripe/STPAddCardViewController.m +++ b/Stripe/STPAddCardViewController.m @@ -148,7 +148,7 @@ - (void)createAndSetupViews { BOOL requiredFields = self.configuration.requiredBillingAddressFields; BOOL needsAddress = requiredFields != STPBillingAddressFieldsNone && !self.addressViewModel.isValid; BOOL buttonVisible = (needsAddress && - [self.shippingAddress containsContentForFields:requiredFields] + [self.shippingAddress containsContentForBillingAddressFields:requiredFields] && !self.hasUsedShippingAddress); addressHeaderView.buttonHidden = !buttonVisible; [addressHeaderView setNeedsLayout]; diff --git a/Stripe/STPAddress.m b/Stripe/STPAddress.m index a978984c8f6..b8067716960 100644 --- a/Stripe/STPAddress.m +++ b/Stripe/STPAddress.m @@ -275,7 +275,7 @@ - (BOOL)containsRequiredFields:(STPBillingAddressFields)requiredFields { return containsFields; } -- (BOOL)containsContentForFields:(STPBillingAddressFields)desiredFields { +- (BOOL)containsContentForBillingAddressFields:(STPBillingAddressFields)desiredFields { switch (desiredFields) { case STPBillingAddressFieldsNone: return NO; From bccc42f01db495c266052faff0a3180fe53c03d6 Mon Sep 17 00:00:00 2001 From: Dan Jackson Date: Wed, 8 Nov 2017 13:28:36 -0800 Subject: [PATCH 3/6] Put parens around bitwise AND used in a boolean condition --- Stripe/STPShippingAddressViewController.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Stripe/STPShippingAddressViewController.m b/Stripe/STPShippingAddressViewController.m index 04aed567ae9..91edd9642d0 100644 --- a/Stripe/STPShippingAddressViewController.m +++ b/Stripe/STPShippingAddressViewController.m @@ -138,7 +138,7 @@ - (void)createAndSetupViews { [headerView.button addTarget:self action:@selector(useBillingAddress:) forControlEvents:UIControlEventTouchUpInside]; PKAddressField requiredFields = self.configuration.requiredShippingAddressFields; - BOOL needsAddress = requiredFields & PKAddressFieldPostalAddress && !self.addressViewModel.isValid; + BOOL needsAddress = (requiredFields & PKAddressFieldPostalAddress) && !self.addressViewModel.isValid; BOOL buttonVisible = (needsAddress && [self.billingAddress containsContentForShippingAddressFields:requiredFields] && !self.hasUsedBillingAddress); From 4f08fccffa0e2c1f8cfd125cc85ab1c5a5f9de19 Mon Sep 17 00:00:00 2001 From: Dan Jackson Date: Wed, 8 Nov 2017 14:19:58 -0800 Subject: [PATCH 4/6] Add (unfortunately repetitive) tests for containsContentFor...AddressFields: methods --- Tests/Tests/STPAddressTests.m | 120 ++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/Tests/Tests/STPAddressTests.m b/Tests/Tests/STPAddressTests.m index 999bef8adb6..9dbbe6c6f62 100644 --- a/Tests/Tests/STPAddressTests.m +++ b/Tests/Tests/STPAddressTests.m @@ -428,6 +428,51 @@ - (void)testContainsRequiredFieldsFull { XCTAssertTrue([address containsRequiredFields:STPBillingAddressFieldsFull]); } +- (void)testContainsContentForBillingAddressFields { + STPAddress *address = [STPAddress new]; + + // Empty address should return false for everything + XCTAssertFalse([address containsContentForBillingAddressFields:STPBillingAddressFieldsNone]); + XCTAssertFalse([address containsContentForBillingAddressFields:STPBillingAddressFieldsZip]); + XCTAssertFalse([address containsContentForBillingAddressFields:STPBillingAddressFieldsFull]); + + // 1+ characters in postalCode will return true for .Zip && .Full + address.postalCode = @"0"; + XCTAssertFalse([address containsContentForBillingAddressFields:STPBillingAddressFieldsNone]); + XCTAssertTrue([address containsContentForBillingAddressFields:STPBillingAddressFieldsZip]); + XCTAssertTrue([address containsContentForBillingAddressFields:STPBillingAddressFieldsFull]); + // empty string returns false + address.postalCode = @""; + XCTAssertFalse([address containsContentForBillingAddressFields:STPBillingAddressFieldsNone]); + XCTAssertFalse([address containsContentForBillingAddressFields:STPBillingAddressFieldsZip]); + XCTAssertFalse([address containsContentForBillingAddressFields:STPBillingAddressFieldsFull]); + address.postalCode = nil; + + // Test every other property that contributes to the full address, ensuring it returns True for .Full only + // This is *not* refactoring-safe, but I think it's better than a bunch of duplicated code + for (NSString *propertyName in @[@"line1", @"line2", @"city", @"state", @"country"]) { + for (NSString *testValue in @[@"a", @"0", @"Foo Bar"]) { + [address setValue:testValue forKey:propertyName]; + XCTAssertFalse([address containsContentForBillingAddressFields:STPBillingAddressFieldsNone]); + XCTAssertFalse([address containsContentForBillingAddressFields:STPBillingAddressFieldsZip]); + XCTAssertTrue([address containsContentForBillingAddressFields:STPBillingAddressFieldsFull]); + [address setValue:nil forKey:propertyName]; + } + + // Make sure that empty string is treated like nil, and returns false for these properties + [address setValue:@"" forKey:propertyName]; + XCTAssertFalse([address containsContentForBillingAddressFields:STPBillingAddressFieldsNone]); + XCTAssertFalse([address containsContentForBillingAddressFields:STPBillingAddressFieldsZip]); + XCTAssertFalse([address containsContentForBillingAddressFields:STPBillingAddressFieldsFull]); + [address setValue:nil forKey:propertyName]; + } + + // ensure it still returns false for everything since it has been cleared + XCTAssertFalse([address containsContentForBillingAddressFields:STPBillingAddressFieldsNone]); + XCTAssertFalse([address containsContentForBillingAddressFields:STPBillingAddressFieldsZip]); + XCTAssertFalse([address containsContentForBillingAddressFields:STPBillingAddressFieldsFull]); +} + - (void)testContainsRequiredShippingAddressFields { STPAddress *address = [STPAddress new]; XCTAssertTrue([address containsRequiredShippingAddressFields:PKAddressFieldNone]); @@ -458,6 +503,81 @@ - (void)testContainsRequiredShippingAddressFields { XCTAssertTrue([address containsRequiredShippingAddressFields:PKAddressFieldAll]); } +- (void)testContainsContentForShippingAddressFields { + STPAddress *address = [STPAddress new]; + + // Empty address should return false for everything + XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldNone]); + XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldName]); + XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldPhone]); + XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldEmail]); + XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldPostalAddress]); + + // Name + address.name = @"Smith"; + XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldNone]); + XCTAssertTrue([address containsContentForShippingAddressFields:PKAddressFieldName]); + XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldPhone]); + XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldEmail]); + XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldPostalAddress]); + address.name = @""; + + // Phone + address.phone = @"1"; + XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldNone]); + XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldName]); + XCTAssertTrue([address containsContentForShippingAddressFields:PKAddressFieldPhone]); + XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldEmail]); + XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldPostalAddress]); + address.phone = @""; + + // Email + address.email = @"f"; + XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldNone]); + XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldName]); + XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldPhone]); + XCTAssertTrue([address containsContentForShippingAddressFields:PKAddressFieldEmail]); + XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldPostalAddress]); + address.email = @""; + + // Test every property that contributes to the full address + // This is *not* refactoring-safe, but I think it's better than a bunch more duplicated code + for (NSString *propertyName in @[@"line1", @"line2", @"city", @"state", @"postalCode", @"country"]) { + for (NSString *testValue in @[@"a", @"0", @"Foo Bar"]) { + [address setValue:testValue forKey:propertyName]; + XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldNone]); + XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldName]); + XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldPhone]); + XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldEmail]); + XCTAssertTrue([address containsContentForShippingAddressFields:PKAddressFieldPostalAddress]); + [address setValue:@"" forKey:propertyName]; + } + } + + // ensure it still returns false for everything with empty strings + XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldNone]); + XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldName]); + XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldPhone]); + XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldEmail]); + XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldPostalAddress]); + + // Try a hybrid address, and make sure some bitwise combinations work + address.name = @"a"; + address.phone = @"1"; + address.line1 = @"_"; + XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldNone]); + XCTAssertTrue([address containsContentForShippingAddressFields:PKAddressFieldName]); + XCTAssertTrue([address containsContentForShippingAddressFields:PKAddressFieldPhone]); + XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldEmail]); + XCTAssertTrue([address containsContentForShippingAddressFields:PKAddressFieldPostalAddress]); + + XCTAssertTrue([address containsContentForShippingAddressFields:PKAddressFieldName | PKAddressFieldEmail]); + XCTAssertTrue([address containsContentForShippingAddressFields:PKAddressFieldPhone | PKAddressFieldEmail]); + XCTAssertTrue([address containsContentForShippingAddressFields:PKAddressFieldAll]); + +} + + - (void)testShippingInfoForCharge { STPAddress *address = [STPFixtures address]; PKShippingMethod *method = [[PKShippingMethod alloc] init]; From 1852613962b075d94b69780c1579dc693fb702cb Mon Sep 17 00:00:00 2001 From: Dan Jackson Date: Wed, 8 Nov 2017 16:36:23 -0800 Subject: [PATCH 5/6] Cast composed PKAddressField values to fix compiler warning. This matches `testContainsRequiredShippingAddressFields` --- Tests/Tests/STPAddressTests.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Tests/STPAddressTests.m b/Tests/Tests/STPAddressTests.m index 9dbbe6c6f62..85b9c459681 100644 --- a/Tests/Tests/STPAddressTests.m +++ b/Tests/Tests/STPAddressTests.m @@ -571,8 +571,8 @@ - (void)testContainsContentForShippingAddressFields { XCTAssertFalse([address containsContentForShippingAddressFields:PKAddressFieldEmail]); XCTAssertTrue([address containsContentForShippingAddressFields:PKAddressFieldPostalAddress]); - XCTAssertTrue([address containsContentForShippingAddressFields:PKAddressFieldName | PKAddressFieldEmail]); - XCTAssertTrue([address containsContentForShippingAddressFields:PKAddressFieldPhone | PKAddressFieldEmail]); + XCTAssertTrue([address containsContentForShippingAddressFields:(PKAddressField)(PKAddressFieldName|PKAddressFieldEmail)]); + XCTAssertTrue([address containsContentForShippingAddressFields:(PKAddressField)(PKAddressFieldPhone|PKAddressFieldEmail)]); XCTAssertTrue([address containsContentForShippingAddressFields:PKAddressFieldAll]); } From af113759409c66f6dafc311003c08074b9e344a3 Mon Sep 17 00:00:00 2001 From: Dan Jackson Date: Wed, 8 Nov 2017 21:42:27 -0800 Subject: [PATCH 6/6] Fix (dumb) test failures. I made a dumb mistake in STPAddCardViewController, declared the wrong type for the `requiredFields` variable. The snapshot tests for Add Card and Shipping Address were apparently relying on the using a non-nil & empty Address to display the "Use <> address" button. Put a piece of data into the address to keep triggering the button. --- Stripe/STPAddCardViewController.m | 2 +- Tests/Tests/STPAddCardViewControllerLocalizationTests.m | 1 + Tests/Tests/STPShippingAddressViewControllerLocalizationTests.m | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Stripe/STPAddCardViewController.m b/Stripe/STPAddCardViewController.m index 6d674ee1c4c..c6e2b6ee4a1 100644 --- a/Stripe/STPAddCardViewController.m +++ b/Stripe/STPAddCardViewController.m @@ -145,7 +145,7 @@ - (void)createAndSetupViews { } [addressHeaderView.button addTarget:self action:@selector(useShippingAddress:) forControlEvents:UIControlEventTouchUpInside]; - BOOL requiredFields = self.configuration.requiredBillingAddressFields; + STPBillingAddressFields requiredFields = self.configuration.requiredBillingAddressFields; BOOL needsAddress = requiredFields != STPBillingAddressFieldsNone && !self.addressViewModel.isValid; BOOL buttonVisible = (needsAddress && [self.shippingAddress containsContentForBillingAddressFields:requiredFields] diff --git a/Tests/Tests/STPAddCardViewControllerLocalizationTests.m b/Tests/Tests/STPAddCardViewControllerLocalizationTests.m index af62b6d5e32..9839a28b62f 100644 --- a/Tests/Tests/STPAddCardViewControllerLocalizationTests.m +++ b/Tests/Tests/STPAddCardViewControllerLocalizationTests.m @@ -51,6 +51,7 @@ - (void)performSnapshotTestForLanguage:(NSString *)language delivery:(BOOL)deliv STPAddCardViewController *addCardVC = [[STPAddCardViewController alloc] initWithConfiguration:config theme:[STPTheme defaultTheme]]; addCardVC.shippingAddress = [STPAddress new]; + addCardVC.shippingAddress.line1 = @"1"; // trigger "use shipping address" button UINavigationController *navController = [UINavigationController new]; navController.view.frame = CGRectMake(0, 0, 320, 750); diff --git a/Tests/Tests/STPShippingAddressViewControllerLocalizationTests.m b/Tests/Tests/STPShippingAddressViewControllerLocalizationTests.m index 57fdf2e54f6..01cd0058cca 100644 --- a/Tests/Tests/STPShippingAddressViewControllerLocalizationTests.m +++ b/Tests/Tests/STPShippingAddressViewControllerLocalizationTests.m @@ -47,6 +47,7 @@ - (void)performSnapshotTestForLanguage:(NSString *)language shippingType:(STPShi [STPLocalizationUtils overrideLanguageTo:language]; STPUserInformation *info = [STPUserInformation new]; info.billingAddress = [STPAddress new]; + info.billingAddress.email = @"@"; // trigger "use billing address" button STPShippingAddressViewController *shippingVC = [[STPShippingAddressViewController alloc] initWithConfiguration:config theme:[STPTheme defaultTheme]