问题
I want to do automatic testing using test data from here with Norwegian BankId. But I can't get hold of the input field using Selenium.
What I try to do:
- Go to https://www.banknorwegian.no/
- Click on "Logg inn"
- Click on "BankID på mobil."
- Click on "BankID" under "Alternativer for innlogging"
- Enter "02105892090" (test user from above link) and click on "Logg inn"
- Enter "02105892090" again in the "Engangskode" and click on the submit button.
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>
I can get to (6.) but then I can't get hold of the <input>
with type="password"
under "Engangskode". It's in an iframe
which makes it harder. This is what I've tried:
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");
}
But I get the error message:
OpenQA.Selenium.NoSuchElementException : no such element: Unable to locate element: {"method":"css selector","selector":"input[type='password']"}
Does anyone have any idea how to do this?
EDIT:
With the help of all of you this is the code that finally worked:
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);
}
回答1:
The field associated with the text Engangskode is within a #shadow-root (open)
which is with in a child <iframe>
which is within the parent <iframe>
. So to send a character sequence to the desired field you need to:
- Induce WebDriverWait for the parent frame to be available and switch to it.
- Induce WebDriverWait for the child frame to be available and switch to it.
- Induce WebDriverWait for the desired
ElementToBeClickable()
which is with in the#shadow-root (open)
.
You can use the following solution:
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");
Browser Snapshot:
回答2:
Here you have 2 iframes (nested iframes), so that you need to switch twice. First switch to iframe with id=ifmSingicat then to the first iframe of the switched 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']"));
Note: I'm not C# developer, hope above syntax is correct.
回答3:
If you are switched to correct iframe, then it just that you need to add some wait. It will provide some time to iframe elements to get loaded.
来源:https://stackoverflow.com/questions/59231027/selenium-send-keys-to-input-password-in-a-shadow-root-open-and-multiple-ifra