webdriver modal window click() not working - c#

I've been browsing around trying to find a solution to this but none of the solutions have worked for me thus far.
Here is a quick test I've thrown together where its simply trying to click the 'close' button to close a modal pop up. I can step through my test in Visual Studio and it will work fine. When I run the test in Nunit, it will error. I've tried the following based upon others issues and suggestions given to them:-
putting in waits all over the place
changing from the chrome driver to firefox
changing to maximised window mode
re-working it every which way I can think of
The modal is not an iframe or anything like that. I seem to be getting the following error:
Exception has been thrown by the target of an invocation.
----> System.InvalidOperationException : Element is not clickable at point (922.5, 342.0999755859375). Other element would receive the click:
which is why I was fiddling with maximised and normal sized modes.
Looking for any suggestions as it's got me stumped..
Thanks
[Test(Description = "Test to check if the cancel button closes the modal window when clicked on the 'Reset Password' modal")]
public void CheckCancelPasswordResetOnModalWorks()
{
bool modalFoundSuccess = false;
bool forgotPasswordControlFound = false;
_driver.Navigate().GoToUrl(_baseURL + "login");
if (_loginPage.CheckForgotPasswordControlExists())
{
forgotPasswordControlFound = true;
_loginPage.ClickForgotPasswordButton();
if (_loginPage.CheckResetPasswordModalIsDisplayed())
{
modalFoundSuccess = true;
_loginPage.ClickCancelResetPasswordButton();
if (_loginPage.CheckResetPasswordModalIsDisplayed() != true)
{
modalFoundSuccess = false;
}
Assert.IsFalse(modalFoundSuccess, "The modal window did not close when the 'cancel' button was clicked on the modal pop up");
}
Assert.IsTrue(forgotPasswordControlFound, "Could not find the 'Forgotten Password' Modal box on the page");
}
Assert.IsTrue(forgotPasswordControlFound, "Was not able to find the 'Forgot Password' button on the '/login' page.");
}
Page Item
public class LoginPage : Page
{
private IWebDriver _driver;
public string userNameValidationText = "Username must be filled in.";
public string passwordValidationText = "Password must be filled in.";
public string incorrectLoginValidationText = "The user name or password is incorrect";
[FindsBy(How = How.ClassName, Using = "scfForm")]
private IWebElement _WFFMForm;
[FindsBy(How = How.XPath, Using = "//div[#class='scfSubmitButtonBorder']/input")]
private IWebElement _loginButton;
[FindsBy(How = How.XPath, Using = "//div[#class='scfSingleLineGeneralPanel']/input")]
private IWebElement _userNameField;
[FindsBy(How = How.XPath, Using = "//div[#class='scfPasswordGeneralPanel']/input")]
private IWebElement _passwordField;
[FindsBy(How = How.XPath, Using = "//div[#id='divForgotPassword']")]
private IWebElement _resetPasswordModal;
[FindsBy(How = How.XPath, Using = "//div[#id='divForgotPassword']/p/input")]
private IWebElement _forgotPasswordEmailInputField;
[FindsBy(How = How.XPath, Using = "//div[#id='divForgotPassword']/a[contains(., 'Reset My Password')]")]
private IWebElement _resetPasswordButton;
[FindsBy(How = How.XPath, Using = "//div[#id='divForgotPassword']/a[contains(., 'Cancel')]")]
private IWebElement _cancelResetPasswordButton;
[FindsBy(How = How.XPath, Using = "//div[#class='forgot-password']/a[contains(., 'Forgot Password')]")]
private IWebElement _forgotPasswordButton;
public LoginPage(IWebDriver driver)
: base(driver)
{
_driver = driver;
PageFactory.InitElements(_driver, this);
}
public void InputUserNameText(string phoneText)
{
_userNameField.Clear();
_userNameField.SendKeys(phoneText);
}
public void InputPasswordText(string queryText)
{
_passwordField.Clear();
_passwordField.SendKeys(queryText);
}
public void InputResetPasswordEmail(string resetEmail)
{
_forgotPasswordEmailInputField.Clear();
_forgotPasswordEmailInputField.SendKeys(resetEmail);
}
public void ClickLoginButton()
{
_loginButton.Click();
}
public void ClickResetButton()
{
WebDriverWait wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(10));
wait.Until((d) => { return CheckModalHasLoaded(); });
_resetPasswordButton.Click();
}
public void ClickCancelResetPasswordButton()
{
WebDriverWait wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(20));
wait.Until((d) => { return CheckModalHasLoaded(); });
_cancelResetPasswordButton.Click();
}
public void ClickForgotPasswordButton()
{
_forgotPasswordButton.Click();
}
public void ClickLoginButtonForEmtpyValidation()
{
_loginButton.Click();
WebDriverWait wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(10));
wait.Until((d) => { return CheckValidationTopBoxExists(); });
}
public bool CheckValidationForIncorrectLoginExists()
{
return Utility.IsThisElementPresent(_driver, By.XPath("//div[#class='scfSubmitSummary']/span"));
}
public bool loginFormExistsCheck()
{
return Utility.IsThisElementPresent(_driver, By.ClassName("scfForm"));
}
public bool CheckValidationTopBoxExists()
{
return Utility.IsThisElementPresent(_driver, By.ClassName("scfValidationSummary"));
}
public bool CheckResetPasswordModalIsDisplayed()
{
return Utility.IsThisElementPresent(_driver, By.XPath("//div[#id='divForgotPassword']"));
}
public bool CheckForgotPasswordControlExists()
{
return Utility.IsThisElementPresent(_driver, By.ClassName("forgot-password"));
}
public bool CheckModalHasLoaded()
{
return Utility.IsThisElementPresent(_driver, By.XPath("//div[#id='divForgotPassword']"));
}
}

If the modal is already in the DOM(ie. not loaded via ajax) you may need to change it to wait for element visible (assuming the modal is hidden). This is because the element is present always, just not visible. This explains why it works when you step through it in debug mode also.
Try using something like
WebDriverWait wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(10));
wait.Until(ExpectedConditions.ElementIsVisible(By.XPath("//div[#id='ElementYouWantToTarget']")));

to me this sounds like either your control lost focus or you did not focus onto right control.
What did you do to find the right control and then have focus on it ?

Related

how to call element in static void?

I'm doing a little selenium program with c#. I want to wait max 5 seconds to interact button or something if its visible. I've made a code for it but I cannot call that code inside static void main it says an object is required non-static field. how do I fix this ?
an error : An object reference is required for the non-static field, method, or property 'Program.waitForPageUntilElementIsVisible(By, int)
class Program
{
public IWebDriver driver;
static void Main(string[] args)
{
IWebDriver driver = new ChromeDriver();
driver.Navigate().GoToUrl("https://www.mail.com/int/");
IWebElement login = driver.FindElement(By.Id("login-button"));
login.Click();
IWebElement email = driver.FindElement(By.Id("login-email"));
waitForPageUntilElementIsVisible(By.Id("login-email"), 5);
email.SendKeys("CarlosdanielGrossen95#mail.com");
}
public IWebElement waitForPageUntilElementIsVisible(By locator,int maxseconds)
{
return new WebDriverWait(driver, TimeSpan.FromSeconds(maxseconds))
.Until(ExpectedConditions.ElementExists((locator)));
}
}
}
An object reference is required for the non-static field, method, or property 'Program.waitForPageUntilElementIsVisible(By, int)
Make the method static.
public static IWebElement waitForPageUntilElementIsVisible(By locator,int maxseconds)
{
return new WebDriverWait(driver, TimeSpan.FromSeconds(maxseconds))
.Until(ExpectedConditions.ElementExists((locator)));
}
Define this method in a separate class and call this method with PageWait Object.
public class PageWait
{
public IWebElement waitForPageUntilElementIsVisible(By locator,int maxseconds)
{
return new WebDriverWait(driver, TimeSpan.FromSeconds(maxseconds))
.Until(ExpectedConditions.ElementExists((locator)));
}
}
class Program {
public IWebDriver driver;
static void Main(string[] args)
{
IWebDriver driver = new ChromeDriver();
driver.Navigate().GoToUrl("https://www.mail.com/int/");
IWebElement login = driver.FindElement(By.Id("login-button"));
login.Click();
IWebElement email = driver.FindElement(By.Id("login-email"));
new PageWait().waitForPageUntilElementIsVisible(By.Id("login-email"), 5);
email.SendKeys("CarlosdanielGrossen95#mail.com");
}
}

WPF WebBrowser not loading

I'm having a problem with the WebBrowser control. I have added it to one of the windows, but it doesen't load the page that i navigate to. I want to access to the control from the other windows, so i made public methods like Navigate etc. I have tried adding WebBrowser to other forms and it seems to work normally. It worked on this window when it was without any added code. I'm using the AutoResetEvent , so when the site would load it would continue the program. Could anyone tell me where could be the problem in this code?
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
readonly AutoResetEvent thread1Step = new AutoResetEvent(false);
public void EnterForm(string ElementId, string value)
{
HTMLDocument document = (HTMLDocument)TempBrowser.Document;
document.getElementById(ElementId).innerText = value;
}
public void Navigate(string url)
{
TempBrowser.Navigate(url);
thread1Step.WaitOne();
thread1Step.Reset();
}
public void PressButton(string id)
{
HTMLDocument doc = (HTMLDocument)TempBrowser.Document;
IHTMLElement btn = doc.getElementById(id);
if (btn != null)
{
btn.click();
}
}
public void Scroll(int n)
{
HTMLDocument doc = (HTMLDocument)TempBrowser.Document;
doc.parentWindow.scroll(0, n);
}
private void TempBrowser_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
thread1Step.Set();
}
public void CallFunction(string Funct)
{
TempBrowser.InvokeScript(Funct);
}
}
I prepared an async code for WPF based on my other answer ...
public static class MyExtensions
{
public static Task NavigateAsync(this WebBrowser browser, Uri uri)
{
var tcs = new TaskCompletionSource<object>();
LoadCompletedEventHandler loadCompleted = null;
loadCompleted = (s, e) =>
{
browser.LoadCompleted -= loadCompleted;
tcs.SetResult(e.WebResponse);
};
browser.LoadCompleted += loadCompleted;
browser.Navigate(uri);
return tcs.Task;
}
}
Now you can remove thread1Step and TempBrowser_LoadCompleted method. Just use
await TempBrowser.NavigateAsync(url);
DoYourWork(); //At this point your page is loaded. Read its content...

C# Extending Selenium Webdriver Class

I would like to add a static string property that will track the name of the current test running. I figured the best way to go about this was to use the WebDriver since it is the only object that is carried throughout all of my page objects.
Is there a way to extend the WebDriver class to add a string property that I can set?
EDIT: Since WebDriver uses the IWebDriver interface rather would I extend the interface perhaps?
EDIT #2: Adding example of what I currently have to load my WebDriver:
protected static NLog.Logger _logger = LogManager.GetCurrentClassLogger();
protected static IWebDriver _driver;
/// <summary>
/// Spins up an instance of FireFox webdriver which controls the browser using a
/// FireFox plugin using a stripped down FireFox Profile.
/// </summary>
protected static void LoadDriver()
{
ChromeOptions options = new ChromeOptions();
try
{
var profile = new FirefoxProfile();
profile.SetPreference("browser.helperApps.neverAsk.saveToDisk", "application/octet-stream doc xls pdf txt");
_driver = new FirefoxDriver(profile);
_driver.Navigate().GoToUrl("http://portal.test-web01.lbmx.com/login?redirect=%2f");
}
catch(Exception e)
{
Console.WriteLine(e.Message);
throw;
}
}
Ok let's stop the half answer practice (That is the full implementation of generic IWebDriver) after that you can call all the regular methods like you use in standard driver + you have your additional CurrentTest variable.
you can add more constructors for best compatibility.
class MyWebDriver<T> where T : IWebDriver, new()
{
IWebDriver driver;
public string CurrentTest { get; set; }
public MyWebDriver()
{
driver = new T();
}
public void Dispose()
{
this.driver.Dispose();
}
public IWebElement FindElement(By by)
{
return this.driver.FindElement(by);
}
public ReadOnlyCollection<IWebElement> FindElements(By by)
{
return this.driver.FindElements(by);
}
public void Close()
{
this.driver.Close();
}
public void Quit()
{
this.driver.Quit();
}
public IOptions Manage()
{
return this.driver.Manage();
}
public INavigation Navigate()
{
return driver.Navigate();
}
public ITargetLocator SwitchTo()
{
return this.SwitchTo();
}
public string Url
{
get
{
return this.driver.Url;
}
set
{
this.driver.Url = value;
}
}
public string Title
{
get
{
return this.driver.Title;
}
}
public string PageSource
{
get
{
return this.driver.PageSource;
}
}
public string CurrentWindowHandle
{
get
{
return this.driver.CurrentWindowHandle;
}
}
public ReadOnlyCollection<string> WindowHandles
{
get
{
return this.WindowHandles;
}
}
}
public class MyTest
{
public void main()
{
MyWebDriver<FirefoxDriver> driver = new MyWebDriver<FirefoxDriver>();
driver.CurrentTest = "Entering to google website with Firefox Driver";
driver.Navigate().GoToUrl("www.google.com");
}
}
You will need to wrap the WebDriver using the "Decorator" design pattern.
public class MyWebDriver : IWebDriver
{
private IWebDriver webDriver;
public string CurrentTest { get; set; }
public MyWebDriver(IWebDriver webDriver)
{
this.webDriver = webDriver
}
public Method1()
{
webDriver.Method1();
}
public Method2()
{
webDriver.Method2();
}
...
}
And then pass in whichever driver you are using at the time.
var profile = new FirefoxProfile();
MyWebDriver driver = new MyWebDriver(new FirefoxDriver(profile));
This way you are delegating the interface methods of IWebDriver to FirefoxDriver but can add whatever additions are appropriate.
what if you do something like
class MyWebDriver
{
private IWebDriver driver;
private static string CurrentTest;
....
//make constractors / getters, setters
}
execution
MyWebDriver d = new MyWebDriver(....)
...
Just use a sub class that has WebDriver as its parent:
public class MyWebDriver : WebDriver
{
private string _currentTest;
}
Then you can use MyWebDriver everywhere and set _currentTest as needed.

How to prevent StaleElementReferenceException in PageFactory in Selenium C#?

I have a Selenium WebDriver Page Object Model in C# 6. I am experiencing StaleElementReferenceExceptions while trying to click on ajax-loaded nav bar elements. This is confusing, because I'm using PageFactory, without any [CacheLookup]s.
Here's the code in question. I've tried to simplify to just the important parts. (I actually pass around a Driver, a wrapper around IWebDriver.) MenuBar.SelectEnglish<T>() throws the exception.
public class Tests
{
[Test]
public void SelectEnglishTest()
{
homePage
.MenuBar.SelectEnglish<HomePage>();
}
// ...
}
public class MenuBar : PageObject
{
[FindsBy(How = How.CssSelector, Using = "...")]
private IWebElement Language { get; set; }
[FindsBy(How = How.CssSelector, Using = "...")]
private IWebElement English { get; set; }
public T SelectEnglish<T>() where T : Page
{
Language.Click();
IWait<IWebDriver> wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(5));
wait.Until(ExpectedConditions.ElementToBeClickable(English));
English.Click();
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-US");
return (T)Activator.CreateInstance(typeof(T), Driver);
}
// ...
}
public class HomePage : PageObject
{
public MenuBar MenuBar { get; private set; }
// ...
}
public class PageObject
{
protected IWebDriver Driver { get; }
protected PageObject(IWebDriver driver)
{
Driver = driver;
PageFactory.InitElements(this, new RetryingElementLocator(Driver, TimeSpan.FromSeconds(20)));
}
// ...
}
What is causing this error? What can I do about it?
From the docs, Stale Element Reference Exception
A stale element reference exception is thrown in one of two cases, the first being more common than the second:
- The element has been deleted entirely.
- The element is no longer attached to the DOM.
Since you mentioned the element is loaded using Ajax, most likely the element changed after your page object fetched it. Just fetch it again or wait for the Ajax to complete before fetching the affected elements.
EDIT 1
Here's some sample code to show how you can fetch an element using a method even while using PageFactory.
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Support.PageObjects;
using System;
namespace C_Sharp_Selenium_Test
{
class Program
{
static void Main(string[] args)
{
FirefoxDriver driver = new FirefoxDriver();
driver.Navigate().GoToUrl("http://www.google.com");
HomePage homePage = new HomePage(driver);
PageFactory.InitElements(driver, homePage);
homePage.search("stack overflow");
homePage.getSearchBox().Clear();
homePage.getSearchBox().SendKeys("c# pagefactory");
homePage.getSearchButton().Click();
}
}
public class HomePage
{
private By searchBox = By.Id("lst-ib");
private By searchButton = By.Name("btnG");
// add other elements in here that use FindsBy() to be loaded using PageFactory.InitElements()
private IWebDriver driver;
public void search(String s)
{
getSearchBox().SendKeys(s);
getSearchButton().Click();
}
public IWebElement getSearchBox()
{
return driver.FindElement(searchBox);
}
public IWebElement getSearchButton()
{
return driver.FindElement(searchButton);
}
public HomePage(IWebDriver driver)
{
this.driver = driver;
}
}
}

how can I automate firefox login to website from c#

I'd like to send a command from a c# app to open a web page in firefox and fill in a form and click a button.
I dont want to use Selenium, what can i do to build this on my own?
The reason frameworks like selenium work is because websites are tempermental and browsers like firefox already implement the requests and responses needed, and frameworks like selenium build on top of that.
As for the profile problem, look here to get some info on creating custom profiles for selenium to use and then instantiate the driver like this:
driver = new FirefoxDriver(new FirefoxProfile(#"...\AppData\Roaming\Mozilla\Firefox\Profiles\7923jt85.default"));
I personaly prefer Selenium's API. Basically I used the IDE extension in firefox to record and export a C# test case, and then used the output to figure out how Selenium parses the html, and then built a library wrapper to make it customizable to my needs.
(The exported test case has a lot of NUnit test framework attributes, I just delete all of those, and call the methods given.)
The example below will open firefox, search google for "Cute Fluffy Cats", and then click on the Images tab.
You can use the API to do more if necessary, its just a matter of seeing what is available in the documentation.
(You can copy this source, create a console project in visual studio, add the selenium references and see it execute right before you very eyes.)
Another alternative is WatiN, but it is similar to Selenium, a test framework for people who build and want to test the user experience of their websites.
using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Support.UI;
namespace SeleniumTests
{
public class Googletest
{
private IWebDriver driver;
private WebDriverWait wait;
private StringBuilder verificationErrors;
private string baseURL;
private bool acceptNextAlert = true;
public static void Main(string[] args)
{
var gt = new Googletest();
gt.SetupTest();
gt.TheGoogleTest();
//gt.TeardownTest();
}
public void SetupTest()
{
driver = new FirefoxDriver();
wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
baseURL = "https://www.google.com/";
verificationErrors = new StringBuilder();
}
public void TeardownTest()
{
try
{
driver.Quit();
}
catch (Exception)
{
// Ignore errors if unable to close the browser
}
}
public void TheGoogleTest()
{
driver.Navigate().GoToUrl(baseURL + "/");
driver.FindElement(By.Id("gbqfq")).Clear();
driver.FindElement(By.Id("gbqfq")).SendKeys("Cute Fluffy Cats");
driver.FindElement(By.Id("gbqfb")).Click();
wait.Until(d => d.FindElement(By.LinkText("Images"))).Click();
}
private bool IsElementPresent(By by)
{
try
{
driver.FindElement(by);
return true;
}
catch (NoSuchElementException)
{
return false;
}
}
private bool IsAlertPresent()
{
try
{
driver.SwitchTo().Alert();
return true;
}
catch (NoAlertPresentException)
{
return false;
}
}
private string CloseAlertAndGetItsText()
{
try
{
IAlert alert = driver.SwitchTo().Alert();
string alertText = alert.Text;
if (acceptNextAlert)
{
alert.Accept();
}
else
{
alert.Dismiss();
}
return alertText;
}
finally
{
acceptNextAlert = true;
}
}
}
}

Categories

Resources