In the Selenium docs I can see how to take a normal screenshot:
http://seleniumhq.org/docs/04_webdriver_advanced.html
But I would like to use captureentirepagescreenshot with a remote webdriver, C#
Is this possible? any examples?
Please use selenium webdriver version 2.33. Below code is a c# code so please download selenium webdriver dlls for .net from link http://docs.seleniumhq.org/download/
Selenium webdriver has inbuilt function called ITakesScreenshot to take screenshot runtime.
Please see below code
`public static void SaveScreenShot(string screenshotFirstName)
{
var folderLocation = "Screenshot folder path";
var screenshot = ((ITakesScreenshot)Driver).GetScreenshot();
var filename = new StringBuilder(folderLocation);
filename.Append(screenshotFirstName);
filename.Append(DateTime.Now.ToString("dd-MM-yyyy HH_mm_ss"));\\append date and time
filename.Append(".png"); \\append image extension
screenshot.SaveAsFile(filename.ToString(), System.Drawing.Imaging.ImageFormat.Png);
}`
Hope this will work for you.
Thanks,
Anshul
If you use a IWebDriver implementation (such as InternetExplorerDriver, FirefoxDriver) you can simply cast it to a ITakesScreenshot interface and use the GetScreenShot() method:
IWebDriver driver = new InternetExplorerDriver();
Screenshot screenShot = ((ITakesScreenshot)driver).GetScreenshot();
screenShot.SaveAsFile(/*fullFileNameAndPath*/, ImageFormat.Png);
But if you want to to do this with a RemoteWebDriver you can't, because it doesn't implement the ITakesScreenshot interface. So, you have to create a new class based on RemoteWebDriver that implements this interface and adds the GetScreenshot() method such as:
public class ScreenShotRemoteWebDriver : RemoteWebDriver, ITakesScreenshot
{
public ScreenShotRemoteWebDriver(Uri RemoteAdress, ICapabilities capabilities)
: base(RemoteAdress, capabilities) { }
/// <summary>
/// Gets a <see cref="Screenshot"/> object representing the image of the page on the screen.
/// </summary>
/// <returns>A <see cref="Screenshot"/> object containing the image.</returns>
public Screenshot GetScreenshot()
{
// Get the screenshot as base64.
Response screenshotResponse = this.Execute(DriverCommand.Screenshot, null);
string base64 = screenshotResponse.Value.ToString();
// ... and convert it.
return new Screenshot(base64);
}
}
Now you can use it as you would for a IWebDriver:
RemoteWebDriver driver = new ScreenShotRemoteWebDriver(/*uri*/, /*capabilities*/);
Screenshot screenShot = ((ITakesScreenshot)driver).GetScreenshot();
screenShot.SaveAsFile(/*fullFileNameAndPath*/, ImageFormat.Png);
It took me sometime to understand the maze of classes and interfaces for the drivers as well, but after a while it all makes sense.
Related
OpenQA.Selenium.Support.UI.SelectElement NOT Found
As you can see by the code image, I have entered the 'using' library I need to use. However, it is telling me that "SelectElement" does not exist. Does anyone here know how to go about adding the correct library?
By clicking the above link, you will see the code image.
Here is the code snippet:
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Support;
using OpenQA.Selenium.Support.UI;
using OpenQA.Selenium.Support.UI.SelectElement;
using NUnit.Framework;
namespace ToolsQA.Selenium_Basics
{
class DropDownAndSelectOperations
{
[Test]
public void Test()
{
// Create a new instance of the Firfox Driver
IWebDriver driver = new FirefoxDriver();
driver.Manage().Timeouts().ImplicitWait = TimeSpan.
FromSeconds(10);
// Launch the URL
driver.Url = "http://toolsqa.wpengine.com/automation-practice-
form";
// Step 3: Select "Continents" drop down (Use Id to identify the
element)
// Find "Select" element of "Single Selection" using Id locator.
*SelectElement* oSelection = new
SelectElement(driver.FindElement(By.Id("continents")));
You need to add the Selenium Support package through NuGet. That should solve the problem.
I am trying to create webdriver object reference in the class which is not having main method. it is not allowing me to create the object. Finally, I tried with an instance and it is not working(not identifying driver)
public class LoginPage
{
public static WebDriver driver;
static ResourceLoader loader = new ResourceLoader();
public static String loginVerify(String username, String password)
{
System.out.println("navigated to loginvarify() :: ");
logger.info("username is "+username);
logger.info("password is "+password);
try
{
driver.findElement(By.id(loader.getProperty(Constants.UserName))).sendKeys(username);
}
Please help me
public class LoginPage
{
System.setProperty("webdriver.chrome.driver", "src/main/resources/drivers/osx/chromedriver"); // path to your chrome driver
public static WebDriver driver = new ChromeDriver();
static ResourceLoader loader = new ResourceLoader();
public static String loginVerify(String username, String password)
{
System.out.println("navigated to loginvarify() :: ");
logger.info("username is "+username);
logger.info("password is "+password);
try
{
driver.findElement(By.id(loader.getProperty(Constants.UserName))).sendKeys(username);
}
I have updated your code, kindly refer you are missing your driver initialization. I have initialized to chromeDriver(), if you are using firefox initialize it accordingly.
System.setProperty("webdriver.chrome.driver",
"src/main/resources/drivers/osx/chromedriver"); // path to your chrome
driver
If you are not having the chrome driver, kindly download and place it in your directory path and pass the path reference accordingly.
https://sites.google.com/a/chromium.org/chromedriver/downloads
Let me know if you still face any issue or anything is not clear.
WebDrvier driver = new FireFoxDriver(); //driver initialization
driver.FindElement(By.Id(IdName)); //to find elements by ID in UI
You can define your chrome driver path using System.setProperty("webdriver.chrome.driver", "C:\Spring Workspace\chromedriver\chromedriver.exe"); // path to your chrome driver or you can define the path in the environment variable so you don't have to use this setProperty code again and again......if you are using firefox driver than not need to define any setProperty beacause it is already defined inside org.openqa.selenium.firefox.FirefoxDriver....
With Test Automation's Page Object Model we link pages together like this:
WebDriver driver = new WebDriver()
HomePage homePage = new HomePage(driver);
LoginPage loginPage = homePage.GoToLoginPage();
WelcomePage welcomePage = loginPage.Login();
etc
etc
The big benefit of this is if the Devs change the homepage so it no longer links to the loginpage, I can update my homepage class and see all the tests I need to update (with errors) before even running a test.
With Gherkin however, each row above would form a separate 'Step' and therefore a separate method. Therefore, how can this linking be done?
Is the only way to place instances of the page object classes (e.g. homePage, loginPage, etc) into a cross gherkin statement persistant store (e.g. like a specflow POCO or 'World')?
Ok so having asked numerous dev and test automation experts, it seems the solution is to continue with linking [e.g. WelcomePage welcomePage = loginPage.loginWithValidUser(validUser)] is the way to go.
To persist instance of page objects across steps (e.g. welcomePage in example above) you can use dependency injection tool (creating functionality similar to World extensions in Ruby's implementation of cucumber).
Here is more info:
https://cukes.info/docs/reference/java-di
However, most projects will benefit from a Dependency Injection module
to organize your code better and to share state between Step
Definitions.
More info from SpecFlow (the .net official cucumber implementation):
http://specflow.org/getting-started/beyond-the-basics/
And finally, I have created a whole blog around this area that might help people out, since gherkin/page object interaction is a subject of great interest to me:
http://www.seligmanventures.com/dev-blog/test-automation-page-object-model-with-gherkin
When it comes to most websites (where url's can be used), in my opinion it is best practice to simply use the url instead of an action to get to that same url.
For instance:
# Suggested by OP:
driver = Selenium::Webdriver.for :chrome, prefs: prefs
homepage = Homepage.new(driver)
login = homepage.go_to_login
welcome = login.log_in_as('dave4429')
# My Suggestion:
homepage = Url.new('/')
login = Url.new('/login')
welcome = Url.new('/welcome')
This means that you start from a url instead of having to start at the homepage for every test. You would still have the methods that you suggested, but they would be used in other areas, in order to make sure that the user can access the page through means other than the url.
However, this is not a one stop shop solution. With mobile and desktop applications, your only option may be to go through the home screen, in which case, the method you suggested is definitely the one to go for.
"Page objects themselves should never make verifications or assertions. This is part of your test and should always be within the test’s code, never in an page object." - Selenium HQ
The example I gave was a very basic one, and I would most likely wrap these into modules and classes, to enable coding like this:
google = Project::Pages::Google.new
google.search_for('Hello, World!')
expect(google.found_result?).to_equal(true)
Edit
In addition to this, you seem to have a misconception about how Cucumber works with Gherkin.
You can have multiple lines of code per step, as the step itself is a description of the actions within the step.
For instance:
Given I am logged in as "dave4429"
When I have submitted the "Contact Us" form with the following data:
| dave4429#example.com | David McBlaine | I want to find out more about your Data Protection services, can I talk to a staff member or get a PDF? |
Then an email should be sent to "support#example.com" with the details specified
The definition for the "When" may look like this:
When(/^I have submitted the "Contact Us" form with the following data:$/) do |table|
rows = table.raw
row = rows[0]
contact_us.fill_form({email: row[0], username: row[1], message: row[2]})
contact_us.submit_message
expect(browser.title).to_equal("Message Sent!")
end
It all depends on how much you break down the steps within the definition.
Edit #2
It's also clear to me that you want to do method chaining, something in the way of contact_us.fill_form({email: row[0], username: row[1], message: row[2]}).submit_message, which again, isn't out of the question while using the techniques that I'm suggesting, but the question of whether this chaining should be for each individual page, or whether everything should be included in one class or module, can only be answered by your needs.
It's just my opinion that this would put too much into a single class, and that breaking down that class will allow for more control to be given to the testers, and less redundant code will be written.
Another option I have seen recently would be to store the Page Object instances as Static variables that can be accessed from any class?
After much discussion on this topic, an equally plausible alternative is to not return instances of new pages when using the page object pattern with gherkin. You will lose the benefit of linking that you normally get with POM, but the code will arguably read better and be less complex. Posting this alternative answer, so as a test community we can vote which method is peoples preference.
This can be a bit tricky with Cucumber and Selenium. I've developed a pattern that involves extension methods to the IWebDriver interface for Selenium allowing me to navigate to specific pages using the page objects. I register the IWebDriver object with the SpecFlow dependency injection framework, and then my step definition classes are free to initialize whichever page objects they need.
Registering Selenium Web Driver With SpecFlow
You just need to plug in to the before/after scenario hooks to manage the web driver object:
[Binding]
public class WebDriverFactory
{
private readonly IObjectContainer container;
public WebDriverFactory(IObjectContainer container)
{
this.container = container;
}
[BeforeScenario]
public void CreateWebDriver()
{
var driver = new ChromeDriver(...);
// Configure Chrome
container.RegisterInstanceAs<IWebDriver>(driver);
}
[AfterScenario]
public void DestroyWebDriver()
{
var driver = container.Resolve<IWebDriver>();
if (driver == null)
return;
// Capture screenshot if you want
// var photographer = (ITakeScreenshot)driver;
driver.Quit();
driver.Dispose();
}
}
Then It's a matter of gluing step definitions and page objects together using some extensions on the IWebDriver interface.
Selenium Page Objects
Keep your page objects navigating to one another. For instance the HomePage allows you to navigate to the "Create blog post" page, and returns the page object for that page:
public class HomePage
{
private readonly IWebDriver driver;
private readonly WebDriverWait wait;
private IWebElement CreatePostLink => driver.FindElement(By.LinkText("Create New Blog Post"));
public HomePage(IWebDriver driver)
{
this.driver = driver;
wait = new WebDriverWait(driver, 30);
}
public AddEditBlogPostPage ClickCreatePostLink()
{
CreatePostLink.Click();
wait.Until(d => d.Title.Contains("Create new blog post"));
return new AddEditBlogPostPage(driver);
}
}
And subsequently, the AddEditBlogPostPage returns the BlogPostListingPage when you create a new blog post:
public class AddEditBlogPostPage
{
private readonly IWebDriver driver;
private IWebElement Title => driver.FindElement(By.Id("Title"));
private IWebElement PostDate => driver.FindElement(By.Id("Date"));
private IWebElement Body => driver.FindElement(By.Id("BodyText"));
private IWebElement SaveButton => driver.FindElement(By.XPath("//button[contains(., 'Save Blog Post')]"));
public AddEditBlogPostPage(IWebDriver driver)
{
this.driver = driver;
}
public BlogPostListingPage CreateBlogPost(BlogPostDataRow data)
{
Title.SendKeys(data.Title);
PostDate.SendKeys(data.Date.ToShortDateString());
Body.SendKeys(data.Body);
SaveButton.Click();
return new BlogPostListingPage(driver);
}
}
Step Definitions To Glue Things Together
The step:
When I create a new blog post:
| Field | Value |
| Title | Selenium Page Objects and Cucumber |
| Date | 11/1/2019 |
| Body | ... |
Would have this definition:
[Binding]
public class BlogPostSteps
{
private readonly IWebDriver driver;
public BlogPostSteps(IWebDriver driver)
{
this.driver = driver;
}
[When(#"I add a new blog post:")]
public GivenIAmAddingANewBlogPost(Table table)
{
var addBlogPostPage = driver.GoToCreateBlogPostPage();
var blogPostData = table.CreateInstance<BlogPostDataRow>();
addBlogPostPage.CreateBlogPost(blogPostData);
}
}
The driver.GoToCreateBlogPostPage(); is an extension method on IWebDriver that kicks off the navigation from one page object to another:
public static class SeleniumPageNavigationExtensions
{
public static AddEditBlogPostPage GoToCreateBlogPostPage(this IWebDriver driver)
{
var homePage = new HomePage(driver);
return homePage.ClickCreatePostLink();
}
}
This gives you the flexibility to keep your page objects "pure" and devoid of SpecFlow, Cucumber and Gherkin. You can use these same extension methods and page objects in other tests that do not utilize Gherkin or behavior driven development. This allows for easy reuse of your test classes. Your test projects should be just as purposefully architected as the actual application it tests.
I want to know is any other option available to generate test report except TestNG framework in selenium webdriver
You can try ExtentReports: http://extentreports.com. An example:
public class Main {
public static void main(String[] args) {
// start reporters
ExtentHtmlReporter htmlReporter = new ExtentHtmlReporter("extent.html");
// create ExtentReports and attach reporter(s)
ExtentReports extent = new ExtentReports();
extent.attachReporter(htmlReporter);
// creates a toggle for the given test, adds all log events under it
ExtentTest test = extent.createTest("MyFirstTest", "Sample description");
// log(Status, details)
test.log(Status.INFO, "This step shows usage of log(status, details)");
// info(details)
test.info("This step shows usage of info(details)");
// log with snapshot
test.fail("details", MediaEntityBuilder.createScreenCaptureFromPath("screenshot.png").build());
// test with snapshot
test.addScreenCaptureFromPath("screenshot.png");
// calling flush writes everything to the log file
extent.flush();
}
}
try Allure reporting framework
https://github.com/allure-framework
Hope this helps
i have just set-up the selenium grid on my local machine and everything seems to be up and running.
my question is, is there a way I can run the test case from selenium grid node (command prompt)?
I am using WebDriver for creating my testcase using .Net
Sample code from here
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
// Requires reference to WebDriver.Support.dll
using OpenQA.Selenium.Support.UI;
class GoogleSuggest
{
static void Main(string[] args)
{
// Create a new instance of the Firefox driver.
// Notice that the remainder of the code relies on the interface,
// not the implementation.
// Further note that other drivers (InternetExplorerDriver,
// ChromeDriver, etc.) will require further configuration
// before this example will work. See the wiki pages for the
// individual drivers at http://code.google.com/p/selenium/wiki
// for further information.
WebDriver driver = new RemoteWebDriver(new Uri("http://127.0.0.1:4444/wd/hub"),
DesiredCapabilities.FirefoxDriver());
//Notice navigation is slightly different than the Java version
//This is because 'get' is a keyword in C#
driver.Navigate().GoToUrl("http://www.google.com/");
// Find the text input element by its name
IWebElement query = driver.FindElement(By.Name("q"));
// Enter something to search for
query.SendKeys("Cheese");
// Now submit the form. WebDriver will find the form for us from the element
query.Submit();
// Google's search is rendered dynamically with JavaScript.
// Wait for the page to load, timeout after 10 seconds
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.Until((d) => { return d.Title.ToLower().StartsWith("cheese"); });
// Should see: "Cheese - Google Search"
System.Console.WriteLine("Page title is: " + driver.Title);
//Close the browser
driver.Quit();
}
}
WebDriver driver = new RemoteWebDriver(new Uri("http://127.0.0.1:4444/wd/hub"),
DesiredCapabilities.FirefoxDriver());
OR in c#
IWebDriver driver;
DesiredCapabilities capability = new DesiredCapabilities();
driver = new RemoteWebDriver(
new Uri("http://hub-cloud.com/wd/hub/"), capability);
driver.Navigate().GoToUrl("http://www.google.com");