Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Selenium Webdriver 3.141.0 driver.Manage().Logs.AvailableLogTypes throwing System.NullReference Exception

After my latest Chrome update to 76 version, my Selenium code snippet to get any console logs using driver.Manage().Logs.GetLog(LogType.Browser) is throwing error. Notice the Logs.AvaialbleLogTypes is throwing NullReference exception. Do we need to enable any settings? Is there any other way to get console errors

I tried using LoggingPreferences but that returns invalid argument error and fails to open chrome driver

like image 329
Aarthy Avatar asked Jan 25 '23 22:01

Aarthy


2 Answers

This is my quick and dirty solution (until selenium 4 is out, where this problem is fixed) - it is working, you can refine it and add more checks and validations.

I expose it as an extension method GetBrowserLogs

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Chromium;
using OpenQA.Selenium.Remote;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection;
using System.Text;

namespace SeleniumConsumer
{
    internal static class Program
    {
        private static void Main()
        {
            // setup options
            var options = new ChromeOptions();
            options.SetLoggingPreference(LogType.Browser, LogLevel.All);

            // do whatever actions
            var driver = new ChromeDriver(options)
            {
                Url = "https://www.yahoo.com/"
            };

            // extract logs
            foreach (var log in driver.GetBrowserLogs())
            {
                Console.WriteLine($"{log["timestamp"]}: {log["message"]}");
            }

            // cleanup
            driver.Dispose();
            Console.WriteLine();
            Console.WriteLine("Press any key to exit...");
            Console.ReadLine();
        }
    }

    public static class WebDriverExtensions
    {
        public static IEnumerable<IDictionary<string, object>> GetBrowserLogs(this IWebDriver driver)
        {
            // setup
            var endpoint = GetEndpoint(driver);
            var session = GetSession(driver);
            var resource = $"{endpoint}session/{session}/se/log";
            const string jsonBody = @"{""type"":""browser""}";

            // execute
            using (var httpClient = new HttpClient())
            {
                var content = new StringContent(jsonBody, Encoding.UTF8, "application/json");
                var response = httpClient.PostAsync(resource, content).GetAwaiter().GetResult();
                var responseBody = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
                return AsLogEntries(responseBody);
            }
        }

        private static string GetEndpoint(IWebDriver driver)
        {
            // setup
            const BindingFlags Flags = BindingFlags.Instance | BindingFlags.NonPublic;

            // get RemoteWebDriver type
            var remoteWebDriver = GetRemoteWebDriver(driver.GetType());

            // get this instance executor > get this instance internalExecutor
            var executor = remoteWebDriver.GetField("executor", Flags).GetValue(driver) as DriverServiceCommandExecutor;
            var internalExecutor = executor.GetType().GetField("internalExecutor", Flags).GetValue(executor) as HttpCommandExecutor;

            // get URL
            var uri = internalExecutor.GetType().GetField("remoteServerUri", Flags).GetValue(internalExecutor) as Uri;

            // result
            return uri.AbsoluteUri;
        }

        private static Type GetRemoteWebDriver(Type type)
        {
            if (!typeof(RemoteWebDriver).IsAssignableFrom(type))
            {
                return type;
            }

            while(type != typeof(RemoteWebDriver))
            {
                type = type.BaseType;
            }

            return type;
        }

        private static SessionId GetSession(IWebDriver driver)
        {
            if (driver is IHasSessionId id)
            {
                return id.SessionId;
            }
            return new SessionId($"gravity-{Guid.NewGuid()}");
        }

        private static IEnumerable<IDictionary<string, object>> AsLogEntries(string responseBody)
        {
            // setup
            var value = $"{JToken.Parse(responseBody)["value"]}";
            return  JsonConvert.DeserializeObject<IEnumerable<Dictionary<string, object>>>(value);
        }
    }
}

like image 102
Roei Sabag Avatar answered Feb 07 '23 19:02

Roei Sabag


This is currently broken and only fixed in the Selenium 4 alpha coming out: https://github.com/SeleniumHQ/selenium/issues/7342

From reading the issue it appears that changes to the chromedriver necessitate changes to the .Net Selenium implementation to correct the issue.

like image 26
J.D. Cain Avatar answered Feb 07 '23 19:02

J.D. Cain