diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Droid/packages.config b/src/Mobile/eShopOnContainers/eShopOnContainers.Droid/packages.config
new file mode 100644
index 000000000..5400a56d7
--- /dev/null
+++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Droid/packages.config
@@ -0,0 +1,96 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.Droid/MainApplication.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.Droid/MainApplication.cs
new file mode 100644
index 000000000..770fedc82
--- /dev/null
+++ b/src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.Droid/MainApplication.cs
@@ -0,0 +1,63 @@
+using System;
+
+using Android.App;
+using Android.OS;
+using Android.Runtime;
+using Plugin.CurrentActivity;
+
+namespace eShopOnContainers.TestRunner.Droid
+{
+ //You can specify additional application information in this attribute
+ [Application]
+ public class MainApplication : Application, Application.IActivityLifecycleCallbacks
+ {
+ public MainApplication(IntPtr handle, JniHandleOwnership transer)
+ :base(handle, transer)
+ {
+ }
+
+ public override void OnCreate()
+ {
+ base.OnCreate();
+ RegisterActivityLifecycleCallbacks(this);
+ //A great place to initialize Xamarin.Insights and Dependency Services!
+ }
+
+ public override void OnTerminate()
+ {
+ base.OnTerminate();
+ UnregisterActivityLifecycleCallbacks(this);
+ }
+
+ public void OnActivityCreated(Activity activity, Bundle savedInstanceState)
+ {
+ CrossCurrentActivity.Current.Activity = activity;
+ }
+
+ public void OnActivityDestroyed(Activity activity)
+ {
+ }
+
+ public void OnActivityPaused(Activity activity)
+ {
+ }
+
+ public void OnActivityResumed(Activity activity)
+ {
+ CrossCurrentActivity.Current.Activity = activity;
+ }
+
+ public void OnActivitySaveInstanceState(Activity activity, Bundle outState)
+ {
+ }
+
+ public void OnActivityStarted(Activity activity)
+ {
+ CrossCurrentActivity.Current.Activity = activity;
+ }
+
+ public void OnActivityStopped(Activity activity)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.Droid/packages.config b/src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.Droid/packages.config
new file mode 100644
index 000000000..bd9ce845c
--- /dev/null
+++ b/src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.Droid/packages.config
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.iOS/packages.config b/src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.iOS/packages.config
new file mode 100644
index 000000000..7ca4e6aa9
--- /dev/null
+++ b/src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.iOS/packages.config
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/Behaviors/EventToCommandBehaviorTests.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/Behaviors/EventToCommandBehaviorTests.cs
new file mode 100644
index 000000000..ce6ce8f96
--- /dev/null
+++ b/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/Behaviors/EventToCommandBehaviorTests.cs
@@ -0,0 +1,120 @@
+using Xunit;
+using Xamarin.Forms;
+using System;
+using System.Globalization;
+
+namespace eShopOnContainers.UnitTests
+{
+ public class EventToCommandBehaviorTests
+ {
+ [Fact]
+ public void InvalidEventNameShouldThrowArgumentExceptionText()
+ {
+ var behavior = new MockEventToCommandBehavior
+ {
+ EventName = "OnItemTapped"
+ };
+ var listView = new ListView();
+
+ Assert.Throws(() => listView.Behaviors.Add(behavior));
+ }
+
+ [Fact]
+ public void CommandExecutedWhenEventFiresText()
+ {
+ bool executedCommand = false;
+ var behavior = new MockEventToCommandBehavior
+ {
+ EventName = "ItemTapped",
+ Command = new Command(() =>
+ {
+ executedCommand = true;
+ })
+ };
+ var listView = new ListView();
+ listView.Behaviors.Add(behavior);
+
+ behavior.RaiseEvent(listView, null);
+
+ Assert.True(executedCommand);
+ }
+
+ [Fact]
+ public void CommandCanExecuteTest()
+ {
+ var behavior = new MockEventToCommandBehavior
+ {
+ EventName = "ItemTapped",
+ Command = new Command(() => Assert.True(false), () => false)
+ };
+ var listView = new ListView();
+ listView.Behaviors.Add(behavior);
+
+ behavior.RaiseEvent(listView, null);
+ }
+
+ [Fact]
+ public void CommandCanExecuteWithParameterShouldNotExecuteTest()
+ {
+ bool shouldExecute = false;
+ var behavior = new MockEventToCommandBehavior
+ {
+ EventName = "ItemTapped",
+ CommandParameter = shouldExecute,
+ Command = new Command(o => Assert.True(false), o => o.Equals(true))
+ };
+ var listView = new ListView();
+ listView.Behaviors.Add(behavior);
+
+ behavior.RaiseEvent(listView, null);
+ }
+
+ [Fact]
+ public void CommandWithConverterTest()
+ {
+ const string item = "ItemProperty";
+ bool executedCommand = false;
+ var behavior = new MockEventToCommandBehavior
+ {
+ EventName = "ItemTapped",
+ EventArgsConverter = new ItemTappedEventArgsConverter(false),
+ Command = new Command(o =>
+ {
+ executedCommand = true;
+ Assert.NotNull(o);
+ Assert.Equal(item, o);
+ })
+ };
+ var listView = new ListView();
+ listView.Behaviors.Add(behavior);
+
+ behavior.RaiseEvent(listView, new ItemTappedEventArgs(listView, item));
+
+ Assert.True(executedCommand);
+ }
+
+ private class ItemTappedEventArgsConverter : IValueConverter
+ {
+ private readonly bool _returnParameter;
+
+ public bool HasConverted { get; private set; }
+
+ public ItemTappedEventArgsConverter(bool returnParameter)
+ {
+ _returnParameter = returnParameter;
+ }
+
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ HasConverted = true;
+ return _returnParameter ? parameter : (value as ItemTappedEventArgs)?.Item;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+ }
+
+}
diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/Mocks/MockViewModel.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/Mocks/MockViewModel.cs
new file mode 100644
index 000000000..64acab458
--- /dev/null
+++ b/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/Mocks/MockViewModel.cs
@@ -0,0 +1,53 @@
+using eShopOnContainers.Core.ViewModels.Base;
+using eShopOnContainers.Core.Validations;
+
+namespace eShopOnContainers.UnitTests
+{
+ public class MockViewModel : ViewModelBase
+ {
+ private ValidatableObject _forename;
+ private ValidatableObject _surname;
+
+ public ValidatableObject Forename
+ {
+ get
+ {
+ return _forename;
+ }
+ set
+ {
+ _forename = value;
+ RaisePropertyChanged(() => Forename);
+ }
+ }
+
+ public ValidatableObject Surname
+ {
+ get
+ {
+ return _surname;
+ }
+ set
+ {
+ _surname = value;
+ RaisePropertyChanged(() => Surname);
+ }
+ }
+
+ public MockViewModel()
+ {
+ _forename = new ValidatableObject();
+ _surname = new ValidatableObject();
+
+ _forename.Validations.Add(new IsNotNullOrEmptyRule { ValidationMessage = "Forename is required." });
+ _surname.Validations.Add(new IsNotNullOrEmptyRule { ValidationMessage = "Surname name is required." });
+ }
+
+ public bool Validate()
+ {
+ bool isValidForename = _forename.Validate();
+ bool isValidSurname = _surname.Validate();
+ return isValidForename && isValidSurname;
+ }
+ }
+}
diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/Services/BasketServiceTests.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/Services/BasketServiceTests.cs
new file mode 100644
index 000000000..a14ce5ee0
--- /dev/null
+++ b/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/Services/BasketServiceTests.cs
@@ -0,0 +1,17 @@
+using eShopOnContainers.Core.Services.Catalog;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace eShopOnContainers.UnitTests
+{
+ public class BasketServiceTests
+ {
+ [Fact]
+ public async Task GetFakeBasketTest()
+ {
+ var catalogMockService = new CatalogMockService();
+ var result = await catalogMockService.GetCatalogAsync();
+ Assert.NotEqual(0, result.Count);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/Services/CatalogServiceTests.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/Services/CatalogServiceTests.cs
new file mode 100644
index 000000000..75045d36b
--- /dev/null
+++ b/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/Services/CatalogServiceTests.cs
@@ -0,0 +1,36 @@
+using eShopOnContainers.Core.Services.Catalog;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace eShopOnContainers.UnitTests
+{
+ public class CatalogServiceTests
+ {
+ [Fact]
+ public async Task GetFakeCatalogTest()
+ {
+ var catalogMockService = new CatalogMockService();
+ var catalog = await catalogMockService.GetCatalogAsync();
+
+ Assert.NotEqual(0, catalog.Count);
+ }
+
+ [Fact]
+ public async Task GetFakeCatalogBrandTest()
+ {
+ var catalogMockService = new CatalogMockService();
+ var catalogBrand = await catalogMockService.GetCatalogBrandAsync();
+
+ Assert.NotEqual(0, catalogBrand.Count);
+ }
+
+ [Fact]
+ public async Task GetFakeCatalogTypeTest()
+ {
+ var catalogMockService = new CatalogMockService();
+ var catalogType = await catalogMockService.GetCatalogTypeAsync();
+
+ Assert.NotEqual(0, catalogType.Count);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/Services/MarketingServiceTests.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/Services/MarketingServiceTests.cs
new file mode 100644
index 000000000..14f3bf4cc
--- /dev/null
+++ b/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/Services/MarketingServiceTests.cs
@@ -0,0 +1,29 @@
+namespace eShopOnContainers.UnitTests.Services
+{
+ using System.Threading.Tasks;
+ using Core;
+ using Core.Helpers;
+ using Core.Services.Marketing;
+ using Xunit;
+
+ public class MarketingServiceTests
+ {
+ [Fact]
+ public async Task GetFakeCampaigTest()
+ {
+ var campaignMockService = new CampaignMockService();
+ var order = await campaignMockService.GetCampaignByIdAsync(1, GlobalSetting.Instance.AuthToken);
+
+ Assert.NotNull(order);
+ }
+
+ [Fact]
+ public async Task GetFakeCampaignsTest()
+ {
+ var campaignMockService = new CampaignMockService();
+ var result = await campaignMockService.GetAllCampaignsAsync(GlobalSetting.Instance.AuthToken);
+
+ Assert.NotEqual(0, result.Count);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/Services/OrdersServiceTests.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/Services/OrdersServiceTests.cs
new file mode 100644
index 000000000..f8411ef6f
--- /dev/null
+++ b/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/Services/OrdersServiceTests.cs
@@ -0,0 +1,28 @@
+using eShopOnContainers.Core;
+using eShopOnContainers.Core.Services.Order;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace eShopOnContainers.UnitTests
+{
+ public class OrdersServiceTests
+ {
+ [Fact]
+ public async Task GetFakeOrderTest()
+ {
+ var ordersMockService = new OrderMockService();
+ var order = await ordersMockService.GetOrderAsync(1, GlobalSetting.Instance.AuthToken);
+
+ Assert.NotNull(order);
+ }
+
+ [Fact]
+ public async Task GetFakeOrdersTest()
+ {
+ var ordersMockService = new OrderMockService();
+ var result = await ordersMockService.GetOrdersAsync(GlobalSetting.Instance.AuthToken);
+
+ Assert.NotEqual(0, result.Count);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/ViewModels/CatalogViewModelTests.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/ViewModels/CatalogViewModelTests.cs
new file mode 100644
index 000000000..d50f8f646
--- /dev/null
+++ b/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/ViewModels/CatalogViewModelTests.cs
@@ -0,0 +1,223 @@
+using Xunit;
+using eShopOnContainers.Core.ViewModels;
+using eShopOnContainers.Core.ViewModels.Base;
+using eShopOnContainers.Core.Services.Catalog;
+using eShopOnContainers.Core.Models.Catalog;
+using System.Threading.Tasks;
+using System.Linq;
+
+namespace eShopOnContainers.UnitTests
+{
+ public class CatalogViewModelTests
+ {
+ public CatalogViewModelTests()
+ {
+ ViewModelLocator.RegisterDependencies(true);
+ }
+
+ [Fact]
+ public void AddCatalogItemCommandIsNotNullTest()
+ {
+ var catalogService = new CatalogMockService();
+ var catalogViewModel = new CatalogViewModel(catalogService);
+ Assert.NotNull(catalogViewModel.AddCatalogItemCommand);
+ }
+
+ [Fact]
+ public void FilterCommandIsNotNullTest()
+ {
+ var catalogService = new CatalogMockService();
+ var catalogViewModel = new CatalogViewModel(catalogService);
+ Assert.NotNull(catalogViewModel.FilterCommand);
+ }
+
+ [Fact]
+ public void ClearFilterCommandIsNotNullTest()
+ {
+ var catalogService = new CatalogMockService();
+ var catalogViewModel = new CatalogViewModel(catalogService);
+ Assert.NotNull(catalogViewModel.ClearFilterCommand);
+ }
+
+ [Fact]
+ public void ProductsPropertyIsNullWhenViewModelInstantiatedTest()
+ {
+ var catalogService = new CatalogMockService();
+ var catalogViewModel = new CatalogViewModel(catalogService);
+ Assert.Null(catalogViewModel.Products);
+ }
+
+ [Fact]
+ public void BrandsPropertyuIsNullWhenViewModelInstantiatedTest()
+ {
+ var catalogService = new CatalogMockService();
+ var catalogViewModel = new CatalogViewModel(catalogService);
+ Assert.Null(catalogViewModel.Brands);
+ }
+
+ [Fact]
+ public void BrandPropertyIsNullWhenViewModelInstantiatedTest()
+ {
+ var catalogService = new CatalogMockService();
+ var catalogViewModel = new CatalogViewModel(catalogService);
+ Assert.Null(catalogViewModel.Brand);
+ }
+
+ [Fact]
+ public void TypesPropertyIsNullWhenViewModelInstantiatedTest()
+ {
+ var catalogService = new CatalogMockService();
+ var catalogViewModel = new CatalogViewModel(catalogService);
+ Assert.Null(catalogViewModel.Types);
+ }
+
+ [Fact]
+ public void TypePropertyIsNullWhenViewModelInstantiatedTest()
+ {
+ var catalogService = new CatalogMockService();
+ var catalogViewModel = new CatalogViewModel(catalogService);
+ Assert.Null(catalogViewModel.Type);
+ }
+
+ [Fact]
+ public void IsFilterPropertyIsFalseWhenViewModelInstantiatedTest()
+ {
+ var catalogService = new CatalogMockService();
+ var catalogViewModel = new CatalogViewModel(catalogService);
+ Assert.False(catalogViewModel.IsFilter);
+ }
+
+ [Fact]
+ public async Task ProductsPropertyIsNotNullAfterViewModelInitializationTest()
+ {
+ var catalogService = new CatalogMockService();
+ var catalogViewModel = new CatalogViewModel(catalogService);
+
+ await catalogViewModel.InitializeAsync(null);
+
+ Assert.NotNull(catalogViewModel.Products);
+ }
+
+ [Fact]
+ public async Task BrandsPropertyIsNotNullAfterViewModelInitializationTest()
+ {
+ var catalogService = new CatalogMockService();
+ var catalogViewModel = new CatalogViewModel(catalogService);
+
+ await catalogViewModel.InitializeAsync(null);
+
+ Assert.NotNull(catalogViewModel.Brands);
+ }
+
+ [Fact]
+ public async Task TypesPropertyIsNotNullAfterViewModelInitializationTest()
+ {
+ var catalogService = new CatalogMockService();
+ var catalogViewModel = new CatalogViewModel(catalogService);
+
+ await catalogViewModel.InitializeAsync(null);
+
+ Assert.NotNull(catalogViewModel.Types);
+ }
+
+ [Fact]
+ public async Task SettingProductsPropertyShouldRaisePropertyChanged()
+ {
+ bool invoked = false;
+ var catalogService = new CatalogMockService();
+ var catalogViewModel = new CatalogViewModel(catalogService);
+
+ catalogViewModel.PropertyChanged += (sender, e) =>
+ {
+ if (e.PropertyName.Equals("Products"))
+ invoked = true;
+ };
+ await catalogViewModel.InitializeAsync(null);
+
+ Assert.True(invoked);
+ }
+
+ [Fact]
+ public async Task SettingBrandsPropertyShouldRaisePropertyChanged()
+ {
+ bool invoked = false;
+ var catalogService = new CatalogMockService();
+ var catalogViewModel = new CatalogViewModel(catalogService);
+
+ catalogViewModel.PropertyChanged += (sender, e) =>
+ {
+ if (e.PropertyName.Equals("Brands"))
+ invoked = true;
+ };
+ await catalogViewModel.InitializeAsync(null);
+
+ Assert.True(invoked);
+ }
+
+ [Fact]
+ public async Task SettingTypesPropertyShouldRaisePropertyChanged()
+ {
+ bool invoked = false;
+ var catalogService = new CatalogMockService();
+ var catalogViewModel = new CatalogViewModel(catalogService);
+
+ catalogViewModel.PropertyChanged += (sender, e) =>
+ {
+ if (e.PropertyName.Equals("Types"))
+ invoked = true;
+ };
+ await catalogViewModel.InitializeAsync(null);
+
+ Assert.True(invoked);
+ }
+
+ [Fact]
+ public void AddCatalogItemCommandSendsAddProductMessageTest()
+ {
+ bool messageReceived = false;
+ var catalogService = new CatalogMockService();
+ var catalogViewModel = new CatalogViewModel(catalogService);
+
+ Xamarin.Forms.MessagingCenter.Subscribe(this, MessageKeys.AddProduct, (sender, arg) =>
+ {
+ messageReceived = true;
+ });
+ catalogViewModel.AddCatalogItemCommand.Execute(null);
+
+ Assert.True(messageReceived);
+ }
+
+ [Fact]
+ public async Task FilterCommandSendsFilterMessageTest()
+ {
+ bool messageReceived = false;
+ var catalogService = new CatalogMockService();
+ var catalogViewModel = new CatalogViewModel(catalogService);
+ await catalogViewModel.InitializeAsync(null);
+ catalogViewModel.Brand = catalogViewModel.Brands.FirstOrDefault();
+ catalogViewModel.Type = catalogViewModel.Types.FirstOrDefault();
+
+ Xamarin.Forms.MessagingCenter.Subscribe(this, MessageKeys.Filter, (sender) =>
+ {
+ messageReceived = true;
+ });
+ catalogViewModel.FilterCommand.Execute(null);
+
+ Assert.True(messageReceived);
+ }
+
+ [Fact]
+ public async Task ClearFilterCommandResetsPropertiesTest()
+ {
+ var catalogService = new CatalogMockService();
+ var catalogViewModel = new CatalogViewModel(catalogService);
+
+ await catalogViewModel.InitializeAsync(null);
+ catalogViewModel.ClearFilterCommand.Execute(null);
+
+ Assert.Null(catalogViewModel.Brand);
+ Assert.Null(catalogViewModel.Type);
+ Assert.NotNull(catalogViewModel.Products);
+ }
+ }
+}
diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/ViewModels/MainViewModelTests.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/ViewModels/MainViewModelTests.cs
new file mode 100644
index 000000000..1ccffcd34
--- /dev/null
+++ b/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/ViewModels/MainViewModelTests.cs
@@ -0,0 +1,54 @@
+using Xunit;
+using eShopOnContainers.Core.ViewModels;
+using eShopOnContainers.Core.ViewModels.Base;
+using eShopOnContainers.Core.Models.Navigation;
+using System.Threading.Tasks;
+
+namespace eShopOnContainers.UnitTests
+{
+ public class MainViewModelTests
+ {
+ public MainViewModelTests()
+ {
+ ViewModelLocator.RegisterDependencies(true);
+ }
+
+ [Fact]
+ public void SettingsCommandIsNotNullWhenViewModelInstantiatedTest()
+ {
+ var mainViewModel = new MainViewModel();
+ Assert.NotNull(mainViewModel.SettingsCommand);
+ }
+
+ [Fact]
+ public async Task ViewModelInitializationSendsChangeTabMessageTest()
+ {
+ bool messageReceived = false;
+ var mainViewModel = new MainViewModel();
+ var tabParam = new TabParameter { TabIndex = 2 };
+
+ Xamarin.Forms.MessagingCenter.Subscribe(this, MessageKeys.ChangeTab, (sender, arg) =>
+ {
+ messageReceived = true;
+ });
+ await mainViewModel.InitializeAsync(tabParam);
+
+ Assert.True(messageReceived);
+ }
+
+ [Fact]
+ public void IsBusyPropertyIsFalseWhenViewModelInstantiatedTest()
+ {
+ var mainViewModel = new MainViewModel();
+ Assert.False(mainViewModel.IsBusy);
+ }
+
+ [Fact]
+ public async Task IsBusyPropertyIsTrueAfterViewModelInitializationTest()
+ {
+ var mainViewModel = new MainViewModel();
+ await mainViewModel.InitializeAsync(null);
+ Assert.True(mainViewModel.IsBusy);
+ }
+ }
+}
diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/ViewModels/MarketingViewModelTests.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/ViewModels/MarketingViewModelTests.cs
new file mode 100644
index 000000000..248e39857
--- /dev/null
+++ b/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/ViewModels/MarketingViewModelTests.cs
@@ -0,0 +1,62 @@
+namespace eShopOnContainers.UnitTests.ViewModels
+{
+ using System.Threading.Tasks;
+ using Xunit;
+ using Core.ViewModels.Base;
+ using Core.Services.Marketing;
+ using Core.ViewModels;
+
+ public class MarketingViewModelTests
+ {
+ public MarketingViewModelTests()
+ {
+ ViewModelLocator.RegisterDependencies(true);
+ }
+
+ [Fact]
+ public void GetCampaignsIsNullTest()
+ {
+ var campaignService = new CampaignMockService();
+ var campaignViewModel = new CampaignViewModel(campaignService);
+ Assert.Null(campaignViewModel.Campaigns);
+ }
+
+ [Fact]
+ public async Task GetCampaignsIsNotNullTest()
+ {
+ var campaignService = new CampaignMockService();
+ var campaignViewModel = new CampaignViewModel(campaignService);
+
+ await campaignViewModel.InitializeAsync(null);
+
+ Assert.NotNull(campaignViewModel.Campaigns);
+ }
+
+ [Fact]
+ public void GetCampaignDetailsCommandIsNotNullTest()
+ {
+ var campaignService = new CampaignMockService();
+ var campaignViewModel = new CampaignViewModel(campaignService);
+ Assert.NotNull(campaignViewModel.GetCampaignDetailsCommand);
+ }
+
+ [Fact]
+ public void GetCampaignDetailsByIdIsNullTest()
+ {
+ var campaignService = new CampaignMockService();
+ var campaignViewModel = new CampaignDetailsViewModel(campaignService);
+ Assert.Null(campaignViewModel.Campaign);
+ }
+
+ [Fact]
+ public async Task GetCampaignDetailsByIdIsNotNullTest()
+ {
+ var campaignService = new CampaignMockService();
+ var campaignDetailsViewModel = new CampaignDetailsViewModel(campaignService);
+
+ await campaignDetailsViewModel.InitializeAsync(1);
+
+ Assert.NotNull(campaignDetailsViewModel.Campaign);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/ViewModels/MockViewModelTests.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/ViewModels/MockViewModelTests.cs
new file mode 100644
index 000000000..b6d6e4cc1
--- /dev/null
+++ b/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/ViewModels/MockViewModelTests.cs
@@ -0,0 +1,121 @@
+using Xunit;
+using eShopOnContainers.Core.ViewModels.Base;
+using eShopOnContainers.UnitTests.Helpers;
+using System.ComponentModel;
+
+namespace eShopOnContainers.UnitTests
+{
+ public class MockViewModelTests
+ {
+ public MockViewModelTests()
+ {
+ ViewModelLocator.RegisterDependencies(true);
+ }
+
+ [Fact]
+ public void CheckValidationFailsWhenPropertiesAreEmptyTest()
+ {
+ var mockViewModel = new MockViewModel();
+
+ bool isValid = mockViewModel.Validate();
+
+ Assert.False(isValid);
+ Assert.Null(mockViewModel.Forename.Value);
+ Assert.Null(mockViewModel.Surname.Value);
+ Assert.False(mockViewModel.Forename.IsValid);
+ Assert.False(mockViewModel.Surname.IsValid);
+ Assert.NotEmpty(mockViewModel.Forename.Errors);
+ Assert.NotEmpty(mockViewModel.Surname.Errors);
+ }
+
+ [Fact]
+ public void CheckValidationFailsWhenOnlyForenameHasDataTest()
+ {
+ var mockViewModel = new MockViewModel();
+ mockViewModel.Forename.Value = "John";
+
+ bool isValid = mockViewModel.Validate();
+
+ Assert.False(isValid);
+ Assert.NotNull(mockViewModel.Forename.Value);
+ Assert.Null(mockViewModel.Surname.Value);
+ Assert.True(mockViewModel.Forename.IsValid);
+ Assert.False(mockViewModel.Surname.IsValid);
+ Assert.Empty(mockViewModel.Forename.Errors);
+ Assert.NotEmpty(mockViewModel.Surname.Errors);
+ }
+
+ [Fact]
+ public void CheckValidationPassesWhenOnlySurnameHasDataTest()
+ {
+ var mockViewModel = new MockViewModel();
+ mockViewModel.Surname.Value = "Smith";
+
+ bool isValid = mockViewModel.Validate();
+
+ Assert.False(isValid);
+ Assert.Null(mockViewModel.Forename.Value);
+ Assert.NotNull(mockViewModel.Surname.Value);
+ Assert.False(mockViewModel.Forename.IsValid);
+ Assert.True(mockViewModel.Surname.IsValid);
+ Assert.NotEmpty(mockViewModel.Forename.Errors);
+ Assert.Empty(mockViewModel.Surname.Errors);
+ }
+
+ [Fact]
+ public void CheckValidationPassesWhenBothPropertiesHaveDataTest()
+ {
+ var mockViewModel = new MockViewModel();
+ mockViewModel.Forename.Value = "John";
+ mockViewModel.Surname.Value = "Smith";
+
+ bool isValid = mockViewModel.Validate();
+
+ Assert.True(isValid);
+ Assert.NotNull(mockViewModel.Forename.Value);
+ Assert.NotNull(mockViewModel.Surname.Value);
+ Assert.True(mockViewModel.Forename.IsValid);
+ Assert.True(mockViewModel.Surname.IsValid);
+ Assert.Empty(mockViewModel.Forename.Errors);
+ Assert.Empty(mockViewModel.Surname.Errors);
+ }
+
+ [Fact]
+ public void SettingForenamePropertyShouldRaisePropertyChanged()
+ {
+ bool invoked = false;
+ var mockViewModel = new MockViewModel();
+
+ PropertyChangedEventHandler handler = (sender, e) =>
+ {
+ if (e.PropertyName.Equals("Value"))
+ invoked = true;
+ };
+
+ mockViewModel.Forename.PropertyChanged += handler;
+ mockViewModel.Forename.Value = "John";
+ mockViewModel.Forename.PropertyChanged -= handler;
+
+ Assert.True(invoked);
+ }
+
+ [Fact]
+ public void SettingSurnamePropertyShouldRaisePropertyChanged()
+ {
+ bool invoked = false;
+ var mockViewModel = new MockViewModel();
+
+ PropertyChangedEventHandler handler = (sender, e) =>
+ {
+ if (e.PropertyName.Equals("Value"))
+ invoked = true;
+ };
+
+ mockViewModel.Surname.PropertyChanged += handler;
+ mockViewModel.Surname.Value = "Smith";
+ mockViewModel.Surname.PropertyChanged -= handler;
+
+ Assert.True(invoked);
+ }
+ }
+}
diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/ViewModels/OrderViewModelTests.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/ViewModels/OrderViewModelTests.cs
new file mode 100644
index 000000000..fbfc6a951
--- /dev/null
+++ b/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/ViewModels/OrderViewModelTests.cs
@@ -0,0 +1,55 @@
+using Xunit;
+using eShopOnContainers.Core;
+using eShopOnContainers.Core.ViewModels;
+using eShopOnContainers.Core.ViewModels.Base;
+using eShopOnContainers.Core.Services.Order;
+using System.Threading.Tasks;
+
+namespace eShopOnContainers.UnitTests
+{
+ public class OrderViewModelTests
+ {
+ public OrderViewModelTests()
+ {
+ ViewModelLocator.RegisterDependencies(true);
+ }
+
+ [Fact]
+ public void OrderPropertyIsNullWhenViewModelInstantiatedTest()
+ {
+ var orderService = new OrderMockService();
+ var orderViewModel = new OrderDetailViewModel(orderService);
+ Assert.Null(orderViewModel.Order);
+ }
+
+ [Fact]
+ public async Task OrderPropertyIsNotNullAfterViewModelInitializationTest()
+ {
+ var orderService = new OrderMockService();
+ var orderViewModel = new OrderDetailViewModel(orderService);
+
+ var order = await orderService.GetOrderAsync(1, GlobalSetting.Instance.AuthToken);
+ await orderViewModel.InitializeAsync(order);
+
+ Assert.NotNull(orderViewModel.Order);
+ }
+
+ [Fact]
+ public async Task SettingOrderPropertyShouldRaisePropertyChanged()
+ {
+ bool invoked = false;
+ var orderService = new OrderMockService();
+ var orderViewModel = new OrderDetailViewModel(orderService);
+
+ orderViewModel.PropertyChanged += (sender, e) =>
+ {
+ if (e.PropertyName.Equals("Order"))
+ invoked = true;
+ };
+ var order = await orderService.GetOrderAsync(1, GlobalSetting.Instance.AuthToken);
+ await orderViewModel.InitializeAsync(order);
+
+ Assert.True(invoked);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/eShopOnContainers.UnitTests.csproj b/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/eShopOnContainers.UnitTests.csproj
new file mode 100644
index 000000000..ec4c01599
--- /dev/null
+++ b/src/Mobile/eShopOnContainers/eShopOnContainers.UnitTests/eShopOnContainers.UnitTests.csproj
@@ -0,0 +1,18 @@
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.iOS/packages.config b/src/Mobile/eShopOnContainers/eShopOnContainers.iOS/packages.config
new file mode 100644
index 000000000..1fff8934e
--- /dev/null
+++ b/src/Mobile/eShopOnContainers/eShopOnContainers.iOS/packages.config
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file