Multi-threaded C# Selenium WebDriver automation with Uris not known beforehand

喜欢而已 提交于 2019-12-11 12:08:47

问题


I need to perform some simultaneous webdrivers manipulation, but I am uncertain as to how to do this.

What I am asking here is:

  1. What is the correct way to achieve this ?
  2. What is the reason for the exception I am getting (revealed below)

After some research I ended up with:

1. The way I see people doing this (and the one I ended up using after playing with the API, before searching) is to loop over the window handles my WebDriver has at hand, and perform a switch to and out of the window handle I want to process, closing it when I am finished.

2. Selenium Grid does not seem like an option fore me - am I wrong or it is intended for parallel processing ? Since am running everything in a single computer, it will be of no use for me.


In trying the 1st option, I have the following scenario (a code sample is available below, I skipped stuff that is not relevant/repeat itself (where ever I added 3 dots:

I have a html page, with several submit buttons, stacked.

Clicking each of them will open a new browser/tab (interestingly enough, using ChromeDriver opens tabs, while FirefoxDriver opens separate windows for each.)

As a side note: I can't determine the uris of each submit beforehand (they must be determined by javascript, and at this point, let's just assume I want to handle everything knowing nothing about the client code.

Now, after looping over all the submit buttons, and issuing webElement.Click() on the corresponding elements, the tabs/windows open. The code flows to create a list of tasks to be executed, one for each new tab/window.

The problem is: since all tasks all depend upon the same instance of webdriver to switch to the window handles, seems I will need to add resource sharing locks/control. I am uncertain as whether I am correct, since I saw no mention of locks/resource access control in searching for multi-threaded web driver examples.

On the other hand, if I am able to determine the tabs/windows uris beforehand, I would be able to skip all the automation steps needed to reach this point, and then creating a webDriver instance for each thread, via Navigate().GoToUrl() would be straightforward. But this looks like a deadlock! I don't see webDriver's API providing any access to the newly opened tab/window without performing a switch. And I only want to switch if I do not have to repeat all the automation steps that lead me to the current window !

...

In any case, I keep getting the exception:

Element belongs to a different frame than the current one - switch to its containing frame to use it

at

IWebElement element = cell.FindElement

inside the ToDictionary() block.

I obviously checked that all my selectors are returning results, in chrome's console.

foreach (WebElement resultSet in resultSets)
    resultSet.Click();


foreach(string windowHandle in webDriver.WindowHandles.Skip(1))
{
    dataCollectionTasks.Add(Task.Factory.StartNew<List<DataTable>>(obj =>
    {
        List<DataTable> collectedData = new List<DataTable>();
        string window = obj as string;

        if (window != null)
        {
            webDriver.SwitchTo().Window(windowHandle);
            List<WebElement> dataSets = webDriver.FindElements(By.JQuerySelector(utils.GetAppSetting("selectors.ResultSetData"))).ToList();

            DataTable data = null;

            for (int i = 0; i < dataSets.Count; i += 2)
            {
                data = new DataTable();

                data.Columns.Add("Col1", typeof(string));
                data.Columns.Add("Col2", typeof(string));
                data.Columns.Add("Col3", typeof(string));

                ///...

                //data set header
                if (i % 2 != 0)
                {
                    IWebElement headerElement = dataSets[i].FindElement(OpenQA.Selenium.By.CssSelector(utils.GetAppSetting("selectors.ResultSetDataHeader")));
                    data.TableName = string.Join(" ", headerElement.Text.Split().Take(3));
                }
                //data set records
                else
                {
                    Dictionary<string, string> cells = dataSets[i]
                        .FindElements(OpenQA.Selenium.By.CssSelector(utils.GetAppSetting("selectors.ResultSetDataCell")))
                        .ToDictionary(
                            cell =>
                            {
                                IWebElement element = cell.FindElement(OpenQA.Selenium.By.CssSelector(utils.GetAppSetting("selectors.ResultSetDataHeaderColumn")));
                                return element == null ? string.Empty : element.Text;
                            },
                            cell =>
                            {
                                return cell == null ? string.Empty : cell.Text;
                            });

                    string col1Value, col2Value, col3Value; //...
                    cells.TryGetValue("Col1", out col1Value);
                    cells.TryGetValue("Col2", out col2Value);
                    cells.TryGetValue("Col3", out col3Value);
                    //...

                    data.Rows.Add(col1Value, col2Value, col3Value /*...*/);
                }
            }

            collectedData.Add(data);
        }

        webDriver.SwitchTo().Window(mainWindow);
        webDriver.Close();

        return collectedData;
    }, windowHandle));
} //foreach

Task.WaitAll(dataCollectionTasks.ToArray());
foreach (Task<List<DataTable>> dataCollectionTask in dataCollectionTasks)
{
    results.AddRange(dataCollectionTask.Result);
}

return results;

来源:https://stackoverflow.com/questions/31654380/multi-threaded-c-sharp-selenium-webdriver-automation-with-uris-not-known-beforeh

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!