Skip to content

Commit 73e0a81

Browse files
authored
Merge pull request #141 from MADE-Apps/feature/appmanager-decoupling
Decoupled the AppManager from other Legerity components
2 parents 7b11368 + dd081f6 commit 73e0a81

39 files changed

+905
-244
lines changed

docs/articles/building-with-legerity.md

Lines changed: 107 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -49,22 +49,23 @@ namespace MyWindowsApplication.UiTests
4949

5050
using Legerity;
5151
using Legerity.Windows;
52+
using Legerity.Windows.Extensions;
5253

5354
using NUnit.Framework;
5455

5556
using OpenQA.Selenium.Appium.Windows;
5657
using OpenQA.Selenium.Remote;
5758

58-
public abstract class BaseTestClass
59+
public abstract class BaseTestClass : LegerityTestClass
5960
{
6061
public const string WindowsApplication = "com.madeapps.sampleapp_7mzr475ysvhxg!App";
6162

62-
protected static WindowsDriver<WindowsElement> App => AppManager.WindowsApp;
63+
protected WindowsDriver<WindowsElement> WindowsApp { get; private set; }
6364

6465
[SetUp]
65-
public void StartApp()
66+
public void Initialize()
6667
{
67-
AppManager.StartApp(
68+
WindowsApp = this.StartWindowsApp(
6869
new WindowsAppManagerOptions(WindowsApplication)
6970
{
7071
DriverUri = "http://127.0.0.1:4723",
@@ -74,17 +75,17 @@ namespace MyWindowsApplication.UiTests
7475
}
7576

7677
[TearDown]
77-
public void StopApp()
78+
public void Cleanup()
7879
{
79-
AppManager.StopApp();
80+
StopApp(WindowsApp);
8081
}
8182
}
8283
}
8384
```
8485

8586
### Example base test class for an Android application
8687

87-
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.
88+
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.
8889

8990
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.
9091

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

102103
using Legerity;
103104
using Legerity.Android;
105+
using Legerity.Android.Extensions;
104106

105107
using NUnit.Framework;
106108

107109
using OpenQA.Selenium.Appium.Android;
108110
using OpenQA.Selenium.Remote;
109111

110-
public abstract class BaseTestClass
112+
public abstract class BaseTestClass : LegerityTestClass
111113
{
112-
public const string AndroidApplication = "Tools\\Android\\com.made.sampleapp.apk";
114+
public const string AndroidApplication = "com.made.sampleapp";
115+
116+
public const string AndroidApplicationActivity = $"{AndroidApplication}.MainActivity";
113117

114-
protected static AndroidDriver<AndroidElement> App => AppManager.AndroidApp;
118+
protected AndroidDriver<AndroidElement> AndroidApp { get; private set; }
115119

116120
[SetUp]
117-
public void StartApp()
121+
public void Initialize()
118122
{
119-
AppManager.StartApp(
120-
new AndroidAppManagerOptions(Path.Combine(Environment.CurrentDirectory, AndroidApplication))
123+
AndroidApp = this.StartAndroidApp(
124+
new AndroidAppManagerOptions
121125
{
126+
AppId = AndroidApplication,
127+
AppActivity = AndroidApplicationActivity,
122128
LaunchAppiumServer = true,
123129
DriverUri = "http://localhost:4723/wd/hub"
124130
});
125131
}
126132

127133
[TearDown]
128-
public void StopApp()
134+
public void Cleanup()
129135
{
130-
AppManager.StopApp();
136+
StopApp(AndroidApp);
137+
}
138+
}
139+
}
140+
```
141+
142+
### Example base test class for an iOS application
143+
144+
This example showcases how to start your iOS application using the ID of an app that is already installed on a device.
145+
146+
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.
147+
148+
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.
149+
150+
```csharp
151+
namespace MyIOSApplication.UiTests
152+
{
153+
using System;
154+
using System.Collections.Generic;
155+
using System.IO;
156+
using System.Linq;
157+
using System.Threading.Tasks;
158+
159+
using Legerity;
160+
using Legerity.IOS;
161+
using Legerity.IOS.Extensions;
162+
163+
using NUnit.Framework;
164+
165+
using OpenQA.Selenium.Appium.IOS;
166+
using OpenQA.Selenium.Remote;
167+
168+
public abstract class BaseTestClass : LegerityTestClass
169+
{
170+
public const string IOSApplication = "com.made.sampleapp";
171+
172+
protected IOSDriver<IOSElement> IOSApp { get; private set; }
173+
174+
[SetUp]
175+
public void Initialize()
176+
{
177+
IOSApp = this.StartIOSApp(
178+
new IOSAppManagerOptions
179+
{
180+
AppId = IOSApplication,
181+
DeviceName = "iPhone SE (3rd generation) Simulator",
182+
DeviceId = "56755E6F-741B-478F-BB1B-A48E05ACFE8A",
183+
OSVersion = "15.4",
184+
LaunchAppiumServer = true,
185+
DriverUri = "http://localhost:4723/wd/hub"
186+
});
187+
}
188+
189+
[TearDown]
190+
public void Cleanup()
191+
{
192+
StopApp(IOSApp);
131193
}
132194
}
133195
}
@@ -137,6 +199,8 @@ namespace MyAndroidApplication.UiTests
137199

138200
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/).
139201

202+
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.
203+
140204
When your tests start, the web browser will launch the URL provided to begin running the test scenarios.
141205

142206
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.
@@ -159,16 +223,14 @@ namespace MyWebApplication.UiTests
159223

160224
using OpenQA.Selenium.Remote;
161225

162-
public abstract class BaseTestClass
226+
public abstract class BaseTestClass : LegerityTestClass
163227
{
164228
public const string WebApplication = "http://localhost:5000";
165229

166-
protected static RemoteWebDriver App => AppManager.WebApp;
167-
168230
[SetUp]
169-
public void StartApp()
231+
public void Initialize()
170232
{
171-
AppManager.StartApp(
233+
this.StartApp(
172234
new WebAppManagerOptions(WebAppDriverType.Edge, Path.Combine(Environment.CurrentDirectory, "Tools\\Edge"))
173235
{
174236
Maximize = true,
@@ -178,9 +240,9 @@ namespace MyWebApplication.UiTests
178240
}
179241

180242
[TearDown]
181-
public void StopApp()
243+
public void Cleanup()
182244
{
183-
AppManager.StopApp();
245+
this.StopApp();
184246
}
185247
}
186248
}
@@ -216,7 +278,7 @@ namespace MyApplication.UiTests
216278
using OpenQA.Selenium.Appium.Windows;
217279
using OpenQA.Selenium.Remote;
218280

219-
public abstract class BaseTestClass
281+
public abstract class BaseTestClass : LegerityTestClass
220282
{
221283
public const string AndroidApplication = "Tools\\Android\\com.made.sampleapp.apk";
222284

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

227289
protected BaseTestClass(AppManagerOptions options)
290+
: base(options)
228291
{
229-
Options = options;
230-
}
231-
232-
protected static RemoteWebDriver App => AppManager.App;
233-
234-
protected AppManagerOptions Options { get; }
235-
236-
[SetUp]
237-
public void StartApp()
238-
{
239-
AppManager.StartApp(Options);
240292
}
241293

242-
[TearDown]
243-
public void StopApp()
244-
{
245-
AppManager.StopApp();
246-
Options = null;
247-
}
248-
}
249-
250-
[TestFixtureSource(nameof(TestPlatformOptions))]
251-
public class LoginPageTests : BaseTestClass
252-
{
253-
public LoginPageTests(AppManagerOptions options) : base(options)
254-
{
255-
}
256-
257-
static IEnumerable<AppManagerOptions> TestPlatformOptions => new List<AppManagerOptions>
294+
protected static IEnumerable<AppManagerOptions> TestPlatformOptions => new List<AppManagerOptions>
258295
{
259296
new AndroidAppManagerOptions(Path.Combine(Environment.CurrentDirectory, AndroidApplication))
260297
{
@@ -276,6 +313,26 @@ namespace MyApplication.UiTests
276313
Maximize = true
277314
}
278315
};
316+
317+
[SetUp]
318+
public void Initialize()
319+
{
320+
this.StartApp();
321+
}
322+
323+
[TearDown]
324+
public void Cleanup()
325+
{
326+
this.StopApp();
327+
}
328+
}
329+
330+
[TestFixtureSource(nameof(TestPlatformOptions))]
331+
public class LoginPageTests : BaseTestClass
332+
{
333+
public LoginPageTests(AppManagerOptions options) : base(options)
334+
{
335+
}
279336
}
280337
}
281338
```

samples/W3SchoolsWebTests/BaseTestClass.cs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,39 +4,59 @@ namespace W3SchoolsWebTests
44
using Legerity;
55
using NUnit.Framework;
66
using OpenQA.Selenium;
7+
using OpenQA.Selenium.Remote;
78

89
public abstract class BaseTestClass : LegerityTestClass
910
{
1011
/// <summary>
1112
/// Initializes a new instance of the <see cref="BaseTestClass"/> class with application launch option.
1213
/// </summary>
1314
/// <param name="options">The application launch options.</param>
14-
protected BaseTestClass(AppManagerOptions options) : base(options)
15+
protected BaseTestClass(AppManagerOptions options)
16+
: base(options)
1517
{
1618
}
1719

20+
public bool IsParallelized { get; set; } = false;
21+
1822
[SetUp]
1923
public virtual void Initialize()
2024
{
21-
base.StartApp();
25+
if (!this.IsParallelized)
26+
{
27+
this.StartApp();
28+
}
29+
}
30+
31+
public override RemoteWebDriver StartApp(
32+
Func<IWebDriver, bool> waitUntil = default,
33+
TimeSpan? waitUntilTimeout = default,
34+
int waitUntilRetries = 0)
35+
{
36+
RemoteWebDriver app = base.StartApp(waitUntil, waitUntilTimeout, waitUntilRetries);
2237

2338
try
2439
{
25-
IWebElement closePopup = AppManager.WebApp.FindElement(By.Id("accept-choices"));
40+
IWebElement closePopup = app.FindElement(By.Id("accept-choices"));
2641
closePopup?.Click();
2742
}
2843
catch (Exception)
2944
{
3045
// Ignored.
3146
}
3247

33-
AppManager.WebApp.SwitchTo().Frame("iframeResult");
48+
app.SwitchTo().Frame("iframeResult");
49+
50+
return app;
3451
}
3552

3653
[TearDown]
3754
public virtual void Cleanup()
3855
{
39-
base.StopApp();
56+
if (!this.IsParallelized)
57+
{
58+
base.StopApp();
59+
}
4060
}
4161
}
4262
}

samples/W3SchoolsWebTests/Tests/ButtonTests.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ public class ButtonTests : BaseTestClass
1515
{
1616
private const string Url = "https://www.w3schools.com/tags/tryit.asp?filename=tryhtml_button_test";
1717

18-
public ButtonTests(AppManagerOptions options) : base(options)
18+
public ButtonTests(AppManagerOptions options)
19+
: base(options)
1920
{
2021
}
2122

@@ -38,7 +39,7 @@ public ButtonTests(AppManagerOptions options) : base(options)
3839
[Test]
3940
public void ShouldClickButton()
4041
{
41-
Button button = AppManager.WebApp.FindElementByTagName("button") as RemoteWebElement;
42+
Button button = this.App.FindElementByTagName("button") as RemoteWebElement;
4243
button.Click();
4344
}
4445
}

0 commit comments

Comments
 (0)