我需要同时执行一些 webdrivers 操作,但我不确定如何执行此操作。
我在这里要问的是:
- 实现这一目标的正确方法是什么?
- 我得到异常的原因是什么(如下所示)
经过一番研究,我最终得到:
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;