how to call element in static void? - c#

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");
}
}

Related

SendKeys is not putting the value ToolsQA into the textfield

public static void Main(string[] args)
{
IWebDriver driver = new SafariDriver();
driver.Navigate().GoToUrl("https://demoqa.com/automation-practice-form/");
driver.FindElement(By.Id("firstname")).SendKeys("ToolsQA");
}
I figured out the problem. I should use Name, instead of Id.
driver.FindElement(By.Name("firstname")).SendKeys("ToolsQA");

C# how to automatically call a void or create an object when making a new class

In my test scenario, I basically have two classes Program.CS and SeleniumLibrary.cs
In program.cs I want to make a new class of SeleniumLibrary.cs, but what I want to accomplish is when I do new() I want to make a new instance of my ieDriver automatically.
class Program
{
static void Main(string[] args)
{
//make SeleniumLibrary._iedriver here somehow
SeleniumLibrary.SeleniumLibrary sl = new SeleniumLibrary.SeleniumLibrary();
sl.Navigate("www.google.com");
sl.Navigate("www.nfl.com");
}
}
class SeleniumLibrary
{
private InternetExplorerDriver _ieDriver { get; set; }
private InternetExplorerDriver ieDriver
{
get
{
if (_ieDriver == null)
_ieDriver = new InternetExplorerDriver();
return _ieDriver;
}
}
public void Navigate(string url)
{
ieDriver.Navigate().GoToUrl(url);
}
}
you can see inside of my navigate method I call ieDriver, but is there a way of cleaning up the code above?
I must be misunderstanding something here because whats wrong with:
class SeleniumLibrary
{
private readonly InternetExplorerDriver _ieDriver;
public SeleniumLibrary() //Constructor
{
_ieDriver = new InternetExplorerDriver();
}
public void Navigate(string url)
{
_ieDriver.Navigate().GoToUrl(url);
}
}
This is what DUD is proposing in his answer, I'm just spelling it out.
You can create an c-tor and inside it create the ieDrive

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;
}
}
}

Xunit create new instance of Test class for every new Test ( using WebDriver and C#)

Is there any way to run multiple tests in same browser using Webdriver (Selenium) using Xunit, , at present xunit launches new browser for every new test , below is the sample code
public class Class1
{
private FirefoxDriver driver;
public Class1()
{
driver = new FirefoxDriver();
}
[Fact]
public void Test()
{
driver.Navigate().GoToUrl("http://google.com");
driver.FindElementById("gbqfq").SendKeys("Testing");
}
[Fact]
public void Test2()
{
driver.Navigate().GoToUrl("http://google.com");
driver.FindElementById("gbqfq").SendKeys("Testing again");
}
}
While I don't know Selenium, I do know that xUnit.net creates a new instance of your test class for every test method, so that probably explains why you are seeing the behaviour you're reporting: the driver field is initialized anew for each test method, because the constructor is invoked every time.
In order to reuse a single FirefoxDriver instance, you can use xUnit.net's IUseFixture<T> interface:
public class Class1 : IUseFixture<FirefoxDriver>
{
private FirefoxDriver driver;
public void SetFixture(FirefoxDriver data)
{
driver = data;
}
[Fact]
public void Test()
{
driver.Navigate().GoToUrl("http://google.com");
driver.FindElementById("gbqfq").SendKeys("Testing");
}
[Fact]
public void Test2()
{
driver.Navigate().GoToUrl("http://google.com");
driver.FindElementById("gbqfq").SendKeys("Testing again");
}
}
after some investigation able to find the solution here it is and also updated FirefoxDriver to IWebDriver::
public class SampleFixture : IDisposable
{
private IWebDriver driver;
public SampleFixture()
{
driver = new FirefoxDriver();
Console.WriteLine("SampleFixture constructor called");
}
public IWebDriver InitiateDriver()
{
return driver;
}
public void Dispose()
{
// driver.Close();
driver.Quit();
Console.WriteLine("Disposing Fixture");
}
}
public class Class1 : IUseFixture<SampleFixture>
{
private IWebDriver driver;
public void SetFixture(SampleFixture data)
{
driver = data.InitiateDriver();
}
[Fact]
public void Test()
{
driver.Navigate().GoToUrl("http://google.com");
driver.FindElement(By.Id("gbqfq")).SendKeys("Testing");
}
[Fact]
public void Test2()
{
driver.Navigate().GoToUrl("http://google.com");
driver.FindElement(By.Id("gbqfq")).SendKeys("Testing again");
}
}
IUseFixture doesn't exist any more and seems replaced by IClassFixture. But I can't directly inject the FirefoxDriver as posted by #Mark Seemann:
public class DashboardCategoryBoxes : IClassFixture<FirefoxDriver> {
IWebDriver driver;
public DashboardCategoryBoxes(FirefoxDriver driver) {
//this.driver = wrapper.Driver;
this.driver = driver;
}
}
This throw an error
System.AggregateException : One or more errors occurred. (Class fixture type 'OpenQA.Selenium.Firefox.FirefoxDriver' may only define a single public constructor.) (The following constructor parameters did not have matching fixture data: FirefoxDriver driver)
---- Class fixture type 'OpenQA.Selenium.Firefox.FirefoxDriver' may only define a single public constructor.
---- The following constructor parameters did not have matching fixture data: FirefoxDriver driver
As a workaround, we could create some wrapper class without constructor
public class FirefoxWrapper {
FirefoxDriver driver = new FirefoxDriver();
public FirefoxWrapper Driver {
get { return driver; }
}
}
and fetch the driver from there
public class DashboardCategoryBoxes : IClassFixture<FirefoxWrapper> {
IWebDriver driver;
public DashboardCategoryBoxes(FirefoxWrapper wrapper) {
driver = wrapper.Driver;
}
}

Categories

Resources