I have implemented the following setup in my automation framework:
C# Selenium webDriver
IObjectContainer
Specflow
Nunit 3 Parallelizable
Xpaths (and all selectors) are simply defined as 'private const string'
code sample HomePageSteps (working code):
[Binding]
public class HomePageSteps
{
private IWebDriver _driver;
public HomePageSteps(IWebDriver driver)
{
_driver = driver;
}
private const string LogoTwo = "//img[#alt='xpath']";
[Given(#"I navigation to site")]
public void GivenINavigationToSite()
{
_driver.Navigate().GoToUrl("http://website.com/");
_driver.FindElement(By.XPath(LogoTwo)).Click();
}
}
But I want to use the webDriver PageFactory attribute to handle my page objects. Which I have done / used in other projects that do Not use 'Nunit 3 Parallelizable'.
code example (NOT working code):
[Binding]
public class HomePageSteps
{
private IWebDriver _driver;
public HomePageSteps(IWebDriver driver)
{
_driver = driver;
}
[FindsBy(How = How.XPath, Using = "//img[#alt='xpath']")]
public IWebElement logo { get; set; }
[Given(#"I navigation to site")]
public void GivenINavigationToSite()
{
_driver.Navigate().GoToUrl("http://website.com/");
logo.Click();
}
}
The problem here is that 'logo' is Null. And I'm not sure if this problem is related to a limitation of use ''Nunit 3 Parallelizable' with PageFactory, or with specflow, or something else in my design.
Can anyone please give some guidance?
The reason Page Factory would not initialize non-static driver is that it takes in Static driver. If The constructor for the page is defined like this :
ChromeDriverService service = ChromeDriverService.CreateDefaultService(startDirectory + #"\Drivers\", "chromedriver.exe");
IWebDriver Static driver = new ChromeDriver(Service);
public HomePageSteps()
{
PageFactory.InitElements(driver, this);
}
It would allow you to use the elements as you have defined them.
Please let me know if you have found any other work around to this.
Related
I am running a test case using pagefactory method and have created an appium driver. I'm trying to initialising a page using pagefactory class like this:
The test class:
public class VerifyValidLogin {
#Test
public void CheckValidUser() throws MalformedURLException {
AppiumDriver driver = DeviceFactory.CreateDriver();
login login_page = PageFactory.initElements(driver, login.class);
}
}
DeviceFactory class:
public class DeviceFactory {
public static AppiumDriver<MobileElement> driver;
public static AppiumDriver CreateDriver() throws MalformedURLException {
DesiredCapabilities cap = new DesiredCapabilities();
cap.setCapability( capabilityName: 'deviceName', value: 'Something');
...
URL url = new URL("http://127.0.0.1:4723/wd/hub");
driver = new AppiumDriver<MobileElement>(url,cap);
System.out.print("Application started");
return driver;
}
}
Login class has element locators:
public class login {
AppiumDriver driver;
public login(AppiumDriver ldriver)
{
this.driver=ldriver;
}
#FindBy(how = How.XPATH,using ="xpath");
MobileElement SignInButton;
}
But i'm not sure where i am doing wrong.
The error is
java.lang.RuntimeException: java.lang.InstantiationException: com.Demo.pages.login
at org.openqa.selenium.support.PageFactory.instantiatePage(PageFactory.java:134)
at org.openqa.selenium.support.PageFactory.initElements(PageFactory.java:64)
at com.Demo.Testcases.VerifyValidLogin.CheckValidUser(VerifyValidLogin.java:18)
...
I am new to the automation testing so i'm not able to properly understand the error. Let me know if you need more details.
Initialise elements in constructor
public login(AppiumDriver ldriver)
{
this.driver=ldriver;
PageFactory.initElements(ldriver,this);
}
I'm trying to set up a simple DAL that will return a List of typed objects. Pretty standard data repository stuff. I downloaded all of ABP's code from GitHub, built the DLLs for Abp.Dapper and Abp.EntityFrameworkCore and started following the instructions on this page:
https://aspnetboilerplate.com/Pages/Documents/Dapper-Integration
But I can't even get past step one of this. This code doesn't compile because it doesn't know what SampleApplicationModule is. But there's no guidance in these instructions as to what that is supposed to be.
How am I supposed to use Abp's libraries? I'm lost. Can someone please let me know the minimum number of things I need to do in order to wire up my database to Abp's library and query for a List of typed objects?
Code from Abp's Dapper Integration documentation:
[DependsOn(
typeof(AbpEntityFrameworkCoreModule),
typeof(AbpDapperModule)
)]
public class MyModule : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(typeof(SampleApplicationModule).GetAssembly());
}
}
if you are confused what to write for SampleApplicationModule use the below code
Module Registration
[DependsOn(
typeof(AbpEntityFrameworkModule),
typeof(AbpKernelModule),
typeof(AbpDapperModule)
)]
public class SampleApplicationModule : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}
}
Usage
public class SomeDomainService : ITransientDependency
{
private readonly IDapperRepository<Animal> _animalDapperRepository;
private readonly IRepository<Animal> _animalRepository;
private readonly IDapperRepository<Person> _personDapperRepository;
private readonly IRepository<Person> _personRepository;
private readonly IUnitOfWorkManager _unitOfWorkManager;
public SomeDomainService(
IUnitOfWorkManager unitOfWorkManager,
IRepository<Person> personRepository,
IRepository<Animal> animalRepository,
IDapperRepository<Person> personDapperRepository,
IDapperRepository<Animal> animalDapperRepository)
{
_unitOfWorkManager = unitOfWorkManager;
_personRepository = personRepository;
_animalRepository = animalRepository;
_personDapperRepository = personDapperRepository;
_animalDapperRepository = animalDapperRepository;
}
public void DoSomeStuff()
{
using (IUnitOfWorkCompleteHandle uow = _unitOfWorkManager.Begin())
{
_personRepository.Insert(new Person("Oğuzhan"));
_personRepository.Insert(new Person("Bread"));
_animalRepository.Insert(new Animal("Bird"));
_animalRepository.Insert(new Animal("Cat"));
_unitOfWorkManager.Current.SaveChanges();
Animal animal = _animalRepository.FirstOrDefault(x => x.Name == "Bird");
Person person = _personDapperRepository.Get(1);
int personCount = _personDapperRepository.Count(x => x.Name == "Oğuzhan");
List<Animal> persons = _animalDapperRepository.GetList(x => x.Name.StartsWith("O")).ToList();
uow.Complete();
}
}
}
See the related post for AbpDapper
https://github.com/aspnetboilerplate/aspnetboilerplate/pull/1854#issuecomment-284511423
PS: Abp.Dapper integration is implemented by the community.
I am using Keyword driven framework for automate Log in page for one of the site. here I have used Poi for accessing the Excel sheet Data.
Here Below method openBrowser() and openUrl() are working fine. Problem happened for username() method for accessing the username field. I am using Selenium 3.12 and Chrome driver version 2.39 compatible with Chorme
Here is my code :
public class ActionKeywords {
public static WebDriver driver;
public static void openBrowser(){
System.setProperty("webdriver.chrome.driver","E:\\Pratik_BackUP\\Automation Selenium\\Drivers\\chromedriver.exe");
driver = new ChromeDriver();
System.out.println("open Browser called");
}
public static void openUrl(){
driver.manage().timeouts().implicitlyWait(100,TimeUnit.SECONDS);
driver.get("correct url");
driver.manage().window().maximize();
System.out.println("open Url called");
}
public static void userName(){
driver.findElement(By.xpath(".//*[#id='ctl00_ContentPlaceHolder1_login1_pan']/div/table/tbody/tr[3]/td[1]")).sendKeys("admin");
System.out.println("user Name called");
}
public static void password(){
driver.findElement(By.xpath(".//*[#id='ctl00_ContentPlaceHolder1_login1_pan']/div/table/tbody/tr[4]/td[1]")).sendKeys("Camlin#357");
System.out.println("password called");
}
public static void click_Login(){
driver.findElement(By.xpath(".//*[#id='ctl00_ContentPlaceHolder1_login1_LoginButton']")).click();
System.out.println("LogIn called");
}
public static void waitFor() throws Exception{
Thread.sleep(5000);
}
public static void closeBrowser(){
driver.quit();
System.out.println("close Browser called.");
}
}
Thanks!!
public static void userName(){
WebElement exelement = driver.findElement(By.xpath(".//*[#id='ctl00_ContentPlaceHolder1_login1_UserName']"));
exelement.clear();
Actions actions = new Actions(driver);
actions.moveToElement(exelement);
actions.click();
actions.sendKeys("admin");
actions.build().perform();
}
Above code works fine. Here have used Actions class for solve Actions class
I have been working on Page Object Framework which will have categorized test suites depending on the page. I have followed all steps in order to build a decent framework.
My each Unit Test, contains one method which follows simple steps. So far I have been able to create a few automated test cases. The issue began when I wanted to run more than one test case from the test suite. I have one chrome web driver instance which is in a separate class. Below is an example:
using System;
using System.Dynamic;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;
namespace SystemUiAutomationTestFramework
{
public static class Browser
{
private static readonly IWebDriver _webDriver = new ChromeDriver(Properties.Settings.Default.ChromePathDriver);
public static IWebDriver WebDriver {
get { return _webDriver; }
}
public static ISearchContext Driver
{
get { return _webDriver; }
}
public static string Url
{
get { return _webDriver.Url; }
}
public static string Title
{
get { return _webDriver.Title; }
}
public static void Goto(string url)
{
_webDriver.Manage().Window.Maximize();
_webDriver.Url = url;
}
public static void Close()
{
_webDriver.Quit();
}
}
}
Each test case when it is run is independent and as good practice shows, there should be no test order implementation because it generates flows. I will place two examples which check simple login operation and login validation.
Below you can find a class for the login page:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.AccessControl;
using System.Text;
using System.Threading.Tasks;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.PageObjects;
using OpenQA.Selenium.Support.UI;
namespace SystemUiAutomationTestFramework
{
public class LoginPage
{
static string Url = "http://..";
private static string LoginUrl = "http://...";
private static string PageTitle = "System title page";
private static string LoginPlaceholder = "Login";
private static string PswdPlaceholder = "Password";
private static string ButtonText = "Sign in";
private static string ErrorMessage = "Wrong login or password";
/* LoginPage Elements */
[FindsBy(How = How.Id, Using = "inputLogin")]
private IWebElement inputLogin;
[FindsBy(How = How.Id, Using = "inputPassword")]
private IWebElement inputPassword;
[FindsBy(How = How.TagName, Using = "button")]
private IWebElement loginButton;
[FindsBy(How = How.ClassName, Using = "errorMsg")]
private IWebElement errorMessage;
/*----------------------------------------*/
public void Goto()
{
Browser.Goto(Url);
}
public bool IsAtLoginPage()
{
return Browser.Url == LoginUrl;
}
public bool IsAtLoginPageTitle()
{
return Browser.Title == PageTitle;
}
public bool IsAtLoginField()
{
return inputLogin.GetAttribute("placeholder") == LoginPlaceholder;
}
public bool IsAtPswdField()
{
return inputPassword.GetAttribute("placeholder") == PswdPlaceholder;
}
public bool IsAtLoginButton()
{
return loginButton.Text == ButtonText;
}
public void InputCredentials(string userName, string userPassword)
{
inputLogin.SendKeys(userName);
inputPassword.SendKeys(userPassword);
loginButton.Click();
}
public void WaitErrorMessage()
{
WebDriverWait wait = new WebDriverWait(Browser.WebDriver, TimeSpan.FromSeconds(10));
wait.Until(ExpectedConditions.VisibilityOfAllElementsLocatedBy(By.ClassName("errorMsg")));
}
public bool IsAtErrorMessage()
{
return errorMessage.Text == ErrorMessage;
}
public void ReportPageSuccessLogin()
{
Console.WriteLine("Application Url checked");
Console.WriteLine("Application Title checked");
Console.WriteLine("Login Field present");
Console.WriteLine("Password Field checked");
Console.WriteLine("Sign in button checked");
Console.WriteLine("Login ssuccess");
}
public void ReportPageValidationTest()
{
ReportPageSuccessLogin();
Console.WriteLine("Fake Credentials entered");
Console.WriteLine("Login Button Pressed");
Console.WriteLine("Login or Password validation message displayed: " + errorMessage.Displayed);
}
}
}
I also have an API class for Pagefactoring. As an example:
public static class Pages
{
public static LoginPage LoginPage
{
get
{
var loginPage = new LoginPage();
PageFactory.InitElements(Browser.Driver, loginPage);
return loginPage;
}
}
Now for the test cases, below an example when a user is on the login page, all elements are displaed, logs into the system, system checks if the user has logged into and closes the instance.
using System;
using System.Runtime.Remoting.Channels;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SystemUiAutomationTestFramework;
namespace TestSuite.LoginPage
{
[TestClass]
public class LoginPageTest
{
[TestMethod]
public void Can_Go_LoginPage()
{
Pages.LoginPage.Goto();
Assert.IsTrue(Pages.LoginPage.IsAtLoginPage());
Assert.IsTrue(Pages.LoginPage.IsAtLoginPageTitle());
Assert.IsTrue(Pages.LoginPage.IsAtLoginField());
Assert.IsTrue(Pages.LoginPage.IsAtPswdField());
Assert.IsTrue(Pages.LoginPage.IsAtLoginButton());
Pages.LoginPage.InputCredentials(SettingsService.Username, SettingsService.Userpassword);
Pages.HomePage.IsAtHomePage();
Pages.LoginPage.ReportPageSuccessLogin();
}
[TestCleanup]
public void CleanUp()
{
Browser.Close();
}
}
}
The other one just validates the login page by providing fake login and password and if the error message is correctly displayed the test case finishes also by closing the instance.
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SystemUiAutomationTestFramework;
namespace TestSuite.LoginPage
{
[TestClass]
public class LoginPageValidationTest
{
[TestMethod]
public void Can_Validate_LoginPage()
{
Pages.LoginPage.Goto();
Assert.IsTrue(Pages.LoginPage.IsAtLoginPage());
Assert.IsTrue(Pages.LoginPage.IsAtLoginPageTitle());
Assert.IsTrue(Pages.LoginPage.IsAtLoginField());
Assert.IsTrue(Pages.LoginPage.IsAtPswdField());
Assert.IsTrue(Pages.LoginPage.IsAtLoginButton());
Pages.LoginPage.InputCredentials("abcd.efgh", "test123");
Pages.LoginPage.WaitErrorMessage();
Assert.IsTrue(Pages.LoginPage.IsAtErrorMessage());
Pages.LoginPage.ReportPageValidationTest();
}
[TestCleanup]
public void CleanUp()
{
Browser.Close();
}
}
}
Now the issue happens when I try those two test cases from the Login Page Test Suite, one finishes as passed the other one as failed. From the error message, I understand that it is because the other test case is trying to use an instance of the Webdriver which is already running.
I would like to know your opinion/guides/solution how can I solve this problem. I apologize for the long post but I thought that if I place my code it will be easy for you to understand my issue.
Best regards and thank you for your answers or linking me to the topic which either a duplicate of my issue or there is a solution already for it.
I was able to solve the issue on my own. I have created an
property for my driver class and an Initialize method which is called each time a test class is called. Also refactored my code to be more flexible.
I stuck at point i have one website for example (http://newtours.demoaut.com/) and for that i have created multiple classes likes:
App_Login(),
App_Dashboard(),
App_FliReservation(),
Cancel_Flight();
So want to call above all classes into single class .
can someone guide me on these.
Script sample
App_Login() class
public class App_login {
public static void main(String[] args) {
// TODO Auto-generated method stub
WebDriver driver= new FirefoxDriver();
driver.get("http://newtours.demoaut.com/");
}
}
and i want to call above class into following class
public class Mercurywebapp {
#Test
public void supp_onboarding() throws Exception {
App_Login();
}
public void App_Login() {
// TODO Auto-generated method stub
}
}
when i run above class (i.e.Mercurywebapp) then getting blank screen
Create another instances of all the Classes in the MercuryWebapp
Depends on the access modifiers for the classes
e.g
App_Login testObject = new App_Login();