【问题标题】:Selenium multiple tabs at onceSelenium 一次有多个标签
【发布时间】:2013-08-11 14:47:12
【问题描述】:

我正在使用 Selenium,想知道是否可以一次使用多个 TABS?我不想使用多个浏览器实例(即 IE 双关语的 2 个副本)。如果不可能,如何在按顺序运行的各个选项卡之间进行切换?

谢谢!

【问题讨论】:

    标签: selenium tabs automated-tests multiple-instances


    【解决方案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】:

          如果您使用 seleniumnodejs,这将解决您的问题。

          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();
            

            【讨论】:

              猜你喜欢
              • 2017-12-06
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-07-10
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-04-04
              相关资源
              最近更新 更多