Search code examples
c#seleniumkendo-uiwebdriverscreenshot

Parallel testing in Selenium with Telerik Kendo UI and screenshots subscribed to WebDriver events


The issue is related to Kendo UI's (dropdownlist, combobox, searchbox, etc) onfocusout and blur events, which close menu dropdowns when triggered, or if a browser window loses focus. In my case it was the WebDriver's GetScreenshot() method which calls an active focus on a screenshotted browser. With the parallel testing I'm taking screenshots using EventFiringWebDriver events. There are two windows of Edge/Chrome browser running in parallel and they are flashing constantly since GetScreenshot() is triggered. If Kendo UI element is opened in one of the windows, and the moment when flashing happens at the same time, it automatically triggers onfocusout and blur and dropdown closes. 40% of my tests were false negative because of that.

You can see the demo of the elements here: https://demos.telerik.com/kendo-ui/dropdownlist/index


Solution

  • I was able to overcome the issue with a multi-step solution. This works on Edge/Chrome 103+ and Selenium 4.1+

    Firstly, I got rid of active focus calling by overring the GetScreenshot() method with a direct command to WebDriver.

    public Screenshot GetScreenshot()
        {
            IHasCommandExecutor executor = Driver as IHasCommandExecutor;
            var sessionId = ((WebDriver)Driver).SessionId; //if your driver is wrapped by any other class, you have to cast it to WebDriver first
            var command = new HttpCommandInfo(HttpCommandInfo.PostCommand, $"/session/{sessionId}/chromium/send_command_and_get_result");
            executor.CommandExecutor.TryAddCommand("Send", command); //try to create and add a 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); //execute the added command
        }
    

    Secondly, I found an extension for Chromium browsers, which disables Visibility API. There are a bunch of them, just search "Disable Visibility API" in Chrome Web Store. Apparently, it fakes 'activeness' of a browser window, so onfocusout and blur won't be firing anymore. Now you just have to include the extension when you're instantiating your driver:

    var options = new EdgeOptions();
    options.AddExtension("your path to extension"); //set your path
    new DriverManager().SetUpDriver(new EdgeConfig(), VersionResolveStrategy.MatchingBrowser);
    var service = EdgeDriverService.CreateDefaultService();
    Driver = new EdgeDriver(edgeOptions);