XamarinTestCloudReference

//Note - smart quotes will not work in Repl/XTC

    Common repl commands:
  • tree
  • app.Flash("myButton");
  • app.Flash(x=>x.All("*"));
  • app.Flash(x => x.All("*").Class("UITextFieldLabel").Text("User ID"));
  • app.TapCoordinates(153, 86);
  • app.Repl ();
  • copy
    Common UI commands:
  • app.DismissKeyboard ();
  • app.Screenshot ("User enters phone number");
  • app.EnterText (x => x.Id ("edit_phone"), "5555555555");
  • app.ScrollDownTo ("CREATE", "linear_item");
  • app.SwipeRightToLeft (c => c.Id ("txt_title"));
  • app.DragCoordinates (200, 400, 200, 800); // (from X, from Y, to X, to Y)
  • app.Query(x=>x.Class("FormsTextView").Index(0))
    Common Queries:
  • app.Query("UITextFieldLabel");
  • app.Query();
  • app.Query(x => x.All());
  • app.Query(x => x.All("*"));
  • app.Query(x => x.All("*").Class("UITextFieldLabel"));
  • app.Query(x => x.All("*").Class("UITextFieldLabel").Text("User ID"));
    Complex Combinations:
  • app.Tap (x => x.Text ("Eating Healthy").Sibling ("TheClassName")
  • app.Tap (x => x.Text ("Eating Healthy").Sibling ("*").Id ("send_segment"));
    Common Assertions:
  • Assert.IsTrue(app.Query(q => q.Marked("logoutButton")).Any());
  • Assert.IsFalse(app.Query(q => q.Marked("logoutButton")).Any());
  • Assert.IsNotNull(app.Query(x => x.Text(firstHospitalName)).Any());
  • app.WaitForElement(q => q.Marked("logoutButton"));
    System C# + UITest:
  • var joinedUsername = string.Format ("myemail_{0}@microsoft.com", deviceNumber);
  • var joinedUsername = $"myemail_{deviceNumber}@microsoft.com";
    Sleep/Wait:
  • Thread.Sleep (3000); //this would be 3 seconds
  • Thread.Sleep (TimeSpan.FromMinutes (4));
  • app.WaitForElement (x => x.Text ("Community Terms of Use"));
    Device Numbers:
  • var deviceNumber = Environment.GetEnvironmentVariable ("XTC_DEVICE_INDEX");

App Configuration:
//On iOS - Simulator
return ConfigureApp .iOS
.AppBundle ("../../../iOS/bin/iPhoneSimulator/Debug/XamarinForms.iOS.app")
.DeviceIdentifier ("KJ23d-45648-55D3E-WEF784F0") // Your simulator device ID
.AppBundle("/Users/USERNAME/Projects/MyFavorite.app")

//On iOS - Device
return ConfigureApp
.iOS
.DeviceIdentifier ("e2342asdfa8asdofhiaesd932h3")
.DeviceIp ("10.0.9.33")
.InstalledApp ("com.myfavoriteapp")
.StartApp();

//On Android
return ConfigureApp
.Android
.ApkFile("com.myfavoriteapp.apk") // example implies file is in SolutionFolder > bin > Debug
.StartApp ();

    Setup Issues:
  1. SetUp : System.Exception : Unable to start CalabashHostStrategyProxy - Close down your Terminal/Repl then try running the test again
  2. Unable to Instrument app: - iOS - make sure to add the Calabash Test Server to your app - and make start it in your app delegate

Command Line:
Windows:
packages\Xamarin.UITest.[version]\tools\test-cloud.exe submit yourAppFile.apk thePRIVATENotRealAPINumber00071 --devices 4b1b0c03 --series "master" --locale "en_US" --app-name "SimpleUITestApp" --user myemail@xamarin.com --assembly-dir pathToTestDllFolder

Example: (From here) C:\Users\Administrator\Desktop\CreditCardValidator.Droid (1)\CreditCardValidator.Droid\packages\Xamarin.UITest.2.0.0\tools (Run this) test-cloud.exe submit "C:\Users\Administrator\Desktop\CreditCardValidator.Droid (1)\CreditCardValidator.Droid\CreditCardValidator.Droid\bin\Release\com.xamarin.example.creditcardvalidator.apk" aasd_THIS_IS_WHERE_YOUR_API_KEY_GOES_34341 --devices=8c67ffb4 --assembly-dir "C:\Users\Administrator\Desktop\CreditCardValidator.Droid (1)\CreditCardValidator.Droid\CreditCardValidator.Droid.UITests\bin\Release" --user my.email.addy@xamarin.com

OS X:
mono packages/Xamarin.UITest.[version]/tools/test-cloud.exe submit yourAppFile.apk thePRIVATENotRealAPINumber00071 --devices 4b1b0c03 --series "master" --locale "en_US" --app-name "SimpleUITestApp" --user myemail@xamarin.com --assembly-dir pathToTestDllFolder

Run the command from the directory that contains the NuGet packages directory. Also, make sure you update your app name and the directory of tests. If your app file is not in the same directory as the NuGet packages, please include a direct path to the file.

Example:
from here:
/Users/myusername/SimpleUITestApp

Run:
mono packages/Xamarin.UITest.1.3.15/tools/test-cloud.exe submit Droid/bin/Debug/com.minnick.simpleuitestapp.apk ceMYAPIKEY31dd3FD3234371 --devices 4b1b0c03 --series "master" --locale "en_US" --app-name "SimpleUITestApp" --user MyEmail@xamarin.com --assembly-dir UITests/bin/Debug

Categories: --category "myFavorite" --category "MyOtherFavorite"


  • Cross Platform Properties you can Access:
  • Marked will access Id, label, and text:
  • so you'll be looking for on Android/iOS -> "label", “id" respectively
  • Android -> “contentDescription" => label on repl
  • iOS -> “accessibilityLabel” or "accessibilityIdentifier" => Id on Repl

Setting “AutomationID" Xamarin.Forms in iOS & Android assign the contentDescription and accessibilityIdentifier XAML: < Button x:Name="b" AutomationId="MyButton" Text="Click me" />

C#: < var l = new Label { Text = "Hello, Xamarin.Forms!", AutomationId = "MyLabel" };

Then in your test: app.Query(x=>x.Marked("theGoodWord")); By using ‘Marked' - you’ll pick up all of the above on iOS / Android

Simplest way to do cross platform tests is to name the controls the same on iOS and Android

"Cross Platform Readiness" using Query = System.Func<Xamarin.UITest.Queries.AppQuery, Xamarin.UITest.Queries.AppQuery>;

namespace MySampleApplication
{
    public class HomePage: BasePage
    {
    readonly Query TitleBar;
    readonly Query SearchBtn;

        public HomePage()
        {
    
            if (OnAndroid)
            {
            TitleBar = x => x.Id("toolbar_title");
            SearchBtn = x => x.Id("fab_button");
            }

            if (OniOS)
            {
            TitleBar = x => x.Marked("Hello");
            }
        }
    }
}

^ Use the above in a test (ex. app.Tap(TitleBar); )

Clearing App instead of Deleting it (latest version of UITest) app = ConfigureApp .Android .ApkFile("app_path") .StartApp(Xamarin.UITest.Configuration.AppDataMode.Clear);

ADDING MULTIPLE USERS

var deviceNumber = Environment.GetEnvironmentVariable ("XTC_DEVICE_INDEX");

var joinedUsername = string.Format ("myemail_{0}@microsoft.com", deviceNumber);

CROSS-PLATFORM DIVERGENCE:

readonly Query AddTaskButtonUsingIds; 
readonly Query AddTaskButton; 
  public HomeScreen(IApp app, Platform platform) : base(app, platform)
        {
            AddTaskButtonUsingIds = x => x.Marked("AddButton");

            if (platform == Platform.iOS)
                AddTaskButton = x => x.Class("UIBarButtonItem").Index(0);
            else
                AddTaskButton = x => x.Class("Button").Index(0);
        } 

ANDROID : SETUP

<Button
        android:id="@+id/AddButton"
        android:text="Add Task"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:contentDescription="AddButton" /> 

IOS : SETUP

protected void Initialize()
        {
            var barButton = new UIBarButtonItem(UIBarButtonSystemItem.Add)
            {
                AccessibilityIdentifier = "AddButton"
            };
            NavigationItem.SetRightBarButtonItem (barButton, false);
            NavigationItem.RightBarButtonItem.Clicked += (sender, e) => { ShowTaskDetails(new TodoItem()); };
        } 

WEBVIEW SHORTCUT: The below will get you the URL which you'll need to inspect a. iOS: app.Query(x => x.WebView().Invoke("request").Invoke("URL").Invoke("absoluteString")) b. Android: app.Query(x => x.WebView().Invoke("getUrl"))

NOW INSPECT THAT URL You can view the CSS of that webview - you can do this with Chrome for example: Chrome > View > Developer > Developer Tools

On the right panel - you'll see the HTML/CSS. On the upper left of that panel - you'll see a toggle-able icon (a square with an arrow in it). Toggling that icon will switch between allowing you to navigate through the webpage -- or clicking a specific element and inspecting it. You'll need to do both.

One you find an element you care about you can interact with it.
As an example - let's say you care about this element:

<span class="thing that I am interested in">

Then you can interact with it, like this:

app.Tap(x=>x.CSS(".thing.that.I.am.interested.in"));  //note how . marks preceed the entry and fill in the spaces as well.

You preceeded the class with a "." If it were an ID, you can preceed it with a "#" mark.

c. If HTML is embedded on an internal resource - try this: app.Query(x => x.Css("body"));

ENTER TEXT (need for certain Hybrid situations):

app.Tap("searchButtonBackground");
app.Query(x => x.Class("android.widget.EditText").Invoke("setText", "The Text I want to Enter"));
app.PressEnter();

SOMETMES YOU NEED TO DOWNLOAD THE ANDROID APP ON YOUR DEVICE (FOR EXAMPLE TO ACCESS AN APP FROM THE GOOGLE PLAY STORE): Connect your device to your Mac. Open Terminal: Go here: cd ~/Library/Developer/Xamarin/android-sdk-macosx/platform-tools

NOTE // Do not go here (use adb tools above): (NOT THIS) cd ~/Library/Android/sdk/platform-tools (NOT THIS)

Look for your package: (notice the use of the "./" before command to use a local command vs a global command).

List your 3rd-party packages ./adb shell pm list packages -f -3

Or skip ahead and use this: ./adb shell pm path your-package-name. ./adb shell pm path com.myCompanyApp.android

OUTPUT WILL LOOK LIKE THIS: package:/data/app/XX.XX.XX.apk=YY.YY.YY FROM ABOVE - YOU WANT THIS: /data/app/XX.XX.XX.apk

FOR ANDROID VERSIONS BELOW 7.0// THEN THIS: (GENERAL COMMAND) ./adb pull full/directory/of/the.apk (Example of SPECIFIC COMMAND) ./adb pull /data/app/com.myCompanyApp.android-1/mybase.apk

FOR ANDROID VERSIONS BELOW 7.0+ (GENERAL COMMAND)adb shell cp /data/app/com.theCompanyName.android-1/base.apk /storage/emulated/0/Download (GENERAL COMMAND)adb pull /storage/emulated/0/Download/base.apk

NOW YOUR APK FILE WILL DOWNLOAD THE DIRECTORY WHERE YOU ARE RUNNING YOUR COMMANDS: In this case - it will be called base.apk

IN TERMINAL - you can type the following to open a FINDER WINDOW and then copy your new file base.apk to the directory of your choosing: open .


SITUATIONS WHERE WARNINGS MAY OR MAY-NOT POP-UP

[Test]
public void MyImportantMethod ()
{
//ADD THE BELOW TO YOUR METHOD
	try 
	{
	//DISMISS POP-UP HERE
	//IT IS IMPORTANT TO NOT HAVE SCREENSHOTS HERE OR YOUR SCREENSHOTS WILL BE OUT OF SYNC WHICH WILL TRIGGER ERRORS
    	app.WaitForElement (x => x.Id ("welcome1"));
	app.Tap (x => x.Id ("welcome"));
	} 
	catch (Exception e) 
	{
	Console.WriteLine ("{0} Exception caught.", e);
	}
//ADD THE ABOVE TO YOUR METHOD

// here is where you do the rest of your method
   app.Tap("Sign-in");
   }

IF STATEMENTS You should in general not sure IF statements - you want deterministic tests:

if(!app.Query(x=>x.Marked("foo")).Any()) { //DO THIS }

Date Picker

Date picker - Android //

  1. You can either invoke native methods: https://developer.xamarin.com/api/member/Xamarin.UITest.IApp.Invoke/p/System.String/System.Object/

  2. or try manipulating the date picker in the following way:

First - click into the date field to bring up the spinner:

app.Tap("the_date_spinner_object");

Second - you'll see something like this:

            [DatePicker] id: "the_datePicker"
              [LinearLayout] id: "pickers"
                [NumberPicker] id: "month"
                  [NumberPicker] id: "the_numberpicker_input" text: "Jun"
                [NumberPicker] id: "year"
                  [NumberPicker] id: "the_numberpicker_input" text: "2017"
        [LinearLayout] id: "buttonPanel"
          [Button] id: "cancel_button" text: "Cancel"
          [Button] id: "ok_button" text: "OK"
//pick the Month spinner
app.Tap("the_numberpicker_input");
app.EnterText("May");

//SOMETIMES you may need to split the month into it's letters
//app.EnterText("M");
//app.EnterText("a");
//app.EnterText("y");

// SOMETIMES BEFORE PICKING THE MONTH you can also preceed with clear first before you type in the month
//app.ClearText();

// IF THE DATE IS STILL EDITABLE, YOU MAY WANT TO TAP THE MONTH INPUT AGAIN SO IT DOESN'T GET "OVERWRITTEN" BY LATER STEPS
// app.Tap("the_numberpicker_input");

//pick the Year spinner
app.Tap(x=>x.Marked("the_numberpicker_input").Index(1));
app.EnterText("2016");
app.Tap(x=>x.Marked("ok_button"));

TUTORIAL ON ADDING Calabash to Swift/Objective-C projects: https://github.com/calabash/calabash-ios/wiki/Tutorial%3A-How-to-add-Calabash-to-Xcode Calabash for iOS Github page: https://github.com/calabash/calabash-ios

Xamarin Documentation has a more in-depth Cheat Sheet: https://developer.xamarin.com/guides/testcloud/uitest/cheatsheet/

Guide created for TFS/VSTS with a lot of simple guides: https://www.visualstudio.com/en-us/docs/build/steps/test/xamarin-test-cloud

Thank you to JWhite, Mahdi, Brandon, June, Mike Watson, Brad, AdamB, and Ian Leatherbury