I have got the following method in one file
public class Login
{
static IWebDriver driver;
public static void LogIn(string Env, string User)
{
driver.Navigate().GoToUrl(Env);
driver.Manage().Timeouts().SetPageLoadTimeout(TimeSpan.FromSeconds(3000));
driver.FindElement(By.XPath("//*[#ng-model='email']")).SendKeys(User);
driver.FindElement(By.XPath("//*[#ng-model='password']")).SendKeys("1234");
driver.FindElement(By.XPath("//*[#id=\"ui-view\"]/div/div/div[1]/form/div[2]/button")).Click();
System.Threading.Thread.Sleep(2000);
NUnit.Framework.Assert.IsTrue(driver.FindElement(By.Name("some element")).Displayed,
"Login failed, home page did not display");
}
}
}
And the test I want to call the above method from, in another:
[TestFixture]
public class SmokeTest
{
private IWebDriver driver;
[SetUp]
public void SetUp()
{
driver = new PhantomJSDriver();
}
[Test]
public void Test1()
{
**Login.LogIn("myEnv", "user");**
}
}
I can compile with no issues but once I run Test1 I get the following message:
Automation.SmokeTest.SearchForProduct:
System.NullReferenceException : Object reference not set to an instance of an object.
Nunit points to the Login.LogIn("myEnv", "user"); as the source or error.
Any ideas ?
Ta.
Short answer
static IWebDriver driver; << NULL here
Long answer
You should pass driver through your Login, at your [Test]. It should be something like
[Test]
public void Test1()
{
var loginPage = new Login(driver);
loginpage.LogIn("myEnv", "user");**
}
For your Login, it could be change like following
public class Login
{
/// <summary>
/// Get or set driver
/// </summary>
public IWebDriver Driver { get; set; }
public Login(IWebDriver driver)
{
this.Driver = driver;
}
public static void LogIn(string Env, string User)
{
Driver.Navigate().GoToUrl(Env);
Driver.Manage().Timeouts().SetPageLoadTimeout(TimeSpan.FromSeconds(3000));
Driver.FindElement(By.XPath("//*[#ng-model='email']")).SendKeys(User);
Driver.FindElement(By.XPath("//*[#ng-model='password']")).SendKeys("1234");
Driver.FindElement(By.XPath("//*[#id=\"ui-view\"]/div/div/div[1]/form/div[2]/button")).Click();
System.Threading.Thread.Sleep(2000);
NUnit.Framework.Assert.IsTrue(Driver.FindElement(By.Name("some element")).Displayed,
"Login failed, home page did not display");
}
}
One way would be to change the login method to looks like this:
public static void LogIn(string Env, string User, IWebDriver driver)
by adding passing driver as a var. This way the test stays as single liner
Login.LogIn("myEnv", "user");
Related
There are total 10 test cases. I need to run some testcases with chrome lets say 1-3 and 6-8 test cases with chrome and 4-5 and 9-10 test cases with firefox.
The code in helper file is
static public IWebDriver GetWebDriverC(browserType brt)
{
ChromeOptions cOption = new ChromeOptions();
cOption.AddArgument("no-sandbox");
driver = new ChromeDriver(cOption);
driver.Navigate().GoToUrl(url);
return driver;
}
static public IWebDriver GetWebDriverFF(browserType brt, string url, string username, string password)
{
FirefoxDriverService service = FirefoxDriverService.CreateDefaultService();
service.FirefoxBinaryPath = #"path";
driver = new FirefoxDriver(service);
driver.Navigate().GoToUrl(url);
bool ele1 = AutoItX.WinExists("[CLASS:MozillaDialogClass]") == 1;
if (ele1)
{
AutoItX.WinActivate("[CLASS:MozillaDialogClass]");
AutoItX.Send(username);
AutoItX.Send("{TAB}");
AutoItX.Send(password);
AutoItX.Send("{ENTER}");
}
return driver;
}
Username and password is different for different users.
There are multiple testcases in main file
[TestInitialize]
public void initilize()
{
Webd= Helper.GetWebDriverC(Chrome);
}
[Priority(0)]
[TestMethod]
public void 1()
{
}
[Priority(2)]
[TestMethod]
public void 2()
{
}
.
.
.
[Priority(10)]
[TestMethod]
public void 10()
{
}
There is only one driver in Test initialize that is chrome and chrome gets open before each testcase run. I want that when testcases run on the basis of some condition as mentioned earlier testcases run on the desired Browsers.
How can I achieve that using C# mstest?
The problem here is that you're setting the WebDriver in the TestInitialize step, so any tests within the same class will be using the same driver, in this case Chrome.
One approach would be to have separate test classes for FireFox and Chrome.
Chrome Tests:
public class ChromeTests
{
[TestInitialize]
public void initilize()
{
Webd = Helper.GetWebDriverC(Chrome);
}
[TestMethod]
public void 1()
{
}
}
FireFox tests
public class FireFoxTests
{
[TestInitialize]
public void initilize()
{
Webd = Helper.GetWebDriverFF(Chrome);
}
[TestMethod]
public void 1()
{
}
}
Alternative solutions would include:
Having two WebDrivers in your test class, one for Chrome and one for FireFox, and then you can decide in you tests which driver you wish to use.
Creating a new WebDriver instance in each test
I am just automating a website using SpecFlow+Selenium+pageObject.
When i initialize an object of my SignIn class then i am getting null pointer exception. I tried inside constructor of LoginTest Class(Step definition file) but same error then i moved to first step definition then it is working. The new issue is that i cant use the same object in 2nd step definition since it is initialized locally.
I am adding my code , please tell me what mistake i am making in over all script.
namespace UnitTestProject5.Pages
{
public class SignIn
{
public IWebDriver driver;
[FindsBy(How = How.XPath, Using ("//nav[#role='navigation']/div[3]/div[1]/div/div/div/ul/li[5]/a"))]
public IWebElement Login { get; set; }
public IWebElement Username;
public IWebElement Password;
public IWebElement Signin;
public SignIn(IWebDriver driver)
{
this.driver = driver;
}
public void LoginToMyAccount(String username,String password)
{
Username.SendKeys(username);
Password.SendKeys(password);
Signin.Submit();
}
//...
}
}
And..
namespace UnitTestProject5
{
[Binding]
public class LoginTest
{
IWebDriver driver = null;
// constants con = new constants();
[Given(#"Go to website")]
public void GivenGoToWebsite()
{
driver =new FirefoxDriver();
driver.Navigate().GoToUrl("https://xero.com");
SignIn sin = new SignIn(driver);
PageFactory.InitElements(driver, sin);
sin.Clicklogin();
}
[Given(#"Enter user name & password")]
public void GivenEnterUserNamePassword()
{
sin.
}
[When(#"I press submit")]
public void WhenIPressSubmit()
{
Console.WriteLine("hello");
}
[Then(#"i should be my landing page")]
public void ThenIShouldBeMyLandingPage()
{
Console.WriteLine("hello");
}
}
}
Feature / Scenario:
Feature: Successful Login
Scenario: Successful Login
Given Go to website
And Enter user name & password
When I press submit
Then i should be my landing page
I believe that you're losing the variable between each given-when-then scenario contexts. Each of the methods "Given-When-Then" are executed in a static context and any variables you may have defined in the class are lost between the calls to them. The proper way to adress this is to use the ScenarioContext and FeatureContext objects. Pseudo example below:
:
[Given("Something nice")]
public void WhenIStartSomething()
{
// Add an inspector to the current context
var currentPageInspector = ScenarioContext.Current.Set("PageInspector", new PageInspector());
// Construct other stuff
ScenarioContext.Current.Add("signInInstance", SignIn(...));
}
[When("I do something planned")]
public void WhenIDoSomethingPlanned()
{
var signIn = ScenarioContext.Current.Get<SignIn>();
// do the action with signIn
}
[Then("I should see the following result")]
public void ThenIShouldSeeTheFollowingResult()
{
var currentPageInspector = ScenarioContext.Current.Get<PageInspector>();
currentPageInspector.CurrentPage.Title.ShouldEqual("My Landing Page");
}
What you're basically doing is creating a static instance of your PageInspector and SignIn objects that ONLY EXIST as part of the scenario that they are running in. If you have a different scenario where you repeat any of the steps, the ScenarioContext will ensure that you have a different static context for the objects there.
I have a method that creates 2 remote web drivers. one with chrome and another with firefox:
Driver.cs
public class Driver
{
public static IWebDriver Instance { get; set; }
public static void Initialize()
{
DesiredCapabilities[] browsers = {DesiredCapabilities.Firefox(),DesiredCapabilities.Chrome()};
foreach (DesiredCapabilities browser in browsers)
{
if (browser == DesiredCapabilities.Chrome())
{
var browser = DesiredCapabilities.Chrome();
System.Environment.SetEnvironmentVariable("webdriver.chrome.driver", "C:/Users/jm/Documents/Visual Studio 2013/Projects/VNextAutomation - Copy - Copy (3)/packages/WebDriverChromeDriver.2.10/tools/chromedriver.exe");
ChromeOptions options = new ChromeOptions() { BinaryLocation = "C:/Users/jm/AppData/Local/Google/Chrome/Application/chrome.exe" };
browser.SetCapability(ChromeOptions.Capability, options);
Console.Write("Testing in Browser: " + browser.BrowserName);
Instance = new RemoteWebDriver(new Uri("http://127.0.0.1:4444/wd/hub"), browser);
} else {
Console.Write("Testing in Browser: "+ browser.BrowserName);
Instance = new RemoteWebDriver(new Uri("http://127.0.0.1:4444/wd/hub"), browser);
}
}
Instance.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(15));
}
Then I have a Test class:
[TestClass]
public class LoginTests
{
[TestInitialize]
public void Init()
{
Driver.Initialize();
}
[TestMethod]
public void Failed_login()
{
LoginPage.GoTo();
LoginPage.LoginAs("user").WithPassword("pass").WithDatasource("db").Login();
Assert.IsTrue(LoginFail.IsAt, "Login failure is incorrect");
}
[TestMethod]
public void Admin_User_Can_Login()
{
LoginPage.GoTo();
LoginPage.LoginAs("user").WithPassword("pass").WithDatasource("db").Login();
Assert.IsTrue(HomePage.IsAt, "Failed to login.");
}
[TestCleanup]
public void Cleanup()
{
Driver.Close();
}
}
}
The problem is when Driver.Intialize gets called it doesn't run both chrome and firefox. What I want to happen is that when the Init method gets called it starts both browsers and runs the Test Methods in each browser.
The way I am currently doing this is with NUnit.
I had the same problem and could not find a good way to do it with MSTest.
What I am doing would be:
As you can see I just create a new TestFixture for each browser.
[TestFixture(typeof(ChromeDriver))]
[TestFixture(typeof(InternetExplorerDriver))]
[TestFixture(typeof(FirefoxDriver))]
public class LoginTests<TWebDriver> where TWebDriver : IWebDriver, new()
{
[SetUp]
public void Init()
{
Driver.Initialize<TWebDriver>();
}
[Test]
public void Failed_login()
{
LoginPage.GoTo();
LoginPage.LoginAs("user").WithPassword("pass").WithDatasource("db").Login();
Assert.IsTrue(LoginFail.IsAt, "Login failure is incorrect");
}
[Test]
public void Admin_User_Can_Login()
{
LoginPage.GoTo();
LoginPage.LoginAs("user").WithPassword("pass").WithDatasource("db").Login();
Assert.IsTrue(HomePage.IsAt, "Failed to login.");
}
[TearDown]
public void Cleanup()
{
Driver.Close();
}
}
}
Driver Class
public class Driver<TWebDriver> where TWebDriver : IWebDriver, new()
{
public static IWebDriver Instance { get; set; }
public static void Initialize()
{
if (typeof(TWebDriver) == typeof(ChromeDriver))
{
var browser = DesiredCapabilities.Chrome();
System.Environment.SetEnvironmentVariable("webdriver.chrome.driver", "C:/Users/jm/Documents/Visual Studio 2013/Projects/VNextAutomation - Copy - Copy (3)/packages/WebDriverChromeDriver.2.10/tools/chromedriver.exe");
ChromeOptions options = new ChromeOptions() { BinaryLocation = "C:/Users/jm/AppData/Local/Google/Chrome/Application/chrome.exe" };
browser.SetCapability(ChromeOptions.Capability, options);
Console.Write("Testing in Browser: " + browser.BrowserName);
Instance = new RemoteWebDriver(new Uri("http://127.0.0.1:4444/wd/hub"), browser);
} else {
Console.Write("Testing in Browser: "+ browser.BrowserName);
Instance = new RemoteWebDriver(new Uri("http://127.0.0.1:4444/wd/hub"), browser);
}
}
Instance.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(15));
}
}
I have tried to fit it around your code.
If you wanted to be able to specify a browser to run a test on an adhoc basis rather than all of them every time using TestFixtures, Richard Bradshaw has an excellent tutorial here.
The idea is to use an app config file (and Factory Pattern) that houses values such as the browser, version, platform, selenium hub and port information (as well as any other data you might require in your Hub/Node implementation on Grid) and pull it in at the time of testing to create a WebDriver instance. You can then modify this file in between tests to spin up a WebDriver of a different type if necessary.
We use this to run tests sequentially with NUnit and it has proven quite effective.
an easier and a little bit more straight forward solution using NUnit:
namespace Test
{
//add all browser you want to test here
[TestFixture(typeof(FirefoxDriver))]
[TestFixture(typeof(ChromeDriver))]
public class SkillTest<TWebDriver> where TWebDriver : IWebDriver, new()
{
private IWebDriver _driver;
private string driverPath;
[SetUp]
public void Init()
{
_driver = new TWebDriver();
_driver.Navigate().GoToUrl("https://localhost:5001/");
}
[Test]
public void your_test_case()
{
//some test logic
}
[TearDown]
public void CleanUp()
{
_driver.Quit();
_driver.Dispose();
}
}
}
I have a test class Navigation and I have derived class LeadExTest that is derived from Navigation class. Both class are of [TestClass] type
Now i have a ordered test file, that has a few tests i need to be executed in the order i have shown below.
AdminLogin
do some action
quit browser
AdminLogin, Navigate to page and quit browser test methods belong to Navigation class and do some action belongs to leadextest class
When i execute this ordered test file, admin login and do some action test cases execute just fine, but quit browser method is not getting hit.
//Base class
public class Navigation
{
protected static IWebDriver driver;
protected WebDriverWait wait;
protected StringBuilder verificationErrors;
private string baseURL;
//private bool acceptNextAlert = true;
protected static string advertiserId = "6570";
protected static Actions builder;
[TestInitialize]
public void SetupTest()
{
if (driver == null)
{
driver = new FirefoxDriver();
driver.Manage().Window.Maximize();
baseURL = ConfigurationManager.AppSettings["base_url"].ToString();
verificationErrors = new StringBuilder();
//string url = #"https://stage.madisonlogic.com/login.aspx";
//driver.Navigate().GoToUrl(url.ToString());
driver.Navigate().GoToUrl(ConfigurationManager.AppSettings["test_url"].ToString());
builder = new Actions(driver);
}
wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
}
[TestMethod]
public void adminLogin()
{
CommonFunctions.Login(driver, "rlodha", "a");
if (IsElementPresent(By.ClassName("TopTitle")))
Assert.AreEqual("Admin Center | Dashboard", driver.FindElement(By.ClassName("TopTitle")).Text.Trim().ToString());
else
Assert.Fail("Timed Out");
}
[TestMethod]
public void browserQuit()
{
CommonFunctions.BrowserQuit(driver);
Assert.IsNull(driver);
}
//derived class
[TestMethod]
public void Nav_Lead_Delivery()
{
builder.MoveToElement(driver.FindElement(By.Id("Content_AdvertiserMenu1_LeadsBtn"))).Perform();
driver.FindElement(By.Id("Content_AdvertiserMenu1_LeadExportBtn")).Click();
Console.Write("Hi");
}
Well you are just declaring it as another test method, so of course this isn't going to work.
You need to give MSTest much more of a clue about when to call your method, so replace it with a ClassCleanup to tell MSTest to call this method when all the tests are done.
Here's my code :
[TestInitialize]
public void init()
{
_browser = new DefaultSelenium("localhost", 4444, #"*iehta", "http://localhost:4444");
}
[TestMethod]
public void TestLogin()
{
bool hasText;
_browser.Start();
_browser.Open("http://localhost/testSite.asp");
_browser.Type("id=NomUtilisateur", "admin");
_browser.Type("id=UserPassword", "password");
_browser.Click("name=Submit");
_browser.WaitForPageToLoad("30000");
hasText = _browser.IsTextPresent("test");
Assert.IsTrue(hasText, #"The search result does not contain text ""test"".");
}
[TestMethod]
public void TestRequisitionPhotocopie()
{
_browser.Start();
_browser.Open("http://localhost/testSite.asp");
_browser.Type("id=NomUtilisateur", "admin");
_browser.Type("id=UserPassword", "password");
_browser.Click("name=Submit");
_browser.WaitForPageToLoad("30000");
_browser.Click("link=lnkTest");
_browser.WaitForPageToLoad("30000");
}
[TestCleanup]
public void clean()
{
_browser.Stop();
//_browser.Close();
}
If I run the two test method, the secon test always fail with an error message like this :
Remote server don't exist or is unavaible
If I comment one of the test method, it's working, my two test method are working
Where's my mistake.
Thanks
EDIT :
The error is not happening everytime, but the error is in Selenium Remote Control If i debug the error is in selenium-browserbot.js at line 724 : windowToModify.seleniumAlert = windowToModify.alert;
Selenium log console have nothing in it
Have you tried it like this? I always start selenium in the setup of the test. (i'm also using Nunit
[SetUp]
public void init()
{
_browser = new DefaultSelenium("localhost", 4444, #"*iehta", "http://localhost:4444");
_browser.Start();
_browser.Open("http://localhost/testSite.asp");
}
[TestMethod]
public void TestLogin()
{
bool hasText;
_browser.Type("id=NomUtilisateur", "admin");
_browser.Type("id=UserPassword", "password");
_browser.Click("name=Submit");
_browser.WaitForPageToLoad("30000");
hasText = _browser.IsTextPresent("test");
Assert.IsTrue(hasText, #"The search result does not contain text ""test"".");
}
[TestMethod]
public void TestRequisitionPhotocopie()
{
_browser.Type("id=NomUtilisateur", "admin");
_browser.Type("id=UserPassword", "password");
_browser.Click("name=Submit");
_browser.WaitForPageToLoad("30000");
_browser.Click("link=lnkTest");
_browser.WaitForPageToLoad("30000");
}
[TearDown]
public void clean()
{
_browser.Stop();
//_browser.Close();
}