I have a web page in my web project “CalculatorWeb” where I placed a single text box with id “txtNum1”
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
<form id="frmCalc">
<div style="padding-top:20px;">
My Sample Text Box <br/><br/>
<input id="txtNum1" type="text" />
</div>
</form>
</body>
</html>
Nothing fancy so the page loads up as below
Now I created a feature file “BrowserTest1.feature” to my project “Calculator.Specs”. The code as follows
Feature: BrowserTest1
In order to check url
As browser
I want to be see url of page
#mytag
Scenario: Go to URL
Given I have entered 'http://localhost:58529/'
When I go to that url
Then there is a text box on the page with id 'txtNum1'
I then code a file BrowserTest.cs for unit tests implementation
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;
using TechTalk.SpecFlow;
namespace Calculator.Specs
{
[Binding]
class BrowserTest
{
public string urlPath;
[Given(#"I have entered 'http://localhost:58529/'")]
protected void SetURL()
{
string URLPath = "http://localhost:58529/";
urlPath = URLPath;
}
[When(#"I go to that url")]
protected void NavigateToURL()
{
using (var driver = new ChromeDriver())
{
driver.Navigate().GoToUrl(urlPath);
}
}
[Then(#"there is a text box on the page with id 'txtNum1'")]
protected void TxtBoxExists()
{
bool txtExists = false;
using (var driver = new ChromeDriver())
{
IWebElement txtBox1 = driver.FindElement(By.Id("txtNum1"));
if (txtBox1 != null)
{
txtExists = true;
}
}
Assert.AreEqual(true, txtExists);
}
}
}
As far as I am aware I do have all the required references for Visual Studio IDE to SpecFlow/Selenium integration
When I do run the unit test the web page loads up fine , however I get a failing test when I try to find the element with ID “txtNum1” even though the text box with that ID does exist on the page
Exception details appear as follows
Can anybody point me in the right direction as to what am I missing to enable Selenium to find the text box on the page with ID “txtNum1”
you need to use the same instance of driver between steps, otherwise the driver that navigates to the page is different from the driver that you are trying to get the element from.
you have a couple of choices for this. The simplest is to create a field for your driver instance and use the field in all the steps. This will work as long as all your steps are in the same file.
The other option is to store the driver object in the ScenarioContext.Current (or FeatureContext.Current). These are dictionaries so you can do this:
ScenarioContext.Current["webDriver"] = driver;
This will work ok, but you'll have to cast everytime you get the driver out as the dictionary just takes objects, but you'll be able to share your driver instance between steps regardless of which file they are in.
The third (and IMHO best) option is to create a WebDriverContext class and accept this in your step class constructor. Create your driver once in there (in its constructor) and then every step can use the WebDriverContext instance to access the shared driver.
An example of setting this up can be seen in the answer here
Your driver just needs to proceed a little slower
Add some delay before each driver.FindElement, for instance with :
Thread.Sleep(2000);
IWebElement txtBox1 = driver.FindElement(By.Id("txtNum1"));
Or better yet :
WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0,0,10));
wait.Until(ExpectedConditions.ElementIsVisible(By.Id("txtNum1")));
IWebElement txtBox1 = driver.FindElement(By.Id("txtNum1"));
Found the answer after a bit of code examination. This issue was to do with multiple instances of ChromeDriver in the code. So the first instance was loading the page but when I was trying to find an item on the page I was using a new instance of the page instead of the one that was already used to load the page. So this second instance of the chrome driver with no page loaded was always returning exception with no item found as the there was no page loaded on this instance of chrome driver
Related
I have a Selenium framework that has been smooth sailing ever since it's creation. I implemented the Visual Studio Team Explorer today and after pulling from my remote branch, Intellisense started yelling at me, saying that one of my namespaces does not exist. The lines that it doesn't like are
using PageObjectModel.PageObjects.Maintenance;
and
var SettlementAccountReconciliations = new SettlementAccountReconciliation(_driver);
The SettlementAccountReconciliation is found within the Maintenance directory. Here is my full code for the test class where it does not like the directory:
using NLog.Internal;
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using PageObjectModel.ControlObjects;
using PageObjectModel.PageObjects;
using PageObjectModel.PageObjects.Process;
using PageObjectModel.PageObjects.Status;
using System;
using PageObjectModel.PageObjects.Maintenance; // **LINE WITH MAINTENANCE UNDERLINED**
namespace PageObjectModel.Tests.TaskTesting
{
[TestFixture]
class JiraTaskTesting
{
private IWebDriver _driver;
[OneTimeSetUp]
public void SetUp()
{
_driver = new ChromeDriver();
DriverContext.Driver = _driver;
_driver.Manage().Window.Maximize();
var ConfigManager = new ConfigurationManager();
var Login = new Login(_driver);
Login.SignIn(ConfigManager.AppSettings["Username"], ConfigManager.AppSettings["Password"]);
}
[Test]
public void ReportNameStandardizationSettlementAccountReconciliations()
{
// **LINE WITH UNDERLINE**
var SettlementAccountReconciliations = new SettlementAccountReconciliation(_driver);
var Utilities = new Utilities(_driver);
var ReportPopup = SettlementAccountReconciliations.ExportReconciliationReport();
ReportPopup.StartDate.SetValue(DateTime.Now.ToString("MM/dd/yyyy"));
ReportPopup.EndDate.SetValue(DateTime.Now.ToString("MM/dd/yyyy"));
ReportPopup.ExportButton.Click();
Assert.IsTrue(Utilities.ValidateFilePresent("Settlement Account Reconciliation"));
Utilities.DeleteFile("Settlement Account Reconciliation");
}
Also, here is the SettlementAccountReconciliation found within the Maintenance namespace:
using OpenQA.Selenium;
using OpenQA.Selenium.Support.PageObjects;
using OpenQA.Selenium.Support.UI;
using System;
namespace PageObjectModel.PageObjects.Maintenance
{
public class SettlementAccountReconciliation
{
private readonly IWebDriver _driver;
public SettlementAccountReconciliation(IWebDriver driver)
{
_driver = driver;
PageFactory.InitElements(driver, this);
var Utilities = new Utilities(driver);
string TradingUrl = Utilities.RefactorUrl("/SettlementAccountReconciliation");
driver.Navigate().GoToUrl(TradingUrl);
WebDriverWait Wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
try
{
Wait.Until(ExpectedConditions.ElementExists(By.XPath("//a[text()='Settlement Account Reconciliations']")));
Console.WriteLine("SettlementAccountReconciliation Page Label Found");
}
catch
{
Console.WriteLine("SettlementAccountReconciliation Page Label Not Found, timing out");
}
}
This is an image of what is shown in my test class for the Directives:
And for the SettlementAccountReconciliation constructor:
I have all of my code in the Page Object Model format, and this is how my file structure is lined out:
I know this question is long winded but to continue, the tests run just fine, and the solution builds like a charm. I just need to figure out how to get the text editor to not think there are issues with my code.
Visual Studio tells me that "The type or namespace name 'Maintenance' does not exist in the namespace PageObjectModel.PageObjects'", but it does.
Any help on this would be greatly appreciated.
EDIT:
I fixed it.
I don't why it worked, but it did.
All I did was renamed the Maintenance folder to Maintenance1, recreated the Maintenance folder, and dragged and dropped the SettlementAccountReconciliation class into the Maintenance folder.
I am guessing there was some random property or setting stored in a temp folder somewhere in Timbuktu that was stored for the existing folder that was reset or deleted when the new folder was created.
Thanks to everyone who put time into helping me out!
I've had this issue before myself. Check the file and folder names in your project directory, the namespaces and assembly name within the properties of your project, and check that, if you've added the project as a reference, that the path to the reference is consistent with the actual path. I have a strong feeling that there is some inconsistency somewhere if you've refactored this at any point and the code you think you are referencing isn't actually what is being referenced.
I renamed the Maintenance folder to Maintenance1, recreated the Maintenance folder, and dragged and dropped the SettlementAccountReconciliation class into the Maintenance folder, and it seems to have fixed the issue.
I am guessing there was some random property or setting stored in a temp folder somewhere in Timbuktu that was stored for the existing folder that was reset or deleted when the new folder was created.
Looking for a solution to invoke Navigation in Chrome from outside of chrome by external process.
We have legacy WinForm Software that needs to browse an Angular HTML5 app that requires Chrome to run. (I have no control of this.)
Something along lines of:
Process process = new Process();
process.StartInfo.FileName =
#"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe";
process.StartInfo.Arguments = "google.com" + " --new-window";
process.Start();
And then some way to hook into that process and have the SAME TAB perform navigation.
magic.navigateTab1(www.anothersite.com);
I quite assume its not easily possible, solution may not use Process etc.. Just, anyway to accomplish it from outside chrome?
Whatever solution can't require installing > ~5MB to C# code base.. Ideally, no installation is preferred.
http://cefsharp.github.io/ <- looked into this but this is huge.
Edit 1: Perhaps using something like this..
https://sites.google.com/a/chromium.org/chromedriver/
I used Selenium to achieve that.
First you must add via Nugget the following packages to your solution
Selenium.WebDriver
Selenium.Chrome.WebDriver;
Then reference the following namespaces
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
Create the following property on your class root
IWebDriver driver;
On your class constructor add the following code to create a new Chrome Window handled by Selenium
driver = new ChromeDriver();
Then on your buttons add the following
// Switch the action target to the first tab opened on chrome instace handled by Selenium
driver.SwitchTo().Window(driver.WindowHandles.First());
// Go to a given URL
driver.Navigate().GoToUrl("http://www.yourURL.com.br");
Your code should be like that
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
namespace configure
{
public partial class Form1 : Form
{
IWebDriver driver;
public Form1()
{
InitializeComponent();
driver = new ChromeDriver();
}
private void button1_Click(object sender, EventArgs e)
{
driver.SwitchTo().Window(driver.WindowHandles.First());
driver.Navigate().GoToUrl("http://www.yourURL.com.br");
}
}
}
Hope this solve your problem
I have page which downloads a file which shows a dialog on the bottom with OPEN SAVE CANCEL options, how can I click those options ? I am using IE browser, I saw some solutions using third party AutoIt, Robot class, but I am looking with Selenium and C# only. Attached is the image of what I am talking.. Any idea how can we do this ?
AutoItX3 autoit = new AutoItX3();
autoit.WinActivate("Save");
Thread.Sleep(1000);
autoit.Send("{F6}");
Thread.Sleep(1000);
autoit.Send("{TAB}");
Thread.Sleep(1000);
autoit.Send("{ENTER}");
You can try this code.
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.IE;
using OpenQA.Selenium.Support.UI;
using System.Threading;
using System.Collections.Generic;
using System.Windows.Forms;
//using NUnit.Framework;
namespace SampleTest
{
[TestMethod]
public void Download()
{
IWebDriver driver = new InternetExplorerDriver(#"C:\Users\hamit\Desktop\Selenium\IEDriverServer_Win32_2.48.0");
driver.Navigate().GoToUrl("https://www.spotify.com/se/download/windows/");
Thread.Sleep(2000);
SendKeys.SendWait("#{TAB}"); Thread.Sleep(100);
SendKeys.SendWait("#{TAB}"); Thread.Sleep(100);
SendKeys.SendWait("#{DOWN}"); Thread.Sleep(100);
SendKeys.SendWait("#{DOWN}"); Thread.Sleep(100);
SendKeys.SendWait("#{Enter}");
}
}
like an option - try get all exist buttons and then filter by inner text
var posibleButtons = driver.FindElements(By.TagName("button")).Where(el => el.Text.Contains("Open"));
posibleButtons.Where(// try use some other filters, maybe by styles or ets...
IE 11 for security reasons do not allow us to skip that part. Since this is not the DOM, you cannot handle it with selenium..
AutoIT or similar tools are the only option, which makes the test less reliable..
instead, we added API calls to get the documents instead of actually downloading them.
Tried in Java, file was downloaded.
driver.findElement(By.xpath("//body")).sendKeys(Keys.chord(Keys.CONTROL, "j"));
Thread.sleep(2000);
Robot rb = new Robot();
rb.keyPress(KeyEvent.VK_ENTER);
Explaination:
1 First click on the button / link to download the file.this pop up will be seen enter image description here
2. Click "Ctrl+j" this will open the "View Downloads pop up".
3.Then click enter , since the focus will be on the recent file, it
will be downloaded
I've jjust started off with Selenium Webdriver and I've hit an issuee straight away involving the buttons I'm trying to select/click all have no IDs and share the same class.
So I'm wondering how I select these by the unique text they contain.
I'm thinking possibly with css selector maybe, but I'm unsure how to also tell it to look for specific text to select the element.
All I currently have is:
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenQA.Selenium.Internal;
namespace SeleniumTest1.Methods
{
public class HomePage
{
private readonly IWebDriver _browser;
public HomePage(IWebDriver browser)
{
_browser = browser;
}
public IWebElement SearchBox()
{
return _browser.FindElement(By.Id("searchBox"));
}
public void ImageButton()
{
_browser.FindElement(By.CssSelector("a")).Click();
}
}
}
Very basic so far.
Where I have the CssSelector I'm not sure if theres anyway to say select "a" containing text "xyz".
I've tried search for ways but can't find anything, though I feel this must be an issue which has been raised before, thanks.
Fairly easy if you use xpath.
if it has unique text your xpath should look like something like this
//button[.='xyz']
So, here "." points to the parent in HTML hierarchy and just look for text
You can find the link by the visible text.
IWebElement XyzLink= _browser.FindElement(By.LinkText("xyz"));
Also you can locate the link by partial link text as follows,
IWebElement XyzPartialLink= _browser.FindElement(By.PartialLinkText("XYZ"));
For example this will locate a link element which contains 'XYZ' in its text.
I'm using Selenium's IWebDriver to write Unit Tests in C#.
Such is an example:
IWebDriver defaultDriver = new InternetExplorerDriver();
var ddl = driver.FindElements(By.TagName("select"));
The last line retrieves the select HTML element wrapped in a IWebElement.
I need a way to simulate selection to a specific option in that select list but I can't figure out how to do it.
Upon some research, I found examples where people are using the ISelenium DefaultSelenium class to accomplish the following, but I am not making use of this class because I'm doing everything with IWebDriver and INavigation (from defaultDriver.Navigate()).
I also noticed that ISelenium DefaultSelenium contains a ton of other methods that aren't available in the concrete implementations of IWebDriver.
So is there any way I can use IWebDriver and INavigation in conjunction with ISelenium DefaultSelenium ?
As ZloiAdun mentions, there is a lovely new Select class in the OpenQA.Selenium.Support.UI namespace. That's one of the best ways to access a selection element and it's options because it's api is so easy. Let's say you've got a web page that looks something like this
<!DOCTYPE html>
<head>
<title>Disposable Page</title>
</head>
<body >
<select id="select">
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
<option value="mercedes">Mercedes</option>
<option value="audi">Audi</option>
</select>
</body>
</html>
You're code to access the select would look like this. Note how I create the Select object by passing a normal IWebElement to it's constructor. You have plenty of methods on the Select object. Take a look at the source for more information, until it gets properly documented.
using OpenQA.Selenium.Support.UI;
using OpenQA.Selenium;
using System.Collections.Generic;
using OpenQA.Selenium.IE;
namespace Selenium2
{
class SelectExample
{
public static void Main(string[] args)
{
IWebDriver driver = new InternetExplorerDriver();
driver.Navigate().GoToUrl("www.example.com");
//note how here's i'm passing in a normal IWebElement to the Select
// constructor
Select select = new Select(driver.FindElement(By.Id("select")));
IList<IWebElement> options = select.GetOptions();
foreach (IWebElement option in options)
{
System.Console.WriteLine(option.Text);
}
select.SelectByValue("audi");
//This is only here so you have time to read the output and
System.Console.ReadLine();
driver.Quit();
}
}
}
A couple things to note about the Support class however. Even if you downloaded the latest beta, the support DLL won't be there. The Support package has a relatively long history in the Java libraries (that's where PageObject lives) but it's still pretty fresh in the .Net driver. Fortunately, it's really easy to build from source. I pulled from SVN then referenced the WebDriver.Common.dll from the beta download and built in C# Express 2008. This class hasn't been as well tested as some of the other classes, but my example worked in Internet Explorer and Firefox.
There's a few other things that I should point out based on your code above. Firstly the line you were using to find the select element
driver.FindElements(By.TagName("select"));
is going to find all select elements. you should probably use driver.FindElement, without the 's'.
Also, very rarely would you use INavigation directly. You'll do most of your navigation like driver.Navigate().GoToUrl("http://example.com");
Lastly, DefaultSelenium is the way to access the older Selenium 1.x apis. Selenium 2 is a pretty significant departure from Selenium 1, so unless you're trying to migrate old tests to the new Selenium 2 api (often referred to as the WebDriver api) you won't use DefaultSelenium.
You should get all option elements from your select using ddl.FindElements(By.TagName("option"));. Then you can iterate through the returned collection and select required item(s) by using SetSelected method of the IWebElement
Update: It seems that there's now a C# implementation of the Select in WebDriver - previously it was in Java only. Please take a look at its code and it is easier to use this class