Selenium - 发送密钥以在影子根(打开)和挪威 BankId 的多个 iframe 中输入密码
Selenium - Send keys to input password in a shadow-root (open) and multiple iframes for Norwegian BankId
我想使用来自 here 的测试数据和 Norwegian BankId 进行自动测试。但是我无法使用 Selenium 获取输入字段。
我尝试做的事情:
- 转到https://www.banknorwegian.no/
- 点击"Logg inn"
- 点击"BankID på mobil."
- 单击 "Alternativer for innlogging"
下的 "BankID"
- 输入“02105892090”(上面的测试用户link)然后点击"Logg inn"
- 再次在"Engangskode"中输入“02105892090”并点击提交按钮。
HTML:
<iframe frameborder="0" width="100%" height="100%" src="<URL>" title="BankID">
<div>Lots of divs...</div>
<input data-bind=" attr: { maxlength: maxlength, type: type, id: id, 'data-type': dataType, disabled: disabled, 'aria-disabled': disabled, 'pattern': pattern, 'inputmode': 'numeric', 'max': $data.max, 'min': $data.min, 'step': $data.step, 'tabindex': $data.tabIndex, 'aria-invalid': isInvalid, 'aria-label': label }, value: val, valueUpdate: valueUpdate, css: { error: $data.err, hasFocus: hasFocus, hideCaret: $data.hideCaret, hasValue: hasValue }, event: { focus: onFocus, blur: onBlur }" autocomplete="off" autocapitalize="off" autocorrect="off" formnovalidate="" required="" maxlength="255" type="password" id="qxaTy_DZXMJPMnP_rZae_2" tabindex="2000" aria-invalid="true" pattern="[0-9]*" class="">`
</iframe>
我可以到达 (6.) 但后来我无法在 "Engangskode" 下获得 type="password"
和 type="password"
的 <input>
。它位于 iframe
中,这使得它更难。这是我试过的:
public void EnterSsn(string ssn)
{
var driver = WebDriverFacade.GetDriver;
driver.SwitchTo().DefaultContent();
driver.SwitchTo().Frame(0);
Assert.IsTrue(driver.FindElement(By.CssSelector("input[type='password']")).ControlDisplayed());
driver.FindElement(By.CssSelector("input[type='password']")).SendKeysWrapper(ssn, "SSN");
}
但我收到错误消息:
OpenQA.Selenium.NoSuchElementException : no such element: Unable to locate element: {"method":"css selector","selector":"input[type='password']"}
有人知道怎么做吗?
编辑:
在大家的帮助下,这是最终有效的代码:
public void EnterSsn(string ssn)
{
var driver = WebDriverFacade.GetDriver;
driver.SwitchTo().DefaultContent();
new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.FrameToBeAvailableAndSwitchToIt(By.CssSelector("iframe#ifmSingicat")));
new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.FrameToBeAvailableAndSwitchToIt(By.CssSelector("#bankid-container iframe")));
new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.ElementToBeClickable((IWebElement)((IJavaScriptExecutor)driver).ExecuteScript("return document.querySelector(\".full_width_height\").shadowRoot.querySelector(\"input[type=\'password\']\")"))).SendKeys(ssn);
}
这里有2个iframe(嵌套iframe),所以需要切换两次。
首先切换到id=ifmSingicat的iframe,然后切换到切换iframe的第一个iframe。
//Main document
driver.SwitchTo().DefaultContent();
//Find the first frame, and use switch to frame
IWebElement containerFrame = driver.FindElement(By.Id("ifmSingicat"));
driver.SwitchTo().Frame(containerFrame);
//You are now in iframe "containerFrame", now find the nested iframe
IWebElement contentFrame = driver.FindElement(By.CssSelector("#bankid-container iframe"));
driver.SwitchTo().Frame(contentFrame);
//Now find the elements you want in the nested frame
IWebElement foo = driver.FindElement(By.CssSelector("input[type='password']"));
注意:我不是 C# 开发人员,希望以上语法正确。
如果你切换到正确的iframe,那只是你需要添加一些等待。它将提供一些时间来加载 iframe 元素。
与文本 Engangskode 关联的字段在 #shadow-root (open)
中,该字段在子 [=12= 中] 在父 <iframe>
中。因此,要将 字符序列 发送到所需字段,您需要:
- 为父 框架引入 WebDriverWait 并切换到它.
- 为子 框架引入 WebDriverWait 并切换到它.
- Induce WebDriverWait 用于
#shadow-root (open)
. 中所需的 ElementToBeClickable()
您可以使用以下解决方案:
new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.FrameToBeAvailableAndSwitchToIt(By.CssSelector("iframe#ifmSingicat")));
new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.FrameToBeAvailableAndSwitchToIt(By.CssSelector("iframe[title='BankID']")));
new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.ElementToBeClickable((IWebElement)((IJavaScriptExecutor)driver).ExecuteScript("return document.querySelector('div.full_width_height').shadowRoot.querySelector('input')"))).SendKeys("02105892090");
浏览器快照:
我想使用来自 here 的测试数据和 Norwegian BankId 进行自动测试。但是我无法使用 Selenium 获取输入字段。
我尝试做的事情:
- 转到https://www.banknorwegian.no/
- 点击"Logg inn"
- 点击"BankID på mobil."
- 单击 "Alternativer for innlogging" 下的 "BankID"
- 输入“02105892090”(上面的测试用户link)然后点击"Logg inn"
- 再次在"Engangskode"中输入“02105892090”并点击提交按钮。
HTML:
<iframe frameborder="0" width="100%" height="100%" src="<URL>" title="BankID">
<div>Lots of divs...</div>
<input data-bind=" attr: { maxlength: maxlength, type: type, id: id, 'data-type': dataType, disabled: disabled, 'aria-disabled': disabled, 'pattern': pattern, 'inputmode': 'numeric', 'max': $data.max, 'min': $data.min, 'step': $data.step, 'tabindex': $data.tabIndex, 'aria-invalid': isInvalid, 'aria-label': label }, value: val, valueUpdate: valueUpdate, css: { error: $data.err, hasFocus: hasFocus, hideCaret: $data.hideCaret, hasValue: hasValue }, event: { focus: onFocus, blur: onBlur }" autocomplete="off" autocapitalize="off" autocorrect="off" formnovalidate="" required="" maxlength="255" type="password" id="qxaTy_DZXMJPMnP_rZae_2" tabindex="2000" aria-invalid="true" pattern="[0-9]*" class="">`
</iframe>
我可以到达 (6.) 但后来我无法在 "Engangskode" 下获得 type="password"
和 type="password"
的 <input>
。它位于 iframe
中,这使得它更难。这是我试过的:
public void EnterSsn(string ssn)
{
var driver = WebDriverFacade.GetDriver;
driver.SwitchTo().DefaultContent();
driver.SwitchTo().Frame(0);
Assert.IsTrue(driver.FindElement(By.CssSelector("input[type='password']")).ControlDisplayed());
driver.FindElement(By.CssSelector("input[type='password']")).SendKeysWrapper(ssn, "SSN");
}
但我收到错误消息:
OpenQA.Selenium.NoSuchElementException : no such element: Unable to locate element: {"method":"css selector","selector":"input[type='password']"}
有人知道怎么做吗?
编辑:
在大家的帮助下,这是最终有效的代码:
public void EnterSsn(string ssn)
{
var driver = WebDriverFacade.GetDriver;
driver.SwitchTo().DefaultContent();
new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.FrameToBeAvailableAndSwitchToIt(By.CssSelector("iframe#ifmSingicat")));
new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.FrameToBeAvailableAndSwitchToIt(By.CssSelector("#bankid-container iframe")));
new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.ElementToBeClickable((IWebElement)((IJavaScriptExecutor)driver).ExecuteScript("return document.querySelector(\".full_width_height\").shadowRoot.querySelector(\"input[type=\'password\']\")"))).SendKeys(ssn);
}
这里有2个iframe(嵌套iframe),所以需要切换两次。 首先切换到id=ifmSingicat的iframe,然后切换到切换iframe的第一个iframe。
//Main document
driver.SwitchTo().DefaultContent();
//Find the first frame, and use switch to frame
IWebElement containerFrame = driver.FindElement(By.Id("ifmSingicat"));
driver.SwitchTo().Frame(containerFrame);
//You are now in iframe "containerFrame", now find the nested iframe
IWebElement contentFrame = driver.FindElement(By.CssSelector("#bankid-container iframe"));
driver.SwitchTo().Frame(contentFrame);
//Now find the elements you want in the nested frame
IWebElement foo = driver.FindElement(By.CssSelector("input[type='password']"));
注意:我不是 C# 开发人员,希望以上语法正确。
如果你切换到正确的iframe,那只是你需要添加一些等待。它将提供一些时间来加载 iframe 元素。
与文本 Engangskode 关联的字段在 #shadow-root (open)
中,该字段在子 [=12= 中] 在父 <iframe>
中。因此,要将 字符序列 发送到所需字段,您需要:
- 为父 框架引入 WebDriverWait 并切换到它.
- 为子 框架引入 WebDriverWait 并切换到它.
- Induce WebDriverWait 用于
#shadow-root (open)
. 中所需的
ElementToBeClickable()
您可以使用以下解决方案:
new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.FrameToBeAvailableAndSwitchToIt(By.CssSelector("iframe#ifmSingicat"))); new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.FrameToBeAvailableAndSwitchToIt(By.CssSelector("iframe[title='BankID']"))); new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.ElementToBeClickable((IWebElement)((IJavaScriptExecutor)driver).ExecuteScript("return document.querySelector('div.full_width_height').shadowRoot.querySelector('input')"))).SendKeys("02105892090");
浏览器快照: