mirror of
https://github.com/bitwarden/mobile
synced 2025-12-05 23:53:33 +00:00
Compare commits
6 Commits
feature/tr
...
uitests
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9cc1a501a5 | ||
|
|
b0a8694801 | ||
|
|
b9c1ab7c1d | ||
|
|
4d96b091f7 | ||
|
|
88fee155db | ||
|
|
f930028920 |
@@ -46,6 +46,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.ShareExtension", "src\i
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Autofill", "src\iOS.Autofill\iOS.Autofill.csproj", "{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UiTests", "src\UiTests\UiTests.csproj", "{23FB637B-1705-485F-9464-078FCAF361A8}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
|
||||
@@ -446,6 +448,36 @@ Global
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Release|iPhone.Build.0 = Release|iPhone
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.AppStore|Any CPU.Build.0 = Release|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.FDroid|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.FDroid|Any CPU.Build.0 = Release|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.FDroid|iPhone.ActiveCfg = Release|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.FDroid|iPhone.Build.0 = Release|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.FDroid|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.FDroid|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -464,6 +496,7 @@ Global
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0} = {8904C536-C67D-420F-9971-51B26574C3AA}
|
||||
{F8C3F648-EA5A-4719-8005-85D1690B1655} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
||||
{23FB637B-1705-485F-9464-078FCAF361A8} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {7D436EA3-8B7E-45D2-8D14-0730BD2E0410}
|
||||
|
||||
@@ -64,10 +64,10 @@ namespace Bit.Droid
|
||||
Intent?.Validate();
|
||||
|
||||
base.OnCreate(savedInstanceState);
|
||||
if (!CoreHelpers.InDebugMode())
|
||||
{
|
||||
Window.AddFlags(Android.Views.WindowManagerFlags.Secure);
|
||||
}
|
||||
//if (!CoreHelpers.InDebugMode())
|
||||
//{
|
||||
// Window.AddFlags(Android.Views.WindowManagerFlags.Secure);
|
||||
//}
|
||||
|
||||
#if !DEBUG && !FDROID
|
||||
var appCenterHelper = new AppCenterHelper(_appIdService, _stateService);
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
<ContentPage.ToolbarItems>
|
||||
<ToolbarItem Text="{u:I18n Cancel}" Clicked="Close_Clicked" Order="Primary" Priority="-1" />
|
||||
<ToolbarItem Text="{u:I18n Save}" Clicked="Submit_Clicked" />
|
||||
<ToolbarItem Text="{u:I18n Save}" Clicked="Submit_Clicked" AutomationId="save_button"/>
|
||||
</ContentPage.ToolbarItems>
|
||||
|
||||
<ScrollView>
|
||||
@@ -34,7 +34,8 @@
|
||||
Placeholder="ex. https://bitwarden.company.com"
|
||||
StyleClass="box-value"
|
||||
ReturnType="Go"
|
||||
ReturnCommand="{Binding SubmitCommand}" />
|
||||
ReturnCommand="{Binding SubmitCommand}"
|
||||
AutomationId="server_input"/>
|
||||
</StackLayout>
|
||||
<Label
|
||||
Text="{u:I18n SelfHostedEnvironmentFooter}"
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
Priority="-1"
|
||||
UseOriginalImage="True"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Account}" />
|
||||
AutomationProperties.Name="{u:I18n Account}"/>
|
||||
<ToolbarItem
|
||||
Icon="cog_environment.png" Clicked="Environment_Clicked" Order="Primary"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
@@ -37,15 +37,18 @@
|
||||
<Image
|
||||
x:Name="_logo"
|
||||
Source="logo.png"
|
||||
VerticalOptions="Center" />
|
||||
VerticalOptions="Center"
|
||||
AutomationId="logo_image"
|
||||
/>
|
||||
<Label Text="{u:I18n LoginOrCreateNewAccount}"
|
||||
StyleClass="text-lg"
|
||||
HorizontalTextAlignment="Center">
|
||||
</Label>
|
||||
HorizontalTextAlignment="Center"/>
|
||||
|
||||
<StackLayout Spacing="5">
|
||||
<Button Text="{u:I18n LogIn}"
|
||||
StyleClass="btn-primary"
|
||||
Clicked="LogIn_Clicked" />
|
||||
Clicked="LogIn_Clicked"
|
||||
AutomationId="homepage_login_button"/>
|
||||
<Button Text="{u:I18n CreateAccount}"
|
||||
Clicked="Register_Clicked" />
|
||||
<Button Text="{u:I18n LogInSso}"
|
||||
|
||||
@@ -56,7 +56,8 @@
|
||||
x:Name="_email"
|
||||
Text="{Binding Email}"
|
||||
Keyboard="Email"
|
||||
StyleClass="box-value">
|
||||
StyleClass="box-value"
|
||||
AutomationId="email_input">
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Disabled">
|
||||
@@ -92,7 +93,8 @@
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
ReturnType="Go"
|
||||
ReturnCommand="{Binding LogInCommand}" />
|
||||
ReturnCommand="{Binding LogInCommand}"
|
||||
AutomationId="password_input"/>
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding ShowPasswordIcon}"
|
||||
@@ -107,10 +109,12 @@
|
||||
<StackLayout Padding="10, 0">
|
||||
<Button Text="{u:I18n LogIn}"
|
||||
StyleClass="btn-primary"
|
||||
Clicked="LogIn_Clicked" />
|
||||
Clicked="LogIn_Clicked"
|
||||
AutomationId="loginpage_login_button"/>
|
||||
<Button Text="{u:I18n Cancel}"
|
||||
IsVisible="{Binding ShowCancelButton}"
|
||||
Clicked="Cancel_Clicked" />
|
||||
Clicked="Cancel_Clicked"
|
||||
AutomationId="cancel_button"/>
|
||||
</StackLayout>
|
||||
</StackLayout>
|
||||
</ScrollView>
|
||||
|
||||
@@ -70,6 +70,7 @@ namespace Bit.App.Pages
|
||||
VerticalOptions = LayoutOptions.CenterAndExpand,
|
||||
HorizontalOptions = LayoutOptions.Center,
|
||||
Color = ThemeManager.GetResourceColor("PrimaryColor"),
|
||||
AutomationId = "activity_indicator"
|
||||
};
|
||||
if (targetView != null)
|
||||
{
|
||||
|
||||
12
src/UiTests/Categories/SmokeTest.cs
Executable file
12
src/UiTests/Categories/SmokeTest.cs
Executable file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Bit.UITests.Categories
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
#pragma warning disable SA1649 // File name should match first type name
|
||||
public class SmokeTestAttribute : CategoryAttribute
|
||||
#pragma warning restore SA1649 // File name should match first type name
|
||||
{
|
||||
}
|
||||
}
|
||||
34
src/UiTests/Extensions/IAppExtension.cs
Normal file
34
src/UiTests/Extensions/IAppExtension.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using Xamarin.UITest;
|
||||
using Xamarin.UITest.Queries;
|
||||
|
||||
namespace Bit.UITests.Extensions
|
||||
{
|
||||
public static class IAppExtension
|
||||
{
|
||||
public static void Wait(this IApp app, float seconds)
|
||||
{
|
||||
var waitTime = DateTime.Now + TimeSpan.FromSeconds(seconds);
|
||||
|
||||
app.WaitFor(() => DateTime.Now > waitTime);
|
||||
}
|
||||
|
||||
public static void WaitAndTapElement(this IApp app, Func<AppQuery, AppQuery> elementQuery)
|
||||
{
|
||||
app.WaitForElement(elementQuery);
|
||||
app.Tap(elementQuery);
|
||||
}
|
||||
|
||||
public static void WaitAndTapElement(this IApp app, Func<AppQuery, AppWebQuery> elementQuery)
|
||||
{
|
||||
app.WaitForElement(elementQuery);
|
||||
app.Tap(elementQuery);
|
||||
}
|
||||
|
||||
public static void WaitAndScreenshot(this IApp app, string screenshotTitle)
|
||||
{
|
||||
app.Wait(1); //screenshots tend to be too fast and not capture the previous actions
|
||||
app.Screenshot(screenshotTitle);
|
||||
}
|
||||
}
|
||||
}
|
||||
14
src/UiTests/Helpers/AppState.cs
Normal file
14
src/UiTests/Helpers/AppState.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Xamarin.UITest;
|
||||
|
||||
namespace Bit.UITests.Helpers
|
||||
{
|
||||
public static class AppState
|
||||
{
|
||||
|
||||
public static void EnableScreenshots(this IApp app)
|
||||
{
|
||||
//TODO placeholder, mobile app needs the service / setting to enable Android screenshots first
|
||||
app.Invoke("Zamboni");
|
||||
}
|
||||
}
|
||||
}
|
||||
27
src/UiTests/Helpers/CustomWaitTimes.cs
Normal file
27
src/UiTests/Helpers/CustomWaitTimes.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using Xamarin.UITest.Utils;
|
||||
|
||||
namespace Bit.UITests.Helpers
|
||||
{
|
||||
public class CustomWaitTimes : IWaitTimes
|
||||
{
|
||||
private readonly TimeSpan _timeout;
|
||||
public static readonly TimeSpan DefaultCustomTimeout = TimeSpan.FromSeconds(10);
|
||||
|
||||
public CustomWaitTimes()
|
||||
{
|
||||
_timeout = DefaultCustomTimeout;
|
||||
}
|
||||
|
||||
public CustomWaitTimes(TimeSpan timeoutTimeSpan)
|
||||
{
|
||||
_timeout = timeoutTimeSpan;
|
||||
}
|
||||
|
||||
public TimeSpan GestureCompletionTimeout => _timeout;
|
||||
|
||||
public TimeSpan GestureWaitTimeout => _timeout;
|
||||
|
||||
public TimeSpan WaitForTimeout => _timeout;
|
||||
}
|
||||
}
|
||||
52
src/UiTests/Pages/Accounts/EnvironmentPage.cs
Normal file
52
src/UiTests/Pages/Accounts/EnvironmentPage.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using Bit.UITests.Extensions;
|
||||
using Bit.UITests.Setup;
|
||||
using Query = System.Func<Xamarin.UITest.Queries.AppQuery, Xamarin.UITest.Queries.AppQuery>;
|
||||
|
||||
namespace Bit.UITests.Pages.Accounts
|
||||
{
|
||||
public class EnvironmentPage : BasePage
|
||||
{
|
||||
private readonly Query _saveButton;
|
||||
private readonly Query _serverUrlInput;
|
||||
|
||||
public EnvironmentPage()
|
||||
: base()
|
||||
{
|
||||
if (OnAndroid)
|
||||
{
|
||||
_saveButton = x => x.Marked("save_button");
|
||||
_serverUrlInput = x => x.Marked("server_input");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (OniOS)
|
||||
{
|
||||
_saveButton = x => x.Marked("save_button");
|
||||
_serverUrlInput = x => x.Marked("server_input");
|
||||
}
|
||||
}
|
||||
|
||||
protected override PlatformQuery Trait => new PlatformQuery
|
||||
{
|
||||
Android = x => x.Marked("server_input"),
|
||||
iOS = x => x.Marked("server_input"),
|
||||
};
|
||||
|
||||
public EnvironmentPage TapSaveAndNavigate()
|
||||
{
|
||||
App.Tap(_saveButton);
|
||||
WaitForPageToLeave();
|
||||
return this;
|
||||
}
|
||||
|
||||
public EnvironmentPage InputServerUrl(string serverUrl)
|
||||
{
|
||||
App.ClearText(_serverUrlInput);
|
||||
App.EnterText(_serverUrlInput, serverUrl);
|
||||
App.DismissKeyboard();
|
||||
App.WaitAndScreenshot("After inserting the server url, I can see the field filled");
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
50
src/UiTests/Pages/Accounts/HomePage.cs
Normal file
50
src/UiTests/Pages/Accounts/HomePage.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using Bit.UITests.Setup;
|
||||
using Query = System.Func<Xamarin.UITest.Queries.AppQuery, Xamarin.UITest.Queries.AppQuery>;
|
||||
|
||||
namespace Bit.UITests.Pages.Accounts
|
||||
{
|
||||
public class HomePage : BasePage
|
||||
{
|
||||
private readonly Query _loginButton;
|
||||
private readonly Query _environmentButton;
|
||||
|
||||
public HomePage()
|
||||
: base()
|
||||
{
|
||||
if (OnAndroid)
|
||||
{
|
||||
_loginButton = x => x.Marked("homepage_login_button");
|
||||
|
||||
//TODO a11y uses the same fields as the UI tests and we're prioritising that
|
||||
// improve this by getting the app runtime locale and use the i18n service here instead
|
||||
_environmentButton = x => x.Marked("Options");
|
||||
//_environmentButton = x => x.Marked("environment_button");
|
||||
return;
|
||||
}
|
||||
|
||||
if (OniOS)
|
||||
{
|
||||
_loginButton = x => x.Marked("homepage_login_button");
|
||||
_environmentButton = x => x.Marked("Options");
|
||||
}
|
||||
}
|
||||
|
||||
protected override PlatformQuery Trait => new PlatformQuery
|
||||
{
|
||||
Android = x => x.Marked("logo_image"),
|
||||
iOS = x => x.Marked("logo_image"),
|
||||
};
|
||||
|
||||
public HomePage TapLoginAndNavigate()
|
||||
{
|
||||
App.Tap(_loginButton);
|
||||
return this;
|
||||
}
|
||||
|
||||
public HomePage TapEnvironmentAndNavigate()
|
||||
{
|
||||
App.Tap(_environmentButton);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
90
src/UiTests/Pages/Accounts/LoginPage.cs
Normal file
90
src/UiTests/Pages/Accounts/LoginPage.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
using System;
|
||||
using Bit.UITests.Extensions;
|
||||
using Bit.UITests.Setup;
|
||||
using Query = System.Func<Xamarin.UITest.Queries.AppQuery, Xamarin.UITest.Queries.AppQuery>;
|
||||
|
||||
namespace Bit.UITests.Pages.Accounts
|
||||
{
|
||||
public class LoginPage : BasePage
|
||||
{
|
||||
private readonly Query _loginButton;
|
||||
private readonly Query _cancelButton;
|
||||
private readonly Query _passwordVisibilityToggle;
|
||||
|
||||
private readonly Query _emailInput;
|
||||
private readonly Query _passwordInput;
|
||||
|
||||
|
||||
public LoginPage()
|
||||
: base()
|
||||
{
|
||||
if (OnAndroid)
|
||||
{
|
||||
_loginButton = x => x.Marked("loginpage_login_button");
|
||||
_cancelButton = x => x.Marked("cancel_button");
|
||||
|
||||
//TODO a11y uses the same fields as the UI tests and we're prioritising that
|
||||
// improve this by getting the app runtime locale and use the i18n service here instead
|
||||
_passwordVisibilityToggle = x => x.Marked("Toggle Visibility");
|
||||
|
||||
_emailInput = x => x.Marked("email_input");
|
||||
_passwordInput = x => x.Marked("password_input");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (OniOS)
|
||||
{
|
||||
_loginButton = x => x.Marked("loginpage_login_button");
|
||||
_cancelButton = x => x.Marked("cancel_button");
|
||||
_passwordVisibilityToggle = x => x.Marked("Toggle Visibility");
|
||||
|
||||
_emailInput = x => x.Marked("email_input");
|
||||
_passwordInput = x => x.Marked("password_input");
|
||||
}
|
||||
}
|
||||
|
||||
protected override PlatformQuery Trait => new PlatformQuery
|
||||
{
|
||||
Android = x => x.Marked("email_input"),
|
||||
iOS = x => x.Marked("email_input"),
|
||||
};
|
||||
|
||||
public LoginPage TapLoginAndNavigate()
|
||||
{
|
||||
App.Tap(_loginButton);
|
||||
return this;
|
||||
}
|
||||
|
||||
public LoginPage TapCancelAndNavigate()
|
||||
{
|
||||
App.Tap(_cancelButton);
|
||||
return this;
|
||||
}
|
||||
|
||||
public LoginPage TapPasswordVisibilityToggle()
|
||||
{
|
||||
App.Tap(_passwordVisibilityToggle);
|
||||
return this;
|
||||
}
|
||||
|
||||
public LoginPage InputEmail(string email)
|
||||
{
|
||||
App.ClearText(_emailInput);
|
||||
App.EnterText(_emailInput, email);
|
||||
App.DismissKeyboard();
|
||||
return this;
|
||||
}
|
||||
|
||||
public LoginPage InputPassword(string password)
|
||||
{
|
||||
App.Tap(_passwordInput);
|
||||
App.EnterText(password);
|
||||
App.DismissKeyboard();
|
||||
App.WaitAndScreenshot("After I input the email and password fields, I can see both fields filled");
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
55
src/UiTests/Pages/ExamplePage.cs
Normal file
55
src/UiTests/Pages/ExamplePage.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using Bit.UITests.Extensions;
|
||||
using Bit.UITests.Setup;
|
||||
using Query = System.Func<Xamarin.UITest.Queries.AppQuery, Xamarin.UITest.Queries.AppQuery>;
|
||||
|
||||
namespace Bit.UITests.Pages
|
||||
{
|
||||
public class ExamplePage : BasePage
|
||||
{
|
||||
private readonly Query _loginButton;
|
||||
private readonly Query _passwordInput;
|
||||
|
||||
public ExamplePage()
|
||||
: base()
|
||||
{
|
||||
if (OnAndroid)
|
||||
{
|
||||
_loginButton = x => x.Marked("loginpage_login_button");
|
||||
_passwordInput = x => x.Marked("password_input");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (OniOS)
|
||||
{
|
||||
_loginButton = x => x.Marked("loginpage_login_button");
|
||||
_passwordInput = x => x.Marked("password_input");
|
||||
}
|
||||
}
|
||||
|
||||
protected override PlatformQuery Trait => new PlatformQuery
|
||||
{
|
||||
Android = x => x.Marked("password_input"),
|
||||
iOS = x => x.Marked("password_input"),
|
||||
};
|
||||
|
||||
public ExamplePage TapLogin()
|
||||
{
|
||||
App.Tap(_loginButton);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ExamplePage InputPassword(string password)
|
||||
{
|
||||
App.Tap(_passwordInput);
|
||||
App.EnterText(password);
|
||||
App.DismissKeyboard();
|
||||
|
||||
App.WaitAndScreenshot("After I input the email and password fields, I can see both fields filled");
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
70
src/UiTests/Pages/TabsPage.cs
Normal file
70
src/UiTests/Pages/TabsPage.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using Bit.UITests.Extensions;
|
||||
using Bit.UITests.Helpers;
|
||||
using Bit.UITests.Setup;
|
||||
using Query = System.Func<Xamarin.UITest.Queries.AppQuery, Xamarin.UITest.Queries.AppQuery>;
|
||||
|
||||
namespace Bit.UITests.Pages
|
||||
{
|
||||
public class TabsPage : BasePage
|
||||
{
|
||||
private readonly Query _vaultTab;
|
||||
private readonly Query _sendTab;
|
||||
private readonly Query _accountSwitchingAvatar;
|
||||
private readonly Query _accountSwitchingAddAccount;
|
||||
|
||||
|
||||
public TabsPage()
|
||||
: base()
|
||||
{
|
||||
_vaultTab = x => x.Marked("My Vault");
|
||||
_sendTab = x => x.Marked("Send");
|
||||
_accountSwitchingAvatar = x => x.Marked("Account");
|
||||
_accountSwitchingAddAccount = x => x.Marked("Add Account");
|
||||
|
||||
WaitForNoLoader();
|
||||
}
|
||||
|
||||
protected override PlatformQuery Trait => new PlatformQuery
|
||||
{
|
||||
Android = x => x.Marked("Send"),
|
||||
iOS = x => x.Marked("Send"),
|
||||
};
|
||||
|
||||
public TabsPage WaitForNoLoader()
|
||||
{
|
||||
App.WaitForNoElement(LoadingIndicator, timeout: CustomWaitTimes.DefaultCustomTimeout);
|
||||
App.WaitAndScreenshot("Page finished loading");
|
||||
return this;
|
||||
}
|
||||
|
||||
public TabsPage TapAccountSwitchingAvatar()
|
||||
{
|
||||
App.WaitForElement(_accountSwitchingAvatar);
|
||||
App.Tap(_accountSwitchingAvatar);
|
||||
App.WaitAndScreenshot("Tapping the avatar, I can see the account switching panel");
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public TabsPage TapAccountSwitchingAddAccount()
|
||||
{
|
||||
App.Tap(_accountSwitchingAddAccount);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TabsPage TapVaultTab()
|
||||
{
|
||||
App.Tap(_vaultTab);
|
||||
App.WaitAndScreenshot("Tapping the Vault tab, I can see the Vault view");
|
||||
return this;
|
||||
}
|
||||
|
||||
public TabsPage TapSTab()
|
||||
{
|
||||
App.Tap(_sendTab);
|
||||
App.WaitAndScreenshot("Tapping the Send tab, I can see the Send view");
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
93
src/UiTests/Setup/AppManager.cs
Normal file
93
src/UiTests/Setup/AppManager.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Bit.UITests.Helpers;
|
||||
using Bit.UITests.Setup.SimulatorManager;
|
||||
using Xamarin.UITest;
|
||||
|
||||
namespace Bit.UITests.Setup
|
||||
{
|
||||
internal static class AppManager
|
||||
{
|
||||
private static readonly string _slnPath = GetSlnPath();
|
||||
|
||||
private const string AndroidPackageName = "com.x8bit.bitwarden";
|
||||
private const string IosBundleId = "com.x8bit.bitwarden";
|
||||
private static readonly string _apkPath = Path.Combine(_slnPath, "Android", "bin", "release", $"{AndroidPackageName}-Signed.apk");
|
||||
private static readonly string _iosPath = Path.Combine("..", "..", "..", $"{IosBundleId}.app");
|
||||
|
||||
private static IApp _app;
|
||||
|
||||
private static Platform? _platform;
|
||||
|
||||
public static IApp App
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_app == null)
|
||||
{
|
||||
throw new NullReferenceException("'AppManager.App' not set. Call 'AppManager.StartApp()' before trying to access it.");
|
||||
}
|
||||
|
||||
return _app;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static Platform Platform
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_platform == null)
|
||||
{
|
||||
throw new NullReferenceException("'AppManager.Platform' not set.");
|
||||
}
|
||||
|
||||
return _platform.Value;
|
||||
}
|
||||
|
||||
set => _platform = value;
|
||||
}
|
||||
|
||||
public static void StartApp()
|
||||
{
|
||||
Console.WriteLine($"TestEnvironment.IsTestCloud: {TestEnvironment.IsTestCloud}");
|
||||
Console.WriteLine($"TestEnvironment.Platform: {TestEnvironment.Platform}");
|
||||
Console.WriteLine($"Platform: {Platform}");
|
||||
|
||||
switch (Platform, TestEnvironment.IsTestCloud)
|
||||
{
|
||||
case (Platform.Android, false):
|
||||
_app = ConfigureApp
|
||||
.Android
|
||||
.InstalledApp(AndroidPackageName)
|
||||
//.ApkFile(_apkPath)
|
||||
.StartApp();
|
||||
break;
|
||||
case (Platform.iOS, false):
|
||||
_app = ConfigureApp
|
||||
.iOS
|
||||
.SetDeviceByName("iPhone X") //NOTE Get Devices name in terminal: xcrun instruments -s devices
|
||||
.AppBundle(_iosPath)
|
||||
// .InstalledApp(IosBundleId)
|
||||
.StartApp();
|
||||
break;
|
||||
case (Platform.Android, true):
|
||||
_app = ConfigureApp.Android.WaitTimes(new CustomWaitTimes()).StartApp();
|
||||
break;
|
||||
case (Platform.iOS, true):
|
||||
_app = ConfigureApp.iOS.WaitTimes(new CustomWaitTimes()).StartApp();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static string GetSlnPath()
|
||||
{
|
||||
string currentFile = new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath;
|
||||
var fi = new FileInfo(currentFile);
|
||||
string path = fi.Directory!.Parent!.Parent!.Parent!.FullName;
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
73
src/UiTests/Setup/BasePage.cs
Normal file
73
src/UiTests/Setup/BasePage.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using Bit.UITests.Extensions;
|
||||
using Bit.UITests.Helpers;
|
||||
using NUnit.Framework;
|
||||
using Xamarin.UITest;
|
||||
using Query = System.Func<Xamarin.UITest.Queries.AppQuery, Xamarin.UITest.Queries.AppQuery>;
|
||||
|
||||
namespace Bit.UITests.Setup
|
||||
{
|
||||
public abstract class BasePage
|
||||
{
|
||||
|
||||
protected BasePage()
|
||||
{
|
||||
AssertOnPage(CustomWaitTimes.DefaultCustomTimeout);
|
||||
App.Screenshot("On " + GetType().Name);
|
||||
}
|
||||
|
||||
protected readonly Query LoadingIndicator = x => x.Marked("activity_indicator");
|
||||
|
||||
protected IApp App => AppManager.App;
|
||||
|
||||
protected bool OnAndroid => AppManager.Platform == Platform.Android;
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
protected bool OniOS => AppManager.Platform == Platform.iOS;
|
||||
|
||||
protected abstract PlatformQuery Trait { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the trait is still present. Defaults to no wait.
|
||||
/// </summary>
|
||||
/// <param name="timeout">Time to wait before the assertion fails</param>
|
||||
public void AssertOnPage(TimeSpan? timeout = default(TimeSpan?))
|
||||
{
|
||||
var message = "Unable to verify on page: " + GetType().Name;
|
||||
|
||||
if (timeout == null)
|
||||
{
|
||||
Assert.IsNotEmpty(App.Query(Trait.Current), message);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.DoesNotThrow(() => App.WaitForElement(Trait.Current, timeout: timeout), message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the trait is no longer present. Defaults to a 5 second wait.
|
||||
/// </summary>
|
||||
/// <param name="timeout">Time to wait before the assertion fails</param>
|
||||
public void WaitForPageToLeave(TimeSpan? timeout = default(TimeSpan?))
|
||||
{
|
||||
timeout ??= TimeSpan.FromSeconds(5);
|
||||
var message = "Unable to verify *not* on page: " + GetType().Name;
|
||||
|
||||
Assert.DoesNotThrow(() => App.WaitForNoElement(Trait.Current, timeout: timeout), message);
|
||||
}
|
||||
|
||||
|
||||
public BasePage Wait(int seconds)
|
||||
{
|
||||
App.Wait(seconds);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BasePage Back()
|
||||
{
|
||||
App.Back();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
52
src/UiTests/Setup/BaseTestFixture.cs
Normal file
52
src/UiTests/Setup/BaseTestFixture.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using Bit.UITests.Helpers;
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using Xamarin.UITest;
|
||||
|
||||
namespace Bit.UITests.Setup
|
||||
{
|
||||
|
||||
[TestFixture(Platform.Android)]
|
||||
[TestFixture(Platform.iOS)]
|
||||
public abstract class BaseTestFixture
|
||||
{
|
||||
protected IApp App => AppManager.App;
|
||||
|
||||
protected bool OnAndroid => AppManager.Platform == Platform.Android;
|
||||
|
||||
protected bool OniOS => AppManager.Platform == Platform.iOS;
|
||||
|
||||
protected BaseTestFixture(Platform platform)
|
||||
{
|
||||
AppManager.Platform = platform;
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public virtual void BeforeEachTest()
|
||||
{
|
||||
AppManager.StartApp();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
if (TestContext.CurrentContext.Result.Outcome.Status != TestStatus.Failed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (App == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (TestEnvironment.Platform != TestPlatform.Local)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE uncomment to help debug failing tests
|
||||
//App.Repl();
|
||||
}
|
||||
}
|
||||
}
|
||||
9
src/UiTests/Setup/Csharp9Support.cs
Normal file
9
src/UiTests/Setup/Csharp9Support.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
// NOTE C# 9.0 support
|
||||
// https://stackoverflow.com/a/64749403/859738
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace System.Runtime.CompilerServices
|
||||
{
|
||||
#pragma warning disable SA1649 // File name should match first type name
|
||||
public class IsExternalInit { }
|
||||
#pragma warning restore SA1649 // File name should match first type name
|
||||
}
|
||||
39
src/UiTests/Setup/PlatformQuery.cs
Executable file
39
src/UiTests/Setup/PlatformQuery.cs
Executable file
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using Xamarin.UITest;
|
||||
using Xamarin.UITest.Queries;
|
||||
|
||||
namespace Bit.UITests.Setup
|
||||
{
|
||||
public class PlatformQuery
|
||||
{
|
||||
Func<AppQuery, AppQuery> _current;
|
||||
public Func<AppQuery, AppQuery> Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_current == null)
|
||||
throw new NullReferenceException("Trait not set for current platform");
|
||||
|
||||
return _current;
|
||||
}
|
||||
}
|
||||
|
||||
public Func<AppQuery, AppQuery> Android
|
||||
{
|
||||
set
|
||||
{
|
||||
if (AppManager.Platform == Platform.Android)
|
||||
_current = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Func<AppQuery, AppQuery> iOS
|
||||
{
|
||||
set
|
||||
{
|
||||
if (AppManager.Platform == Platform.iOS)
|
||||
_current = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
47
src/UiTests/Setup/SimulatorManager/InstrumentsRunner.cs
Executable file
47
src/UiTests/Setup/SimulatorManager/InstrumentsRunner.cs
Executable file
@@ -0,0 +1,47 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Bit.UITests.Setup.SimulatorManager
|
||||
{
|
||||
class InstrumentsRunner
|
||||
{
|
||||
static string[] GetInstrumentsOutput()
|
||||
{
|
||||
const string cmd = "/usr/bin/xcrun";
|
||||
|
||||
var startInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = cmd,
|
||||
Arguments = "instruments -s devices",
|
||||
RedirectStandardOutput = true,
|
||||
UseShellExecute = false
|
||||
};
|
||||
|
||||
var proc = new Process();
|
||||
proc.StartInfo = startInfo;
|
||||
proc.Start();
|
||||
var result = proc.StandardOutput.ReadToEnd();
|
||||
proc.WaitForExit();
|
||||
|
||||
var lines = result.Split('\n');
|
||||
return lines;
|
||||
}
|
||||
|
||||
public Simulator[] GetListOfSimulators()
|
||||
{
|
||||
var simulators = new List<Simulator>();
|
||||
var lines = GetInstrumentsOutput();
|
||||
|
||||
foreach (var line in lines)
|
||||
{
|
||||
var sim = new Simulator(line);
|
||||
if (sim.IsValid())
|
||||
{
|
||||
simulators.Add(sim);
|
||||
}
|
||||
}
|
||||
|
||||
return simulators.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
38
src/UiTests/Setup/SimulatorManager/IosSimulatorsManager.cs
Executable file
38
src/UiTests/Setup/SimulatorManager/IosSimulatorsManager.cs
Executable file
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Xamarin.UITest;
|
||||
using Xamarin.UITest.Configuration;
|
||||
|
||||
namespace Bit.UITests.Setup.SimulatorManager
|
||||
{
|
||||
internal static class IosSimulatorsManager
|
||||
{
|
||||
|
||||
public static iOSAppConfigurator SetDeviceByName(this iOSAppConfigurator configurator, string simulatorName)
|
||||
{
|
||||
var deviceId = GetDeviceId(simulatorName);
|
||||
return configurator.DeviceIdentifier(deviceId);
|
||||
}
|
||||
|
||||
public static string GetDeviceId(string simulatorName)
|
||||
{
|
||||
if (!TestEnvironment.Platform.Equals(TestPlatform.Local))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
// See below for the InstrumentsRunner class.
|
||||
IEnumerable<Simulator> simulators = new InstrumentsRunner().GetListOfSimulators();
|
||||
|
||||
var simulator = simulators.FirstOrDefault(x => x.Name.Contains(simulatorName));
|
||||
|
||||
if (simulator == null)
|
||||
{
|
||||
throw new ArgumentException("Could not find a device identifier for '" + simulatorName + "'.", "simulatorName");
|
||||
}
|
||||
|
||||
return simulator.GUID;
|
||||
}
|
||||
}
|
||||
}
|
||||
49
src/UiTests/Setup/SimulatorManager/Simulator.cs
Executable file
49
src/UiTests/Setup/SimulatorManager/Simulator.cs
Executable file
@@ -0,0 +1,49 @@
|
||||
namespace Bit.UITests.Setup.SimulatorManager
|
||||
{
|
||||
internal class Simulator
|
||||
{
|
||||
public Simulator(string line)
|
||||
{
|
||||
ParseLine(line);
|
||||
}
|
||||
|
||||
public string Line { get; private set; }
|
||||
|
||||
public string GUID { get; private set; }
|
||||
|
||||
public string Name { get; private set; }
|
||||
|
||||
public bool IsValid()
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(GUID) && !(string.IsNullOrWhiteSpace(Name));
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Line;
|
||||
}
|
||||
|
||||
void ParseLine(string line)
|
||||
{
|
||||
GUID = string.Empty;
|
||||
Name = string.Empty;
|
||||
Line = string.Empty;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Line = line.Trim();
|
||||
var idx1 = line.IndexOf(" [");
|
||||
|
||||
if (idx1 < 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Name = Line.Substring(0, idx1).Trim();
|
||||
GUID = Line.Substring(idx1 + 2, 36).Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
84
src/UiTests/Tests/LoginTests.cs
Normal file
84
src/UiTests/Tests/LoginTests.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using Bit.UITests.Categories;
|
||||
using Bit.UITests.Pages;
|
||||
using Bit.UITests.Pages.Accounts;
|
||||
using Bit.UITests.Setup;
|
||||
using NUnit.Framework;
|
||||
using Xamarin.UITest;
|
||||
|
||||
namespace Bit.UiTests.Tests
|
||||
{
|
||||
public class LoginTests : BaseTestFixture
|
||||
{
|
||||
record AccountCredentials(string ServerUrl, string Email, string Password);
|
||||
|
||||
private AccountCredentials[] _accounts =
|
||||
{
|
||||
new ("", "", ""),
|
||||
new ("", "", ""),
|
||||
new ("", "", ""),
|
||||
};
|
||||
|
||||
public LoginTests(Platform platform)
|
||||
: base(platform)
|
||||
{
|
||||
}
|
||||
|
||||
[Test]
|
||||
[SmokeTest]
|
||||
public void WaitForAppToLoad()
|
||||
{
|
||||
new HomePage();
|
||||
|
||||
App.Screenshot("App loaded with success!");
|
||||
}
|
||||
|
||||
//[Test]
|
||||
public void LoginWithSuccess()
|
||||
{
|
||||
Login(_accounts[0]);
|
||||
new TabsPage();
|
||||
App.Repl();
|
||||
|
||||
App.Screenshot("After logging in with success, I can see the vault");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AccountSwitchWithSuccess()
|
||||
{
|
||||
Login(_accounts[0], true);
|
||||
new TabsPage()
|
||||
.TapAccountSwitchingAvatar()
|
||||
.TapAccountSwitchingAddAccount();
|
||||
|
||||
Login(_accounts[1]);
|
||||
new TabsPage()
|
||||
.TapAccountSwitchingAvatar()
|
||||
.TapAccountSwitchingAddAccount();
|
||||
|
||||
Login(_accounts[2]);
|
||||
|
||||
new TabsPage()
|
||||
.TapAccountSwitchingAvatar();
|
||||
}
|
||||
|
||||
private void Login(AccountCredentials account, bool changeEnvironment = false)
|
||||
{
|
||||
if (changeEnvironment)
|
||||
{
|
||||
new HomePage()
|
||||
.TapEnvironmentAndNavigate();
|
||||
new EnvironmentPage()
|
||||
.InputServerUrl(account.ServerUrl)
|
||||
.TapSaveAndNavigate();
|
||||
}
|
||||
|
||||
new HomePage()
|
||||
.TapLoginAndNavigate();
|
||||
|
||||
new LoginPage()
|
||||
.InputEmail(account.Email)
|
||||
.InputPassword(account.Password)
|
||||
.TapLoginAndNavigate();
|
||||
}
|
||||
}
|
||||
}
|
||||
59
src/UiTests/UiTests.csproj
Normal file
59
src/UiTests/UiTests.csproj
Normal file
@@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{23FB637B-1705-485F-9464-078FCAF361A8}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>Bit.UiTests</RootNamespace>
|
||||
<AssemblyName>UiTests</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile />
|
||||
<LangVersion>9.0</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
<PackageReference Include="Xamarin.UITest" Version="3.2.6" />
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Categories\SmokeTest.cs" />
|
||||
<Compile Include="Extensions\IAppExtension.cs" />
|
||||
<Compile Include="Setup\SimulatorManager\InstrumentsRunner.cs" />
|
||||
<Compile Include="Setup\SimulatorManager\IosSimulatorsManager.cs" />
|
||||
<Compile Include="Setup\SimulatorManager\Simulator.cs" />
|
||||
<Compile Include="Setup\AppManager.cs" />
|
||||
<Compile Include="Setup\BasePage.cs" />
|
||||
<Compile Include="Setup\BaseTestFixture.cs" />
|
||||
<Compile Include="Setup\Csharp9Support.cs" />
|
||||
<Compile Include="Setup\PlatformQuery.cs" />
|
||||
<Compile Include="Helpers\CustomWaitTimes.cs" />
|
||||
<Compile Include="Helpers\AppState.cs" />
|
||||
<Compile Include="Tests\LoginTests.cs" />
|
||||
<Compile Include="Pages\Accounts\EnvironmentPage.cs" />
|
||||
<Compile Include="Pages\Accounts\HomePage.cs" />
|
||||
<Compile Include="Pages\Accounts\LoginPage.cs" />
|
||||
<Compile Include="Pages\TabsPage.cs" />
|
||||
<Compile Include="Pages\ExamplePage.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
Reference in New Issue
Block a user