First sorry about my English.
Here is my problem:
I make a test for mantisbt with many test cases(report issue), so i put the login in [SetUpFixture] and in [TestFixture] [Test, TestCaseSource("function")] I don't know how to get driver which i use for creating chrome browser to get elements.
Here is my code:
namespace testcailz
{
[SetUpFixture]
public class TestsSetupClass
{
public void login(IWebDriver driver)
{
IWebElement username = driver.FindElement(By.Name("username"));
username.SendKeys("1353049");
IWebElement password = driver.FindElement(By.Name("password"));
password.SendKeys("123456");
IWebElement login = driver.FindElement(By.XPath("//input[#value='Login'][#class='button']"));
login.Click();
}
[SetUp]
public void GlobalSetup()
{
IWebDriver driver = new ChromeDriver();
driver.Navigate().GoToUrl("http://www.cs.hcmus.edu.vn/mantisbt/login_page.php");
login(driver);
}
[TearDown]
public void GlobalTeardown()
{
// Do logout here
}
}
[TestFixture]
public class Class1
{
private static int[] data()
{
return new int[3] { 1, 2, 3 };
}
[Test, TestCaseSource("data")]
public void TestCaiLz(int i)
{
//wanna click to report new issue but how to get driver for Findelement
Assert.AreEqual(i, i);
}
}
}
As per java prospective, create driver object globally in class may be TestsSetupClass
public static WebDriver driver;
#BeforeSuite
public void startUp(){
driver=new FirefoxDriver();
driver.manage().window().maximize();
login(driver);
}
If you what to use this driver in another classes then extends this class. like below in java
public class Home extends Setup{ //...
}
Thank You,
Murali
Related
I need to know how we can use the same instances of a Selenium Driver in different classes? So I have created an instance of the driver in a class, using the code :
IWebDriver driver = new ChromeDriver("C:/Users/Krishna/source/repos/G1ANT.Addon.YouTube/packages/Selenium.Chrome.WebDriver.83.0.0/driver");
So I need to use this instance in the new class, how could I do that?
Thank You
The simplest approach is to put the driver in a static field of another class like below. Or you can use a singleton design pattern for returning the driver instance one and only once throughout the application
public class DriverHelper
{
public static readonly IWebDriver Driver = new ChromeDriver("C:/Users/Krishna/source/repos/G1ANT.Addon.YouTube/packages/Selenium.Chrome.WebDriver.83.0.0/driver");
}
Then access the driver like
var _driver = DriverHelper.Driver;
You need to create utils class for driver instance so you can ignore nullpoint exception. i will share my utils class for driver instance you can use it (create package for utils classes inside you project folder)
package utils;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.io.File;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Paths;
public class TestApp {
private WebDriver driver;
private static TestApp myObj;
// public static WebDriver driver;
utils.PropertyFileReader property = new PropertyFileReader();
public static TestApp getInstance() {
if (myObj == null) {
myObj = new TestApp();
return myObj;
} else {
return myObj;
}
}
//get the selenium driver
public WebDriver getDriver()
{
return driver;
}
//when selenium opens the browsers it will automatically set the web driver
private void setDriver(WebDriver driver) {
this.driver = driver;
}
public static void setMyObj(TestApp myObj) {
TestApp.myObj = myObj;
}
public void openBrowser() {
//String chromeDriverPath = property.getProperty("config", "chrome.driver.path");
//String chromeDriverPath = property.getProperty("config", getChromeDriverFilePath());
System.setProperty("webdriver.chrome.driver", getChromeDriverFilePath());
ChromeOptions options = new ChromeOptions();
options.addArguments("--disable-notifications");
options.addArguments("disable-infobars");
driver = new ChromeDriver(options);
driver.manage().window().maximize();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void navigateToURL() {
String url =property.getProperty("config","url");
driver.get(url);
}
public void closeBrowser()
{
driver.quit();
}
public WebElement waitForElement(By locator, int timeout)
{
WebElement element = new WebDriverWait(TestApp.getInstance().getDriver(), timeout).until
(ExpectedConditions.presenceOfElementLocated(locator));
return element;
}
private String getChromeDriverFilePath()
{
// checking resources file for chrome driver in side main resources
URL res = getClass().getClassLoader().getResource("chromedriver.exe");
File file = null;
try {
file = Paths.get(res.toURI()).toFile();
} catch (URISyntaxException e) {
e.printStackTrace();
}
return file.getAbsolutePath();
}
}
Note if you are using mac mention above chromedriver only
Keep chrome driver in resource folder
TestApp.getInstance().getDriver() -This is way use driver.
the 2 nd option is you can create global variable for driver instance
---**static private WebDriver driver;**
Question is probably really trivial but I cannot handle it in proper way. I'm using Selenium with NUnit, having two clases:
1) "DemoTest" which involves one simply test "DummyTest":
public class DemoTest : TestBase
{
public class RunTest
{
[Test, Category("Main-Tests"), Order(1)]
public void DummyTest()
{
}
}
}
2) "Test base" class where I want to place all of the NUnit/ driver attributes like: "SetUp" / "TearDown"
[TestFixture]
public class TestBase
{
public IWebDriver driver;
public IWebDriver Driver
{
get { return driver; }
set { driver = value; }
}
public string pageURL = "http://automationpractice.com/";
[SetUp]
public void SetUp()
{
driver = new ChromeDriver();
driver.Manage().Timeouts().PageLoad = TimeSpan.FromSeconds(15);
driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(0);
driver.Navigate().GoToUrl(pageURL);
}
[TearDown]
public void TearDown()
{
driver.Close();
driver.Dispose();
}
}
}
As NUnit attributes are declared (SetUp section) my test from DemoTest class should at least move on the page under pageURL variable.
Result is that after running a test it's immediately jump on "passed" without opening the specified address.
"DemoTest" inherits from "Test base" class. Nuget packages are installed correctly. When I'm placing test inside the "Test base" class everything works correctly but I want to have it separated.
Try to fix DemoTest class as follows:
[TestFixture]
public class DemoTest : TestBase
{
[Test, Category("Main-Tests"), Order(1)]
public void DummyTest()
{
}
}
I am creating a new framework as PageFactory has been deprecated.
I am getting the error
BoDi.ObjectContainerException : Interface cannot be resolved: OpenQA.Selenium.IWebDriver (resolution path: UnitTestProject1.Base)
TearDown : BoDi.ObjectContainerException : Interface cannot be resolved: OpenQA.Selenium.IWebDriver (resolution path: UnitTestProject1.Base)
My code snippet of my framework is below. I am not sure how I can resolve this. I am aware I could use Context Injection but am not sure what attributes from my framework I should move and to where.
I was thinking should I move the IWedriver Driver to a class and call this in a constructor but not sure where I should call it in the steps file.
Some help to resolve this issue appreciated, thanks.
using System;
using System.Collections.Generic;
using System.Text;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using SeleniumExtras.PageObjects;
namespace UnitTestProject1
{
public class Base : SpecflowBaseTest
{
protected IWebDriver driver { get; set; }
public Base(IWebDriver Driver)
{
driver = Driver;
//PageFactory.InitElements(Driver, this);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TechTalk.SpecFlow;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using UnitTestProject1.Page;
using OpenQA.Selenium.Remote;
using BoDi;
namespace UnitTestProject1
{
[Binding]
public class SpecflowBaseTest : TechTalk.SpecFlow.Steps
{
// For additional details on SpecFlow hooks see
http://go.specflow.org/doc-hooks
protected IWebDriver Driver { get; set; }
private readonly IObjectContainer objectContainer;
[BeforeScenario]
public void BeforeScenario()
{
Driver = new ChromeDriver();
//this.objectContainer = objectContainer;
//ObjectContainer.RegisterInstanceAs<IWebDriver>(Driver);
Driver.Manage().Window.Maximize();
}
[AfterScenario]
public void AfterScenario()
{
Driver.Close();
Driver.Quit();
}
public void NavigateToURL(string URL)
{
Driver.Navigate().GoToUrl(URL);
}
protected LoginPage LoginPage => new LoginPage(Driver);
}
}
using NUnit.Framework;
using System;
using TechTalk.SpecFlow;
namespace UnitTestProject1.Steps
{
[Binding, Parallelizable]
public class LoginSteps : SpecflowBaseTest
{
[Given(#"I navigate to (.*)")]
public void GivenINavigateToHttpsCompany_Com(string URL)
{
NavigateToURL(URL);
}
[Given(#"I enter bw_(.*) and (.*)")]
public void GivenIEnterBw_Valid_UserAnd(string Username, string
Password)
{
LoginPage.Login(Username, Password);
}
[Then(#"I am logged in as bw_valid_user")]
public void ThenIAmLoggedInAsBw_Valid_User()
{
//LoginPage.
}
}
}
You need to initialize a new IWebDriver object and register it with SpecFlow's dependency injection framework in a [BeforeScenario].
[Binding]
public class SeleniumSpecFlowHooks
{
private readonly IObjectContainer container;
public SeleniumSpecFlowHooks(IObjectContainer container)
{
this.container = container;
}
[BeforeScenario]
public void CreateWebDriver()
{
// Create and configure a concrete instance of IWebDriver
IWebDriver driver = new FirefoxDriver(...)
{
...
};
// Make this instance available to all other step definitions
container.RegisterInstance(driver);
}
[AfterScenario]
public void DestroyWebDriver()
{
IWebDriver driver = container.Resolve<IWebDriver>();
driver.Close();
driver.Dispose();
}
}
Your step definition classes should not be initializing the web driver. Just declare an IWebDriver argument in their constructors.
Base class:
[Binding]
public class SpecflowBaseTest : TechTalk.SpecFlow.Steps
{
protected IWebDriver Driver { get; }
protected LoginPage LoginPage { get; }
public SpecflowBaseTest(IWebDriver driver)
{
Driver = driver;
LoginPage = new LoginPage(driver);
}
public void NavigateToURL(string URL)
{
Driver.Navigate().GoToUrl(URL);
}
}
Child class:
[Binding, Parallelizable]
public class LoginSteps : SpecflowBaseTest
{
[Given(#"I navigate to (.*)")]
public void GivenINavigateToHttpsCompany_Com(string URL)
{
NavigateToURL(URL);
}
[Given(#"I enter bw_(.*) and (.*)")]
public void GivenIEnterBw_Valid_UserAnd(string Username, string Password)
{
LoginPage.Login(Username, Password);
}
[Then(#"I am logged in as bw_valid_user")]
public void ThenIAmLoggedInAsBw_Valid_User()
{
//LoginPage.
}
}
solved by creating a new class
using BoDi;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using TechTalk.SpecFlow;
namespace DoclerQAtests
{
[Binding]
public class WebDriverSupport
{
private readonly IObjectContainer objectContainer;
private ChromeDriver webdriver;
public WebDriverSupport(IObjectContainer objectContainer)
{
this.objectContainer = objectContainer;
}
[BeforeScenario]
public void InitializeWebDriver()
{
this.webdriver = new ChromeDriver();
objectContainer.RegisterInstanceAs<IWebDriver>(webdriver);
}
}
}
For me this issue was resolved by adding a class level field public IWebDriver Driver instead of a local method level driver.
[Binding]
public class DriverSetup
{
private IObjectContainer _objectContainer;
public IWebDriver Driver;
public DriverSetup(IObjectContainer objectContainer)
{
_objectContainer = objectContainer;
}
[BeforeScenario]
public void BeforeScenario()
{
//TODO please supply your Sauce Labs user name in an environment variable
var sauceUserName = Environment.GetEnvironmentVariable("SAUCE_USERNAME", EnvironmentVariableTarget.User);
//TODO please supply your own Sauce Labs access Key in an environment variable
var sauceAccessKey = Environment.GetEnvironmentVariable("SAUCE_ACCESS_KEY", EnvironmentVariableTarget.User);
var sauceOptions = new Dictionary<string, object>
{
["username"] = sauceUserName,
["accessKey"] = sauceAccessKey
};
var chromeOptions = new ChromeOptions
{
BrowserVersion = "latest",
PlatformName = "Windows 10"
};
chromeOptions.AddAdditionalOption("sauce:options", sauceOptions);
Driver = new RemoteWebDriver(new Uri("https://ondemand.saucelabs.com/wd/hub"),
chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(30));
_objectContainer.RegisterInstanceAs(Driver);
}
}
how to do something like this. So the scenario is I have 2 "DoLogin" methods in a different platform (Mobile Version, Desktop Version)
I want to make the code more readable and look something like this
Ex.
if I wanted to login to a desktop version.
webDriver.Desktop.Dologin(accountModel)
If I wanted to login to a mobile version.
webDriver.Mobile.DoLogin(accountModel)
this is what I currently have.
public static class Desktop
{
public static void DoLogin(this ChromeDriver webDriver, AccountModel account)
{
}
}
public static class Mobile
{
public static void DoLogin(this ChromeDriver webDriver, AccountModel account)
{
}
}
EDIT
This is what I'm currently doing to organize it.
public static class Desktop
{
public static void DesktopDoLogin(this ChromeDriver webDriver, AccountModel account)
{
}
}
public static class Mobile
{
public static void MobileDoLogin(this ChromeDriver webDriver, AccountModel account)
{
}
}
whenever I call a method let say desktop what I do is.
webDriver.DesktopDoLogin(account)
or
webDriver.MobileDoLogin(account)
I guess whats important is it works.
I personally don't like using extension methods. This is a preference. I would have most likely implemented it as follows. I have never used Selenium before, so I'm not sure what interface WebDriver is/implements but you can get the gist of the pattern.
public interface IPlatform
{
void Login<T>(T model);
}
public class Desktop : IPlatform
{
private readonly WebDriver _webDriver;
public Desktop(WebDriver driver)
{
_webDriver = driver;
}
public void Login<T>(T model)
{
// do login here
}
}
// usage
IPlatform desktop = new Desktop(/*chromedriver*/); // or inject
desktop.Login<AccountModel>(model);
It seems to me that you can get this:
void Main()
{
var webDriver = new ChromeDriver();
webDriver.Desktop.DoLogin(new AccountModel());
webDriver.Mobile.DoLogin(new AccountModel());
}
By doing this:
public interface IDoLogin
{
void DoLogin(AccountModel account);
}
public class Desktop : IDoLogin
{
private ChromeDriver _webDriver;
public Desktop(ChromeDriver webDriver)
{
_webDriver = webDriver;
}
public void DoLogin(AccountModel account) { }
}
public class Mobile : IDoLogin
{
private ChromeDriver _webDriver;
public Mobile(ChromeDriver webDriver)
{
_webDriver = webDriver;
}
public void DoLogin(AccountModel account) { }
}
public class ChromeDriver
{
public Desktop Desktop;
public Mobile Mobile;
public ChromeDriver()
{
this.Desktop = new Desktop(this);
this.Mobile = new Mobile(this);
}
}
You can do it easily using some static voids like that:-
Public class desktop {
Public static void DoLogin(AccountModel val){
//code for desktop
}
}
Public class mobile {
Public static void DoLogin(AccountModel val){
//code for mobile
}
}
Public class webDriver{
Public static desktop Desktop;
Public static mobile Mobile;
}
//usage
webDriver.mobile.DoLogin(...);
//or
mobile.DoLogin();
Why not using Interface?
Create one common interface with DoLogin Method, and Implement that interface in Desktop and Mobile class.
Common Interface:
public interface ICommon
{
void Login<T>(T model);
}
Implement this interface in your Desktop and Mobile Class.
So I've gone back to basics with a blank project to test this out, I'm trying to use the example...
[TestFixture(typeof(ChromeDriver))]
public class TestWithMultipleBrowsers<TWebDriver> where TWebDriver : IWebDriver, new()
{
private IWebDriver driver;
[SetUp]
public void CreateDriver()
{
this.driver = new TWebDriver();
}
[Test]
public void GoogleTest()
{
driver.Navigate().GoToUrl("http://www.google.com/");
IWebElement query = driver.FindElement(By.Name("q"));
query.SendKeys("Bread" + Keys.Enter);
Thread.Sleep(2000);
Assert.AreEqual("bread - Google Search", driver.Title);
driver.Quit();
}
}
However it just does not run. If I remove the TestFixture typeof parameter though and set the driver manually it works fine.
[TestFixture]
public class TestWithMultipleBrowsers
{
private IWebDriver driver;
[SetUp]
public void CreateDriver()
{
this.driver = new ChromeDriver();
}
[Test]
public void GoogleTest()
{
driver.Navigate().GoToUrl("http://www.google.com/");
IWebElement query = driver.FindElement(By.Name("q"));
query.SendKeys("Bread" + Keys.Enter);
Thread.Sleep(2000);
Assert.AreEqual("bread - Google Search", driver.Title);
driver.Quit();
}
}
Any ideas on why using TextFixture with a parameter would prevent the test from running? I've already checked over CPU settings and Resharper settings based on other posts.
Many Thanks
After comparing NuGet packages with an old project looks like there may be an issue with the most recent version of NUnit. Downgraded to 2.6.4 all seems to be working fine.