How to Take Screenshots With Selenium in C#
Very frequently testers will meet a situation where they need to take screenshot of webpage they are testing , either for base line or as a proof of test result. This is same with automated testing . Even though automated test cases have their own of way of publishing test results, it is always desirable to keep a proof of result.. Screenshot come to help in this regards. In this blog post , I will explain , how to take a screenshot with Selenium Web Driver with C#. In future I will add another couple of post to explain , how to consolidate the screenshots into a PDF document.
In .NET binding, we have an interface called ITakesScreenshot , which helps to capture screenshot of active window. Below code will help to take screenshot and save it in the path specified while calling the function
1 2 3 4 5 6 7 8 9 10 |
|
Element Location Using XPath Axis
During testing we will sometimes come up to situations where developers are not following best practises for testability . We will frequently come up situations where elements doesn’t have any unique identifiable property. XPath axis comes to help in those situations. We can identify elements using various XPath Properties
List of various XPath Axis are available in https://developer.mozilla.org/en-US/docs/Web/XPath/Axes If you have well-defined properties to identify the element, use them as your locator. Please read locator strategy Using XPath and Other Parameters
Below are major one’s which we will frequently use
1. ancestor
This selects all ancestors of current node. That will include parent, grand parents etc Eg :
1
|
|
2. descendant
This selects all children of current node. That will include child, grand child etc Eg:
1
|
|
3. followingis
Th selects everything after the closing tag of current node Eg:
1
|
|
4. following-sibling
This selects all siblings after the closing tah of current node. Eg:
1
|
|
5. preceding
This selects everything prior to current node Eg:
1
|
|
- preceding-sibling
This selects all siblings prior to current node Eg:
1
|
|
7. child
This selects all children of current node
8. parent
This select parent of current node
As usual , you can always use combinations of above in your test. Statements can be constructed in the same way as we traverse the XPath axis
Last , but not least… we can also use regular expression in XPath.
Element Location Using XPath
XPath is XML query language which can be used for selecting nodes in XML. Hence it can be used to identify elements from DOM since they are represented as XHTML documents. Selenium WebDriver also supports XPath for locating elements. They also help to look for elements in both direction and hence it is generally slow compared to all other locator strategy. We can use XPath with both absolute path and relative path.
Absolute XPath
Absolute Path refers to specific location in DOM, by considering it’s complete hierarchy. However this is not an ideal locator strategy since it makes your test very brittle. The absolute path will change if there is any change/realignment etc in UI.
Example of Xpath using absolute path is as below
1
|
|
Relative XPath
With relative Path , we can find element directly without entire structure. It helps to look out for any elements which matches with specified relative path . Example for a relative path based locator strategy is as below.
Note: Relative XPath starts with “//”
1 2 3 4 |
|
Relative XPath - With Attributes
If we need to further narrow down our location strategy, we can use Attributes along with relative XPath. There may be situations where we need to multiple attributes to uniquely identify an element. We can also specify locators to identify for ANY attribute
1 2 3 4 5 6 7 |
|
Relative XPath - Partial Match
Sometimes there may be situations where element attributes like ID are dynamically generated. Those will generally have some unique part in attributes likeID and remaining will be generated dynamically , which will keep on changing. This will need a locator strategy which will help us to identify elements using partial match. Main types are
starts-with()
ends-with()
contains()
1 2 3 4 5 6 7 |
|
Nunit Assert
Assert.AreEqual vs Assert.AreSame
Very frequently I use Assert.AreEqual and Assert.AreSame for doing assertions in the code. Below is high level difference between both.
Assert.AreSame
Assert.AreSame checks whether both comparing objects are exactly the same ( reference indicate same object in memory) .It is normally known as Reference Equality
Assert.AreEqual
Assert.AreEqual checks whether both objects contain same value. It is normally known as Value Equality. For primitive value types ( like int, bool) this is straight forward. But for other types ( especially user defined objects) , it is depends on how the type defines equality.
Hence Assert.AreEqual will fail ( most of the time) when we compare two objects. This link have some discussion point about the same.
Identifying Elements Using Locators in Selenium
Locators are html properties of a web element , which can be considered as an address of the element. An element will have various html properties. We can use Firebug extension or Chrome dev tools to identify different locators of an element.
Selenium Web Driver provides two different methods for identifying html elements .
FindElement for WebDriver and WebElement Class. When locating element matching specified criteria, it looks through DOM( Document Object Model) for matching element and return the first matching element. If there are no matching element, it will throw NoSuchElementFoundException
FindElements for WebDriver and WebElement Class. When locating element matching specified criteria, it looks through DOM( Document Object Model) for matching element and return a list of all matching element. If there are no matching elements, then it will return an empty list .
Note: Both of them doesn’t support regular expression for finding element. Simple way to do that will be to get list of all elements and then iterate to find a matching regular expression
There are multiple criteria which we can use for looking for an element. FindElement and FindElements work exactly same way except for above difference. Different critieria are
driver.FindElement(By.Id(
)) driver.FindElement(By.Name(
)) driver.FindElement(By.ClassName(
)) driver.FindElement(By.TagName(
)) driver.FindElement(By.LinkText(
)) driver.FindElement(By.PartialLinkText(
)) driver.FindElement(By.CssSelector(
)) driver.FindElement(By.XPath(
))
Example:
1 2 3 4 5 |
|
Using any attributes other than XPath and CssSelector are straight forward. More about using XPath and CssSelector in next blog.
Specflow - Sharing Data Between Steps
In Specflow, Step definitions are global. So a scenario can have multiple step definitions which can be present in different classes. Sometimes, there arise a need to share the data between steps residing in different classes. How do we do it??
There are multiple ways to do it
Context Injection
Feature Context
Scenario Context
Let us look into more details about how to store and retrieve data using Scenario Context .
ScenarioContext.Current
How do we add a key value pair to Scenario Context ? It is as simple as below
1 2 3 4 5 6 |
|
How do we retrieve the value from ScenarioContext ?
1 2 3 4 5 6 7 |
|
Note: While retrieving , scenarioContext.Current always return an object . Hence we need use explicit casting while retrieving data from scenario context.
In Nut Shell,
**Set a value for a key ( Store data ) ** ScenarioContext.Current.Add(string key, object value); **Get a value of the key ( Retrieve data) ** var value =(Type) ScenarioContext.Current.[string Key]; var value = ScenarioContext.Current.Get(string Key);
We can use this for storing and passing objects as well
Example of storing webdriver object is as below.(where "browser" is current webdriver object ) ScenarioContext.Current.Add("driver1", browser); IWebDriver driver2 = (IWebDriver)ScenarioContext.Current["driver1"];
Data Driven Framework - XML
I am not going to explain what is data driven framework or what is its benefits. All of them are pretty well-known . If not, just google it.
Here I am going to explain a sample code which can be used to read from xml data files. This will be helpful to implement a data driven frame work for BDD testing , using Specflow or Cucumber
Pre - requiste
Code is written in Csharp . We need to add below reference to visual studio solution
Add reference to System.xml
Add reference to System.Xml.Linq
XML Format
[code language=“xml” ]
[/code]
Node names in above example are Scenario1, Scenario2 and Scenario3
Element or Attribute name are username, password, Email .
You can add any number of nodes and attributes depending on the test scenario
Read specific Value from XML
Below code provides a solution to read values of existing Key/Attribute from a specific node.
1 2 3 4 5 6 7 8 |
|
Read All values for a Scenario from XML
This code gives a solution for reading details of all attributes/key from a node. This comes very handy for reading all data required for a scenario and adding them to scenario context , so that data can be shared across specflow/cucumber step definitions
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Write Data into XML
Below function gives a solution to update value on an existing key/attribute in data sheet . Sometime the data sheet will be copied over to bin folder when we build the solution. That makes it necessary to update both original data sheet and the one in bin folder so that modified data can be used in same test without another rebuild.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Data Driven Framework - Excel
In previous blog post, I have explained about how use XML for making a data driven framework for automation testing . It can be found here. I have also written about how to use jxl library for reading from excel and writing into Excel.
Below is another code snippet to read all values of a row and save it into a hash map for accessing later during automation test.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
Nodejs
This post is just for making notes during my learning of Node.js through various courses and online material. This will be always a work in progress blog post
Node.js is an open source server side runtime environment, which is cross platform.It uses Javascript as its language
check node version
node --version
Making web request in Node we can make webrequest by using inbuilt http or by using ‘request’ example : For making web request by http
1 2 3 4 5 6 |
|
example: Please note that there is no space between key and : while defining options
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Example: We can simply by giving GET . There is no need to close request since we are not going to send any more information to request
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Another option is
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Starting with Node.js and Express
1
|
|
Above command will create a package.json. Leave details are default or change accordingly
1
|
|
Above will install express and also add it as dependency in package.json
1
|
|
Above will create a app.js file. In package.json add below
1 2 3 4 |
|
Now, if we run “npm start” from command line, it will run app.js
Bower
Package manager for web/front end. It is installed with NPM and have flat package hierarchy(doesnt install dependency underneath one level) .It works similar to NPM and have Bower.json for dependency managament.
Create a .bowerrc file and have project specific settings. Now move the components from bower_component to public folder defined earlier. update .bowerrc with below
1 2 3 |
|
now run below
1 2 3 4 |
|
Gulp
It is a task manager for web projects. It have code based config. It is packaged base so that we can use different external packages
Mongo DB
- Install MongoDB from website
- mongoD is command for running server
- mongo is command for running another terminal for interacting with mongo db
- show dbs will show list of db
- Install MongoDB Node.js driver using NPM ```
Volunteering Experience
A couple of months back , I helped out to organize clinical examination for RACP. I created a tool ( Excel Macro) for finalizing exam schedules for all attendees. The roster should consider employee preference, examiner availability, timeslot, venue and other parameters. Below is what I got in return ( even though they misspelled my name).