使用 Selenium Webdriver 与 Stripe Card Element iFrame 交互 - Cucumber/Selenium Java

问题描述 投票:0回答:5

我有一个表单,我想在 Java 中使用 Cucumber 和 Selenium Webdriver 来自动化 - 在这个表单中,我们有一个从 Stripe 使用的卡片元素。我们称之为 div,剩下的由 stripe 完成。我不确定这是否是 iFrame,但是当我使用

Hooks.driver.findElement(By.xpath("xpathOfTheCardNumberField")).sendKeys("123");

命令,它不与其交互,并在控制台日志中返回“无法定位元素”错误。

我已经要求我们的前端也许尝试向字段添加一些 ID 或名称标签,但他告诉我他无法与卡元素内部字段的标记进行交互,只能与卡元素本身进行交互 - 作为 Stripe处理其他一切。

随附卡片元素的图片,以及相关卡片元素的标记。

是否可以让 Selenium 与该元素交互?

非常感谢任何帮助。 卡元前端

标记卡片元素

html iframe selenium-webdriver cucumber stripe-payments
5个回答
6
投票

为了完整性,对 Fabio 接受的答案进行了额外的跟进。

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()

3
投票

我自己实际上已经解决了这个问题,所以我将回答这个问题并关闭它,以防其他人遇到问题。

我认为这是一种通用方法,可以用于任何 iframe,而不仅仅是 Stripe。

首先,您必须告诉您的网络驱动程序将框架切换到您尝试访问的 iframe:

Hooks.driver.switchTo().frame(Hooks.driver.findElement(By.xpath("xpathOfIframe")));

然后,您可以为该 iframe 中的内容创建 webElements,并与它们交互:

WebElement creditcardNumber = Hooks.driver.findElement(By.name("cardnumber"));
creditcardNumber.sendKeys("1234567890000066");

2
投票

当前的 Stripe 配置将卡号、到期日期 (exp-date) 和 cvc 放在不同的 iframe 中。与以前不同,所有内容都在一个 iframe 中,并且上面的解决方案有效。

我只需转移到一个 iframe 即可更新卡信息。然后Stripe发生了变化,前端开发人员更新了支付网页。然后出现了到期日期和 CVC 的“无法定位元素...”错误。同样,我询问开发人员是否可以为 3 个输入输入 ID 或名称。他说,他做不到,Stripe 就做出了支付屏幕。

通常,当您在 Firefox 或 Chrome 中检查信用卡信息时,您将看到输入属于哪个 iframe。

在我们的网页中,卡号位于 __privateStripeFrame5 中。 exp-date 位于 __privateStripeFrame6 中,cvc 位于 __privateStripeFrame7 中。

这是解决我使用 selenium python 更新/测试卡信息时遇到的困境的代码(java 有类似的方法/函数):

# 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() 是一个内部函数,用于查找元素,但其中包含 wait() 函数。您可以使用 find_element_by_name()。

卡号、到期日期和 CVC 使用 selenium (python) 更新:

Stripe Credit Card Information Updated Using Selenium (python)


2
投票

对我来说,这现在有效。我发现 Card 上的 Name 不是 iframe,必须通过 chrome.webdriver 找到它


driver.switch_to.frame(frame_reference=driver.find_element(By.XPATH, '/html/body/div[1]/div/main[2]/section/div/div[2]/div/article/div/form/fieldset[3]/div[2]/div/div/div/iframe'))
creditNumber = driver.find_element_by_name("cardnumber").send_keys("4242 4242 4242 4242")
time.sleep(1)

driver.switch_to.default_content()

driver.switch_to.frame(frame_reference=driver.find_element(By.XPATH, '/html/body/div[1]/div/main[2]/section/div/div[2]/div/article/div/form/fieldset[3]/div[3]/div[2]/div[1]/div/div/iframe'))
expiryDate = driver.find_element_by_name("exp-date").send_keys("1223")

driver.switch_to.default_content()

driver.switch_to.frame(frame_reference=driver.find_element(By.XPATH, '/html/body/div[1]/div/main[2]/section/div/div[2]/div/article/div/form/fieldset[3]/div[3]/div[2]/div[2]/div/div/iframe'))
cvc = driver.find_element_by_name("cvc").send_keys("345")

driver.switch_to.default_content()
time.sleep(1)

nameOnCard = driver.find_element_by_name("name_on_card").send_keys("Testing")

0
投票

主要问题是在多个 iframe 中导航。 Stripe 的支付页面旨在增强安全性,通常使用多个嵌套或动态加载的 iframe,这使得直接查找元素变得困难。

这是对我有用的解决方案:

列出所有 iframe:我首先列出页面上的所有 iframe,以确定哪个 iframe 包含所需的元素。 切换到正确的 Iframe:我遍历所有 iframe 以找到包含 cardNumber 输入字段的 iframe。 等待可见性:我确保 iframe 和元素在与它们交互之前已完全加载且可见。 这是我使用的通用代码:

public void inputPaymentDetails(String numCard, String dataCard, String cvcCard, String nameCard) 抛出异常 { 尝试 { // 确保所有元素都已加载 线程.sleep(4000); // 如果可能的话替换为 WebDriverWait 以获得更好的处理

    driver.switchTo().defaultContent(); // Switch back to the main context
    List<WebElement> iframes = driver.findElements(By.tagName("iframe"));
    System.out.println("Total iframes found: " + iframes.size());

    for (int i = 0; i < iframes.size(); i++) {
        try {
            WebElement iframe = iframes.get(i);
            System.out.println("Checking iframe index: " + i);

            // Switch to current iframe
            driver.switchTo().frame(iframe);

            // Try to find the card number field in the current iframe
            List<WebElement> elements = driver.findElements(By.xpath("//*[@id='cardNumber']"));
            if (elements.size() > 0) {
                System.out.println("'cardNumber' field found in iframe index: " + i);
                break;
            } else {
                System.out.println("'cardNumber' field NOT found in iframe index: " + i);
            }

            driver.switchTo().defaultContent(); // Switch back to the main content if not found
        } catch (NoSuchElementException e) {
            System.err.println("Error while checking iframe index: " + i + " - " + e.getMessage());
        }
    }

    // Interact with the found card number field
    WebElement cardNumberField = driver.findElement(By.id("cardNumber"));
    if (cardNumberField != null) {
        System.out.println("Found 'cardNumber' field, entering the card number...");
        cardNumberField.sendKeys(numCard);
    } else {
        System.out.println("'cardNumber' field not found within the iframe.");
    }

    // Repeat similar steps for expiration date and CVC fields if they are in different iframes

    // Switch back to main content
    driver.switchTo().defaultContent();

    // Input name on card
    WebElement nameField = driver.findElement(By.name("name_on_card"));
    if (nameField != null) {
        System.out.println("Found 'name_on_card' field, entering the cardholder's name...");
        nameField.sendKeys(nameCard);
    } else {
        System.out.println("'name_on_card' field not found in the main context.");
    }

    // Optionally click the submit button or take further actions

} catch (NoSuchElementException e) {
    System.err.println("Error: Element not found - " + e.getMessage());
} catch (Exception e) {
    System.err.println("Error during the execution of inputPaymentDetails method: " + e.getMessage());
}

}

© www.soinside.com 2019 - 2024. All rights reserved.