From c26cddb5e28cfd35e99a3a2c3d3ae8ed3f5b629e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alaksiej=20Miale=C5=A1ka?= Date: Mon, 28 Feb 2022 14:16:50 +0200 Subject: [PATCH] [DevTools] Performance monitoring (#216) +semver: feature --- .../Aquality.Selenium/Aquality.Selenium.xml | 29 +++++++++++ .../Browsers/DevToolsPerformanceExtensions.cs | 50 +++++++++++++++++++ .../Integration/DevToolsEmulationTests.cs | 7 +-- .../Integration/DevToolsPerformanceTests.cs | 32 ++++++++++++ 4 files changed, 115 insertions(+), 3 deletions(-) create mode 100644 Aquality.Selenium/src/Aquality.Selenium/Browsers/DevToolsPerformanceExtensions.cs create mode 100644 Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/DevToolsPerformanceTests.cs diff --git a/Aquality.Selenium/src/Aquality.Selenium/Aquality.Selenium.xml b/Aquality.Selenium/src/Aquality.Selenium/Aquality.Selenium.xml index 44dd8f71..7f1ab861 100644 --- a/Aquality.Selenium/src/Aquality.Selenium/Aquality.Selenium.xml +++ b/Aquality.Selenium/src/Aquality.Selenium/Aquality.Selenium.xml @@ -580,6 +580,35 @@ to throw an exception if a response is not received; otherwise, . A JToken based on a command created with the specified command name and parameters. + + + Implementation of version-independent performance DevTools commands as extensions for . + For more information, see . + + + + + Disable collecting and reporting metrics. + + Current instance of . + A task for asynchronous command. + + + + Enable collecting and reporting metrics. + + Current instance of . + Time domain to use for collecting and reporting duration metrics. + Allowed Values: timeTicks, threadTicks. + A task for asynchronous command. + + + + Retrieve current values of run-time metrics. + + Current instance of . + A task for asynchronous command with current values for run-time metrics as result. + Factory that creates instance of desired Browser based on . diff --git a/Aquality.Selenium/src/Aquality.Selenium/Browsers/DevToolsPerformanceExtensions.cs b/Aquality.Selenium/src/Aquality.Selenium/Browsers/DevToolsPerformanceExtensions.cs new file mode 100644 index 00000000..d926a2bf --- /dev/null +++ b/Aquality.Selenium/src/Aquality.Selenium/Browsers/DevToolsPerformanceExtensions.cs @@ -0,0 +1,50 @@ +using Newtonsoft.Json.Linq; +using OpenQA.Selenium.DevTools.V85.Performance; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Threading.Tasks; + +namespace Aquality.Selenium.Browsers +{ + /// + /// Implementation of version-independent performance DevTools commands as extensions for . + /// For more information, see . + /// + public static class DevToolsPerformanceExtensions + { + /// + /// Disable collecting and reporting metrics. + /// + /// Current instance of . + /// A task for asynchronous command. + public static async Task DisablePerfomanceMonitoring(this DevToolsHandling devTools) + { + await devTools.SendCommand(new DisableCommandSettings()); + } + + /// + /// Enable collecting and reporting metrics. + /// + /// Current instance of . + /// Time domain to use for collecting and reporting duration metrics. + /// Allowed Values: timeTicks, threadTicks. + /// A task for asynchronous command. + public static async Task EnablePerfomanceMonitoring(this DevToolsHandling devTools, string timeDomain = null) + { + await devTools.SendCommand(new EnableCommandSettings { TimeDomain = timeDomain }); + } + + /// + /// Retrieve current values of run-time metrics. + /// + /// Current instance of . + /// A task for asynchronous command with current values for run-time metrics as result. + public static async Task> GetPerformanceMetrics(this DevToolsHandling devTools) + { + JToken result = await devTools.SendCommand(new GetMetricsCommandSettings()); + return (result["metrics"] as JArray) + .ToDictionary(item => item["name"].ToString(), item => double.Parse(item["value"].ToString(), CultureInfo.InvariantCulture)); + } + } +} diff --git a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/DevToolsEmulationTests.cs b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/DevToolsEmulationTests.cs index 1aeadae6..7e881d11 100644 --- a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/DevToolsEmulationTests.cs +++ b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/DevToolsEmulationTests.cs @@ -78,7 +78,7 @@ void setAction(long width, long height, bool isMobile, double scaleFactor) private static void CheckDeviceMetricsOverride(Action setAction) { - long getWindowHeight() => AqualityServices.Browser.ExecuteScriptFromFile("Resources.GetWindowSize.js"); + static long getWindowHeight() => AqualityServices.Browser.ExecuteScriptFromFile("Resources.GetWindowSize.js"); var initialValue = getWindowHeight(); Assume.That(initialValue, Is.Not.EqualTo(DeviceModeSettingHeight), "To check that override works, initial value should differ from the new one"); setAction(DeviceModeSettingWidth, DeviceModeSettingHeight, DeviceModeSettingMobile, DeviceModeSettingDeviceScaleFactor); @@ -174,7 +174,7 @@ public void Should_BePossibleTo_SetScriptExecutionDisabled_AndEnableAgain() [Test] public void Should_BePossibleTo_SetTouchEmulationEnabled_AndDisabled() { - bool isTouchEnabled() => AqualityServices.Browser.ExecuteScriptFromFile("Resources.IsTouchEnabled.js"); + static bool isTouchEnabled() => AqualityServices.Browser.ExecuteScriptFromFile("Resources.IsTouchEnabled.js"); Assume.That(isTouchEnabled, Is.False, "Touch should be initially disabled"); Assert.DoesNotThrowAsync(() => DevTools.SetTouchEmulationEnabled(true), "Should be possible to enable touch emulation"); @@ -188,7 +188,8 @@ public void Should_BePossibleTo_SetTouchEmulationEnabled_AndDisabled() public void Should_BePossibleTo_SetEmulatedMedia() { const string emulatedMedia = "projection"; - string getMediaType() => AqualityServices.Browser.ExecuteScriptFromFile("Resources.GetMediaType.js"); + + static string getMediaType() => AqualityServices.Browser.ExecuteScriptFromFile("Resources.GetMediaType.js"); var initialValue = getMediaType(); Assume.That(initialValue, Does.Not.Contain(emulatedMedia), "Initial media type should differ from value to be set"); diff --git a/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/DevToolsPerformanceTests.cs b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/DevToolsPerformanceTests.cs new file mode 100644 index 00000000..5a1405aa --- /dev/null +++ b/Aquality.Selenium/tests/Aquality.Selenium.Tests/Integration/DevToolsPerformanceTests.cs @@ -0,0 +1,32 @@ +using Aquality.Selenium.Browsers; +using NUnit.Framework; +using OpenQA.Selenium.DevTools.V96.Performance; +using System.Collections.Generic; + +namespace Aquality.Selenium.Tests.Integration +{ + internal class DevToolsPerformanceTests : UITest + { + private static DevToolsHandling DevTools => AqualityServices.Browser.DevTools; + + [Test] + public void Should_BePossibleTo_CollectPerformanceMetrics() + { + Assert.DoesNotThrowAsync(() => DevTools.EnablePerfomanceMonitoring(), "Should be possible to enable performance monitoring"); + + AqualityServices.Browser.GoTo("http://www.google.com"); + IDictionary metrics = null; + Assert.DoesNotThrowAsync(async () => metrics = await DevTools.GetPerformanceMetrics(), "Should be possible to get performance metrics"); + CollectionAssert.IsNotEmpty(metrics, "Some metrics should be returned"); + + AqualityServices.Browser.Refresh(); + IDictionary otherMetrics = DevTools.GetPerformanceMetrics().GetAwaiter().GetResult(); + CollectionAssert.AreNotEqual(otherMetrics, metrics, "Some additional metrics should have been collected"); + + Assert.DoesNotThrowAsync(() => DevTools.DisablePerfomanceMonitoring(), "Should be possible to disable performance monitoring"); + AqualityServices.Browser.Refresh(); + metrics = DevTools.GetPerformanceMetrics().GetAwaiter().GetResult(); + CollectionAssert.IsEmpty(metrics, "Metrics should have not been collected after performance monitoring have been disabled"); + } + } +}