/// <summary>
        /// Waits for a page to load
        /// </summary>
        /// <param name="element">An element from the previous page. If omitted, the code will wait for the body of the page to be viosible</param>
        public void WaitForPageToLoad(IWebElement element)
        {
            if (RecordPerformance)
            {
                RatTimerCollection.StartTimer();
            }

            if (element == null)
            {
                var load = new WebDriverWait(Driver, BaseSettings.Timeout)
                           .Until(ExpectedConditions.ElementIsVisible(By.TagName("body")));
            }
            else if (typeof(TWebDriver) != typeof(OperaDriver))
            {
                var wait = new WebDriverWait(Driver, Preferences.BaseSettings.Timeout)
                           .Until(
                    ExpectedConditions.StalenessOf(element));
            }
            else
            {
                //TODO: Investigate the Opera Driver with respect to DOM staleness
                Console.Out.WriteLine("Opera does not currently seem to report staleness of the DOM. Under investigation");
            }

            if (RecordPerformance)
            {
                RatTimerCollection.StopTimer(EnumTiming.PageLoad);
            }
        }
        /// <summary>
        /// Creates a chrome driver instance in modile emulation mode
        /// </summary>
        /// <param name="height">The height of the screen</param>
        /// <param name="width">The width of the screen</param>
        /// <param name="userAgent">The user agent returned by the device</param>
        /// <param name="pixelRatio">The pixel ratio of the screen</param>
        /// <param name="touch">(Optional Parameter) Whether touch actions are enabled</param>
        /// <param name="driverSettings">Settings file for the Driver being instantiated.</param>
        /// <param name="performanceTimings">Whether to obtain performance timings for the browser.</param>
        public RatDriver(long height, long width, string userAgent, double pixelRatio,
                         [Optional, DefaultParameterValue(false)] bool touch,
                         [Optional, DefaultParameterValue(null)] ChromeSettings driverSettings,
                         [Optional, DefaultParameterValue(false)] bool performanceTimings)
        {
            try
            {
                RecordPerformance = performanceTimings;
                if (performanceTimings)
                {
                    InitialiseRatWatch(performanceTimings);
                }

                string driverType = typeof(TWebDriver).Name;

                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ||
                    RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                {
                    GetProcesses(driverType, ProcessCollectionTime.InitialisationStart);
                }

                if (typeof(TWebDriver) == typeof(ChromeDriver))
                {
                    EstablishDriverSettings(driverType);
                    if (!_runTests)
                    {
                        throw new LiberatorOSException(_browserError);
                    }

                    ChromeDriverControl controller = new ChromeDriverControl(driverSettings);
                    Driver = (TWebDriver)controller.StartMobileDriver(height, width, userAgent, pixelRatio, touch);
                    WindowHandles.Add(Driver.CurrentWindowHandle, Driver.Title);

                    if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ||
                        RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                    {
                        GetProcesses(driverType, ProcessCollectionTime.InitialisationEnd);
                    }
                }
                else
                {
                    Console.Out.WriteLine("{0} does not currently allow the loading of profiles.", driverType);
                    Console.Out.WriteLine("Please switch to Chrome if mobile emulation is required");
                }

                if (performanceTimings)
                {
                    RatTimerCollection.StopTimer(EnumTiming.Instantiation);
                }
            }
            catch (Exception ex)
            {
                if (ex.GetType() != typeof(LiberatorOSException))
                {
                    Console.Out.WriteLine("An unexpected error has been detected.");
                }
                HandleErrors(ex);
            }
        }
        /// <summary>
        /// Creates a firefox instance using a profile directory path
        /// </summary>
        /// <param name="profileDirectory">The path of the profile directory</param>
        /// <param name="cleanDirectory">Whether to clean the directory</param>
        /// <param name="driverSettings">Settings file for the Driver being instantiated.</param>
        /// <param name="performanceTimings">Whether to obtain performance timings for the browser.</param>
        public RatDriver(string profileDirectory, bool cleanDirectory,
                         [Optional, DefaultParameterValue(null)] FirefoxSettings driverSettings,
                         [Optional, DefaultParameterValue(false)] bool performanceTimings)
        {
            try
            {
                RecordPerformance = performanceTimings;
                if (performanceTimings)
                {
                    InitialiseRatWatch(performanceTimings);
                }

                string driverType = typeof(TWebDriver).Name;

                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ||
                    RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                {
                    GetProcesses(driverType, ProcessCollectionTime.InitialisationStart);
                }

                if (typeof(TWebDriver) == typeof(FirefoxDriver))
                {
                    EstablishDriverSettings(driverType);
                    if (!_runTests)
                    {
                        throw new LiberatorOSException(_browserError);
                    }
                    FirefoxDriverControl controller = new FirefoxDriverControl(driverSettings);
                    Driver = (TWebDriver)controller.StartDriverLoadProfileFromDisk(profileDirectory, cleanDirectory);
                    WindowHandles.Add(Driver.CurrentWindowHandle, Driver.Title);

                    if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ||
                        RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                    {
                        GetProcesses(driverType, ProcessCollectionTime.InitialisationEnd);
                    }
                }
                else
                {
                    Console.Out.WriteLine("{0} does not currently allow the loading of profiles.", driverType);
                    Console.Out.WriteLine("Please switch to Firefox if named profile loading is required");
                }

                if (performanceTimings)
                {
                    RatTimerCollection.StopTimer(EnumTiming.Instantiation);
                }
            }
            catch (Exception ex)
            {
                if (ex.GetType() != typeof(LiberatorOSException))
                {
                    Console.Out.WriteLine("An unexpected error has been detected.");
                }
                HandleErrors(ex);
            }
        }
        /// <summary>
        /// Base constructor for RatDriver
        /// </summary>
        /// <param name="driverSettings">Settings file for the Driver being instantiated.</param>
        /// <param name="performanceTimings">Whether to obtain performance timings for the browser.</param>
        public RatDriver([Optional, DefaultParameterValue(null)] IDriverSettings driverSettings,
                         [Optional, DefaultParameterValue(false)] bool performanceTimings)
        {
            try
            {
                RecordPerformance = performanceTimings;
                if (performanceTimings)
                {
                    InitialiseRatWatch(performanceTimings);
                }


                string driverType = typeof(TWebDriver).Name;
                EstablishDriverSettings(driverType);

                if (!_runTests)
                {
                    throw new LiberatorOSException(_browserError);
                }

                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ||
                    RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
                {
                    GetProcesses(driverType, ProcessCollectionTime.InitialisationStart);
                }


                string          type       = "Liberator.Driver.BrowserControl." + driverType + "Control";
                IBrowserControl controller = (IBrowserControl)Activator.CreateInstance(Type.GetType(type), driverSettings);
                Driver = (TWebDriver)controller.StartDriver();

                if (performanceTimings)
                {
                    RatTimerCollection.StopTimer(EnumTiming.Instantiation);
                }

                WaitForPageToLoad(null);
                WindowHandles.Add(Driver.CurrentWindowHandle, Driver.Title);


                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ||
                    RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
                {
                    GetProcesses(driverType, ProcessCollectionTime.InitialisationEnd);
                }
            }
            catch (Exception ex)
            {
                if (ex.GetType() != typeof(LiberatorOSException))
                {
                    Console.Out.WriteLine("An unexpected error has been detected.");
                }
                HandleErrors(ex);
            }
        }