From 6ecc875b72d563877a6461a495d68d1eed5c5000 Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Mon, 16 Sep 2024 20:10:57 +0800 Subject: [PATCH] A bunch more things --- .../BaseUITests.cs | 1 + .../MainPageTests.cs | 3 + .../PlaywrightServerTests.cs | 2 +- .../UITestsSetupFixture.cs | 4 + .../Commands/AppiumClickCoordinatesCommand.cs | 6 +- .../AppiumAutomatedApp.cs | 62 -------------- .../AppiumAutomatedAppElement.cs | 18 ---- .../AppiumAutomationFramework.cs | 84 ------------------- .../AppiumAutomationOptionsBuilder.cs | 43 ---------- ...ppiumAutomationOptionsBuilderExtensions.cs | 18 ---- ...rightAutomationOptionsBuilderExtensions.cs | 18 ++++ .../AutomationTestSuiteBuilderExtensions.cs | 52 ++++++------ ...iumAutomatedAppOptionsBuilderExtensions.cs | 16 ---- .../Commands/AppiumClickCoordinatesCommand.cs | 32 ------- .../Commands/AppiumClickElementCommand.cs | 34 -------- .../Commands/AppiumElementCommand.cs | 24 ------ .../Commands/AppiumGetElementTextCommand.cs | 14 ---- .../Commands/AppiumGetPageSourceCommand.cs | 14 ---- .../Commands/AppiumGetScreenshotCommand.cs | 17 ---- ...ghtAutomatedAppOptionsBuilderExtensions.cs | 16 ++++ .../PlaywrightClickCoordinatesCommand.cs | 23 +++++ .../Commands/PlaywrightClickElementCommand.cs | 17 ++++ .../Commands/PlaywrightElementCommand.cs | 24 ++++++ .../PlaywrightGetElementTextCommand.cs | 14 ++++ .../PlaywrightGetPageSourceCommand.cs | 12 +++ .../PlaywrightGetScreenshotCommand.cs | 17 ++++ .../PlaywrightAutomatedApp.cs | 62 ++++++++++++++ .../PlaywrightAutomatedAppElement.cs | 18 ++++ .../PlaywrightAutomationFramework.cs | 84 +++++++++++++++++++ .../PlaywrightAutomationOptionsBuilder.cs | 33 ++++++++ .../PlaywrightBy.cs | 24 +++++- .../SeleniumClickCoordinatesCommand.cs | 9 +- ...iumAutomatedAppOptionsBuilderExtensions.cs | 4 +- .../AutomationTestSuiteBuilderTests.cs | 74 ++++++++-------- .../PlaywrightDriverManagerTests.cs | 32 ++++--- 35 files changed, 459 insertions(+), 466 deletions(-) delete mode 100644 src/DeviceRunners.UIAutomation.Playwright/AppiumAutomatedApp.cs delete mode 100644 src/DeviceRunners.UIAutomation.Playwright/AppiumAutomatedAppElement.cs delete mode 100644 src/DeviceRunners.UIAutomation.Playwright/AppiumAutomationFramework.cs delete mode 100644 src/DeviceRunners.UIAutomation.Playwright/AppiumAutomationOptionsBuilder.cs delete mode 100644 src/DeviceRunners.UIAutomation.Playwright/AutomatedBrowsers/Edge/AppiumAutomationOptionsBuilderExtensions.cs create mode 100644 src/DeviceRunners.UIAutomation.Playwright/AutomatedBrowsers/Edge/PlaywrightAutomationOptionsBuilderExtensions.cs delete mode 100644 src/DeviceRunners.UIAutomation.Playwright/Commands/AppiumAutomatedAppOptionsBuilderExtensions.cs delete mode 100644 src/DeviceRunners.UIAutomation.Playwright/Commands/AppiumClickCoordinatesCommand.cs delete mode 100644 src/DeviceRunners.UIAutomation.Playwright/Commands/AppiumClickElementCommand.cs delete mode 100644 src/DeviceRunners.UIAutomation.Playwright/Commands/AppiumElementCommand.cs delete mode 100644 src/DeviceRunners.UIAutomation.Playwright/Commands/AppiumGetElementTextCommand.cs delete mode 100644 src/DeviceRunners.UIAutomation.Playwright/Commands/AppiumGetPageSourceCommand.cs delete mode 100644 src/DeviceRunners.UIAutomation.Playwright/Commands/AppiumGetScreenshotCommand.cs create mode 100644 src/DeviceRunners.UIAutomation.Playwright/Commands/PlaywrightAutomatedAppOptionsBuilderExtensions.cs create mode 100644 src/DeviceRunners.UIAutomation.Playwright/Commands/PlaywrightClickCoordinatesCommand.cs create mode 100644 src/DeviceRunners.UIAutomation.Playwright/Commands/PlaywrightClickElementCommand.cs create mode 100644 src/DeviceRunners.UIAutomation.Playwright/Commands/PlaywrightElementCommand.cs create mode 100644 src/DeviceRunners.UIAutomation.Playwright/Commands/PlaywrightGetElementTextCommand.cs create mode 100644 src/DeviceRunners.UIAutomation.Playwright/Commands/PlaywrightGetPageSourceCommand.cs create mode 100644 src/DeviceRunners.UIAutomation.Playwright/Commands/PlaywrightGetScreenshotCommand.cs create mode 100644 src/DeviceRunners.UIAutomation.Playwright/PlaywrightAutomatedApp.cs create mode 100644 src/DeviceRunners.UIAutomation.Playwright/PlaywrightAutomatedAppElement.cs create mode 100644 src/DeviceRunners.UIAutomation.Playwright/PlaywrightAutomationFramework.cs create mode 100644 src/DeviceRunners.UIAutomation.Playwright/PlaywrightAutomationOptionsBuilder.cs diff --git a/sample/test/DeviceTestingKitApp.UITests.NUnitTests/BaseUITests.cs b/sample/test/DeviceTestingKitApp.UITests.NUnitTests/BaseUITests.cs index 75772dd..9bd7abc 100644 --- a/sample/test/DeviceTestingKitApp.UITests.NUnitTests/BaseUITests.cs +++ b/sample/test/DeviceTestingKitApp.UITests.NUnitTests/BaseUITests.cs @@ -9,6 +9,7 @@ namespace DeviceTestingKitApp.UITests.NUnitTests; [TestFixture("android")] [TestFixture("windows")] [TestFixture("web")] +[TestFixture("web_playwright")] [Parallelizable(ParallelScope.Fixtures)] public abstract class BaseUITests { diff --git a/sample/test/DeviceTestingKitApp.UITests.NUnitTests/MainPageTests.cs b/sample/test/DeviceTestingKitApp.UITests.NUnitTests/MainPageTests.cs index 6d048ee..54a3d05 100644 --- a/sample/test/DeviceTestingKitApp.UITests.NUnitTests/MainPageTests.cs +++ b/sample/test/DeviceTestingKitApp.UITests.NUnitTests/MainPageTests.cs @@ -13,6 +13,7 @@ public MainPageTests(string appKey) public void InitialStateIsCorrect() { var element = App.FindElement(by => by.Id("CounterButton")); + Assert.NotNull(element); Assert.That(element.GetText(), Is.EqualTo("Click me!")); } @@ -21,6 +22,7 @@ public void InitialStateIsCorrect() public async Task SingleIncrementIncrementsByOne() { var element = App.FindElement(by => by.Id("CounterButton")); + Assert.NotNull(element); element.Click(); await Task.Delay(500); @@ -36,6 +38,7 @@ public async Task SingleIncrementIncrementsByOne() public async Task ClickingMultipleTimesKeepsIncrementing(int clicks, string text) { var element = App.FindElement(by => by.Id("CounterButton")); + Assert.NotNull(element); for (var i = 0; i < clicks; i++) { diff --git a/sample/test/DeviceTestingKitApp.UITests.NUnitTests/PlaywrightServerTests.cs b/sample/test/DeviceTestingKitApp.UITests.NUnitTests/PlaywrightServerTests.cs index 5b3b4ec..1c9993b 100644 --- a/sample/test/DeviceTestingKitApp.UITests.NUnitTests/PlaywrightServerTests.cs +++ b/sample/test/DeviceTestingKitApp.UITests.NUnitTests/PlaywrightServerTests.cs @@ -18,7 +18,7 @@ public async Task IsReady() using var playwright = await Playwright.CreateAsync(); await using var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions { Channel = "msedge" }); - + var page = await browser.NewPageAsync(); await page.GotoAsync("https://playwright.dev/dotnet"); diff --git a/sample/test/DeviceTestingKitApp.UITests.NUnitTests/UITestsSetupFixture.cs b/sample/test/DeviceTestingKitApp.UITests.NUnitTests/UITestsSetupFixture.cs index dfc7b43..2966f72 100644 --- a/sample/test/DeviceTestingKitApp.UITests.NUnitTests/UITestsSetupFixture.cs +++ b/sample/test/DeviceTestingKitApp.UITests.NUnitTests/UITestsSetupFixture.cs @@ -1,5 +1,6 @@ using DeviceRunners.UIAutomation; using DeviceRunners.UIAutomation.Appium; +using DeviceRunners.UIAutomation.Playwright; using DeviceRunners.UIAutomation.Selenium; using NUnit.Framework.Internal; @@ -23,6 +24,9 @@ public void OneTimeSetUp() .UseAppId("com.companyname.devicetestingkitapp_9zz4h110yvjzm!App"))) .AddSelenium(selenium => selenium .AddMicrosoftEdge("web", options => options + .UseInitialUrl("https://localhost:7096/"))) + .AddPlaywright(playwright => playwright + .AddMicrosoftEdge("web_playwright", options => options .UseInitialUrl("https://localhost:7096/"))); TestSuite = builder.Build(); diff --git a/src/DeviceRunners.UIAutomation.Appium/Commands/AppiumClickCoordinatesCommand.cs b/src/DeviceRunners.UIAutomation.Appium/Commands/AppiumClickCoordinatesCommand.cs index 6e5b3d9..a8d2b91 100644 --- a/src/DeviceRunners.UIAutomation.Appium/Commands/AppiumClickCoordinatesCommand.cs +++ b/src/DeviceRunners.UIAutomation.Appium/Commands/AppiumClickCoordinatesCommand.cs @@ -6,15 +6,17 @@ namespace DeviceRunners.UIAutomation.Appium; -public class AppiumClickCoordinatesCommand : AppiumElementCommand +public class AppiumClickCoordinatesCommand : AutomatedAppCommand { public AppiumClickCoordinatesCommand() : base(CommonCommandNames.ClickCoordinates) { } - public override object? Execute(AppiumAutomatedApp app, AppiumElement appiumElement, IReadOnlyDictionary parameters) + public override object? Execute(AppiumAutomatedApp app, IReadOnlyDictionary? parameters = null) { + if (parameters is null) + throw new ArgumentException("No coordinates found in parameters", nameof(parameters)); if (!parameters.TryGetValue("x", out var x)) throw new ArgumentException("X coordinate not found in parameters", nameof(parameters)); if (!parameters.TryGetValue("y", out var y)) diff --git a/src/DeviceRunners.UIAutomation.Playwright/AppiumAutomatedApp.cs b/src/DeviceRunners.UIAutomation.Playwright/AppiumAutomatedApp.cs deleted file mode 100644 index 334bf6d..0000000 --- a/src/DeviceRunners.UIAutomation.Playwright/AppiumAutomatedApp.cs +++ /dev/null @@ -1,62 +0,0 @@ -namespace DeviceRunners.UIAutomation.Playwright; - -/// -/// This type represents an automated app that is driven by Playwright. -/// -public class PlaywrightAutomatedApp : IAutomatedApp -{ - //private readonly PlaywrightAutomatedAppOptions _options; - //private readonly IPlaywrightDiagnosticLogger? _logger; - - //public PlaywrightAutomatedApp(PlaywrightAutomationFramework playwright, PlaywrightAutomatedAppOptions options, IPlaywrightDiagnosticLogger? logger = null) - //{ - // Framework = playwright; - // _options = options; - // _logger = logger; - // DriverManager = new PlaywrightDriverManager(Framework.ServiceManager, _options); - // Commands = new AutomatedAppCommandManager(this, options.Commands); - //} - - //public PlaywrightAutomationFramework Framework { get; } - - //public PlaywrightServiceManager ServiceManager => Framework.ServiceManager; - - //public PlaywrightDriverManager DriverManager { get; } - - //public PlaywrightDriver Driver => DriverManager.Driver; - - public IAutomatedAppCommandManager Commands { get; } - - IReadOnlyList IContainsElements.FindElements(Action by) => null; - IAutomatedAppElement IContainsElements.FindElement(Action by) => null; - - //public PlaywrightAutomatedAppElement FindElement(Action by) - //{ - // ArgumentNullException.ThrowIfNull(by); - - // var playwrightBy = _options.ByFactory.Create(this); - // by(playwrightBy); - - // var element = Driver.FindElement(playwrightBy.ToBy()); - - // return new PlaywrightAutomatedAppElement(this, element); - //} - - //IAutomatedAppElement IContainsElements.FindElement(Action by) => - // FindElement(by); - - //public IReadOnlyList FindElements(Action by) - //{ - // ArgumentNullException.ThrowIfNull(by); - - // var playwrightBy = _options.ByFactory.Create(this); - // by(playwrightBy); - - // var elements = Driver.FindElements(playwrightBy.ToBy()); - - // return elements.Select(e => new PlaywrightAutomatedAppElement(this, e)).ToList(); - //} - - //IReadOnlyList IContainsElements.FindElements(Action by) => - // FindElements(by); -} diff --git a/src/DeviceRunners.UIAutomation.Playwright/AppiumAutomatedAppElement.cs b/src/DeviceRunners.UIAutomation.Playwright/AppiumAutomatedAppElement.cs deleted file mode 100644 index 62a55fb..0000000 --- a/src/DeviceRunners.UIAutomation.Playwright/AppiumAutomatedAppElement.cs +++ /dev/null @@ -1,18 +0,0 @@ -//using OpenQA.Selenium.Playwright; - -//namespace DeviceRunners.UIAutomation.Playwright; - -//public class PlaywrightAutomatedAppElement : IAutomatedAppElement -//{ -// public PlaywrightAutomatedAppElement(PlaywrightAutomatedApp app, PlaywrightElement element) -// { -// App = app; -// PlaywrightElement = element; -// } - -// public PlaywrightAutomatedApp App { get; } - -// public PlaywrightElement PlaywrightElement { get; } - -// IAutomatedApp IAutomatedAppElement.App => App; -//} diff --git a/src/DeviceRunners.UIAutomation.Playwright/AppiumAutomationFramework.cs b/src/DeviceRunners.UIAutomation.Playwright/AppiumAutomationFramework.cs deleted file mode 100644 index b1fb481..0000000 --- a/src/DeviceRunners.UIAutomation.Playwright/AppiumAutomationFramework.cs +++ /dev/null @@ -1,84 +0,0 @@ -////namespace DeviceRunners.UIAutomation.Playwright; - -/////// -/////// This type is responsible for creating and managing Playwright automated app instances. -/////// -////public class PlaywrightAutomationFramework : IAutomationFramework -////{ -//// private readonly PlaywrightServiceManagerOptions _options; -//// private readonly IReadOnlyList _apps; -//// private readonly IPlaywrightDiagnosticLogger? _logger; -//// private PlaywrightServiceManager? _serviceManager; -//// private bool _disposed; - -//// public PlaywrightAutomationFramework(PlaywrightServiceManagerOptions options, IEnumerable apps, IPlaywrightDiagnosticLogger? logger = null) -//// { -//// _options = options; -//// _apps = apps.ToList(); -//// _logger = logger; -//// } - -//// public PlaywrightServiceManager ServiceManager -//// { -//// get -//// { -//// ObjectDisposedException.ThrowIf(_disposed, typeof(PlaywrightAutomationFramework)); -//// return _serviceManager ??= new PlaywrightServiceManager(_options, _logger); -//// } -//// } - -//// public IReadOnlyList AvailableApps => _apps; - -//// public IAutomatedApp CreateApp(PlaywrightAutomatedAppOptions options) -//// { -//// return new PlaywrightAutomatedApp(this, options, _logger); -//// } - -//// public void StartApp(PlaywrightAutomatedApp app) -//// { -//// app.DriverManager.StartDriver(); -//// } - -//// public void StopApp(PlaywrightAutomatedApp app) -//// { -//// app.DriverManager.ShutdownDriver(); -//// } - -//// public void RestartApp(PlaywrightAutomatedApp app) -//// { -//// app.DriverManager.RestartDriver(); -//// } - -//// IReadOnlyList IAutomationFramework.AvailableApps => _apps; - -//// IAutomatedApp IAutomationFramework.CreateApp(IAutomatedAppOptions options) -//// { -//// if (options is not PlaywrightAutomatedAppOptions playwrightOptions) -//// throw new ArgumentException($"Expected {nameof(PlaywrightAutomatedAppOptions)} but got {options.GetType().Name}", nameof(options)); - -//// return CreateApp(playwrightOptions); -//// } - -//// void IAutomationFramework.StartApp(IAutomatedApp app) => StartApp(AsPlaywrightApp(app)); - -//// void IAutomationFramework.StopApp(IAutomatedApp app) => StopApp(AsPlaywrightApp(app)); - -//// void IAutomationFramework.RestartApp(IAutomatedApp app) => RestartApp(AsPlaywrightApp(app)); - -//// public void Dispose() -//// { -//// if (_disposed) -//// return; - -//// _disposed = true; - -//// _serviceManager?.Dispose(); -//// } - -//// private static PlaywrightAutomatedApp AsPlaywrightApp(IAutomatedApp app) -//// { -//// if (app is not PlaywrightAutomatedApp playwrightApp) -//// throw new ArgumentException($"Expected {nameof(PlaywrightAutomatedApp)} but got {app.GetType().Name}", nameof(app)); -//// return playwrightApp; -//// } -////} diff --git a/src/DeviceRunners.UIAutomation.Playwright/AppiumAutomationOptionsBuilder.cs b/src/DeviceRunners.UIAutomation.Playwright/AppiumAutomationOptionsBuilder.cs deleted file mode 100644 index ede068c..0000000 --- a/src/DeviceRunners.UIAutomation.Playwright/AppiumAutomationOptionsBuilder.cs +++ /dev/null @@ -1,43 +0,0 @@ -//namespace DeviceRunners.UIAutomation.Playwright; - -///// -///// This type is responsible for building the options for the Playwright automation framework. -///// -//public class PlaywrightAutomationOptionsBuilder -//{ -// private readonly List _loggers = []; -// private readonly Dictionary _apps = []; - -// public PlaywrightAutomationOptionsBuilder UseServiceAddress( -// string hostAddress = PlaywrightServiceManagerOptions.DefaultHostAddress, -// int port = PlaywrightServiceManagerOptions.DefaultHostPort) -// { -// Options.HostAddress = hostAddress; -// Options.HostPort = port; - -// return this; -// } - -// public PlaywrightAutomationOptionsBuilder AddLogger(IPlaywrightDiagnosticLogger logger) -// { -// _loggers.Add(logger); - -// return this; -// } - -// public PlaywrightAutomationOptionsBuilder AddApp(string key, PlaywrightAutomatedAppOptions options) -// { -// if (_apps.TryGetValue(key, out var existing)) -// throw new InvalidOperationException($"App with key '{key}' was already added: {existing}"); - -// _apps[key] = options; - -// return this; -// } - -// internal PlaywrightServiceManagerOptions Options { get; } = new(); - -// internal IReadOnlyCollection Apps => _apps.Values; - -// internal IReadOnlyCollection Loggers => _loggers; -//} diff --git a/src/DeviceRunners.UIAutomation.Playwright/AutomatedBrowsers/Edge/AppiumAutomationOptionsBuilderExtensions.cs b/src/DeviceRunners.UIAutomation.Playwright/AutomatedBrowsers/Edge/AppiumAutomationOptionsBuilderExtensions.cs deleted file mode 100644 index aaa8ef9..0000000 --- a/src/DeviceRunners.UIAutomation.Playwright/AutomatedBrowsers/Edge/AppiumAutomationOptionsBuilderExtensions.cs +++ /dev/null @@ -1,18 +0,0 @@ -//namespace DeviceRunners.UIAutomation.Playwright; - -//public static partial class PlaywrightAutomationOptionsBuilderExtensions -//{ -// public static PlaywrightAutomationOptionsBuilder AddAndroidApp(this PlaywrightAutomationOptionsBuilder builder, string key, Action optionsAction) -// { -// var optionsBuilder = new AndroidPlaywrightAutomatedAppOptionsBuilder(key); - -// optionsBuilder.AddDefaultPlaywrightCommands(); -// optionsBuilder.AddDefaultAndroidPlaywrightCommands(); - -// optionsAction(optionsBuilder); - -// builder.AddApp(key, optionsBuilder.Build()); - -// return builder; -// } -//} diff --git a/src/DeviceRunners.UIAutomation.Playwright/AutomatedBrowsers/Edge/PlaywrightAutomationOptionsBuilderExtensions.cs b/src/DeviceRunners.UIAutomation.Playwright/AutomatedBrowsers/Edge/PlaywrightAutomationOptionsBuilderExtensions.cs new file mode 100644 index 0000000..d42306d --- /dev/null +++ b/src/DeviceRunners.UIAutomation.Playwright/AutomatedBrowsers/Edge/PlaywrightAutomationOptionsBuilderExtensions.cs @@ -0,0 +1,18 @@ +namespace DeviceRunners.UIAutomation.Playwright; + +public static partial class PlaywrightAutomationOptionsBuilderExtensions +{ + public static PlaywrightAutomationOptionsBuilder AddMicrosoftEdge(this PlaywrightAutomationOptionsBuilder builder, string key, Action optionsAction) + { + var optionsBuilder = new EdgePlaywrightAutomatedAppOptionsBuilder(key); + + optionsBuilder.AddDefaultPlaywrightCommands(); + //optionsBuilder.AddDefaultAndroidPlaywrightCommands(); + + optionsAction(optionsBuilder); + + builder.AddApp(key, optionsBuilder.Build()); + + return builder; + } +} diff --git a/src/DeviceRunners.UIAutomation.Playwright/AutomationTestSuiteBuilderExtensions.cs b/src/DeviceRunners.UIAutomation.Playwright/AutomationTestSuiteBuilderExtensions.cs index e47a0cb..e6113a9 100644 --- a/src/DeviceRunners.UIAutomation.Playwright/AutomationTestSuiteBuilderExtensions.cs +++ b/src/DeviceRunners.UIAutomation.Playwright/AutomationTestSuiteBuilderExtensions.cs @@ -1,34 +1,34 @@ -//namespace DeviceRunners.UIAutomation.Playwright; +namespace DeviceRunners.UIAutomation.Playwright; -//public static class AutomationTestSuiteBuilderExtensions -//{ -// public static AutomationTestSuiteBuilder AddPlaywright(this AutomationTestSuiteBuilder builder, Action optionsAction) -// { -// var optionsBuilder = new PlaywrightAutomationOptionsBuilder(); +public static class AutomationTestSuiteBuilderExtensions +{ + public static AutomationTestSuiteBuilder AddPlaywright(this AutomationTestSuiteBuilder builder, Action optionsAction) + { + var optionsBuilder = new PlaywrightAutomationOptionsBuilder(); -// optionsAction(optionsBuilder); + optionsAction(optionsBuilder); -// var playwright = new PlaywrightAutomationFramework( -// optionsBuilder.Options, -// optionsBuilder.Apps, -// new CompositeLogger(optionsBuilder.Loggers)); + var playwright = new PlaywrightAutomationFramework( + optionsBuilder.Options, + optionsBuilder.Apps, + new CompositeLogger(optionsBuilder.Loggers)); -// builder.AddAutomationFramework(playwright); + builder.AddAutomationFramework(playwright); -// return builder; -// } + return builder; + } -// class CompositeLogger : IPlaywrightDiagnosticLogger -// { -// private readonly List _loggers; + class CompositeLogger : IPlaywrightDiagnosticLogger + { + private readonly List _loggers; -// public CompositeLogger(IEnumerable loggers) => -// _loggers = loggers.ToList(); + public CompositeLogger(IEnumerable loggers) => + _loggers = loggers.ToList(); -// public void Log(string message) -// { -// foreach (var logger in _loggers) -// logger.Log(message); -// } -// } -//} + public void Log(string message) + { + foreach (var logger in _loggers) + logger.Log(message); + } + } +} diff --git a/src/DeviceRunners.UIAutomation.Playwright/Commands/AppiumAutomatedAppOptionsBuilderExtensions.cs b/src/DeviceRunners.UIAutomation.Playwright/Commands/AppiumAutomatedAppOptionsBuilderExtensions.cs deleted file mode 100644 index 3b2bf50..0000000 --- a/src/DeviceRunners.UIAutomation.Playwright/Commands/AppiumAutomatedAppOptionsBuilderExtensions.cs +++ /dev/null @@ -1,16 +0,0 @@ -//namespace DeviceRunners.UIAutomation.Playwright; - -//public static partial class PlaywrightAutomatedAppOptionsBuilderExtensions -//{ -// public static TBuilder AddDefaultPlaywrightCommands(this TBuilder builder) -// where TBuilder : PlaywrightAutomatedAppOptionsBuilder -// { -// builder.AddCommand(new PlaywrightGetPageSourceCommand()); -// builder.AddCommand(new PlaywrightGetScreenshotCommand()); -// builder.AddCommand(new PlaywrightGetElementTextCommand()); -// builder.AddCommand(new PlaywrightClickElementCommand()); -// builder.AddCommand(new PlaywrightClickCoordinatesCommand()); - -// return builder; -// } -//} diff --git a/src/DeviceRunners.UIAutomation.Playwright/Commands/AppiumClickCoordinatesCommand.cs b/src/DeviceRunners.UIAutomation.Playwright/Commands/AppiumClickCoordinatesCommand.cs deleted file mode 100644 index e638754..0000000 --- a/src/DeviceRunners.UIAutomation.Playwright/Commands/AppiumClickCoordinatesCommand.cs +++ /dev/null @@ -1,32 +0,0 @@ -//using OpenQA.Selenium.Playwright; -//using OpenQA.Selenium.Playwright.Interactions; -//using OpenQA.Selenium.Interactions; - -//using PointerInputDevice = OpenQA.Selenium.Playwright.Interactions.PointerInputDevice; - -//namespace DeviceRunners.UIAutomation.Playwright; - -//public class PlaywrightClickCoordinatesCommand : PlaywrightElementCommand -//{ -// public PlaywrightClickCoordinatesCommand() -// : base(CommonCommandNames.ClickCoordinates) -// { -// } - -// public override object? Execute(PlaywrightAutomatedApp app, PlaywrightElement playwrightElement, IReadOnlyDictionary parameters) -// { -// if (!parameters.TryGetValue("x", out var x)) -// throw new ArgumentException("X coordinate not found in parameters", nameof(parameters)); -// if (!parameters.TryGetValue("y", out var y)) -// throw new ArgumentException("Y coordinate not found in parameters", nameof(parameters)); - -// var touchDevice = new PointerInputDevice(PointerKind.Mouse); -// var sequence = new ActionSequence(touchDevice, 0); -// sequence.AddAction(touchDevice.CreatePointerMove(CoordinateOrigin.Viewport, Convert.ToInt32(x), Convert.ToInt32(y), TimeSpan.FromMilliseconds(5))); -// sequence.AddAction(touchDevice.CreatePointerDown(PointerButton.TouchContact)); -// sequence.AddAction(touchDevice.CreatePointerUp(PointerButton.TouchContact)); -// app.Driver.PerformActions([sequence]); - -// return null; -// } -//} diff --git a/src/DeviceRunners.UIAutomation.Playwright/Commands/AppiumClickElementCommand.cs b/src/DeviceRunners.UIAutomation.Playwright/Commands/AppiumClickElementCommand.cs deleted file mode 100644 index e4ff79f..0000000 --- a/src/DeviceRunners.UIAutomation.Playwright/Commands/AppiumClickElementCommand.cs +++ /dev/null @@ -1,34 +0,0 @@ -//using OpenQA.Selenium; -//using OpenQA.Selenium.Playwright; - -//namespace DeviceRunners.UIAutomation.Playwright; - -//public class PlaywrightClickElementCommand : PlaywrightElementCommand -//{ -// public PlaywrightClickElementCommand() -// : base(CommonCommandNames.ClickElement) -// { -// } - -// public override object? Execute(PlaywrightAutomatedApp app, PlaywrightElement playwrightElement, IReadOnlyDictionary parameters) -// { -// try -// { -// playwrightElement.Click(); -// return null; -// } -// catch (Exception ex) when (ex is WebDriverException || ex is InvalidOperationException) -// { -// // Some elements aren't "clickable" from an automation perspective, such -// // as borders and labels. In this case, we can try to tap the element using -// // its center point - which is what the click does anyway. - -// var pointString = playwrightElement.GetAttribute("ClickablePoint"); -// var parts = pointString.Split(','); -// double x = double.Parse(parts[0]); -// double y = double.Parse(parts[1]); - -// return app.Commands.Execute(CommonCommandNames.ClickCoordinates, ("x", x), ("y", y)); -// } -// } -//} diff --git a/src/DeviceRunners.UIAutomation.Playwright/Commands/AppiumElementCommand.cs b/src/DeviceRunners.UIAutomation.Playwright/Commands/AppiumElementCommand.cs deleted file mode 100644 index 9edf397..0000000 --- a/src/DeviceRunners.UIAutomation.Playwright/Commands/AppiumElementCommand.cs +++ /dev/null @@ -1,24 +0,0 @@ -//using OpenQA.Selenium.Playwright; - -//namespace DeviceRunners.UIAutomation.Playwright; - -//public abstract class PlaywrightElementCommand : AutomatedAppCommand -//{ -// protected PlaywrightElementCommand(string name) -// : base(name) -// { -// } - -// public abstract object? Execute(PlaywrightAutomatedApp app, PlaywrightElement playwrightElement, IReadOnlyDictionary parameters); - -// public override object? Execute(PlaywrightAutomatedApp app, IReadOnlyDictionary? parameters = null) -// { -// if (parameters is null || !parameters.TryGetValue("element", out var element)) -// throw new ArgumentException("Element not found in parameters", nameof(parameters)); - -// if (element is not PlaywrightAutomatedAppElement playwrightElement) -// throw new ArgumentException("Element is not an Playwright element", nameof(parameters)); - -// return Execute(app, playwrightElement.PlaywrightElement, parameters); -// } -//} diff --git a/src/DeviceRunners.UIAutomation.Playwright/Commands/AppiumGetElementTextCommand.cs b/src/DeviceRunners.UIAutomation.Playwright/Commands/AppiumGetElementTextCommand.cs deleted file mode 100644 index 36405dd..0000000 --- a/src/DeviceRunners.UIAutomation.Playwright/Commands/AppiumGetElementTextCommand.cs +++ /dev/null @@ -1,14 +0,0 @@ -//using OpenQA.Selenium.Playwright; - -//namespace DeviceRunners.UIAutomation.Playwright; - -//public class PlaywrightGetElementTextCommand : PlaywrightElementCommand -//{ -// public PlaywrightGetElementTextCommand() -// : base(CommonCommandNames.GetElementText) -// { -// } - -// public override object? Execute(PlaywrightAutomatedApp app, PlaywrightElement playwrightElement, IReadOnlyDictionary parameters) => -// playwrightElement.Text; -//} diff --git a/src/DeviceRunners.UIAutomation.Playwright/Commands/AppiumGetPageSourceCommand.cs b/src/DeviceRunners.UIAutomation.Playwright/Commands/AppiumGetPageSourceCommand.cs deleted file mode 100644 index 7359824..0000000 --- a/src/DeviceRunners.UIAutomation.Playwright/Commands/AppiumGetPageSourceCommand.cs +++ /dev/null @@ -1,14 +0,0 @@ -//namespace DeviceRunners.UIAutomation.Playwright; - -//public class PlaywrightGetPageSourceCommand : AutomatedAppCommand -//{ -// public PlaywrightGetPageSourceCommand() -// : base(CommonCommandNames.GetPageSource) -// { -// } - -// public override object? Execute(PlaywrightAutomatedApp app, IReadOnlyDictionary? parameters = null) -// { -// return app.Driver.PageSource; -// } -//} diff --git a/src/DeviceRunners.UIAutomation.Playwright/Commands/AppiumGetScreenshotCommand.cs b/src/DeviceRunners.UIAutomation.Playwright/Commands/AppiumGetScreenshotCommand.cs deleted file mode 100644 index 69771ac..0000000 --- a/src/DeviceRunners.UIAutomation.Playwright/Commands/AppiumGetScreenshotCommand.cs +++ /dev/null @@ -1,17 +0,0 @@ -//namespace DeviceRunners.UIAutomation.Playwright; - -//public class PlaywrightGetScreenshotCommand : AutomatedAppCommand -//{ -// public PlaywrightGetScreenshotCommand() -// : base(CommonCommandNames.GetScreenshot) -// { -// } - -// public override object? Execute(PlaywrightAutomatedApp app, IReadOnlyDictionary? parameters = null) -// { -// if (app.Driver.GetScreenshot() is { } screenshot) -// return new Base64StringInMemoryFile(screenshot.AsBase64EncodedString); - -// return null; -// } -//} diff --git a/src/DeviceRunners.UIAutomation.Playwright/Commands/PlaywrightAutomatedAppOptionsBuilderExtensions.cs b/src/DeviceRunners.UIAutomation.Playwright/Commands/PlaywrightAutomatedAppOptionsBuilderExtensions.cs new file mode 100644 index 0000000..4eaed6a --- /dev/null +++ b/src/DeviceRunners.UIAutomation.Playwright/Commands/PlaywrightAutomatedAppOptionsBuilderExtensions.cs @@ -0,0 +1,16 @@ +namespace DeviceRunners.UIAutomation.Playwright; + +public static partial class PlaywrightAutomatedAppOptionsBuilderExtensions +{ + public static TBuilder AddDefaultPlaywrightCommands(this TBuilder builder) + where TBuilder : PlaywrightAutomatedAppOptionsBuilder + { + builder.AddCommand(new PlaywrightGetPageSourceCommand()); + builder.AddCommand(new PlaywrightGetScreenshotCommand()); + builder.AddCommand(new PlaywrightGetElementTextCommand()); + builder.AddCommand(new PlaywrightClickElementCommand()); + builder.AddCommand(new PlaywrightClickCoordinatesCommand()); + + return builder; + } +} diff --git a/src/DeviceRunners.UIAutomation.Playwright/Commands/PlaywrightClickCoordinatesCommand.cs b/src/DeviceRunners.UIAutomation.Playwright/Commands/PlaywrightClickCoordinatesCommand.cs new file mode 100644 index 0000000..7ff325d --- /dev/null +++ b/src/DeviceRunners.UIAutomation.Playwright/Commands/PlaywrightClickCoordinatesCommand.cs @@ -0,0 +1,23 @@ +namespace DeviceRunners.UIAutomation.Playwright; + +public class PlaywrightClickCoordinatesCommand : AutomatedAppCommand +{ + public PlaywrightClickCoordinatesCommand() + : base(CommonCommandNames.ClickCoordinates) + { + } + + public override object? Execute(PlaywrightAutomatedApp app, IReadOnlyDictionary? parameters = null) + { + if (parameters is null) + throw new ArgumentException("No coordinates found in parameters", nameof(parameters)); + if (!parameters.TryGetValue("x", out var x)) + throw new ArgumentException("X coordinate not found in parameters", nameof(parameters)); + if (!parameters.TryGetValue("y", out var y)) + throw new ArgumentException("Y coordinate not found in parameters", nameof(parameters)); + + app.Page.Mouse.ClickAsync(Convert.ToInt32(x), Convert.ToInt32(y)).GetAwaiter().GetResult(); + + return null; + } +} diff --git a/src/DeviceRunners.UIAutomation.Playwright/Commands/PlaywrightClickElementCommand.cs b/src/DeviceRunners.UIAutomation.Playwright/Commands/PlaywrightClickElementCommand.cs new file mode 100644 index 0000000..aa971d2 --- /dev/null +++ b/src/DeviceRunners.UIAutomation.Playwright/Commands/PlaywrightClickElementCommand.cs @@ -0,0 +1,17 @@ +using Microsoft.Playwright; + +namespace DeviceRunners.UIAutomation.Playwright; + +public class PlaywrightClickElementCommand : PlaywrightElementCommand +{ + public PlaywrightClickElementCommand() + : base(CommonCommandNames.ClickElement) + { + } + + public override object? Execute(PlaywrightAutomatedApp app, ILocator playwrightElement, IReadOnlyDictionary parameters) + { + playwrightElement.ClickAsync().GetAwaiter().GetResult(); + return null; + } +} diff --git a/src/DeviceRunners.UIAutomation.Playwright/Commands/PlaywrightElementCommand.cs b/src/DeviceRunners.UIAutomation.Playwright/Commands/PlaywrightElementCommand.cs new file mode 100644 index 0000000..16a7f26 --- /dev/null +++ b/src/DeviceRunners.UIAutomation.Playwright/Commands/PlaywrightElementCommand.cs @@ -0,0 +1,24 @@ +using Microsoft.Playwright; + +namespace DeviceRunners.UIAutomation.Playwright; + +public abstract class PlaywrightElementCommand : AutomatedAppCommand +{ + protected PlaywrightElementCommand(string name) + : base(name) + { + } + + public abstract object? Execute(PlaywrightAutomatedApp app, ILocator playwrightElement, IReadOnlyDictionary parameters); + + public override object? Execute(PlaywrightAutomatedApp app, IReadOnlyDictionary? parameters = null) + { + if (parameters is null || !parameters.TryGetValue("element", out var element)) + throw new ArgumentException("Element not found in parameters", nameof(parameters)); + + if (element is not PlaywrightAutomatedAppElement playwrightElement) + throw new ArgumentException("Element is not an Playwright element", nameof(parameters)); + + return Execute(app, playwrightElement.PlaywrightElement, parameters); + } +} diff --git a/src/DeviceRunners.UIAutomation.Playwright/Commands/PlaywrightGetElementTextCommand.cs b/src/DeviceRunners.UIAutomation.Playwright/Commands/PlaywrightGetElementTextCommand.cs new file mode 100644 index 0000000..27a286c --- /dev/null +++ b/src/DeviceRunners.UIAutomation.Playwright/Commands/PlaywrightGetElementTextCommand.cs @@ -0,0 +1,14 @@ +using Microsoft.Playwright; + +namespace DeviceRunners.UIAutomation.Playwright; + +public class PlaywrightGetElementTextCommand : PlaywrightElementCommand +{ + public PlaywrightGetElementTextCommand() + : base(CommonCommandNames.GetElementText) + { + } + + public override object? Execute(PlaywrightAutomatedApp app, ILocator playwrightElement, IReadOnlyDictionary parameters) => + playwrightElement.TextContentAsync().GetAwaiter().GetResult(); +} diff --git a/src/DeviceRunners.UIAutomation.Playwright/Commands/PlaywrightGetPageSourceCommand.cs b/src/DeviceRunners.UIAutomation.Playwright/Commands/PlaywrightGetPageSourceCommand.cs new file mode 100644 index 0000000..bd2f78b --- /dev/null +++ b/src/DeviceRunners.UIAutomation.Playwright/Commands/PlaywrightGetPageSourceCommand.cs @@ -0,0 +1,12 @@ +namespace DeviceRunners.UIAutomation.Playwright; + +public class PlaywrightGetPageSourceCommand : AutomatedAppCommand +{ + public PlaywrightGetPageSourceCommand() + : base(CommonCommandNames.GetPageSource) + { + } + + public override object? Execute(PlaywrightAutomatedApp app, IReadOnlyDictionary? parameters = null) => + app.Page.ContentAsync().GetAwaiter().GetResult(); +} diff --git a/src/DeviceRunners.UIAutomation.Playwright/Commands/PlaywrightGetScreenshotCommand.cs b/src/DeviceRunners.UIAutomation.Playwright/Commands/PlaywrightGetScreenshotCommand.cs new file mode 100644 index 0000000..3acba62 --- /dev/null +++ b/src/DeviceRunners.UIAutomation.Playwright/Commands/PlaywrightGetScreenshotCommand.cs @@ -0,0 +1,17 @@ +namespace DeviceRunners.UIAutomation.Playwright; + +public class PlaywrightGetScreenshotCommand : AutomatedAppCommand +{ + public PlaywrightGetScreenshotCommand() + : base(CommonCommandNames.GetScreenshot) + { + } + + public override object? Execute(PlaywrightAutomatedApp app, IReadOnlyDictionary? parameters = null) + { + if (app.Page.ScreenshotAsync().GetAwaiter().GetResult() is { } screenshot) + return new ByteArrayInMemoryFile(screenshot); + + return null; + } +} diff --git a/src/DeviceRunners.UIAutomation.Playwright/PlaywrightAutomatedApp.cs b/src/DeviceRunners.UIAutomation.Playwright/PlaywrightAutomatedApp.cs new file mode 100644 index 0000000..7aa4cb7 --- /dev/null +++ b/src/DeviceRunners.UIAutomation.Playwright/PlaywrightAutomatedApp.cs @@ -0,0 +1,62 @@ +using Microsoft.Playwright; + +namespace DeviceRunners.UIAutomation.Playwright; + +/// +/// This type represents an automated app that is driven by Playwright. +/// +public class PlaywrightAutomatedApp : IAutomatedApp +{ + private readonly PlaywrightAutomatedAppOptions _options; + private readonly IPlaywrightDiagnosticLogger? _logger; + + public PlaywrightAutomatedApp(PlaywrightAutomationFramework playwright, PlaywrightAutomatedAppOptions options, IPlaywrightDiagnosticLogger? logger = null) + { + Framework = playwright; + _options = options; + _logger = logger; + DriverManager = new PlaywrightDriverManager(Framework.ServiceManager, _options); + Commands = new AutomatedAppCommandManager(this, options.Commands); + } + + public PlaywrightAutomationFramework Framework { get; } + + public PlaywrightServiceManager ServiceManager => Framework.ServiceManager; + + public PlaywrightDriverManager DriverManager { get; } + + public IPage Page => DriverManager.Page; + + public IAutomatedAppCommandManager Commands { get; } + + public PlaywrightAutomatedAppElement FindElement(Action by) + { + ArgumentNullException.ThrowIfNull(by); + + var playwrightBy = _options.ByFactory.Create(this); + by(playwrightBy); + + var elements = playwrightBy.Locate(Page); + + return new PlaywrightAutomatedAppElement(this, elements.First); + } + + IAutomatedAppElement IContainsElements.FindElement(Action by) => + FindElement(by); + + public IReadOnlyList FindElements(Action by) + { + ArgumentNullException.ThrowIfNull(by); + + var playwrightBy = _options.ByFactory.Create(this); + by(playwrightBy); + + var elements = playwrightBy.Locate(Page); + var all = elements.AllAsync().GetAwaiter().GetResult(); + + return all.Select(e => new PlaywrightAutomatedAppElement(this, e)).ToList(); + } + + IReadOnlyList IContainsElements.FindElements(Action by) => + FindElements(by); +} diff --git a/src/DeviceRunners.UIAutomation.Playwright/PlaywrightAutomatedAppElement.cs b/src/DeviceRunners.UIAutomation.Playwright/PlaywrightAutomatedAppElement.cs new file mode 100644 index 0000000..8e98b5c --- /dev/null +++ b/src/DeviceRunners.UIAutomation.Playwright/PlaywrightAutomatedAppElement.cs @@ -0,0 +1,18 @@ +using Microsoft.Playwright; + +namespace DeviceRunners.UIAutomation.Playwright; + +public class PlaywrightAutomatedAppElement : IAutomatedAppElement +{ + public PlaywrightAutomatedAppElement(PlaywrightAutomatedApp app, ILocator element) + { + App = app; + PlaywrightElement = element; + } + + public PlaywrightAutomatedApp App { get; } + + public ILocator PlaywrightElement { get; } + + IAutomatedApp IAutomatedAppElement.App => App; +} diff --git a/src/DeviceRunners.UIAutomation.Playwright/PlaywrightAutomationFramework.cs b/src/DeviceRunners.UIAutomation.Playwright/PlaywrightAutomationFramework.cs new file mode 100644 index 0000000..321dcce --- /dev/null +++ b/src/DeviceRunners.UIAutomation.Playwright/PlaywrightAutomationFramework.cs @@ -0,0 +1,84 @@ +namespace DeviceRunners.UIAutomation.Playwright; + +/// +/// This type is responsible for creating and managing Playwright automated app instances. +/// +public class PlaywrightAutomationFramework : IAutomationFramework +{ + private readonly PlaywrightServiceManagerOptions _options; + private readonly IReadOnlyList _apps; + private readonly IPlaywrightDiagnosticLogger? _logger; + private PlaywrightServiceManager? _serviceManager; + private bool _disposed; + + public PlaywrightAutomationFramework(PlaywrightServiceManagerOptions options, IEnumerable apps, IPlaywrightDiagnosticLogger? logger = null) + { + _options = options; + _apps = apps.ToList(); + _logger = logger; + } + + public PlaywrightServiceManager ServiceManager + { + get + { + ObjectDisposedException.ThrowIf(_disposed, typeof(PlaywrightAutomationFramework)); + return _serviceManager ??= new PlaywrightServiceManager(_options, _logger); + } + } + + public IReadOnlyList AvailableApps => _apps; + + public IAutomatedApp CreateApp(PlaywrightAutomatedAppOptions options) + { + return new PlaywrightAutomatedApp(this, options, _logger); + } + + public void StartApp(PlaywrightAutomatedApp app) + { + app.DriverManager.StartDriver(); + } + + public void StopApp(PlaywrightAutomatedApp app) + { + app.DriverManager.ShutdownDriver(); + } + + public void RestartApp(PlaywrightAutomatedApp app) + { + app.DriverManager.RestartDriver(); + } + + IReadOnlyList IAutomationFramework.AvailableApps => _apps; + + IAutomatedApp IAutomationFramework.CreateApp(IAutomatedAppOptions options) + { + if (options is not PlaywrightAutomatedAppOptions playwrightOptions) + throw new ArgumentException($"Expected {nameof(PlaywrightAutomatedAppOptions)} but got {options.GetType().Name}", nameof(options)); + + return CreateApp(playwrightOptions); + } + + void IAutomationFramework.StartApp(IAutomatedApp app) => StartApp(AsPlaywrightApp(app)); + + void IAutomationFramework.StopApp(IAutomatedApp app) => StopApp(AsPlaywrightApp(app)); + + void IAutomationFramework.RestartApp(IAutomatedApp app) => RestartApp(AsPlaywrightApp(app)); + + public void Dispose() + { + if (_disposed) + return; + + _disposed = true; + + _serviceManager?.Dispose(); + } + + private static PlaywrightAutomatedApp AsPlaywrightApp(IAutomatedApp app) + { + if (app is not PlaywrightAutomatedApp playwrightApp) + throw new ArgumentException($"Expected {nameof(PlaywrightAutomatedApp)} but got {app.GetType().Name}", nameof(app)); + return playwrightApp; + } +} diff --git a/src/DeviceRunners.UIAutomation.Playwright/PlaywrightAutomationOptionsBuilder.cs b/src/DeviceRunners.UIAutomation.Playwright/PlaywrightAutomationOptionsBuilder.cs new file mode 100644 index 0000000..28e0f1c --- /dev/null +++ b/src/DeviceRunners.UIAutomation.Playwright/PlaywrightAutomationOptionsBuilder.cs @@ -0,0 +1,33 @@ +namespace DeviceRunners.UIAutomation.Playwright; + +/// +/// This type is responsible for building the options for the Playwright automation framework. +/// +public class PlaywrightAutomationOptionsBuilder +{ + private readonly List _loggers = []; + private readonly Dictionary _apps = []; + + public PlaywrightAutomationOptionsBuilder AddLogger(IPlaywrightDiagnosticLogger logger) + { + _loggers.Add(logger); + + return this; + } + + public PlaywrightAutomationOptionsBuilder AddApp(string key, PlaywrightAutomatedAppOptions options) + { + if (_apps.TryGetValue(key, out var existing)) + throw new InvalidOperationException($"App with key '{key}' was already added: {existing}"); + + _apps[key] = options; + + return this; + } + + internal PlaywrightServiceManagerOptions Options { get; } = new(); + + internal IReadOnlyCollection Apps => _apps.Values; + + internal IReadOnlyCollection Loggers => _loggers; +} diff --git a/src/DeviceRunners.UIAutomation.Playwright/PlaywrightBy.cs b/src/DeviceRunners.UIAutomation.Playwright/PlaywrightBy.cs index adad1d4..76f4e72 100644 --- a/src/DeviceRunners.UIAutomation.Playwright/PlaywrightBy.cs +++ b/src/DeviceRunners.UIAutomation.Playwright/PlaywrightBy.cs @@ -1,8 +1,30 @@ -namespace DeviceRunners.UIAutomation.Playwright; +using Microsoft.Playwright; + +namespace DeviceRunners.UIAutomation.Playwright; public class PlaywrightBy : IBy { + private Func? _action; + void IBy.Selector(string selector, string value) { + if (!SetBy(selector, value)) + throw new ArgumentException($"Unknown element selector '{selector}' with value '{value}'."); } + + protected bool SetLocator(Func action) + { + _action = action; + return true; + } + + protected virtual bool SetBy(string selector, string value) => + selector switch + { + BySelectors.Id => SetLocator(p => p.Locator("css=#" + value)), + BySelectors.AccessibilityId => SetLocator(p => p.GetByTestId(value)), + _ => false + }; + + public ILocator Locate(IPage page) => _action?.Invoke(page) ?? throw new InvalidOperationException("No element selector was specified."); } diff --git a/src/DeviceRunners.UIAutomation.Selenium/Commands/SeleniumClickCoordinatesCommand.cs b/src/DeviceRunners.UIAutomation.Selenium/Commands/SeleniumClickCoordinatesCommand.cs index 048bcc1..482f103 100644 --- a/src/DeviceRunners.UIAutomation.Selenium/Commands/SeleniumClickCoordinatesCommand.cs +++ b/src/DeviceRunners.UIAutomation.Selenium/Commands/SeleniumClickCoordinatesCommand.cs @@ -1,17 +1,18 @@ -using OpenQA.Selenium; -using OpenQA.Selenium.Interactions; +using OpenQA.Selenium.Interactions; namespace DeviceRunners.UIAutomation.Selenium; -public class SeleniumClickCoordinatesCommand : SeleniumElementCommand +public class SeleniumClickCoordinatesCommand : AutomatedAppCommand { public SeleniumClickCoordinatesCommand() : base(CommonCommandNames.ClickCoordinates) { } - public override object? Execute(SeleniumAutomatedApp app, WebElement seleniumElement, IReadOnlyDictionary parameters) + public override object? Execute(SeleniumAutomatedApp app, IReadOnlyDictionary? parameters = null) { + if (parameters is null) + throw new ArgumentException("No coordinates found in parameters", nameof(parameters)); if (!parameters.TryGetValue("x", out var x)) throw new ArgumentException("X coordinate not found in parameters", nameof(parameters)); if (!parameters.TryGetValue("y", out var y)) diff --git a/src/DeviceRunners.UIAutomation.Selenium/SeleniumAutomatedAppOptionsBuilderExtensions.cs b/src/DeviceRunners.UIAutomation.Selenium/SeleniumAutomatedAppOptionsBuilderExtensions.cs index e7ef02a..0ef4594 100644 --- a/src/DeviceRunners.UIAutomation.Selenium/SeleniumAutomatedAppOptionsBuilderExtensions.cs +++ b/src/DeviceRunners.UIAutomation.Selenium/SeleniumAutomatedAppOptionsBuilderExtensions.cs @@ -2,8 +2,8 @@ public static partial class SeleniumAutomatedAppOptionsBuilderExtensions { - private const string DriverOptionPrefix = SeleniumAutomatedAppOptionsExtensions.DriverOptionPrefix; - private const string InitialUrlDriverOption = SeleniumAutomatedAppOptionsExtensions.InitialUrlDriverOption; + private const string DriverOptionPrefix = DriverOptionsExtensions.DriverOptionPrefix; + private const string InitialUrlDriverOption = DriverOptionsExtensions.InitialUrlDriverOption; private static TBuilder AddAdditionalOption(this TBuilder builder, string name, object value) where TBuilder : SeleniumAutomatedAppOptionsBuilder diff --git a/test/DeviceRunners.UIAutomation.Playwright.Tests/AutomationTestSuiteBuilderTests.cs b/test/DeviceRunners.UIAutomation.Playwright.Tests/AutomationTestSuiteBuilderTests.cs index b76c9eb..51d17ed 100644 --- a/test/DeviceRunners.UIAutomation.Playwright.Tests/AutomationTestSuiteBuilderTests.cs +++ b/test/DeviceRunners.UIAutomation.Playwright.Tests/AutomationTestSuiteBuilderTests.cs @@ -1,37 +1,37 @@ -//using DeviceRunners.UIAutomation; -//using DeviceRunners.UIAutomation.Playwright; - -//using Xunit; - -//namespace UIAutomationPlaywrightTests; - -//public class AutomationTestSuiteBuilderTests : IDisposable -//{ -// AutomationTestSuite? suite; - -// [Fact] -// public void CanBuild() -// { -// suite = AutomationTestSuiteBuilder.Create() -// .AddPlaywright(options => { }) -// .Build(); - -// Assert.NotNull(suite); -// } - -// [Fact] -// public void CanAddFramework() -// { -// suite = AutomationTestSuiteBuilder.Create() -// .AddPlaywright(options => { }) -// .Build(); - -// var framework = Assert.Single(suite.Frameworks); -// Assert.IsType(framework); -// } - -// public void Dispose() -// { -// suite?.Dispose(); -// } -//} +using DeviceRunners.UIAutomation; +using DeviceRunners.UIAutomation.Playwright; + +using Xunit; + +namespace UIAutomationPlaywrightTests; + +public class AutomationTestSuiteBuilderTests : IDisposable +{ + AutomationTestSuite? suite; + + [Fact] + public void CanBuild() + { + suite = AutomationTestSuiteBuilder.Create() + .AddPlaywright(options => { }) + .Build(); + + Assert.NotNull(suite); + } + + [Fact] + public void CanAddFramework() + { + suite = AutomationTestSuiteBuilder.Create() + .AddPlaywright(options => { }) + .Build(); + + var framework = Assert.Single(suite.Frameworks); + Assert.IsType(framework); + } + + public void Dispose() + { + suite?.Dispose(); + } +} diff --git a/test/DeviceRunners.UIAutomation.Playwright.Tests/PlaywrightDriverManagerTests.cs b/test/DeviceRunners.UIAutomation.Playwright.Tests/PlaywrightDriverManagerTests.cs index 9a50f3e..de6c2b0 100644 --- a/test/DeviceRunners.UIAutomation.Playwright.Tests/PlaywrightDriverManagerTests.cs +++ b/test/DeviceRunners.UIAutomation.Playwright.Tests/PlaywrightDriverManagerTests.cs @@ -1,7 +1,5 @@ using DeviceRunners.UIAutomation.Playwright; -using Microsoft.Playwright; - using Xunit; using Xunit.Abstractions; @@ -63,19 +61,19 @@ public void CanStartWithInitialUrl() Assert.Equal("https://github.com/mattleibow/DeviceRunners", page.Url); } - //[Fact] - //public void CanReadPageContents() - //{ - // var builder = new EdgePlaywrightAutomatedAppOptionsBuilder("test"); - // builder.UseInitialUrl("https://github.com/mattleibow/DeviceRunners"); - // var options = builder.Build(); - - //using var playwright = new PlaywrightServiceManager(new (), Logger); - //using var driverManager = new PlaywrightDriverManager(playwright, options, Logger); - // driverManager.StartDriver(); - // var driver = driverManager.Driver!; - - // var element = driver.FindElement(By.ClassName("markdown-heading")); - // Assert.Equal("Test Device Runners", element.Text); - //} + [Fact] + public async Task CanReadPageContents() + { + var builder = new EdgePlaywrightAutomatedAppOptionsBuilder("test"); + builder.UseInitialUrl("https://github.com/mattleibow/DeviceRunners"); + var options = builder.Build(); + + using var playwright = new PlaywrightServiceManager(new(), Logger); + using var driverManager = new PlaywrightDriverManager(playwright, options, Logger); + driverManager.StartDriver(); + var page = driverManager.Page!; + + var element = page.Locator("css=.markdown-heading").First; + Assert.Equal("Test Device Runners", await element.TextContentAsync()); + } }