Selenium在条带信用卡输入中发送密钥顺序不正确
使用selenium将键发送到输入字段后,结果与预期不符-键的插入顺序不正确 e、 g.发送密钥('42424242')->结果为“42242424” 编辑:在一些机器上,我只是随机观察问题,10次尝试中有1次。在另一台机器上是10/10 这种情况在Stripe payment form+中特别发生,我只在Chrome版本69中看到这个问题(在以前的版本中,它工作正常) 这可以很容易地在样本条站点上复制: python代码示例:Selenium在条带信用卡输入中发送密钥顺序不正确,selenium,google-chrome,selenium-chromedriver,stripe-payments,Selenium,Google Chrome,Selenium Chromedriver,Stripe Payments,使用selenium将键发送到输入字段后,结果与预期不符-键的插入顺序不正确 e、 g.发送密钥('42424242')->结果为“42242424” 编辑:在一些机器上,我只是随机观察问题,10次尝试中有1次。在另一台机器上是10/10 这种情况在Stripe payment form+中特别发生,我只在Chrome版本69中看到这个问题(在以前的版本中,它工作正常) 这可以很容易地在样本条站点上复制: python代码示例: from selenium import webdriver dr
from selenium import webdriver
driver = webdriver.Chrome()
driver.get('https://stripe.github.io/elements-examples/')
driver.switch_to.frame(driver.find_element_by_tag_name('iframe')) # First iframe
cc_input = driver.find_element_by_css_selector('input[name="cardnumber"]')
cc_input.send_keys('4242424242424242')
结果:
我可以通过一个接一个地发送钥匙来获得通过,但这也不是100%可靠(加上非常慢)
我不确定这是硒(3.14.1)/chromedriver(2.41.578737)的问题,还是我做错了什么
有什么想法吗?编辑
非常感谢@Benno——他的回答是正确的。
我将添加基于他的JS为我工作的python解决方案
driver.get('https://stripe.github.io/elements-examples/')
driver.switch_to.frame(driver.find_element_by_tag_name('iframe')) # First iframe
cc_input = driver.find_element_by_css_selector('input[name="cardnumber"]')
value = "4242424242424242"
driver.execute_script('''
input = arguments[0];
var nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
nativeInputValueSetter.call(input, "{}");
var eventCard = new Event("input", {{bubbles: true}});
input.dispatchEvent(eventCard);
'''.format(value), cc_input)
driver.switch_to.default_content()
driver.quit()
经过几个小时的尝试,我放弃了,接受了这个事实,这确实是一个随机的问题,并采取了解决办法
Cookie/本地历史(如评论中所示)似乎不是问题所在。webdriver总是生成一个“干净”的浏览器实例,没有Cookie或本地存储。我们在MacOS和Ubuntu 18.04上遇到了完全相同的问题,在我们的CI服务器上也遇到了同样的问题,该服务器具有Gractor 5.4.1和selenium和chromedriver的相同版本。自Chrome69之后,它才开始出现故障,v70的情况更糟 更新-正在工作(暂时) 经过进一步的调查,我记得React倾向于覆盖更改/输入事件,信用卡输入、ccv输入等中的值是从React组件状态呈现的,而不仅仅是从输入值呈现的。于是我开始寻找,发现 我们的测试正在进行(目前):
//信用输入示例
函数creditCardInput():ElementFinder{
返回元素(by.xpath('//input[contains(@name,“cardnumber”)]'))
}
/// ... 我们的方法的片段。。。
等待重新编辑CardInputsReady()
等待剥离输入(creditCardInput,ccNumber)
等待剥离输入(信用卡到期,ccExpiry)
等待剥离输入(信用卡CVC、ccCvc)
wait browser.wait(this.hasCreditCardZip(),未定义,'Should has creditCardZip')
等待剥离输入(creditCardZip、ccZip)
等待browser.switchTo().defaultContent()
/// ... 剪
异步函数ensurectardinputisready():Promise{
wait browser.wait(ExpectedConditions.presenceOf(paymentIFrame()),未定义,“应具有付款iframe”)
wait browser.switchTo().frame(wait paymentIFrame().getWebElement())
等等(
ExpectedConditions.presenceOf(creditCardInput()),
未定义,
'应该有信用卡输入'
)
}
/**
*自版本69以来,条带网关的SendKeys在Chrome中出现问题。钥匙坏了,
*导致测试失败。
*/
异步函数stripeInput(inputElement:function,value:string):承诺{
等待browser.executeScript(`
var nativeInputValueSetter=Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,“value”).set;
调用(参数[0],“${value}”);
var-inputEvent=new事件('input',{bubbles:true});
参数[0]。dispatchEvent(inputEvent);
`,inputElement()
)
等待浏览器。睡眠(100)
const typedInValue=await inputElement().getWebElement().getAttribute('value'))
if(typedInValue.replace(/\s/g',)==值){
返回
}
抛出新错误(${inputElement}`上的`失败集'${typedInValue}')
}
以前的想法(只是偶尔奏效):
from selenium import webdriver
driver = webdriver.Chrome()
driver.get('https://stripe.github.io/elements-examples/')
driver.switch_to.frame(driver.find_element_by_tag_name('iframe')) # First iframe
cc_input = driver.find_element_by_css_selector('input[name="cardnumber"]')
cc_input.send_keys('4242424242424242')
我已经使用设置了一个最小的repu,当测试按顺序运行时它会成功,但不是并行运行(我们认为这是由于切换到iframe时的焦点/模糊问题)
我们的解决方案是类似的,尽管我们从观察测试中注意到input.clear()不适用于iframe中使用的tel输入
这仍然是偶尔失败的,但频率要低得多
/**
* Types a value into an input field, and checks if the value of the input
* matches the expected value. If not, it attempts for `maxAttempts` times to
* type the value into the input again.
*
* This works around an issue with ChromeDriver where sendKeys() can send keys out of order,
* so a string like "0260" gets typed as "0206" for example.
*
* It also works around an issue with IEDriver where sendKeys() can press the SHIFT key too soon
* and cause letters or numbers to be converted to their SHIFT variants, "6" gets typed as "^", for example.
*/
export async function slowlyTypeOutField (
value: string,
inputElement: Function,
maxAttempts = 20
): Promise<void> {
for (let attemptNumber = 0; attemptNumber < maxAttempts; attemptNumber++) {
if (attemptNumber > 0) {
await browser.sleep(100)
}
/*
Executing a script seems to be a lot more reliable in setting these flaky fields than using the sendKeys built-in
method. However, I struggled in finding out which JavaScript events Stripe listens to. So we send the last key to
the input field to trigger all events we need.
*/
const firstPart = value.substring(0, value.length - 1)
const secondPart = value.substring(value.length - 1, value.length)
await browser.executeScript(`
arguments[0].focus();
arguments[0].value = "${firstPart}";
`,
inputElement()
)
await inputElement().sendKeys(secondPart)
const typedInValue = await inputElement().getAttribute('value')
if (typedInValue === value) {
return
}
console.log(`Tried to set value ${value}, but instead set ${typedInValue} on ${inputElement}`)
}
throw new Error(`Failed after ${maxAttempts} attempts to set value on ${inputElement}`)
}
/**
*在输入字段中键入值,并检查输入的值
*与预期值匹配。如果没有,则尝试“maxAttempts”次以
*再次在输入中键入值。
*
*这解决了ChromeDriver的一个问题,其中sendKeys()可以按顺序发送密钥,
*例如,像“0260”这样的字符串被键入为“0206”。
*
*它还解决了IEDriver中sendKeys()可能过早按下SHIFT键的问题
*并将字母或数字转换为其移位变量,例如,“6”被键入为“^”。
*/
导出异步函数slowlyTypeOutField(
值:字符串,
inputElement:函数,
最大尝试次数=20
):承诺{
for(设attemptNumber=0;attemptNumber0){
等待浏览器。睡眠(100)
}
/*
在设置这些不稳定的字段时,执行脚本似乎比使用内置sendKeys要可靠得多
然而,我很难找到Stripe侦听的JavaScript事件。因此,我们将最后一个键发送到
用于触发我们需要的所有事件的输入字段。
*/
const firstPart=value.substring(0,value.length-1)
常数第二部分=
input_data = "someimputdata"
some_xpath = "//*[contains(@id,'input_fax.number_')]"
element = web_driver_obj.find_element_by_xpath(some_xpath)
element.clear()
element.send_keys(input_data)
web_driver_obj.execute_script("arguments[0].value = '{0}';".format(input_data), element)
from selenium.webdriver.common.keys import Keys
my_value = "123"
my_xpath="//input[@class='form-text']"
element = driver.find_element_by_xpath(my_xpath)
element.clear()
element.send_keys(Keys.BACKSPACE * 3, my_value)