1

我需要同时执行一些 webdrivers 操作,但我不确定如何执行此操作。

我在这里要问的是:

  1. 实现这一目标的正确方法是什么?
  2. 我得到异常的原因是什么(如下所示)

经过一番研究,我最终得到:

1 . 我看到人们这样做的方式(以及我在使用 API 之后,在搜索之前最终使用的方式)是循环遍历我的 WebDriver 手头的窗口句柄,并执行切换到和退出我想要的窗口句柄处理,完成后关闭它。

2 . Selenium Grid 对我来说似乎不是一个选择 - 我错了还是它用于并行处理?由于我在一台计算机上运行所有内容,因此对我来说毫无用处。


在尝试第一个选项时,我有以下场景(下面提供了一个代码示例,我跳过了不相关/重复本身的内容(我添加了 3 个点:

我有一个 html 页面,有几个提交按钮,堆叠。

单击它们中的每一个将打开一个新的浏览器/选项卡(有趣的是,使用 ChromeDriver 打开选项卡,而 FirefoxDriver 为每个打开单独的窗口。)

附带说明:我无法事先确定每个提交的 uri(它们必须由 javascript 确定,此时,让我们假设我想处理对客户端代码一无所知的所有事情。

现在,在遍历所有提交按钮并在相应元素上发出 webElement.Click() 之后,选项卡/窗口打开。代码流以创建要执行的任务列表,每个新选项卡/窗口一个。

问题是:由于所有任务都依赖于同一个 webdriver 实例来切换到窗口句柄,看来我需要添加资源共享锁/控制。我不确定我是否正确,因为在搜索多线程 Web 驱动程序示例时,我没有看到锁/资源访问控制的提及。

另一方面,如果我能够事先确定选项卡/窗口 uri,我将能够跳过达到这一点所需的所有自动化步骤,然后为每个线程创建一个 webDriver 实例,通过Navigate().GoToUrl()将是简单的。但这看起来像一个僵局!我没有看到 webDriver 的 API 在不执行切换的情况下提供对新打开的选项卡/窗口的任何访问。如果我不必重复所有将我引导到当前窗口的自动化步骤,我只想切换!

...

无论如何,我不断收到异常:

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

IWebElement element = cell.FindElement

块内ToDictionary()

我显然在 chrome 的控制台中检查了我所有的选择器都返回了结果。

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;
4

0 回答 0