Selenium 一次有多个标签
Posted
技术标签:
【中文标题】Selenium 一次有多个标签【英文标题】:Selenium multiple tabs at once 【发布时间】:2013-08-11 14:47:12 【问题描述】:我正在使用 Selenium,想知道是否可以一次使用多个 TABS?我不想使用多个浏览器实例(即 IE 双关语的 2 个副本)。如果不可能,如何在按顺序运行的各个选项卡之间进行切换?
谢谢!
【问题讨论】:
【参考方案1】:如果有打开新窗口/标签的链接,那么您可以使用driver.switchTo().window();
但是,如果您想在多个窗口上运行某些东西,那么我建议您拥有多个 webdriver 实例。它更易于管理,并且受支持(有打开新选项卡/窗口的变通方法,例如按热键打开新窗口,但不支持)。
如果你想让多个线程都作用于同一个驱动程序实例,但不同的选项卡,这是不可能的。
【讨论】:
精彩的答案。我还有第二个问题。使用 IE,如何让它切换到新标签页?我正在使用 C#。 driver.switchTo().window() 请求一个字符串。谢谢 您必须使用 driver.getWindowHandles() 获取窗口句柄。然后,您可以遍历窗口并测试 URL 或标题,以确保它是您想要的。 我想我需要更多的例子。我正在使用 C#。我认为那可能是 java.. 是的,它的 java。我不知道在 C# 中会是什么,但它们的名称通常相似。 @venzen 我们该怎么做?你有一个示例 Github 项目吗?【参考方案2】:无需多个浏览器实例即可在各个选项卡之间切换。 Web 驱动程序处理不同窗口和处理不同选项卡的方式有所不同。案例 1: 如果有多个窗口,则以下代码可以提供帮助:
//Get the current window handle
String windowHandle = driver.getWindowHandle();
//Get the list of window handles
ArrayList tabs = new ArrayList (driver.getWindowHandles());
System.out.println(tabs.size());
//Use the list of window handles to switch between windows
driver.switchTo().window(tabs.get(0));
//Switch back to original window
driver.switchTo().window(mainWindowHandle);
案例 2: 如果同一窗口中有多个选项卡,则只有一个窗口句柄。因此,在窗口句柄之间切换会使控件保持在同一个选项卡中。 在这种情况下,使用 Ctrl + \t (Ctrl + Tab) 在选项卡之间切换更有用。
//Open a new tab using Ctrl + t
driver.findElement(By.cssSelector("body")).sendKeys(Keys.CONTROL +"t");
//Switch between tabs using Ctrl + \t
driver.findElement(By.cssSelector("body")).sendKeys(Keys.CONTROL +"\t");
详细的示例代码可以在这里找到:http://design-interviews.blogspot.com/2014/11/switching-between-tabs-in-same-browser-window.html
【讨论】:
非常有用的评论,对我有用,尤其是在使用多个标签的情况下。【参考方案3】:要打开多个标签:
driver = new ChromeDriver();
IjavascriptExecutor jscript = driver as IJavaScriptExecutor;
for (int i = 0; i < 10; i++)
driver.Navigate().GoToUrl(this.baseURL);
jscript.ExecuteScript("window.open('0', '_blank');", this.baseURL);
在它们之间切换:
for (int i = 0; i < driver.WindowHandles.Count; i++)
driver.SwitchTo().Window(driver.WindowHandles[i])]);
【讨论】:
【参考方案4】:试试下面的代码。
String oldTab = driver.getWindowHandle();
driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
ArrayList<String> newTab = new ArrayList<String>(driver.getWindowHandles());
newTab.remove(oldTab);
driver.switchTo().window(newTab.get(0));
【讨论】:
【参考方案5】:我最近实现了一个简单的多线程实用程序,它允许在单独的线程上的单独选项卡上运行测试只需一个 WEBDRIVER 实例。 WebDriver
的问题在于它一次只能聚焦一个选项卡(窗口)。因此,要在多个选项卡中进行测试,WebDriver
必须分别关注每个选项卡。我确信我的实现并不完美,但它是(在 Kotlin 中实现):
用法:
fun test()
val results = ParallelNavigator(webDriver,
listOf(
::test1,
::test2,
::test3
)
).start()
println(results)
// Output: [Success, Failure: java.lang.RuntimeException: Some error, Success]
fun test1(pn: ParallelNavigator)
/* ... open url, find elements etc. so stuff */
pn.resumeNext() // transfer flow to another unfinished thread (test2 if not finished)
/* ... do more stuff */
pn.resumeNext() // again transfer flow to another thread
fun test2(pn: ParallelNavigator) /* ... */
fun test3(pn: ParallelNavigator) /* ... */
实施:
import org.openqa.selenium.JavascriptExecutor
import org.openqa.selenium.WebDriver
import org.openqa.selenium.support.ui.WebDriverWait
import java.util.concurrent.locks.Condition
import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.thread
import kotlin.concurrent.withLock
class ParallelNavigator(private val webDriver: WebDriver, executions: List<(ParallelNavigator) -> Unit>)
private val _executions: List<TabExecution> = executions.map TabExecution(it)
private var currentExecutionIndex: Int = -1
fun start(): List<Result>
createTabs()
return runInternal()
fun resumeNext()
if (_executions.isEmpty())
throw RuntimeException("No executions provided.")
val currentExecution: TabExecution? = if (currentExecutionIndex != -1)
_executions[currentExecutionIndex]
else null
val unfinished = _executions.filter !it.finished
if(unfinished.isEmpty())
return
val nextExecutionIndex = if (currentExecutionIndex >= unfinished.lastIndex || currentExecutionIndex <= -1)
0
else
currentExecutionIndex + 1
val nextExecution = unfinished[nextExecutionIndex]
currentExecutionIndex = nextExecutionIndex
webDriver.switchTo().window(nextExecution.windowHandle)
nextExecution.lock.withLock
nextExecution.condition.signal()
currentExecution?.lock?.withLock
if (!currentExecution.finished)
currentExecution.condition.await()
sealed class Result
class Success : Result()
override fun toString(): String
return "Success"
class Failure(val ex: Throwable) : Result()
override fun toString(): String
return "Failure: $ex.javaClass.name: $ex.message"
class Unfinished : Result()
override fun toString(): String
return "Unfinished"
data class TabExecution(
val test: (ParallelNavigator) -> Unit,
val lock: ReentrantLock = ReentrantLock(),
var finished: Boolean = false
)
lateinit var windowHandle: String
lateinit var condition: Condition
lateinit var thread: Thread
private fun createTabs() = with(webDriver)
navigate().to("about:blank")
val homeWindowHandle = windowHandle
for (execution in _executions)
execution.windowHandle = openNewTab()
webDriver.switchTo().window(homeWindowHandle)
private fun runInternal(): List<Result>
val results = _executions.map Result.Unfinished() as Result .toMutableList()
for (index in _executions.indices)
val execution = _executions[index]
val condition = execution.lock.newCondition()
execution.condition = condition
execution.thread = thread(start = false)
execution.lock.withLock
condition.await()
try
execution.test(this)
results[index] = Result.Success()
catch (ex: Throwable)
ex.printStackTrace()
results[index] = Result.Failure(ex)
execution.finished = true
currentExecutionIndex--
resumeNext()
execution.thread.start()
resumeNext() // run first execution
for (execution in _executions)
execution.thread.join()
return results
fun waitForNewTabToOpen(oldWindowHandles: Set<String>) = with(webDriver)
waitForNewTabToOpen(oldWindowHandles, 10)
fun waitForNewTabToOpen(oldWindowHandles: Set<String>, seconds: Int) = with(webDriver)
WebDriverWait(webDriver, seconds.toLong()).until<Boolean> WebDriver -> availableWindowHandles().size > oldWindowHandles.size
fun availableWindowHandles(): Set<String> = with(webDriver)
return webDriver.getWindowHandles()
private fun getNewTabHandle(oldWindowHandles: Set<String>): String = with(webDriver)
waitForNewTabToOpen(oldWindowHandles)
val newWindowHandles = availableWindowHandles().toMutableSet()
newWindowHandles.removeAll(oldWindowHandles)
return newWindowHandles.iterator().next()
fun openNewTab(): String = with(webDriver)
val oldHandles = availableWindowHandles()
(webDriver as JavascriptExecutor).executeScript("Object.assign(document.createElement('a'), target: '_blank', href: 'about:blank').click();")
waitForNewTabToOpen(oldHandles)
return getNewTabHandle(oldHandles)
【讨论】:
【参考方案6】:如果您使用 selenium 和 nodejs,这将解决您的问题。
driver.get('https://www.google.com/')
.then(_ =>
driver.findElement(webdriver.By.tagName('body'))
)
.then(bodyElement =>
bodyElement.sendKeys(webdriver.Key.chord(webdriver.Key.CONTROL, 't'))
)
.catch(err =>
console.log(err);
)
【讨论】:
【参考方案7】:如果您希望同时运行多个窗口,请对多个 IWebDriver 实例使用线程
前:
public void Work()
IWebDriver driver = new ChromeDriver("D:\\Drivers");
driver.Navigate().GoToUrl(URL);
\\Do the rest
public void Work2()
IWebDriver driver = new ChromeDriver("D:\\Drivers");
driver.Navigate().GoToUrl(URL2);
\\Do the rest
然后像这样调用函数:
Thread thread1 = new Thread(new ThreadStart(Work));
thread1.Start();
Thread thread2 = new Thread(new ThreadStart(Work2));
thread2.Start();
【讨论】:
以上是关于Selenium 一次有多个标签的主要内容,如果未能解决你的问题,请参考以下文章
行为驱动:Cucumber + Selenium + Java - 使用标签实现测试分组
使用 Python 和 Selenium 按标签获取多个元素
Selenium 网格执行 - 如何使用 sendkeys 将多个文件一起(一次)上传到网页