I work with webDriver in #IE9 and I find one problem. If I started tests in Run mode, then all test fail because webDriver not exists (two window ie), but if I put breakpoint in tests and start tests Debug mode I have passed all tests. Please tell me, what do, because I don't know.
This my code:
private void MyMethods(IWebdriver driver)
{
foreach (var item in driver.WindowHandles) // if I put breakpoint, I see 2 count Window Handles else this methods don't work.
{
if (driver.SwitchTo().Window(item).Title == "PortalSubMenuPopupForm")
{
driver.SwitchTo().Window(item);
break;
}
}
}
Selenium has an "issue" with IE where new windows might not appear on the WindowHandles list right away.
The solution is either
wait a fixed amount of time before calling driver.WindowHandles
or
use the WebDriverWait class to wait for the number of elements under WindowHandles to change
I think the second one is more robust. Here is a quick implementation:
public void LaunchNewWindow(IWebElement element)
{
int windowsBefore = driver.WindowHandles.Count;
element.Click();
TimeSpan timeout = new TimeSpan(0, 0, 10);
WebDriverWait wait = new WebDriverWait(driver, timeout);
wait.Until((_driver) =>
{
return _driver.WindowHandles.Count != windowsBefore;
//optionally use _driver.WindowHandles.Count > windowsBefore
});
}
Now you can use the function like so:
IWebElement clickMe = //some element that launches a new window
LaunchNewWindow(clickMe);
foreach (var item in driver.WindowHandles)
{
//etc.
}
Related
Angular Material Select (mat-select) inside Form Field (mat-form-field) ignores Selenium click
When test runs, dropdown doesn't appear after click is made by Selenium. If it is made manually by me, test continues and passes.
I also tried to use SelectElement class but it's not applicable since mat-select doesn't use any select elements
public class Page definition:
[FindsBy(How = How.XPath, Using = "//*[#id='form']//mat-form-field//*[#class='mat-form-field-flex' and .//*[#formcontrolname='network']]")] // also tried all surrounding elements from DOM including mat-form-field and mat-select (look at attached screenshot)
public IWebElement _formNetworkFormControl;
public bool IsFormNetworkFormControlComponentPresent()
{
return ExtendedWebElementOperations.IsElementDisplayed(_formNetworkFormControl);
}
// Click dropdown
public void ClickFormNetworkFormControl(IWebDriver webdriver)
{
// Wait is needed until data is loaded and select is enabled
WebDriverWait wait = new WebDriverWait(webdriver, timeout: TimeSpan.FromSeconds(15));
wait.Until(ExpectedConditions.ElementToBeClickable(_formNetworkFormControl));
_formNetworkFormControl.Click();
}
// To select option after dropdown click
public void SelectByOptionName(IWebDriver webdriver, string optionName)
{
string xpath = $"//mat-option[span[text()[contains(.,'{optionName}')]]]";
WebDriverWait wait = new WebDriverWait(webdriver, timeout: TimeSpan.FromSeconds(5));
wait.Until(ExpectedConditions.ElementIsVisible(By.XPath(xpath)));
IWebElement optionNameSelect = webdriver.FindElement(By.XPath(xpath));
optionNameSelect.Click();
}
Test:
var testedPage = new Page(Driver);
testedPage.ClickAddRingTestFormNetworkFormControl(Driver); // click is made but dropdown doesn't appear
testedPage.SelectByOptionName(Driver, networkName); // if select is clicked manually, this works great
The problem is that mat-select has aria-disabled='true' until required data is loaded, so
wait.Until(ExpectedConditions.ElementToBeClickable(_formNetworkFormControl));
doesn't cover this case.
I fixed it with updating Page class following way:
public IWebElement IsElementHasTrueAriaDisabledAttribute(IWebDriver webdriver, IWebElement element)
{
if (element.GetAttribute("aria-disabled").Equals("false"))
{
return element;
}
return null;
}
public void ClickFormNetworkFormControl(IWebDriver webdriver)
{
WebDriverWait wait = new WebDriverWait(webdriver, timeout: TimeSpan.FromSeconds(15));
wait.Until<IWebElement>((d) =>
{
return IsElementHasTrueAriaDisabledAttribute(d, _formNetworkFormControl);
});
_formNetworkFormControl.Click();
}
I try to send keys to input field but can't do it...
I have tried different ways to wait till element is visible but got timeout exceptions...
IWebElement userName = driver.FindElement(By.Id("UserName"));
IWebElement userPassword = driver.FindElement(By.Id("Password"));
IWebElement subButton = driver.FindElement(By.XPath(("//button[contains(.,'Вхід')]")));
while (true)
{
userName = driver.FindElement(By.Id("UserName"));
if (userName.Displayed)
{
userName.SendKeys("test");
break;
}
}
subButton.Click();
Using this method gives me always timeout:
public static void WaitForElementLoad(By by, int timeoutInSeconds)
{
if (timeoutInSeconds > 0)
{
WebDriverWait wait = new WebDriverWait(webDriver, TimeSpan.FromSeconds(timeoutInSeconds));
wait.Until(ExpectedConditions.ElementIsVisible(by));
}
}
If its hidden just send/execute a simple js by selenium that will show the element. But it cant be a little bit more tricki. Set the window size to a bigger one eg 2000x2000. If something is not placed in the viewport selenium will not see it.
please try to use JavaScript to scroll to the element and then perform other operations on the element
((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView(true);", element);
I need to click an okay button which might appear after completing a field - it might take 5 seconds to appear. So i need (if) Wait for existence 5 seconds. I'm using PageFactory in a pages framework, I've seen some solutions but cant figure out how to implement them in this context.
[FindsBy(How = How.Name, Using = "OK")]
private IWebElement alertOKBtn;
public void PopulateFields //method to populate the form
{
// Populate fields
dateFromField.SendKeys(DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss"));
// Click on this field
descriptionField.Click();
//OK button might appear, might take 5secs - pseudcode
if ( ***alertOKBtn exists, wait for it for 5 secs..*** )
{
alertOkBtn.Click();
}
//continue populating form
}
The PopulateFields method is called from the [Test] as:-
Pages.PTW.PopulateFields();
where Pages.PTW is a get method to PageFactory.InitElements(browser.Driver, page); return page;
Managed to resolve it - in PopulateFields i now do this:-
//wait to see if alert popup appears - give it 8 secs
string waitToSee = browser.wait(alertOKBtn, 8);
if ( waitToSee == "true" )
{
alertOKBtn.Click(); //alert popup did appear
}
Then I've added a method to my browser.class :-
public static string wait(IWebElement elem, int timeout ) //waits for existence of element up to timeout amount
{
try
{
var wait = new WebDriverWait(webDriver, TimeSpan.FromSeconds(timeout));
wait.Until(ExpectedConditions.ElementToBeClickable(elem));
return "true";
}
catch (Exception e ) //didnt appear so exception thrown return false
{
return "false";
}
So it now waits up to 8 seconds and if it doesnt appear it ignores and moves on. Thanks Bendram for the pointers.
Need to add conditional wait. That means, your code should wait till the control appears and then perform the action.
WebDriverWait class which inherits DefaultWait class serves the purpose. The below is the code snippet.
var wait = new WebDriverWait(this.driver, waitTime);
wait.Until(ExpectedConditions.ElementToBeClickable(alertOkBtn));
alertOkBtn.Click();
In some of my projects to correctly save forms user needs to perform click on "Save" or "Save changes" button. That click cause whole page to reload (changes done will be visible on page after that reload), but if something is wrong validation will stops page from reloading.
I want to create a simple assertion to check if that page was reloaded, if not my test will fail. I tried to use this code:
public bool WasPageRefreshed(float seconds)
{
DriverLocal.Manage().Timeouts().SetPageLoadTimeout(TimeSpan.MinValue);
string getReadyState = "return document.readyState;";
for (int i = 0; i < 10; i++)
{
string readyState = GetJsExecutor().ExecuteScript(getReadyState) as string;
if (readyState != "complete")
return true;
Thread.Sleep(TimeSpan.FromMilliseconds(seconds / 10));
}
DriverLocal.Manage().Timeouts().SetPageLoadTimeout(TimeSpan.FromSeconds(60));
return false;
}
I use it in Assert.True() to check if page was reloaded but it doesn't work always (I can use it 5 times on same form - 3 times its ok, 2 times test will fail).
Is there a way to upgrade it to work correctly in 100% of usage?
Or maybe there is another way to check if page was reloaded?
For Webpage load, there is unfortunately no one size fits all solution. Every situation varies. How you wait in your automation suite is very critical. Explicit waits are recommended way of waiting, instead of using Javascript options, you can just wait for a new element after the page load or wait for invisibility of certain element that tells you that the page is loaded
new WebDriverWait(driver, TimeSpan.FromSeconds(timeOut))
.Until(ExpectedConditions
.ElementExists((By.Id("new Element Id"))));
or
new WebDriverWait(driver, TimeSpan.FromSeconds(timeOut))
.Until(ExpectedConditions
.InvisibilityOfElementLocated((By.Id("old Element Id"))));
You can check ExpectedElements docs here
There may be some Ajax call works asynchronously. You can wait until ajax call finished, then do your case, see this:
public void WaitForAjax()
{
while (true) // break if ajax return false
{
var ajaxIsComplete = (bool)(driver as IJavaScriptExecutor).ExecuteScript("return jQuery.active == 0");
if (ajaxIsComplete)
break;
Thread.Sleep(100);
}
}
As my opinion, you better use SeleniumWait instead of Sleep. Try this
public bool WasPageRefreshed(double seconds)
{
WebDriverWait wait = new WebDriverWait(DriverLocal, TimeSpan.FromSeconds(seconds));
wait.PollingInterval = TimeSpan.FromSeconds(1);
string getReadyState = "return document.readyState;";
try
{
wait.Until(d =>
{
string readyState = GetJsExecutor().ExecuteScript(getReadyState) as string;
if (readyState == "complete")
return true;
});
}
catch (Exception)
{
}
return false;
}
I suggest you Wait for a specific element that marked the status of a refreshed page.
Got problem with proper method for waiting until element is visible.
Let me describe how page works. Page is loaded, dropdown is shown, but then, there is progress bar appearing (jquery block UI), because data is loaded from db, according to some conditions.
So i used two methods, one for wait for element to be present, then wait to dissapear, but on some occassions (maybe there are loaded in other way, etc.) i got Internet Explorer crash (so no exception by selenium, but crash of IE). Below methods and execution:
public IWebElement WaitForPageElementToLoad(By by, IWebDriver driver, int timeInSeconds)
{
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeInSeconds));
wait.Until(ExpectedConditions.ElementIsVisible(by));
return driver.FindElement(by);
}
public void WaitForPageElementToBeRemoved(By by, IWebDriver driver, int timeInSeconds)
{
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeInSeconds));
wait.Until<bool>((d) =>
{
try
{
IWebElement element = d.FindElement(by);
return false;
}
catch (NoSuchElementException)
{
return true;
}
});
}
Execution:
WaitForPageElementToLoad(By.XPath("//div[#class='blockUI blockOverlay']"), ieDriver, 25);
WaitForPageElementToBeRemoved(By.XPath("//div[#class='blockUI blockOverlay']"), ieDriver, 25);
WaitForPageElementToLoad(By.Id("clientSelector"), ieDriver, 25);
I think webdriver is searching through elements during some work, i do not how to figure that out, to write it properly. Maybe you'll have some hints, etc.