Anton Komyshan
Anton Komyshan

Reputation: 1581

Selenium. Bring-up window on the front

If you run the following code, then at each iteration of the cycle, the browser will bring up on the front and get focus.

public class Program
{
  private static void Main()
  {
    var driver = new ChromeDriver();
    driver.Navigate().GoToUrl("https://i.imgur.com/cdA7SBB.jpg");
    for (int i = 0; i < 100; i++)
    {
      var ss = ((ITakesScreenshot)driver).GetScreenshot();
      ss.SaveAsFile("D:/imgs/i.jpg");
    }
  }
}

The question is: why does this happen and can it be turned off? headless mod does not fit.

It seems that this always happens when Selenium needs to save / read the file or start the process.

Upvotes: 3

Views: 5725

Answers (3)

pwrngr
pwrngr

Reputation: 178

I was struggling with an issue when generic GetScreenshot() in parallel testing was causing browser to lose focus. Some elements were being removed from DOM and my tests were failing. I've come up with a working solution for Edge and Chrome 100+ with Selenium 4.1:

public Screenshot GetScreenshot()
    {
        IHasCommandExecutor executor = webDriverInstance as IHasCommandExecutor;
        var sessionId = ((WebDriver)webDriverInstance).SessionId;
        var command = new HttpCommandInfo(HttpCommandInfo.PostCommand, $"/session/{sessionId}/chromium/send_command_and_get_result");
        executor.CommandExecutor.TryAddCommand("Send", command);

        var response = Send(executor, "Page.captureScreenshot", new JObject { { "format", "png" }, { "fromSurface", true } });
        var base64 = ((Dictionary<string, object>)response.Value)["data"];
        return new Screenshot(base64.ToString());
    }

    private Response Send(IHasCommandExecutor executor, string cmd, JObject args)
    {         
        var json = new JObject { { "cmd", cmd }, { "params", args } }; 
        var command = new Command("Send", json.ToString());
        return executor.CommandExecutor.Execute(command);
    }

Upvotes: 0

Florent B.
Florent B.

Reputation: 42528

To take a screenshot, chromedriver activates the window. It's by design and there's no option to avoid it even though it's technically possible. For the relevant sources have a look at window_commands.cc.

You could however avoid the effect by moving the window off-screen:

driver.Manage().Window.Position = new Point(-32000, -32000);

or by launching the browser off-screen:

var options = new ChromeOptions();
options.AddArgument("--window-position=-32000,-32000");

UPDATE

You can avoid the activation by taking the screenshot directly via the devtool API. Here's a class to override GetScreenshot:

using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Remote;
using JObject = System.Collections.Generic.Dictionary<string, object>;


class ChromeDriverEx : ChromeDriver
{
    public ChromeDriverEx(ChromeOptions options = null) 
        : base(options ?? new ChromeOptions()) {
        var repo = base.CommandExecutor.CommandInfoRepository;
        repo.TryAddCommand("send", new CommandInfo("POST", "/session/{sessionId}/chromium/send_command_and_get_result"));
    }

    public new Screenshot GetScreenshot() {
        object response = Send("Page.captureScreenshot", new JObject {{"format", "png"}, {"fromSurface", true}});
        string base64 = (string)((JObject)response)["data"];
        return new Screenshot(base64);
    }

    protected object Send(string cmd, JObject args) {
        return this.Execute("send",  new JObject {{"cmd", cmd}, {"params", args}}).Value;
    }
}

usage:

var driver = new ChromeDriverEx();
driver.Url = "https://stackoverflow.com";
driver.GetScreenshot().SaveAsFile("/tmp/screenshot.png");
driver.Quit();

Upvotes: 7

undetected Selenium
undetected Selenium

Reputation: 193228

When you invoke Navigate().GoToUrl("url") method through your Automation script, it is expected that your script will be interacting with some of the elements on the webpage. So for Selenium to interact with those elements, Selenium needs focus. Hence opening up the browser, bring up on the front and getting the focus is the default phenomenon implemented through Navigate().GoToUrl("url").

Now Default Mode or Headless Mode is controlled by the ChromeOption/FirefoxOptions class which is passed as an argument while initializing the WebDriver instance and will call Navigate().GoToUrl("url"). So, Navigate().GoToUrl("url") would have no impact how the WebDriver instance is controlling the Mode of Operation i.e. Default Mode or Headless Mode.

Now when you try to invoke the method from ITakesScreenshot Interface i.e. ITakesScreenshot.GetScreenshot Method which is defined as :

Gets a Screenshot object representing the image of the page on the screen.

In case of WebDriver instance which extends ITakesScreenshot, makes the best effort depending on the browser to return the following in order of preference:

  1. Entire page
  2. Current window
  3. Visible portion of the current frame
  4. The screenshot of the entire display containing the browser

There may be some instances when the browser looses the focus. In that case you can use IJavascriptExecutor to regain the focus as follows :

((IJavascriptExecutor) driver).executeScript("window.focus();");

Upvotes: 1

Related Questions