I have been bouncing between guides and YouTube videos trying to implement Selenium Grid 2 on an existing project for a couple of days and I've gotten stuck, please help!
Our framework is Specflow 3.0.220, Selenium WebDriver 3.141.0, C#, NUnit 3.12.0, Selenium Grid selenium-server-standalone-3.141.59.
My initial objectives to implement Selenium Grid 2 are as follows:
- Set up a hub and node(s) on my local machine = done.
- Run a test through one of the nodes = done.
- Run a test on all nodes simultaneously = headache.
Regarding item 2, I have set up two nodes, one is a Chrome node and one is a Firefox node. I can run a test through both of them, but not simultaneously.
I feel that I missing a piece of the puzzle here.
Here's the set-up:
Scenario Outline: Log in
Given I launch the site for <profile> and <environment> and <parallelEnvironment>
When I log in to the Normal account
Then I see that I am logged in
Examples:
| profile | environment | parallelEnvironment |
| parallel | Chrome75 | grid |
If profile is parallel and parallelEnvironment is grid, environment is ignored. The reason for parallelEnvironment is because we may still use Browserstack in the interim while setting up Selenium Grid.
These steps use relevant step files etc and page files (but not using Page Object Model as that's been deprecated).
The driver set-up is as follows:
namespace OurAutomation
{
[Binding]
public sealed class BrowserStack
{
private BrowserStackDriver bsDriver;
public static BrowserStackDriver bdriver;
[BeforeScenario]
public void BeforeScenario()
{
bsDriver = new BrowserStackDriver();
bdriver = bsDriver;
}
[AfterScenario]
public void AfterScenario()
{
bsDriver.Cleanup();
}
}
public class CustomRemoteWebDriver : RemoteWebDriver
{
public CustomRemoteWebDriver(Uri remoteAddress, ChromeOptions options) : base(remoteAddress, options)
{
}
public string getSessionID()
{
return base.SessionId.ToString();
}
}
public class BrowserStackDriver
{
private IWebDriver driver;
public static bool isBrowserStack = false;
public static string Platform;
public static string theEnvironment;
public static string sessionId;
public BrowserStackDriver()
{
}
public string GetString(string property)
{
if (TestContext.Parameters[property] == null)
{
throw new ArgumentException("Property does not exist, does not have a value, or a test setting is not selected. You may need to add the .runsettings file in Visual Studio (Test > Test Settings > Select Test Settings File).");
}
else
{
return TestContext.Parameters[property].ToString();
}
}
public IWebDriver Init(string profile, string environment, string parallelEnvironment)
{
String testString = GetString("BuildNumber");
theEnvironment = environment;
NameValueCollection caps = ConfigurationManager.GetSection("capabilities/" + profile) as NameValueCollection;
NameValueCollection settings = ConfigurationManager.GetSection("environments/" + environment) as NameValueCollection;
ChromeOptions chromeOptions = new ChromeOptions();
if (profile == "single")
{
// logic to invoke relevant browser locally based on Specflow parameter 'profile'
Thread.Sleep(3000);
}
else if (profile == "parallel")
{
if (parallelEnvironment == "browserstack")
{
foreach (string key in caps.AllKeys)
{
chromeOptions.AddAdditionalCapability(key, caps[key]);
}
foreach (string key in settings.AllKeys)
{
chromeOptions.AddAdditionalCapability(key, settings[key]);
}
string username = Environment.GetEnvironmentVariable("BROWSERSTACK_USERNAME");
if (username == null)
{
username = ConfigurationManager.AppSettings.Get("user");
}
string accesskey = Environment.GetEnvironmentVariable("BROWSERSTACK_ACCESS_KEY");
if (accesskey == null)
{
accesskey = ConfigurationManager.AppSettings.Get("key");
}
chromeOptions.AddAdditionalCapability("browserstack.user", username);
chromeOptions.AddAdditionalCapability("browserstack.key", accesskey);
chromeOptions.AddAdditionalCapability("browserstack.local", "true");
chromeOptions.AddAdditionalCapability("build", GetString("BuildNumber"));
chromeOptions.AddAdditionalCapability("name", TestContext.CurrentContext.Test.MethodName);
chromeOptions.AddAdditionalCapability("project", GetString("Project"));
BrowserStackDriver.isBrowserStack = true;
driver = new CustomRemoteWebDriver(
new Uri("http://" + ConfigurationManager.AppSettings.Get("server") + "/wd/hub/"), chromeOptions);
CustomRemoteWebDriver browserRemoteDriver = driver as CustomRemoteWebDriver;
sessionId = browserRemoteDriver.getSessionID();
}
else if (parallelEnvironment == "grid")
{
driver = new RemoteWebDriver(new Uri("http://000.00.00.00:4444/wd/hub"), chromeOptions);
}
}
return driver;
}
public void Cleanup()
{
Thread.Sleep(2000);
if (isBrowserStack)
{
Log.Status status = (TestContext.CurrentContext.Result.Message == null) ? Log.Status.Passed : Log.Status.Failed;
string reason = (TestContext.CurrentContext.Result.Message == null) ? "Passed" : "Error see exception";
Log.UpdateTestStatus(status, reason, sessionId);
}
driver.Quit();
driver = null;
}
}
}
So in here...
else if (parallelEnvironment == "grid")
{
driver = new RemoteWebDriver(new Uri("http://000.00.00.00:4444/wd/hub"), chromeOptions);
}
...I enter the address of one of the nodes and the test gets conducted. However, I just want to send the test to the hub and for it to then execute that one test on all active nodes in their related browsers simultaneously. How do I achieve that? The guides and videos only seem to be taking me so far.
thank you
UPDATE:
So I'm inching further in the right direction I think. Had to roll this back to basics, so I can see how to implement this in my existing project. I've made this work in my grid: https://github.com/teixeira-fernando/Parallel-Execution-with-Selenium-Grid
However I note that I need to add attributes to the tests (to run one test on multiple browsers simultaneously)...
namespace Tutorial_parallel_execution
{
[TestFixture(BrowserType.Chrome)]
[TestFixture(BrowserType.Firefox)]
[TestFixture(BrowserType.Opera)]
[TestFixture(BrowserType.IE)]
[Parallelizable(ParallelScope.Fixtures)]
public class GoogleTesting : Hooks
{
public GoogleTesting(BrowserType browser) : base(browser)
{
}
[Test]
public void GoogleTest()
{
Driver.Navigate().GoToUrl("http://www.google.com");
Driver.FindElement(By.Name("q")).SendKeys("selenium");
Driver.FindElement(By.Name("btnK")).Click();
Assert.That(Driver.PageSource.Contains("Selenium"), Is.EqualTo(true),
"The text selenium doenst exist");
}
}
}
However, since my project started complaining similarly to this SpecFlow Visual Studio extension attempted to use SpecFlow code-behind generator 1.9, I started using SpecFlow.Tools.MsBuild.Generation and lost access to the tests (the code-behind files) in order to add the attributes. The only attribute I can add is [Parallelizable(ParallelScope.Fixtures)] but I have to put this in AssemblyInfo.cs - the other attributes can't be added there.
Do I need to be downgrading the versions of Specflow/Selenium etc in order to make this work??