I am learning how to create framework for web applications using Selenium. I am now learning how to create page object models with page navigation. The video I am currently on is showing how to do this, but the code at the end of the video does not work. He is trying to use a return type of the Class to initialize all the objects in that class, and he fails in doing so, because he uses a non-parameterized constructor. So is there a way to initialize my page elements when using a non-parameterized constructor?
Video located here: http://youtu.be/IUBwtLG9hbs
In the above video, he is just creating a simple test to enter the text "Selenium" into the google text box. Click on search. Click on the Selenium link. Then click on the Download tab on the Selenium webpage.
At the end of the video, he is trying to show how to use Page Navigation by initializing the elements after a button or link is clicked that sends you to a new page. The goal of this test is to map all of the elements of the Selenium web page after the click of the Selenium link from the Google page.
So he adds "return new SeleniumPageObjects();" to the following method in the GoogleHomePageObjects class:
public SeleniumPageObjects ClickSelenium()
{
lnkSelenium.Click();
return new SeleniumPageObjects();
}
Then in the main/test method in the Test class, he adds the following to click on the Selenium link and then return all of the mapped objects of the Selenium page:
SeleniumPageObjects selPage = page.ClickSelenium();
He then adds a constructor in the SeleniumPageObjects class:
public SeleniumPageObjects()
{
}
It throws a NullReferenceException because it never initialized the selenium page objects (See below code of how it is done without using a return type). How can this be fixed? He says to watch part 7, but I watched part 7 and the erroneous code is never addressed.
NOTE: I already know how to explicitly initialize page objects in my main/test method. For instance, add this to the main/test method:
SeleniumPageObjects selPage = new SeleniumPageObjects(driver);
And initialize the elements in the SeleniumPageObjects class:
public SeleniumPageObjects(IWebDriver driver)
{
PageFactory.InitElements(driver, this);
}
I just want to know how to do this when using a return type, as this accomplishes the Page Relation he is talking about.
There are two possible ways to fix this issue.
Method 1
Create a static property for the Driver instance in a class and use the static property in all the pages
E.g.
public SeleniumPageObjects(IWebDriver driver)
{
PageFactory.InitElements(driver, this);
}
Can be changed to
public SeleniumPageObjects()
{
PageFactory.InitElements(StaticClass.Driver, this);
}
So the StaticClass can look something like this
public class StaticClass
{
public static IWebDriver Driver {get;set;}
}
Method 2
Create a BaseClass for page and create the WebDriver property in it, so that while inheriting the Baseclass for the page you will get the reference for Driver as well
E.g
Base Class
public class BaseClass
{
public static IWebDriver Driver {get;set;}
}
So, the Selenium Page Object Class will look like this
public class SeleniumPageObject : BaseClass
{
public SeleniumPageObjects()
{
PageFactory.InitElements(Driver, this);
}
}
Hope this answers your question !!!
Thanks,
Karthik KK
http://www.executeautomation.com
Related
I have a Blazor application where I program the code of each razor page in the related xxx.razor.cs Class in C#. I have the case that I use common functions in this C# codes. So instead of repeating the common functions in each class, I want to define a common class, and then call the function from each class. How can I do that? I have tried it like in a C# desktop application but it didn't work.
Commonclass test = new Commonclass();
test.CommonFunction();
I don't know why but after trying for hours I see my error always just when I have posted my question. I had copied the common class from another directory. I forgot to correct the namespace. After correcting it worked.
I think the accepted way to do this is dependency injection. Either a scoped or singleton service.
Program.cs
builder.Services.AddSingleton<Commonclass>();
Razor Page
[Inject] Commonclass test { get; set; }
protected override async Task OnAfterRenderAsync(bool firstRender)
{
test.CommonFunction();
}
I've started learning Selenium Webdriver. It seems pretty easy but I'm not sure how to use PageObject Pattern. I understand the idea, I guess, but I don't know how to map many pages in one project. For example: the site contains many subsites (i.e. login page, create an account page) and I'd like to create PageObject for each of them. When I execute my script, I'm getting messages that elements haven't been found. What should I do? Should I create a separete drviers or what?
Seems that you are doing everything correct: create a new object for each page. Create different objects for common elements that are the same on a lot of pages (like footer, header menu, etc.).
Then to combine page objects, first you need to start somewhere. For example from you main page. So use the MainPageObj to interact wit the main page. As soon as you navigate to another page you need to use a method in your MainPageObj class.
This method must return a page object of the new page. So if you open a Login page from the main page then your method OpenLoginPage() should return LoginPageObj.
Example: MainPageObj and LoginPageObj are page object classes.
MainPageObj class has method:
public LoginPageObj OpenLoginPage()
{
LoginButton.Click();
return new LoginPageObj();
}
So use this method in this way:
MainPageObj mainPage = new MainPageObj ();
LoginPageObj loginPage = mainPage.OpenLoginPage();
Simple?)
If you want to make it more beautifyl then add static class Pages and add static methods for each page object you have to this class. Each method must return a new instance of your specific page object.
Example:
public static class RealSites
{
public static class Kinopoisk
{
public static Kinopoisk.MainPage MainPage
{
get { return new Kinopoisk.MainPage(); }
}
}
}
And in your tests use it this way:
Pages.RealSites.Kinopoisk.MainPage.OpenMoviePage(url);
Pages.RealSites.Kinopoisk.MoviePage.DoSomethigElseMethod();
You can refer this link to understand page object model and after this you can also create for your application
http://www.seleniumeasy.com/selenium-tutorials/simple-page-object-model-framework-example
If you want to learn then selenium easy is best site to learn for beginners.
This is basicly the design question, Like what would be the best way to structure my code within my web asp.net 4.0 web forms application. My General Design is like this...
Master Page
Has few User Controls
Content Pages
Inherit from Base Class
User Controls within Content Pages
I need to get some setting stuff from database in one CALL & store results into a Class. and then this class will be shared throughout the Pages (in Master Page, Base Class, Content Pages and user controls).
What would be the best place to initialize this class and easily access it throughout the page lifectycle.
Should I Hit Database & initialize the Class in BASE PAGE and then update Master Pages from within the BASE Class..like this
Page.master.findControl("label").Text = myClass.Setting1
and then Content Pages and its user control would need access to this class as well.
Please advise the best practice.
If this is completely shared data common for all users of your application, put it in a data container exposed as a static property of a class, and fill this container with data from database in the static constructor of this class.
public class SettingsData
{
public string Setting1;
public string Setting2;
}
public static class DataHolder
{
public static SettingsData Settings = new SettingsData();
static DataHolder()
{
// open connection to db and query for values
Settings.Setting1 = <value from db>;
Settings.Setting2 = <value from db>;
}
}
then in code
Label1.Text = DataHolder.Settings.Setting1;
Given a URL, I have to be able to know what the page's Type is that resides at that URL. For example, lets say I have a couple pages.
//first.aspx
public partial class FirstPage : System.Web.UI.Page { }
//second.aspx
public partial class SecondPage : MyCustomPageType { }
I would like to be able to call a method in the following manner with the following results:
GetPageTypeByURL("first.aspx"); //"FirstPage"
GetPageTypeByURL("second.aspx"); //"SecondPage"
Is this possible? How can I do this?
From this answer, it appears that you can get the class of a specific page. You may then be able to use reflection to determine its base type. (Note: I haven't attempted this, it's just a suggestion.)
System.Web.Compilation.BuildManager.GetCompiledType(Me.Request.Url.AbsolutePath)
What about this?
public Type GetPageTypeByURL(string url)
{
object page = BuildManager.CreateInstanceFromVirtualPath(url, typeof(object));
return page.GetType().BaseType.BaseType;
}
Usage:
Type pageType = GetPageTypeByURL("~/default.aspx");
Just a thought:
I assume that you calling the page from some other program.
Get the HTML, search for your distinguishing HTML / hidden element that tells you what the page is.
If you are on the server just load up the page as a text file and read it.
Page page = (Page)System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath(url, typeof(Page));
CustomerPage page = (CustomerPage) SomeMagicalPageCreater.CreatePage("CustomerPage.aspx");
https://forums.asp.net/t/1315395.aspx
This is what I found.
I have a base page (inherited from System.Web.UI.Page and all my pages inherit from this base page) in my .Net web application and at the moment if I put the following methods:
protected int GetProfileTenant()
{
try
{
ProfileCommon p = Profile.GetProfile(Profile.UserName);
return Convert.ToInt32(p.TenantID);
}
catch
{
return -1;
}
}
the error come up saying that "the Name Profile does not existin the current context".
This methods if I put this into the page (inherited from the base page clas) works well (no issue).
Any ideas?
Thanks
Thanks
Add System.web namespace in the class.
and try this
HttpContext.Current.Profile.UserName
I don't have a clear-cut answer for you, but there is some "magic" happening in the way profiles work (a class matching your profile properties gets generated). Apparently the Profile property gets injected into the top level page class. Have you tried using HttpContext.Current.Profile instead?