问题
I have an form that I want to automate using Cucumber and Selenium Webdriver in Java - in this form, we have a card element which we use from Stripe. We call the div, and stripe does the rest. I'm unsure if this is an iFrame, but when I use the
Hooks.driver.findElement(By.xpath("xpathOfTheCardNumberField")).sendKeys("123");
command, it does not interact with it and returns the "Unable to locate element" error in the console log.
I have asked our front-ender to perhaps try and add some ID's or Name tags to the fields, but he informs me that he cannot interact with the markup for the fields inside of the card element, only the card element itself - as Stripe deal with everything else.
Attached is a picture of the card element, as well as the markup for the card element in question.
Is it possible to get Selenium to interact with this element?
Any help is greatly appreciated. Card element front end
Mark up for the card element
回答1:
Additional follow-up to the accepted answer by Fabio for completeness.
self.browser = webdriver.Chrome()
# fill in the other fields as usual (i.e. self.browser.find_element_by_id(...))
# When you arrive at the iframe for the card number, exp. date, CVC, and zip:
self.browser.switch_to.frame(frame_reference=self.browser.find_element(By.XPATH, '//iframe[@name="__privateStripeFrame3"]'))
# This switches to the iframe, which Selenium can now start selecting elements from.
# The remaining form elements can be found by name
self.browser.find_element_by_name('cardnumber').send_keys('4242 4242 4242 4242')
# And find the other elements the same way as above (exp-date, cvc, postal).
# Finally, switch back to the default content to select the submit button
self.browser.switch_to.default_content()
self.browser.find_element_by_tag_name('button').click()
回答2:
I've actually figured this out myself, so I'm going to answer the question and close it off in case anyone else is having issues with it.
I think this is a blanket method that can be used for any iframes, not just Stripe.
Firstly, you must tell your webdriver to switch frames to the iframe you are trying to access:
Hooks.driver.switchTo().frame(Hooks.driver.findElement(By.xpath("xpathOfIframe")));
Then, you can create webElements for the things within that iframe, and interact with them:
WebElement creditcardNumber = Hooks.driver.findElement(By.name("cardnumber"));
creditcardNumber.sendKeys("1234567890000066");
回答3:
The current Stripe configuration puts cardnumber, the expiry date (exp-date) and cvc in different iframes. Unlike before, all are in one iframe and the solution above worked.
I was able to update the card information by just transferring to one iframe. Then the Stripe changes came and the front-end developer updated the payment web page. Then came the 'Unable to locate element ...' error for the expiry date and the cvc. Likewise, I asked the developer if he can put id's or names for the 3 inputs. He said, he cannot do it and Stripe makes the payment screen.
Normally, when you inspect in Firefox or in Chrome the credit card infos, you will see what iframe the inputs belong to.
In our web page, the cardnumber is in the __privateStripeFrame5. The exp-date is in the __privateStripeFrame6, and the cvc in the __privateStripeFrame7.
Here's the code that solved my dilemma in updating/testing the card infos using selenium python (java has similar methods/functions):
# has_zip_code - True or False
# added params for flexibility
# exp_date - expiration date
# cvc_val - 3-digit number
def enter_card_details_and_submit(driver, card_num, exp_date, cvc_val, has_zip_code):
#print("\n{} -------------------------------------------\n".format(PI_WIN))
print("Use card number ... {}".format(card_num))
print(card_num)
driver.switch_to.frame(frame_reference=wait_and_get_elem_by(driver, By.NAME, "__privateStripeFrame5"))
card_num_text = wait_and_get_elem_by(driver, By.NAME, "cardnumber")
card_num_text.click()
time.sleep(1)
card_num_text.send_keys(card_num)
driver.switch_to.default_content()
print("\nEnter expiry month/year ...")
iframe6 = wait_and_get_elem_by(driver, By.NAME, "__privateStripeFrame6")
driver.switch_to.frame(iframe6)
exp_dt = wait_and_get_elem_by(driver, By.NAME, "exp-date")
exp_dt.click()
time.sleep(1)
exp_dt.send_keys(exp_date)
driver.switch_to.default_content()
print("\nEnter CVC ...")
driver.switch_to.frame(frame_reference=wait_and_get_elem_by(driver, By.NAME, "__privateStripeFrame7"))
cvc = wait_and_get_elem_by(driver, By.NAME, "cvc")
cvc.click()
time.sleep(1)
cvc.send_keys(cvc_val)
.
.
.
wait_and_get_elem_by() is an internal function that finds the element but with wait() function in it. You can use find_element_by_name().
The cardnumber, exp-date, and cvc are updated using selenium (python):
来源:https://stackoverflow.com/questions/48805576/using-selenium-webdriver-to-interact-with-stripe-card-element-iframe-cucumber