0
votes

I have automated regression tests that run every morning. Currently, it launches dozens of threads simultaneously, each running its own webdriver in each thread.

                ChromeOptions option = new ChromeOptions();
                option.AddArgument("--headless");
                IWebDriver driver = new ChromeDriver(option);                    

                try
                {
                    SuiteDriver(driver, suiteTable);
                    LogMonitor.UEErrorHandling();
                }
                catch (Exception ex)
                {
                    WritetoLogFile("Exception in Main - " + ex);
                }
                finally
                {
                    workbook.Dispose();
                    driver.Quit();
                }

When the tests complete there are a bunch of webdriver instances still running. When I attempt to clean these up at the end of the test run using driver.Quit() it closes more than just the driver in its own thread, causing the other tests to fail to complete. Driver.Quit() doesn't seem to differentiate between the driver launched by this one instance and other drivers launched by other instances of the test.

Is there a way to ensure driver.Quit() or driver.Close() only closes the instance of webdriver launched by that specific executable running in that thread only?

2
You will have to use ThreadLocal<WebDriver> instances for each thread. While quiting the driver, you will have to use thread specific driver. There are plenty of examples on this.Sureshmani Kalirajan
explanation: even though each thread has its own Chrome instance, they are all sharing the same chromedriver executable that is driving the browser... when you call quit(), it stops the chromedriver process and all subsequent requests from other threads can no longer communicate with the browser. –Corey Goldberg

2 Answers

0
votes

Below is an example of thread-safe execution in C# using System.Threading.ThreadLocal

ThreadLocal<IWebDriver> DriversThread = new ThreadLocal<IWebDriver>();

IWebDriver Driver
{
    set => DriversThread.Value = value;
    get => DriversThread.Value;
}

string directoryPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); // Pass this directory path to chromedriver when you are installing chromedriver through Nuget packages.
ChromeOptions chromeOpt = new ChromeOptions();
chromeOpt.AddArguments("--headless");
Driver = new ChromeDriver(directoryPath, chromeOpt);

Driver.Url = "https://google.co.in";

Driver.Quit();

This will set thread specific drivers, each thread will have its own driver no matter how many threads are being executed.

0
votes

Try and give each webdriver it's own profile, and if needed download path.

private ChromeOptions GetChromeOptions()
{
    var options = new ChromeOptions();

    ProfilePath = Path.Combine(AppContext.BaseDirectory, "tmp", Guid.NewGuid().ToString());
    DownloadPath = Path.Combine(ProfilePath, "Downloads");
    if (!Directory.Exists(DownloadPath))
    {
        Directory.CreateDirectory(DownloadPath);
    }
    options.AddUserProfilePreference("download.default_directory", DownloadPath);
    //--lang=en-US,en headless does not define a language by default 
    options.AddArguments("--incognito", "--lang=en-US,en", $@"--user-data-dir={ProfilePath}");
    return options;
}

I'm using xUnit to spawn dozens of headless chromes tests and I've not ever seen the dispose close all of the instances. The only difference I can think of is that I am spawning each with their own profile.

I would suggest using the setup and teardown of your testing framework onto a base class to handle the setup and teardown for all tests.

public class PageLoad: IDisposable
{
    private IWebDriver _driver;

    public void PageLoad()
    {
        _driver = new ChromeDriver();
    }

    [Fact]
    public void PageLoadTest()
    {
        _driver.Navigate().GoToUrl("http://google.com");
        Assert.True(_driver.FindElement(By.XPath("//*[@id='hplogo']")).Displayed);
    }

    public void Dispose()
    {
        _driver.Dispose();
    }
}

You can also wrap the driver in a using statement

using (var driver = new ChromeDriver())
{
    driver.Navigate().GoToUrl("http://google.com");
    Assert.True(_driver.FindElement(By.XPath("//*[@id='hplogo']")).Displayed);
}