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
Related
Using .net 6, bUnit 1.13.5 Mudblazor 6.0.17
I am trying to write unit tests for a razor component that is in a dialog box and bUnit is unable to find any of the components or class/ids in it. I am getting the following error...
Message:
Bunit.ElementNotFoundException : No elements were found that matches the selector '#CancelButton'
in the ColumnTrackerEditDialog.razor there is the following line
<MudButton id="CancelButton" OnClick="#Cancel">Cancel</MudButton>
This should always be rendered and it not under any conditional statements. The unit test for this is as follows (so far)
[Test]
public async Task ColumnTrackerEditDialogUITest_CancelButton()
{
var item = GetColumnTrackerPeco();
PopulateData(item);
var page = TestContext!.RenderComponent<ColumnTrackerEditDialog>(parameters =>
parameters.Add(p => p.Item, item));
Assert.IsNotNull(page);
var cancelButton = page.Find("#CancelButton");
Assert.IsNotNull(cancelButton);
cancelButton.Click();
}
The test set up is fine as the page is not null and on non dialog pages I can find elements by ids, classes or components.
Is this an issue because it's a dialog or am I missing something else?
I have tried to find "button", ".mud-button" and other classes, as well as .FindComponent and other tags within the component and it's not finding anything.
Is the component being added asynchronously? If that's the case, try using cut.WaitForElement("#CancelButton") instead.
Another approach is to stub out the MudBlazor component, so it's not directly influences your test, and instead find the stub and assert you passed the expected parameters to it. Learn more here: https://bunit.dev/docs/providing-input/substituting-components
I'm creating a test automation framework in C# .Net using Appium to automate IOS and Android and wanted to use Page Object Design Pattern. So I wanted to utilize the PageFactory extension.
By adding the DotNetSeleniumExtras.PageObjects.Core as NuGet package results in an error (red squiggly lines). 4 errors
CS7069: Reference to type 'IFindsById" claims it is defined in 'WebDriver', but it could not be found.
I needed this extension DotNetSeleniumExtras.PageObjects.Core in order for me to instantiate the Page objects and be able to implement the Page Object Design pattern.
Please let me know if I'm missing something here or if there are any workarounds. Thanks in advance!
Below is my code for added context:
using NUnit.Framework;
using OpenQA.Selenium.Appium.iOS;
using OpenQA.Selenium.Appium.PageObjects;
using SeleniumExtras.PageObjects;
using OpenQA.Selenium;
using OpenQA.Selenium.Appium;
namespace NativeApp_TestAutomation.Tests.Specs.IOS
{
[TestFixture]
public class LoginTest
{
private IOSDriver<IOSElement> _driver;
private HomeScreen _pageObject;
[OneTimeSetUp]
public void BeforeAll()
{
var capabilities = Capabilities.GetIOSCapabilities("");
var serverUri = Env.ServerIsRemote() ? AppiumServer.RemoteServerUri : AppiumServer.LocalServiceUri;
_driver = new IOSDriver<IOSElement>(serverUri, capabilities, Env.LaunchTimeoutSeconds);
var timeSpan = new TimeOutDuration(new TimeSpan(0, 0, 0, 5, 0));
_pageObject = new HomeScreen(_driver);
PageFactory.InitElements(_driver, _pageObject, new AppiumPageObjectMemberDecorator(timeSpan));
}
}
}
I'm getting the red squiggly lines here with all having the same errors.
One of the most common reasons for that is a mixture of version and assemblies because of different versions and their compatibility.
If you can try following steps the issues most likely would be solved:
Appium.net latest come out with dependency on DotNetSeleniumExtras.PageObjects v3.11.0 and WebDriver 3.141.0
DotNetSeleniumExtras.Core of v3.12.0 (do not use latest, target v3.12.0) come out with dependency on WebDriver 3.12.0
DotNetSeleniumExtras.PageObjects v3.11.0 rely on WebDriver 3.11.0
So by adding WebDriver 3.12.0 version conflict should be fixed.
This one is a simplest approach - if previous version have enough features then It's done and you can just wait for updates.
The second option that can help you is a binding redirects. The idea is pretty simple, you need to ensure that app know where your WebDriver and it is of correct version.
One good explanation is here (but believe me this is the last thing you want to do, fixed in one place become broken in another) Adding a bindingRedirect to a .Net Standard library
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
I'm moving from a Java environment to .NET and need to write Webdriver tests using a page object model.
In Java I would use the following annotation:
#FindBy(linkText = "More details")
WebElement moreDetailsButton;
Please would someone be able to tell me how to define a WebElement using C#? Also, is the PageFactory.initElements used the same way?
Thanks
Steve
Yes, there is a direct translation.
You are looking for FindsBy:
[FindsBy(How = How.LinkText, Using = "More details")]
private IWebElement moreDetailsButton;
As for the PageFactory.initElements, yes, it's a very similar thing in .NET, usually called in the constructor of the Page Object:
public class LoginPage
{
private IWebDriver _driver;
public LoginPage(IWebDriver driver)
{
_driver = driver;
PageFactory.InitElements(_driver);
}
}
Note, that the Selenium project is entirely open source. You can easily see the source the Page Objects 'helper' classes here.
I am trying to use CssSelector to locate an element on my webpage. I am using Firefox driver.
Here is how I am using the locator (I checked that Selenium IDE is able to locate my element with this
[FindsBy(How = How.CssSelector, Using = "label:contains('Version: 2.0.')")]
public IWebElement labelVersion;
But when use this in the C# code and initialize it with
PageFactory.InitElements in my constructor.
I hit this error... (the error itself is pretty clear but I don't know how to fix it)
Appreciate any inputs.
OPC.Tests.SmokeTest (TestFixtureSetUp): SetUp :
OpenQA.Selenium.InvalidSelectorException : The given selector
css=label:contains('Version: 2.0.') is either invalid or does not
result in a WebElement. The following error occurred: [Exception...
"An invalid or illegal string was specified" code: "12" nsresult:
"0x8053000c (NS_ERROR_DOM_SYNTAX_ERR)" location:
"file:///........../anonymous439571104.webdriver-profile/extensions/fxdriver#googlecode.com/components/driver_component.js
Line: 5811"]
Selenium delegates CSS queries down to the browser. This means that CSS queries need to follow CSS standard.
Unfortunately :contains was removed from the standard a while back. I recommend that you redo your selector with whats available from the spec or use XPATH.
:contains works in Selenium RC because RC uses Sizzle, the selector search library in jQuery if you are wondering why it works in RC and not WebDriver