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();
}
Related
I am testing form validation with selenium using C#. I have a update button that when clicked pops up a form with the users previously enter info. I am trying to test a user trying to submit an empty update form by finding the element and clearing the field. When submitting a form with empty values, I have validation errors that should display under the field. This works when running my program manually. When running my test, I can see that the fields are being cleared but when I hit submit, my form is repopulating with the data that had previously been there. I have also tried to clear the form, then in an empty string for the keys but it still repopulates the form when I hit submit. I also tried to clear the form and then fill it in using special characters to prompt a different error message. The form is clearing but then it is taking the value that was entered before and putting the special character to the end of that value. Here is part of my code:
var user = new Users(driver);
user.EditUserByEmail("pinocchio#aol.com");
driver.FindElement(By.Name("firstName")).Clear();
driver.FindElement(By.Name("lastName")).Clear();
driver.FindElement(By.Name("email")).Clear();
user.EnterFirstName("$");
user.EnterLastName("$");
user.EnterEmail("$");
var modal = new Modal(driver);
modal.SubmitForm();
These are the methods I am using in the Users class:
public void EnterFirstName(string firstName)
{
WebDriverWait wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(30));
var firstNameInput = wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementToBeClickable(By.Name("firstName")));
firstNameInput.SendKeys(firstName);
}
public void EnterLastName(string lastName)
{
WebDriverWait wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(30));
var lastNameInput = wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementToBeClickable(By.Name("lastName")));
lastNameInput.SendKeys(lastName);
}
public void EnterEmail(string email)
{
WebDriverWait wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(30));
var emailInput = wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementToBeClickable(By.Name("email")));
emailInput.SendKeys(email);
}
The form clears and then this is what is entered in:
By my code I would expect each field to just be entered with a $. I don't know how or why the previous data is repopulating.
Sometimes you just need to brute-force this kind of thing. An extension method can clean things up while giving you a way to retry an operation that fails:
namespace OpenQA.Selenium
{
public static class WebElementExtensions
{
public static void EnterText(this IWebElement element, string text)
{
element.Clear();
if (!string.IsNullOrEmpty(element.GetProperty("value")))
{
System.Threading.Thread.Sleep(500);
element.Clear();
}
element.SendKeys(text);
}
public static void EnterTextRobustly(this IWebElement element, string text)
{
element.EnterText(text);
if (element.GetProperty("value") == text)
return;
System.Threading.Thread.Sleep(500);
element.EnterText(text);
if (element.GetProperty("value") == text)
return;
System.Threading.Thread.Sleep(500);
element.EnterText(text);
if (element.GetProperty("value") != text)
throw new WebDriverException($"Failed to enter text into a text field. Expected value: '{text}'; Actual value: '{element.GetProperty("value")}'");
}
}
}
And to use it:
// for example, in EnterLastName(...)
lastNameInput.EnterTextRobustly(lastName);
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 have a number of tests. Sometimes if an element can't be found it just clicks on the top left of the screen. This doesn't happen all the time however it does happen. I'm not sure why this is happening. In my setUp method I'm telling it to click the element "Maximize" however if it can't find that element I put it into a catch and ignore it. For some reason when it can't find the element it just clicks on the top left corner of the screen that has the application session.
Has anyone any ideas why this is happening or is it just how selenium sometimes responds
My code is as follows
private string wordId = OfficeVersion.Word();
private string excelId = OfficeVersion.Excel();
private string powerPointId = OfficeVersion.PowerPoint();
private const string AppDriverUrl = "http://127.0.0.1:4723";
public static WindowsDriver<WindowsElement> excelSession;
public static WebDriverWait webDriverWait;
xl.Workbook WB;
public static bool skipTearDown = false;
WindowsElement create;
WindowsElement blankWorkBook;
public static DesiredCapabilities appCapabilities = new DesiredCapabilities();
[TestInitialize]
appCapabilities.SetCapability("app", excelId);
var initialSession = new WindowsDriver<WindowsElement>(new Uri(AppDriverUrl), appCapabilities);
var capabilities = new DesiredCapabilities();
capabilities.SetCapability("app", "Root");
excelSession = new WindowsDriver<WindowsElement>(new Uri(AppDriverUrl), capabilities);
webDriverWait = new WebDriverWait(excelSession, TimeSpan.FromSeconds(10));
CommonMethods.keyCheck(excelSession);
webDriverWait = new WebDriverWait(excelSession, TimeSpan.FromSeconds(10));
CommonMethods.IsElementDisplayed(excelSession, new StackTrace(true).GetFrame(0).GetFileLineNumber(), new StackTrace(true).GetFrame(0).GetMethod(), "CreateErrorIcon", "Create error when launching Excel");
try
{
This is the element I'm having trouble ignoring if it doesn't exist
webDriverWait.Until(ExpectedConditions.ElementToBeClickable(excelSession.FindElementByName("Maximize"))).Click();
}
catch (Exception)
{
//ignore
}
You can try to get the current window handle first and then attempt to locate and get the Webelement that points to the Maximize button for the window. Possibly, you might also need give a simple wait on the WebElement locate just to be safe.
This api might be useful for a C# client to selenium - driver.SwitchTo().Window(handle)
And for details, you can check here
I was running into the same problem when trying to select an item from a combo-box. Trying click on the item would always just result in a click on the top left of the screen. Super frustrating.
I got around it by using an Action to move the mouse to the element and then performing a click.
var a = new Actions(Session);
a.MoveToElement(v);
a.Click();
a.Perform();
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.
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.
}