27

I have trawled the web and the WebDriver API. I don't see a way to open new tabs using WebDriver/Selenium2.0 .

Can someone please confirm if I am right?

Thanks, Chris. P.S: The current alternative I see is to either load different urls in the same window or open new windows.

ChrisOdney
  • 6,066
  • 10
  • 38
  • 48
  • I've added the correct answer to your specific question, but given your statement about "alternatives", I suspect there's more to your question. If you'd like to provide more context, a more complete answer could be given. – JimEvans Jun 22 '11 at 18:21

17 Answers17

35

There is totally a cross-browser way to do this using webdriver, those who say you can not are just too lazy. First, you need to use WebDriver to inject and anchor tag into the page that opens the tab you want. Here's how I do it (note: driver is a WebDriver instance):

/**
 * Executes a script on an element
 * @note Really should only be used when the web driver is sucking at exposing
 * functionality natively
 * @param script The script to execute
 * @param element The target of the script, referenced as arguments[0]
 */
public void trigger(String script, WebElement element) {
    ((JavascriptExecutor)driver).executeScript(script, element);
}

/** Executes a script
 * @note Really should only be used when the web driver is sucking at exposing
 * functionality natively
 * @param script The script to execute
 */
public Object trigger(String script) {
    return ((JavascriptExecutor)driver).executeScript(script);
}

/**
 * Opens a new tab for the given URL
 * @param url The URL to 
 * @throws JavaScriptException If unable to open tab
 */
public void openTab(String url) {
    String script = "var d=document,a=d.createElement('a');a.target='_blank';a.href='%s';a.innerHTML='.';d.body.appendChild(a);return a";
    Object element = trigger(String.format(script, url));
    if (element instanceof WebElement) {
        WebElement anchor = (WebElement) element; anchor.click();
        trigger("var a=arguments[0];a.parentNode.removeChild(a);", anchor);
    } else {
        throw new JavaScriptException(element, "Unable to open tab", 1);
    }       
}

Next, you need to tell webdriver to switch its current window handle to the new tab. Here's how I do that:

/**
 * Switches to the non-current window
 */
public void switchWindow() throws NoSuchWindowException, NoSuchWindowException {
    Set<String> handles = driver.getWindowHandles();
    String current = driver.getWindowHandle();
    handles.remove(current);
    String newTab = handles.iterator().next();
    locator.window(newTab);
}

After this is done, you may then interact with elements in the new page context using the same WebDriver instance. Once you are done with that tab, you can always return back to the default window context by using a similar mechanism to the switchWindow function above. I'll leave that as an exercise for you to figure out.

Jonathan Azoff
  • 676
  • 7
  • 4
  • 2
    what is the `locator` in the last line of `switchWindow()`? – jamesfzhang Mar 13 '12 at 19:21
  • 2
    In regular non-remote version of Webdriver, I believe a locator could be just driver.switchTo() right? – djangofan Apr 02 '12 at 18:42
  • 6
    I agree that the code provided here will open a new tab in any given browser window through WebDriver. However, there's no guarantee that a particular driver will be able to control the resulting new tab. – JimEvans May 02 '12 at 09:18
  • Nice workaround...just i'm unable to catch the new tab created. I'm using C#.net Any help is appreciated – sumit_batcoder Dec 18 '12 at 07:19
  • 5
    @Jonathan Azoff How do you control the tab that is opened then? Opening a tab is doable but will cause you endless grief if the driver can't handle tabs – AutomatedTester Mar 06 '13 at 21:33
  • Tried for hours to open a new tab by sending keys CONTROL 't', this is the only solution that worked for me. +1 – maxenglander Dec 16 '14 at 23:46
  • [This SO post helped with this answer for C#](http://stackoverflow.com/questions/6229769/execute-javascript-using-selenium-webdriver-in-c-sharp). To get the JavaScriptExectutor create a method like `public static IJavaScriptExecutor Scripts(this IWebDriver driver) { return (IJavaScriptExecutor)driver; }` – JabberwockyDecompiler May 27 '15 at 17:52
30

The Selenium WebDriver API does not support managing tabs within the browser at present.

JimEvans
  • 27,201
  • 7
  • 83
  • 108
  • Thanks Jim, I wanted to be sure that there is no way of handling tabs. By "Alternatives" I only mean how else could I handle tabbed browsing, there are no special cases involved, so opening multiple windows seems fine to me. – ChrisOdney Jun 23 '11 at 07:31
  • 19
    Downvoters: This is the answer you're going to get from the project itself. Just because it's not an answer you like, doesn't mean it's wrong or of poor quality. – JimEvans May 02 '12 at 09:19
  • @JimEvans, this answer is of poor quality because it doesn't answer the question. Answers below that show workarounds are more useful. An answer that says "Here's a kludgy way to do that" will always be more useful than an answer that says "You can't do that." – Ryan Lundy Mar 06 '14 at 21:07
  • 1
    @Kyralessa Respectfully, I disagree. The legitimate answer sometimes *is*, "You can't do that." And that's true in this case. The API doesn't, and won't support it. Any of the so-called workarounds in other answers may give you a new tab opened, but there's no guarantee that WebDriver will be able to open the new tab. In fact, I'm quite sure that at least one browser won't. Rather than give false hope that any solution will work cross-browser (one of the main promises of WebDriver), it's far better to be clear about the limitations. – JimEvans Mar 07 '14 at 00:19
  • @JimEvans, I'm not saying your answer isn't correct. The trouble is that it isn't helpful. "There's no way to do that" doesn't help anyone solve his/her problem. And in fact there are workarounds to do it; I was able to do it with a ChromeDriver just by simulating a control-click on a link. Selenium recognizes the tabs as separate windows. Editing your answer to include workarounds of this sort would make it helpful, and not merely "correct". – Ryan Lundy Mar 07 '14 at 16:45
  • 1
    @Kyralessa You were able to get it to work in Chrome. Great. Tell me, does it also work in IE or Safari? Oh, and remember that just because it works in Chrome today, since it's explicitly unsupported by the API, there is absolutely no guarantee it will continue to work in future versions. Glad you were able to make it work in some case, though. – JimEvans Mar 07 '14 at 22:26
  • @JimEvans, let me try to explain this again. Not everyone is doing cross-browser work. One example is internal web applications, where it makes more sense to specify a standard browser than to do the work to support multiple browsers. So a good answer would say, "It's not officially supported; but there are some non-cross-browser ways to do it, such as this and this, in case that helps in your specific situation." – Ryan Lundy Jul 18 '14 at 15:56
  • 1
    There is no need to reiterate what you've already stated. I completely understand. I simply don't agree with you. Since you seem determined to attempt to convince people that an answer provided **by the project itself** is wrong or less useful than an answer that cannot be guaranteed to work by the authors of the project, and also are determined to have the last word on the subject, I'll simply let this be my last comment on the matter. – JimEvans Jul 18 '14 at 20:00
9
        var windowHandles = webDriver.WindowHandles;
        var script = string.Format("window.open('{0}', '_blank');", url);
        scriptExecutor.ExecuteScript(script);
        var newWindowHandles = webDriver.WindowHandles;
        var openedWindowHandle = newWindowHandles.Except(windowHandles).Single();
        webDriver.SwitchTo().Window(openedWindowHandle);
user2283070
  • 177
  • 1
  • 5
4

I had the same issue and found an answer. Give a try.

Robot r = new Robot(); 
r.keyPress(KeyEvent.VK_CONTROL); 
r.keyPress(KeyEvent.VK_T); 
r.keyRelease(KeyEvent.VK_CONTROL); 
r.keyRelease(KeyEvent.VK_T);

It will open a new tab you can perform your actions in the new tab.

kleopatra
  • 51,061
  • 28
  • 99
  • 211
deactivate
  • 71
  • 3
  • 8
1

Hey @Paul and who ever is having issue opening a second tab in python. Here is the solution

I'm not sure if this is a bug within the webdriver or because it isn't compatible yet with mutlitab but it is definitely acting wrong with it and I will show how to fix it.

Issue: well I see more than one issue.

First issue has to do that when you open a 2nd tab you can only see one handle instead of two.

2nd issue and here is where my solution comes in. It seems that although the handle value is still stored in the driver the window has lost sync with it for reason.

Here is the solution by fixing the 2nd issue:

elem = browser.find_element_by_xpath("/html/body/div[2]/div[4]/div/a") #href link
time.sleep(2) 
elem.send_keys(Keys.CONTROL + Keys.RETURN + "2") #Will open a second tab

#solution for the 2nd issue is here    
for handle in browser.window_handles:
        print "Handle is:" + str(handle) #only one handle number
        browser.switch_to_window(handle)

time.sleep(3)

#Switch the frame over. Even if you have switched it before you need to do it again
browser.switch_to_frame("Frame") 


"""now this is how you handle closing the tab and working again with the original tab"""

#again switch window over
elem.send_keys(Keys.CONTROL + "w")
for handle in browser.window_handles:
    print "HandleAgain is:" + str(handle) #same handle number as before
    browser.switch_to_window(handle)

#again switch frame over if you are working with one
browser.switch_to_frame("Frame") 

time.sleep(3)
#doing a second round/tab
elem = browser.find_element_by_xpath("/html/body/div[2]/div[4]/div/a") #href link
time.sleep(2) 
elem.send_keys(Keys.CONTROL + Keys.RETURN + "2") #open a 2nd tab again

"""Got it? find the handle, switch over the window then switch the frame"""

It is working perfectly for me. I'm open for questions...

Khaled Nakawa
  • 35
  • 1
  • 10
1

Do this

_webDriver.SwitchTo().Window(_webDriver.WindowHandles.Where(x => x != _webDriver.CurrentWindowHandle).First());

or Last() etc.

PS there is no guarantee that the WindowHandles are in the order displayed on your browser, therefore, I would advise you keep some history of current windows before you do the command to that caused a new tab to open. Then you can compare your stored window handles with the current set and switch to the new one in the list, of which, there should only be one.

Jay Byford-Rew
  • 5,736
  • 1
  • 35
  • 36
1
@Test
 public void openTab() {
  //Open tab 2 using CTRL + t keys.
  driver.findElement(By.cssSelector("body")).sendKeys(Keys.CONTROL +"t");


 //Open URL In 2nd tab.
  driver.get("http://www.qaautomated.com/p/contact.html");

  //Call switchToTab() method to switch to 1st tab
  switchToTab(); 
}

public void switchToTab() {
  //Switching between tabs using CTRL + tab keys.
  driver.findElement(By.cssSelector("body")).sendKeys(Keys.CONTROL +"\t");
  //Switch to current selected tab's content.
  driver.switchTo().defaultContent();  
 } 

we can use keyboard events and automate opening and switching between multiple tabs very easily. This example is refered from HERE

anuja jain
  • 1,367
  • 13
  • 19
1

Though there is no API for opening a new tab, you can just create a new instance of WebDriver calling it something slightly different and passing the URL you want in the new tab. Once you have done all you need to do, close that tab and make the new driver NULL so that it does not interfere with the original instance of Webdriver. If you need both tabs open, then ensure you refer to the appropriate instance of WebDriver. Used this for Sitecore CMS automation and it worked.

1

There's no way we can create new TAB or handle tabs using web driver / selenium 2.0

You can open a new window instead.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
Mayur Shah
  • 279
  • 3
  • 4
1

Thanks for the great idea @Jonathan Azoff !

Here's how I did it in Ruby:

def open_new_window(url)
  a = @driver.execute_script("var d=document,a=d.createElement('a');a.target='_blank';a.href=arguments[0];a.innerHTML='.';d.body.appendChild(a);return a", url)
  a.click
  @driver.switch_to.window(@driver.window_handles.last)
end
bbbco
  • 1,508
  • 1
  • 10
  • 25
0

I would prefer opening a new window. Is there really a difference in opening a new window vs opening a new tab from an automated solution perspective ?

you can modify the anchors target property and once clicked the target page would open in a new window.

Then use driver.switchTo() to switch to the new window. Use it to solve your issue

iamsankalp89
  • 4,607
  • 2
  • 15
  • 36
Shrikant Khadilkar
  • 256
  • 1
  • 3
  • 14
0

IJavaScriptExecutor is very useful class which can manipulate HTML DOM on run time through JavaScript, below is sample code on how to open a new browser tab in Selenium through IJavaScriptExecutor:

IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
                object linkObj = js.ExecuteScript("var link = document.createElement('a');link.target='_blank';link.href='http://www.gmail.com';link.innerHTML='Click Me';document.getElementById('social').appendChild(link);return link");
                /*IWebElement link = (IWebElement)linkObj;
                link.Click();*/
                browser.Click("//*[@id='social']/a[3]");

Just to give an insight, there are no methods in Selenium which would allow you to open new tab, the above code would dynamically create an anchor element and directs it open an new tab.

Anand
  • 1
0

You can try this way, since there is action_chain in the new webdriver. I'm using Python, so please ignore the grammar:

act = ActionChains(driver)
act.key_down(Keys.CONTROL)
act.click(link).perform()
act.key_up(Keys.CONTROL)
likeitlikeit
  • 5,563
  • 5
  • 42
  • 56
Li Liu
  • 1
  • 1
0

For MAC OS

from selenium import webdriver
from selenium.webdriver.common.keys import Keys

driver = webdriver.Firefox()
driver.get("http://google.com")
body = driver.find_element_by_tag_name("body")
body.send_keys(Keys.COMMAND + 't')
0

Java Robot can be used to send Ctrl+t (or Cmd+t if MAC OS X) as follows:

int vkControl = IS_OS_MAC ? KeyEvent.VK_META : KeyEvent.VK_CONTROL;
Robot robot = new Robot();
robot.keyPress(vkControl);
robot.keyPress(KeyEvent.VK_T);
robot.keyRelease(vkControl);
robot.keyRelease(KeyEvent.VK_T);

A complete running example using Chrome as browser can be forked here.

Boni García
  • 4,618
  • 5
  • 28
  • 44
0

I must say i tried this as well, and while it seemingly works with some bindings (Java, as far as Jonathan says, and ruby too, apparently), with others it doesnt: selenium python bindings report just one handle per window, even if containing multiple tabs

Pa_
  • 641
  • 1
  • 5
  • 17
-2

Instead of opening new tab you can open new window using below code.

for(String childTab : driver.getWindowHandles())
    {
        driver.switchTo().window(childTab);
    }
bugCracker
  • 3,656
  • 9
  • 37
  • 58