Skip to content

Commit

Permalink
Merge pull request #141 from MADE-Apps/feature/appmanager-decoupling
Browse files Browse the repository at this point in the history
Decoupled the AppManager from other Legerity components
  • Loading branch information
jamesmcroft authored Jun 9, 2022
2 parents 7b11368 + dd081f6 commit 73e0a81
Show file tree
Hide file tree
Showing 39 changed files with 905 additions and 244 deletions.
157 changes: 107 additions & 50 deletions docs/articles/building-with-legerity.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,22 +49,23 @@ namespace MyWindowsApplication.UiTests

using Legerity;
using Legerity.Windows;
using Legerity.Windows.Extensions;

using NUnit.Framework;

using OpenQA.Selenium.Appium.Windows;
using OpenQA.Selenium.Remote;

public abstract class BaseTestClass
public abstract class BaseTestClass : LegerityTestClass
{
public const string WindowsApplication = "com.madeapps.sampleapp_7mzr475ysvhxg!App";

protected static WindowsDriver<WindowsElement> App => AppManager.WindowsApp;
protected WindowsDriver<WindowsElement> WindowsApp { get; private set; }

[SetUp]
public void StartApp()
public void Initialize()
{
AppManager.StartApp(
WindowsApp = this.StartWindowsApp(
new WindowsAppManagerOptions(WindowsApplication)
{
DriverUri = "http://127.0.0.1:4723",
Expand All @@ -74,17 +75,17 @@ namespace MyWindowsApplication.UiTests
}

[TearDown]
public void StopApp()
public void Cleanup()
{
AppManager.StopApp();
StopApp(WindowsApp);
}
}
}
```

### Example base test class for an Android application

This example showcases how to start your Android application using a path to a compiled APK. You can also choose to launch your application by application ID and activity if the application is already installed.
This example showcases how to start your Android application using the ID and activity of an app that is already installed on a device. You can also choose to launch your application by APK if the application is not installed.

When your tests start, the `LaunchAppiumServer` property of the `AndroidAppManagerOptions` will automatically start a new Appium server process, if one is not already running. This support allows you to easily run your tests as part of a CI build without additional overhead of scripting the process to run.

Expand All @@ -101,33 +102,94 @@ namespace MyAndroidApplication.UiTests

using Legerity;
using Legerity.Android;
using Legerity.Android.Extensions;

using NUnit.Framework;

using OpenQA.Selenium.Appium.Android;
using OpenQA.Selenium.Remote;

public abstract class BaseTestClass
public abstract class BaseTestClass : LegerityTestClass
{
public const string AndroidApplication = "Tools\\Android\\com.made.sampleapp.apk";
public const string AndroidApplication = "com.made.sampleapp";

public const string AndroidApplicationActivity = $"{AndroidApplication}.MainActivity";

protected static AndroidDriver<AndroidElement> App => AppManager.AndroidApp;
protected AndroidDriver<AndroidElement> AndroidApp { get; private set; }

[SetUp]
public void StartApp()
public void Initialize()
{
AppManager.StartApp(
new AndroidAppManagerOptions(Path.Combine(Environment.CurrentDirectory, AndroidApplication))
AndroidApp = this.StartAndroidApp(
new AndroidAppManagerOptions
{
AppId = AndroidApplication,
AppActivity = AndroidApplicationActivity,
LaunchAppiumServer = true,
DriverUri = "http://localhost:4723/wd/hub"
});
}

[TearDown]
public void StopApp()
public void Cleanup()
{
AppManager.StopApp();
StopApp(AndroidApp);
}
}
}
```

### Example base test class for an iOS application

This example showcases how to start your iOS application using the ID of an app that is already installed on a device.

When your tests start, the `LaunchAppiumServer` property of the `IOSAppManagerOptions` will automatically start a new Appium server process, if one is not already running. This support allows you to easily run your tests as part of a CI build without additional overhead of scripting the process to run.

You also have to provide additional properties that allows you to choose the device that the application should be under test on using the `DeviceName` or `DeviceId` property. This is useful if you wish to pick a specific emulator or physical device.

```csharp
namespace MyIOSApplication.UiTests
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

using Legerity;
using Legerity.IOS;
using Legerity.IOS.Extensions;

using NUnit.Framework;

using OpenQA.Selenium.Appium.IOS;
using OpenQA.Selenium.Remote;

public abstract class BaseTestClass : LegerityTestClass
{
public const string IOSApplication = "com.made.sampleapp";

protected IOSDriver<IOSElement> IOSApp { get; private set; }

[SetUp]
public void Initialize()
{
IOSApp = this.StartIOSApp(
new IOSAppManagerOptions
{
AppId = IOSApplication,
DeviceName = "iPhone SE (3rd generation) Simulator",
DeviceId = "56755E6F-741B-478F-BB1B-A48E05ACFE8A",
OSVersion = "15.4",
LaunchAppiumServer = true,
DriverUri = "http://localhost:4723/wd/hub"
});
}

[TearDown]
public void Cleanup()
{
StopApp(IOSApp);
}
}
}
Expand All @@ -137,6 +199,8 @@ namespace MyAndroidApplication.UiTests

This example showcases how to start your web application using a URL using a specific browser and associated driver. This example is using the Microsoft Edge browser with a path to the [Microsoft Edge Web Driver](https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/).

You can also use the web driver NuGet packages in your test project to automatically pull in the specific version of a web drive you require.

When your tests start, the web browser will launch the URL provided to begin running the test scenarios.

You also have additional properties that allows you to maximize the browser window, or set the size. This is useful in scenarios where your application has responsive UI and you wish to test it under those views.
Expand All @@ -159,16 +223,14 @@ namespace MyWebApplication.UiTests

using OpenQA.Selenium.Remote;

public abstract class BaseTestClass
public abstract class BaseTestClass : LegerityTestClass
{
public const string WebApplication = "http://localhost:5000";

protected static RemoteWebDriver App => AppManager.WebApp;

[SetUp]
public void StartApp()
public void Initialize()
{
AppManager.StartApp(
this.StartApp(
new WebAppManagerOptions(WebAppDriverType.Edge, Path.Combine(Environment.CurrentDirectory, "Tools\\Edge"))
{
Maximize = true,
Expand All @@ -178,9 +240,9 @@ namespace MyWebApplication.UiTests
}

[TearDown]
public void StopApp()
public void Cleanup()
{
AppManager.StopApp();
this.StopApp();
}
}
}
Expand Down Expand Up @@ -216,7 +278,7 @@ namespace MyApplication.UiTests
using OpenQA.Selenium.Appium.Windows;
using OpenQA.Selenium.Remote;

public abstract class BaseTestClass
public abstract class BaseTestClass : LegerityTestClass
{
public const string AndroidApplication = "Tools\\Android\\com.made.sampleapp.apk";

Expand All @@ -225,36 +287,11 @@ namespace MyApplication.UiTests
public const string WindowsApplication = "com.madeapps.sampleapp_7mzr475ysvhxg!App";

protected BaseTestClass(AppManagerOptions options)
: base(options)
{
Options = options;
}

protected static RemoteWebDriver App => AppManager.App;

protected AppManagerOptions Options { get; }

[SetUp]
public void StartApp()
{
AppManager.StartApp(Options);
}

[TearDown]
public void StopApp()
{
AppManager.StopApp();
Options = null;
}
}

[TestFixtureSource(nameof(TestPlatformOptions))]
public class LoginPageTests : BaseTestClass
{
public LoginPageTests(AppManagerOptions options) : base(options)
{
}

static IEnumerable<AppManagerOptions> TestPlatformOptions => new List<AppManagerOptions>
protected static IEnumerable<AppManagerOptions> TestPlatformOptions => new List<AppManagerOptions>
{
new AndroidAppManagerOptions(Path.Combine(Environment.CurrentDirectory, AndroidApplication))
{
Expand All @@ -276,6 +313,26 @@ namespace MyApplication.UiTests
Maximize = true
}
};

[SetUp]
public void Initialize()
{
this.StartApp();
}

[TearDown]
public void Cleanup()
{
this.StopApp();
}
}

[TestFixtureSource(nameof(TestPlatformOptions))]
public class LoginPageTests : BaseTestClass
{
public LoginPageTests(AppManagerOptions options) : base(options)
{
}
}
}
```
30 changes: 25 additions & 5 deletions samples/W3SchoolsWebTests/BaseTestClass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,59 @@ namespace W3SchoolsWebTests
using Legerity;
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Remote;

public abstract class BaseTestClass : LegerityTestClass
{
/// <summary>
/// Initializes a new instance of the <see cref="BaseTestClass"/> class with application launch option.
/// </summary>
/// <param name="options">The application launch options.</param>
protected BaseTestClass(AppManagerOptions options) : base(options)
protected BaseTestClass(AppManagerOptions options)
: base(options)
{
}

public bool IsParallelized { get; set; } = false;

[SetUp]
public virtual void Initialize()
{
base.StartApp();
if (!this.IsParallelized)
{
this.StartApp();
}
}

public override RemoteWebDriver StartApp(
Func<IWebDriver, bool> waitUntil = default,
TimeSpan? waitUntilTimeout = default,
int waitUntilRetries = 0)
{
RemoteWebDriver app = base.StartApp(waitUntil, waitUntilTimeout, waitUntilRetries);

try
{
IWebElement closePopup = AppManager.WebApp.FindElement(By.Id("accept-choices"));
IWebElement closePopup = app.FindElement(By.Id("accept-choices"));
closePopup?.Click();
}
catch (Exception)
{
// Ignored.
}

AppManager.WebApp.SwitchTo().Frame("iframeResult");
app.SwitchTo().Frame("iframeResult");

return app;
}

[TearDown]
public virtual void Cleanup()
{
base.StopApp();
if (!this.IsParallelized)
{
base.StopApp();
}
}
}
}
5 changes: 3 additions & 2 deletions samples/W3SchoolsWebTests/Tests/ButtonTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ public class ButtonTests : BaseTestClass
{
private const string Url = "https://www.w3schools.com/tags/tryit.asp?filename=tryhtml_button_test";

public ButtonTests(AppManagerOptions options) : base(options)
public ButtonTests(AppManagerOptions options)
: base(options)
{
}

Expand All @@ -38,7 +39,7 @@ public ButtonTests(AppManagerOptions options) : base(options)
[Test]
public void ShouldClickButton()
{
Button button = AppManager.WebApp.FindElementByTagName("button") as RemoteWebElement;
Button button = this.App.FindElementByTagName("button") as RemoteWebElement;
button.Click();
}
}
Expand Down
Loading

0 comments on commit 73e0a81

Please sign in to comment.