>> This week's Xamarin Show, I have my good friend Suwiky coming
on to tell us how to optimize our user interface
automation tasks with a page-based awesomeness. So tune in. [MUSIC] >> Welcome back everyone
to The Xamarin Show. I'm your host James Montemagno, and today I have my best friend
in the entire world Suwiky, all the way from San Francisco? >> Oh yeah. >> Yeah, welcome. Welcome to beautiful sun shiny
super warm Seattle Washington. >> It is. It's been super warm. Got all extra layers out
we've been pretty cool. >> Looking good. Now, you
are on our MCAT team. >> Yes. >> Now, I don't know
what that stands for, except for has a cool name. >> It does. >> But I know you work often
with our customers and your specialty is on automated
user interface scripts, and that's what you're here to
talk about. Is that correct? >> Yes, that's right. So, I'm on the Mobile Customer Advisory Team. >> Cool. Cool name. >> Yes. That's what MCAT
stands for and that's what we do we basically help customers
be successful using our tools, specifically Xamarin and I am
the in-house expert in our UI tests. >> Awesome and you've been in and around the Xamarin ecosystem
for a long time. Correct? >> Not too much. Maybe like
three years there's now. >> That was a pretty good longtime. >> That's a long time. >> Yeah. I think so. I mean, I only worked to Xamarin for fives. >> Hey. Close enough. >> Yeah. We're good. So you're
going to be talking about what when it comes to UI
because I think we've talked about in previous, previous, previous episodes on like
the idea of UI testing, but what specifically do
you want to talk about? >> So what I'm going to
show is this pattern that we like to use in
our team so it's called the page object pattern and it
basically helps you write super-large UI tests
which are cross-platform and it's great to maintain
and super easy to understand. >> So first off, why
should people even write user interface tests and
what are they? I guess too. >> Okay. So, UI testing
or user interface testing we have a lot of tools
now in the market lets you automate your user test, so before which used to have, you have manual testers, open up
your app on different devices, make sure flows are working, buttons are rendering correctly
or your lists are scrolling, apps not crashing, just
basic, just user tests. Now, that we're in
the cool modern age, we can automate these tests. We don't need a human being coming
and doing all the test for you. It's still a test and I feel developers are getting lazy writing
the test was really important. For things like one
of the most commonly use seen cases that we
have is login page, you have your text fields, or your username and password, but then you have
the keyboard hovering over the login button and
then the user say, "Oh, wait. Where the login button go"? Or like they don't auto dismiss that keyboard and allow
someone to just you know. Or maybe attach the enter button
to be the login button close. It's important, plus even
just basic things like, "Oh, it works on x form factors
but doesn't work on the other form factors but you claim that you support all
these form factors." >> I see. >> Screen rotation sometimes
messes up your app and if you don't have that locked and someone turns it over that's,
you have crashes. So, user interface testing
is important. >> So it sounds like if I
was to summarize at that, it's like you have unit tests to test your code but the
UI tests is to ensure that the things that you
are telling your users are expect your users to do actually work on all of these crazy devices. >> Exactly. >> It's not just like, oh it runs
in the simulator on your device, it's that they're
reusable testable tests. >> Exactly. >> Reusable testable
tests. That's the word. >> [inaudible] Yeah. >> Cool. So what does
this page-based thingy? >> Okay. So, like we do any mobile
app development you have, your UI code and then you
have the code behind and to basically always making an
app based on this page, this is the purpose of this page, then user goes with this page, that's the purpose of this page. We've modeled this pattern
around a similar process, so a Dev can also just come
in and write these tests. You don't have to be a expert tester to come and understand
what's going on. We treat each page of an app as
an individual object of its own. So, you have your homepage, you can have a details page, you can have a list page
depending on what type of app and each page has its own elements, so you can only interact
with those elements. So that way you can sort of
abstract out these queries that you have to interact and
query for these elements, and gestures, and
methods that interact with the buttons are all again
living in that one page object. >> It's how you
describing it makes me feel as if it's almost
like a view model is the code behind logic for
the view and then there's page-based UI tests are like all the things that are
going to interact with it. You're not testing the code because the view model is probably
tested in a unit test. But this is like helper methods and budget like commands
as much as I can call. So, as I'm adding new things to
my app, as I add a new page, I have to imagine that one of the main reasons for this has
to be for code reuse, right? >> Basically. That's the whole idea
plus making it easier, again like if it's a Xamarin app, you can take it into
the next level and basically if you have automation ID
setup you can basically repurpose those same strings
and use them in your code itself to query for elements
on that [inaudible]. >> Oh, that's great. >> So, that's like
a next level optimizations, you ever want to go there. But yes, the idea
being is since you are the development of an app and
you know what's on your page, you know what the behavior
is supposed to be. If it's a swipy gesture,
what's supposed to happen? When you're writing,
you wrote your page, you wrote your MVVM backend logic, you wrote unit tests for that, come back around make sure the UI still looking good and
write a UI tests for it. >> Got it. >> All can be part of that same flow. >> Awesome. Well, let's take a look. So, you're here and what? VS for Mac? >> Yes. Exactly. Awesome VS for Mac. >> So what do we have?
What am I looking at here? >> So this is the app
from our Kinect demo. >> Cool. >> Yes and I noticed that someone
hadn't written UI tests for it. >> Oh, no. >> Oh, yes. So this is-. >> By the way, she's
looking at me as if I'm the one that wrote the app and then
I am the one that [inaudible]. >> Usually, you're
the one who does this. No, it's David Art now and I
will pick a bone with him later. But I will do everyone a good favor, so what I'm showing you what
I'm going to put in as a PR. It should show up hopefully in
the actual sample app but yes, so I basically just cloned the exact sample app nothing fancy
everybody has access to this. All I did was adding the first four components
of a UI test project. So 123 where's the other one
I'm looking for? >> This is just another project with some specific packages or something? >> Yes. So I've added this
as a new- so you just go with old good old
fashioned Add new project. Pick a regular
multi-platform UI test app. So when you first load the app, you actually don't get
all of these pages when we close away and what you do get? So you get, oops extra and extra, get my resolution backup here so I really can see what's
going on but yes, you basically get this test page and you get an app initializer
not an app manager. >> Okay. >> So to adopt our pattern
there's two ways you can do it. So we have a GitHub repo with this whole structure of the first
four base-pages that you need. To get started already shared
up there just copy paste, make sure you just adjust
your namespaces and your copy-pasting or we
have a handy little new get package that's called
Xamarin.UItest.pop and that will just auto inject these same codes for you and
fixed in space [inaudible]. >> Super app, I like that. >> Yeah, so that's super handy and
so basically once you come in, the first step we want
to do is you'll have an initial app initializer page, you want to delete
that and we move over to our app manager page
where we are right now. So step one, since we are testing mobile apps we need to tell
the code where the app is, so with VS for Mac
we'd have the inbuilt integration options so you
could basically just refer it, so let me pull up
my test pad again. Oops. Here it is. Hello friend. Let's get you here. So, you could basically
go "Test Apps", right click on open "Add App
Projects" so they'll refer back to your solutions in the solution itself or you can do what I did
over here which was I pre-built the binaries and I have them in this folder called Binaries and
just like pointing it to that. Only reason I like doing this is because sometimes if it's
a really large project, you'll end up having to
wait for it to rebuild your app project and then build
your tests and then run it. So, if you're in a hurry
like I am most days, just have your APKs ready and your IP is built up
and you're good to go. >> Then I assume here,
if you run it this way, you can probably set up some CI automation to work
a little bit with this too. >> For sure. It's very extensible. That's the beauty of this
also like we've put in all these extensibility
options that you can customize this to
your complete need. You don't have to even use it as if you don't like some section of it. >> So I have this I-app
and a platform. >> Yeah. So, all of
this is basically just initializing the app
variable for UI tests, so that's your app that
you're interacting with. So, everything that
we'll be doing today is going to be based off app, so app dot whatever. Platform, basically just over here, we have it, it just gets the platform value and
set it as Android or iOS. Then, we've made it extensible in the sense that anywhere
else in the code, if you have some
platform specific logic you can just go platform dot. If platform dot something, you have your platform over there. >> It kind of Xamarin Forms
has the platform. >> Exactly. So, you will
basically not even have to look into the rest of
the code because this is just boilerplate stuff from
the old app initializer, all you'd be doing is
coming in and editing the top three lines to put it in and the rest of it you
can just leave as is. The next thing you'll
be doing is coming into the test, which is again, you get like the one default test for free when you add the project. What you'll do is
basically change this up. So, this is where we will introduce the two other files
that you get for free. So, as you'll notice, there's the "Tests" class which
has the test but it's inheriting from "BaseTestFixture" What is
this BaseTestFixture, you asked? >> I was about to ask, so, yes, what is BaseTestFixture? >> Yeah. So, this is what we give you as part of those four startup files. This is startup file number three. So, this BaseTestFixture
basically takes over everything that involves
configuring the test. So, things like the setup and it'll start your apps
before each test. We have the app variable pointing
to the correct app instance, so we're not recreating new ones
every time you do an app dot. Then, we add this cool
new extensibility. So, remember the platform iOS
and Android that I mentioned, we just aliased it to be
on Android and on iOS. >> Got it. >> That is a purpose for this when
we'll be setting up the pages, just to make it much more
easier to read your queries. So you're like, "I'm on this page and inside
the constructor of a page you'll see if on Android these
are all the queries look like. So, it just makes it
easier for someone to follow plus if it's someone who's had no testing
knowledge or just wants to understand
what is being tested, they can just read through it
like English, and it makes sense. >> Very readable. It was nice. >> Yeah. That was
the purpose of doing this. What other cool thing, you can do here is, since this is going
to be inherited by every test class that you have, you can add things like say you have some pre-test setup
that you want to do or you don't want to maybe test like maybe the first
two pages of the apps, so you can basically
make it to put in a little helper method
here that says, "Hey, this is pretest method, just maybe click through
these two pages and just go to page number three and
we start testing with it." >> Here you started
to put like all your nice little helper methods that every single test is going to
use and that makes sense to me. >> So this is super reusable
This is where that comes in. >> Reminds me of
my base view model that I create so instead of reproducing the code over and over
and over and over again, you put it in a base view model, inheritance, C# is awesome
and go from there. >> Are you noticing that
people are inspired from? >> I can see this, yeah. >> Awesome. So, that's
your BaseTestFixture, so your test is going to
force inherit from that. You have a little initialization for platform and that's when
you start writing tests. So, the test tag is our good old
and Unit test tag stays the same. You get in your test method and this is where
the magic of UI test, the page object pattern
basically comes in. So, what do you see when
you read those two lines? >> Yeah. So, here it
says, well, first, we're going to Add to Cart, so we're going to add
something to a cart. >> So, that's our test flow
that we're going to do today. So, you can see,
the first step it does is new homepage but if you were to just read it like
a regular person, skip, don't look at the news. So like homepage, select a menu option called home
appliances, totally makes sense. >> It does exactly what
my user would be doing in there and like
I'm on my homepage, I see a menu options
that had this thing, I see a list page, I hit the first item. >> There you go. That's it. >> This is code that
you wrote, so this in- >> So, this is, yeah, this
is what we're going to, now that's the next step
we're going to go into the actual pages and how they are going to
come together to make this test so much easy
to read and understand. So, this is all you are
doing the test page, so let's hop on to the base page
and get some base pages going. All right, so the base page. Like I mentioned at
the beginning page object model, so each page is independent. This is the base base at every page in your app is
going to inherit from. What this is doing is basically
again getting back are on Android, on iOS, just getting
all those initializations done. The cool bit over here is what
we call the platform trait. >> What's that? >> So the trait, so just to get the main principle and to get
the whole page uniqueness working, what we encouraged
the way this pattern, the way it works is, you need to find a unique element on that page. So, the system can verify, okay, this is the page I'm expecting, I check for the trait, the trait exist therefore
I am on this page, and now I can start
interacting with this page. >> I have a login page and maybe there's a
button that says log in, that's going to be
my key identifier in there. >> Exactly. >> Okay. >> Since, again since there's also
cases where you're not having your source code with you
like we have it right now but you could add a UI tests
and not have the source code. All you can have is like the, because that's how extensible
the platform is. So, in cases like that, how would you know what's your page. So, find a unique element on each
page and that's your page trait. >> Okay. >> So that's what we do here, plus setting the page trait does this awesome thing where we
basically give you a free assertion. So, we assert on page, that's what we need your trait for. So, the base page, you automatically throw all errors
that you haven't implemented a trait if you try and make
a page and not implement it. What a loop will check
is that trait exists and as soon as it finds
that the trait exists, it's going to actually take
a free screenshot for you. So, it's absent or compatible. So, if you say forget to add screenshots which kind
of people tend to do. >> It is always be there. >> It'll have the one default
page screenshots for free, so you absent or upload
will not be for waste. Then you can, "Oh no, I needed more screenshots.". >> That's super nice because that is something I always forget and you get like this app center, I run down, it's just
a bunch of blank things, you don't see anything along the way, it's like start and stop. >> Exactly. So we threw this little extra bit in because anyway
they're verifying it on the page, so might as well just
grab a screenshot of it. So, you get that for free. So that's all the
"BasePage" basically does. We have another one in
case you ever want to use it, it's called "WaitForPageToLeave". So in case you have an animation
with something that goes away, we do assert on page for free and we have this
thrown in there if you in case want to add
that other check in like, "Okay. Now, verify that actually
left this page." Useful for animations,
splash screens and things like that. So, it's in there,
feel free to use it. Again, like with the
"BaseTestFixture", again if you have
any common functionality, awesome example for
that is if your app has a hamburger menu and if every page has accessed
with a hamburger menu, you don't want to re-implement
that menu option for every page. Dump it in your base page and every page is automatically
going to get access to it. >> So, this BasePage is really
common actions that you want to use inside of a test that maybe are common between all of your pages, where the BaseTestFixture was
helper methods for the test frame, where the test set up and tear down, this is specific, "I'm
on this page here, some common things that I
want to do just like on a paid or content pages in
Xamarin forms that have on appearing and on disappearing. Same thing. Got it. Cool. Very cool. >> Exactly. Same concepts. Exactly. Try to keep it as
similar, easy to follow. So, that's your BasePage. So let hop onto some pages. So, I'm going to go back to
the test again and you notice. So, we have two pages already
set up. So, the homepage, so let me-. >> Yeah, we have the app. >> Yeah, this is the app. >> So, it's an awesome
little TailwindTraders app from the Connect demo. This is our homepage and this is what the homepage is
going to look like. So let me pull homepage up
to see what's going on here. Homepage. So first thing, inheriting from the base page, the next thing it's going
to force you to implement this section over here which
is your platform trait. >> Got it. >> Right. You notice
you have to set up a separate trait for Android and iOS. There are instances
where you might have the same query if you have set up Xamarin form same
with an automation ID, with the same string, but
we just wanted to keep the option open that we can't assume that's always
going to be the case. >> Yeah. >> But that's so
basically you come in for each platform you put in your trait. So, I've my Android emulator
up and for Android, I'm looking with a main scroll view that's this giant
scroll view over here. So, that is what I decided
would be my trait. The next bit that we do
here once you come in is, if you look at the constructor, this is where we have different elements that
I want to interact with, that's what I'm going to set it up. This is a two-step process. First thing, you're going to
set up the variables up here. Xamarin UI test uses
these funky-looking app queries. What we've done is
to make the test and the whole code more readable we
alias it to just the word query. >> That's super nice. >> Yeah. This is again for free in the example that we have
up on GitHub as well. So, you can just copy paste this. Even if you're doing
regular UI tests, it's a cool little alias to have. So, that's it. So, once
you are in so like I said, every element in the UI
tests is a query, right? That's how we sort of setting up all the different elements on the screen, so I have the menu button which is the top button over here
and once this opens up, it's all of these menu options. >> Got it. >> Right. So, I'd set very simple setup so I
have those two things, the variables, initialized,
setting up the queries over here. Now, there's two different types of queries that I have set up here. The first one is per platform. I have the menu button
defined separately, that's because the
queries were different. >> I see. So, you have
this on Android and iOS because in the code, when you investigated it, they're actually different
strings it looks like to represent how you
would interact with it. >> It's actually just like
what the name this element itself. >> Okay. That's what
UI test is going to be looking for to interact with. >> Exactly. When it
queries for element, it's run and try and match maybe the name or the
ID or you can even use the types of elements like classes and buttons
and things like that. So, this is what it's
going to use to, okay, I'm looking for something
marked with a string, okay. >> Okay. >> It's marked with
the word three bar. So, I'll open up app in awhile and you get to see more of this
when we set up our last page. Essentially, this is
what a page looks like and the second thing is
you notice this menu options. Now, menu options isn't living
inside any platform right now. It's just hanging out outside. This is where the cross-platform
magic actually comes in. The query for this is basically, it just looks for a string
with a word in it, because I wanted to generalize
this a little bit because I didn't want to go find each things, ID or user class, like a gigantic query for this. It's a regular string and
it's going to be the same between iOS and Android
version of this app. >> I see. >> So, this can live on the outside, you don't have to break it
down to each platform version, if you don't have to copy paste this. In the future, say, the dev goes and actually puts
in an ID or something for it. You have just come and change
it in this one location. >> Got it. Right now you may pass in sync or gardening but ideally, you're going to put in an ID
underscore, whatever, the automation. >> Yes, something more unique.
So, it's a little bit of an investment to set all this up but in the long run, it's
totally going to pay off. >> It's not too much code,
it doesn't look like that. >> It's almost. We give you
a bunch of stuff for free. All you have to do is
you would be doing all of this stuff anyways
to write your UI tests. You'll be going into your Apple, doing all the interactions,
copy pasting it into your test. But only thing is then,
if you don't maintain it in a right way when you
have to go update these tests, you're going to feel annoyed and lazy because I'll
have to go and find, replace every single
instance of this, so we just make it much nicer
and much more easier to read. >> Yeah, it's very readable testing. >> Cool. Now, that we
have the elements, let's interact with them. So, the action we're
doing on the homepage is selecting the menu option. So, two steps in that first one. I like doing WaitForElements, it's kind of like
a cheat assert for me. Also, it's a built-in method from
UI tests which is optimized, has its own little polling
timer built into it. So, you'll just basically
verify that, okay, has this element appeared and ready on the screen and that will
interact with it, that's the back. >> So, make sure it's
visible interact. >> Exactly. >> Make sure it's visible interact. >> Yeah. If you're doing a visual, like if your test is basically
maybe to confirm that a bunch of strings and images and stuff are
like loading correctly, maybe WaitForElement wouldn't
be the right test for that, you could go back to using asserts. So, assert is not null, assert
is true. You could use those. But for something like this, I would always still recommend
that just do a wait for sometimes there's an animation
or there's is a lag, you never know, it's a slow end, it's like one of the low CPU devices. Give it a couple of
seconds to appear. >> Yes, you can't press
on home appliances until the fly on navigation
is fully come out right. >> Exactly. A lot of test fails because of
just simple things like this. So, it's a good tip to know. So, next thing, it doesn't
want to taps on it, fly out menu opens,
we're going to click on the first option,
that's home appliances. >> Then you're kind of
done with this one because we're writing our first test here, we're just trying to open it. Right now, if you'd gone
back to the homepage, I'd imagine you can
start writing a bunch of different helper methods for all these other things,
right, like a search. >> Exactly, so right now we're just focusing on the simple flow
of just adding something to a cart but the
most optimized and my workflow, if I'm setting up a UI test
I just be setting up pages. >> Got it. >> If you have a team of other people who are working
with you, divide up the pages. You set up this page
and the aim being, we're going to write every method to interact with everything
on that page. >> Got it. >> Then, come back together
and one single person can then just go write the tests
because all the methods are ready. >> Okay, cool. >> Yeah, so we have this. Similarly, I have set up the page already for
the home appliances list. >> Oh, cool. Nice. >> It picks up
the first item basically. What we're going to do
right now is actually write up the page for this last bit. >> So after you tap on it? >> Yeah, and we're going to
write the test to add to Cart. >> Okay. >> So, super simple, just going to add in the one "Add to Cart" button, get the queries, bot platform
and boom, good to go. >> Right here, I have to
imagine you have to wait for this page to be here and then
you're going to have to scroll. >> Yeah. >> You have to hit a button. >> Yes. >> Then validate that,
it's also added to cart. >> Yeah. So, we'll see
what happens because I haven't done this
myself. So, let's see. >> Okay. That's the best way to do it when you come to Xamarin to do alive. >> Yeah. So, let me
add in my page file. >> Okay. >> So, we are doing, let's do appliance detail page. >> Okay. A new page? >> It's new page. First step, we're going to inherit
from base page and then you'll see me do something
that I usually cheat. I'm just going to copy this
and then you need to set up. So, it's already crapping out
because you don't have a base trait. So, let's make it happy.
I'll put this in here. >> Now, how do you know
what those are though? >> Yeah. Now, I'm going
to figure that out. >> Oh I see, okay. >> I'm just being
the initial scaffolding setups which is making this happy because it now let me build my test and that's when
we're going to do it. So, if you come back to my test. I have the first few
floors already set up and have an app.Repl
that'll pull up the read eval print loop and we can now start interacting
and querying for elements. >> So, kind of here's the first page, run the Repl code and so then we can start to figure out what those
identifiers are on that page. >> Yeah, exactly. >> You went down into
the UnitTest menu? >> Oh yeah, this is the UnitTest
view. So when you build the test, it's going to populate all
of the different tests that you have and since ours
is a cross-platform test, you'll see Tests(Android)
and Tests(iOS). Double clicking on
any test underneath that subgroup will be launch
it for that specific platform. >> Okay, cool. >> So I'm doing if Android because
I'm a handy emulator open. >> Well, you're going
to go, I've seen some. >> So it's already interacting- >> Whenever I used to show UI test and I will just start to
write something and I was like, look at it do it, and it's like, wow, it's just like
magically doing stuff. >> Oh yeah, it's
awesome, super awesome. >> So what's this?
What am I seeing here? >> So it went through, selected the first appliance on the list and we're on the
appliance detail page and they'll be having
a network issue because it's refusing to load
the image, interesting. Doesn't matter for us, we
don't care about the image, we care about the button. >> Yes. >> So, first thing, I need to get this bigger. Right, so first thing to do,
you're going to hit tree. Look at what's going on here. >> So you text tree
and now you see stuff? >> Yeah. So, what Repl does
is, when you hit tree, it'll give you like
a hierarchy view of every element visible
currently on the screen. >> Oh cool. >> So, you can see, there's not too many IDs here but if you
just follow along a little bit, you can see there's
the cart so that I'm assuming is this little icon up here. This is the main label. Again, this is the text
from down below over here. That's drawn up and you
can notice it doesn't have our "Add to Cart" button because
it's not on the screen right now. So let's do some handy. So Repl basically hasn't
IntelliSense in it. So all of the methods
that you can use to interact and query an element
with, it's all here for you. You don't have to go and
remember anything ever. So, with cool IntelliSense, I'm going to scroll,
just scroll down. So, all right, my "Add to
Cart" button has appeared. So, let's tree again, make sure we can see it. Okay, I see a giant text for "Add to Cart" which is
awesome, which is perfect. So let's verify this works. My favorite trip to do is app.Flash and then you
give it the query. So again, with the query, once
open your lambda statement, IntelliSense will prompt
you, what do you want to do? Do you want to search by class? Do you want to search
by a button type? Do you want to do
the parent, sibling. There's so many different ways
you can query for an element. Best practice would be to try
and get IDs that are unique. Trying to get through
the class path and stuff is nice but it makes
your test brittle. They change, they throw
another element right above, that's going to throw
up your class paths. >> Yeah, from "Add to
Cart" you change it to "Add" for instance,
they made me break it. >> Exactly right. So, right now, since I don't have
any other way of referring to, I'm going to go with
the string "Add to Cart" but best practice would be ask
your devs to put in IDs. >> Got it. >> All right. So, I'm
going to use marked, we have "Add to Cart." Flash will flash
that element onscreen. So, I know for sure that, okay, This is the one I want to
interact with so let me copy over this query and we know
we're going to tap on it. So I'm going to come
back and do that. I'm going to quickly go into the whole appliance
detail page and, whoops! I was actually going
to look for the trait, I totally forgot about that. >> Yes, how do we know that
we're actually on this page? So we need to see that
something is there. >> So, if we scroll
back up a little bit, let's do the tree again. I have a feeling we can default to the little
cart icon at the top. >> For the scroll view, right? >> We will go for the scroll view. That's actually not a bad idea. There's the shell content. We go over the shell content
scroll view. We can do that. >> So basically, anything
that makes this unique? >> Yes. >> Ideally like again,
identifiers help? >> Oh yeah, for sure. >> Yes because we see
no resource entry 88 that's not super-duper helpful. >> Exactly, that's like
the auto-generated IDs from Android. So again, if you're going
ask it to put in a name, give all the unique elements, something, just unique values, just makes it easier to write
and maintain your UI test. >> Got it. >> So, okay, let's quickly use
this as my Android traits. I'm going to replace this value here and what I'm
going to do next is, I'm going to set up the button. So, I need my handy little alias. Let me dump this back here. All right, like an alias away. So, let's do read only query. We're going to look for our button. What's going to add cart button. >> Got it. >> Cool. So right now, I'm going to assume that
they're going to have different values on each platform. >> Okay, because it may be
not all caps for instance. >> Exactly, yes. So for
now I'm going to add. >> I think it just hovering
outside your class. >> Oh, yeah, who? Let's move
you back in, there we go. All right so addCartButton
and I have my handy little. >> What? Oh, yeah, little nice. >> My query trait, query from before. So we have it verified on Android. We know this is going to do this, so another cool way to optimize it, I know we don't have our iOS query yet but the action is going to
be the same so I'm going to finish off this page initial setup and I'm going to just put in public, no, this is going to be our add, so what you want to call
the method "Add to Cart"? >> Yeah, sure sounds good. >> So now, there's
another cool thing we do here. So if the action is going to
not navigate out of your page, don't make the return type void
make it the same page type. The advantage of doing that is when you're going to
go and write your tests, you can dasiy-chain
all your method calls that way. >> Oh, I see. >> It will make your page, it will
make that test look much nicer. Or it's like new upper page every
time if to make these all void. So unless it's a navigation out, you can just give it the page type. >> So use that, we call it
the builder pattern, correct? >> Yeah. >> You're building up and what
we're doing is returning the page itself so I can say
dot Add to Cart, dot. >> Verify added or something like that that's
the next thing will add here, so let's do "Add to Cart" and so I'm going to do my WaitFor
and it's the addCartButton, so like I can set this up
right now even though I don't have my page yet. So I don't have my iOS query yet because it's going to
be the same variable that's going to reference anyway, so it's cool super optimized way
to do it and I'm going to do. So, okay, another thing, this was hidden below and I
had to scroll to get to it. >> I was just about to
ask for that, yeah. >> Yeah, so WaitForElement would not work so I have a feeling you
can do let's test this out. So I'm going to instead
do scroll down. >> So it's cool because
you can type a little bit here into the Repl
just to validate that, "Hey, this is what I'm
going to need to put. I'm going to need to write this code inside back in Visual
Studio," to make sure it actually works and validate
it before, fake testing it. >> Exactly. So what did I screw up? Okay, let's see. So
let's ScrollDownTo. >> So before you
scroll down randomly, now you're scrolling down to. >> Yes, so, because before I didn't know my query
and I didn't know how I got to tell UI test
what to ScrollDownTo, so the ScrollDownTo API basically, you just need to give it
a target it's looking for. >> Oh, cool. >> So you can overwrite it
with a string right now, you can also give it
an actual query, do what I did too. >> Oh, So you could
actually pass it the query. So you can say actually,
hey ScrollDownTo this query because I need
to then tap on that query? >> Exactly. >> Cool. >> Sweet, right? So what
we're going to do here is instead of "WaitFor" I'm going
to make this my "ScrollDownTo". >> Because that would fail if
it couldn't ScrollDownTo it, so it's almost very
similar to "WaitFor". >> "WaitFor", exactly. Yes, so I'm gonna "ScrollDownTo" and
then I'm going to put my "WaitFor" just to confirm the fact that it is on
the screen and now I can tap it. >> Got it. >> So then, I'm going to put
in my tab for addCartButton. >> So that's nice because
you're just reusing this addCartButton which is
that query over and over again, so I'm not to interact with
this thing over and over again. >> Yeah. Let's throw back the page. So this method is
setup and good to go. So I know for sure it's going
to work on Android right now. All I need to do to complete
this page setup is get the iOS trait and iOS query
for that add button. >> Very cool. >> Cool. So I'm going
to come in here, "Launch a test for iOS" and I haven't changed
anything from before. It still has the Repl
statement in here. >> Okay, so we're going do
the same thing that we just did on Android but for iOS? >> Exactly. So it's
pulling up my simulator. >> Now, you are doing
these in emulators and simulators but I assume you can
also do them on device, too? >> Yes, you can. >> Okay. >> Yes. >> All right, cool. But
simulator's pretty fast. >> I mean it's convenient too. In most cases, you'll be fine
but always do a run on a device. Just make sure or use App Center. Like oh, no, what's going on here? Come on, enter. There you go. All right. I intervened
just in time. Sweet. >> Perfect. >> All right, so let me
zoom in to the Repl again. So we basically are now
hunting for just two values; for a trait and for the
"Add to Cart" query. >> Got it. >> Right. So let's do a tree again. All right, so we see so
much of stuff in here. >> Yeah. So much stuff,
look at all that stuff. >> Star, star, star.
We have an image. We have all sorts of content. >> You even see the "Add
to Cart" button, yeah. >> So this is on an iPhone X
so it's a giant screen, so I would suggest maybe we could
use that as our trait but just, looking back on what happened
on the Android smaller device, probably on a smaller iOS device, the trait check would fail. >> Got it. >> So let's look for
something a little more higher up on the screen
is a little more generic. So try and look for
that scroll view here, let me see if I can find it. Okay, that's "Add to Cart" button. >> If you say UI image like is that? >> Oh, yeah, that
could work actually, that could be a good one. Let's try if I can query for this. >> So it's fun because you're like, I see it but how would
I query for it, right? >> So since we are
using the UI image, things inside the square
brackets are the classes. So I'm going to try
a different query type this time, which we haven't used
yet, as our class. So let's see if this works. Yes, if you can have
a gazillion UI images. Since we have a bunch
of them, no problem. Let's narrow it down a little bit. So I'm going to index zero. So the first one in this array of results and let's flash it to
see if it's the first image. >> Cool. >> It is, cool. So I have
a good enough query. I'm going to copy this for our trait. Let's go back to
appliance detail page. So, like I said, this is the reason we
kept it extensible because it won't always be
the same on each platform. >> You might be raving
your UI and you might need to change things or finally
add some automation ideas. >> Exactly. So, it just makes
your life easier to write the tests. All right, so we have this, the next thing we need is
our "Add to Cart" button. >> I think you're going to
get lucky here too, right? >> Oh, yeah, I think so, All right. Add to Cart, these same strings, so let's remove "If on Android" because it's
the same on each platform. >> Nice. >> All right, so we
have a button set. All right, another question that I would have considered if I was
writing this for the first time, again, so we saw two different
screen sizes, you'd be wondering, hey, but this doesn't technically
need to "ScrollDownTo". "ScrollDownTo" underneath
the way the API works, it's actually going to
first do a query check. >> Oh, okay. >> If it doesn't see
it on the screen, it'll scroll down, check again, scroll down, check again. So at this point, it's not going
to fail trying to store down to, it will be like, hey, I
don't need to scroll down, it's already on the screen for me. So again, the UI test framework
is amazing this way so you don't have to worry about small things
like this and you can write the same test and run it on
all different form factors. >> Very nice. >> Awesome. So looks like
this stuff is ready and good to go. Let's go back into our test
and add the last step. >> Yes. You no longer need to Repl
because you already wrote it. >> Exactly. >> Then if you want to add
another page or validate something else like that one. >> Exactly. Yes, so
my usual flow would be always go in and set up all these
pages like we did just now. So I'll have like a Repl running constantly unlike page,
page, page, page. Set up the whole page,
set up all the methods, and then I'll come into the test and actually start writing the flows. >> Got it. >> Because I'd have all of my methods ready to interact with
all the elements. >> Nice. >> So, we have all the first
two steps already done. Let's add in the next page, that's the appliance detail page. All right, and then I'm going to
do "Add to Cart" and it works. >> It sounds nice because
it's only going to then open, it will validate that,
it's on the page and then open it and then done. >> Exactly, cool? >> Very cool. >> So, let's see if we have
everything working correctly so far. I'm going to quit out of this. Let me quickly build a UI test. >> So, you wrote this one UI test
and that's going to work on either iOS or Android? >> Android. Because the whole way, the whole page was your test-based test fixtures setting up the platform targets.
So, it knows that's what. >> Everything. >> That's the one that's driving this little view window over here telling it there are
two different platform tests. Your base page and your
pages have now been collaboratively working to set up all the queries for each platform. So you have the shared queries, they are shared
between both platforms and if they're not the same, you have them set up already. So, it's just like literally, you're going to call
into this method and we'll just like replace
that variable value at runtime. So, it will be the like,
oh it's my "New" button, I have it set up a different value on iOS and different value
Android but I'm good to know, because I know what else,
everything else stays the same. >> Got it, cool. >> You're right, yeah. Basically,
you wrote one page and you have tests for two platforms
kind of like Xamarin forms? >> Yes. >> All right, let me
get this test running. So, let's quit out of the simulator. Let's run our test to see
if this works correctly. >> Yes, right. >> All right, let me pull
up my Android emulator. Let's run this on Android. >> So, I had to do
just double-tap and then it should launch it basically? >> Yes, it doesn't get focus back to the emulator but it'll
just relaunch your tests. >> Got it, okay. It starts
a new session every single time, so it's kind of like
a clean sessions basically. >> Yes, exactly. >> Cool. >> You can easily control that. They are like setups in
the startup that you can like, if you want to disable a clearing out AppData and things,
you can set it up. >> Cool. We'll see how
everything's working. So now we're pressing
the home appliances. >> Okay. >> Some network issues. >> Yeah, let me quickly
refresh that, come on. There we go, found our
appliance and quick cool tip, if you're wondering
what's going on and if seeing nothing happening on this way, this is a cool little window here called application
outputs dash unit tests. So this will basically
see you what is getting printed out from
the UI test framework itself. So, you can watch
through all the steps. All of them waiting for element
matching home appliance, that was the trait for the last page and it then was
tapping on coordinates as actually the actual element but UI test will infer that as
coordinates, and tap on it. So, it scroll down. >> Now, I tapped it. >> It did. We don't have
functionality yet in the app. Good feedback for the devs. >> Yeah. >> But they can still use this UI test to make sure that at least this point
didn't break anything. >> Very cool. >> No regressions, so. >> It's super simple code
and the test, just a few lines of code, you already have it up and running? >> Yeah. >> Very cool. >> It's kind of easy to
follow through also, like if you just read through
the words in the test, you'll be like, "Okay, yeah,
homepage, makes sense, appliance, yeah appliance
page "Add to Cart". Yeah that's just a person can do. >> Very cool. Awesome.
Well, this has been really great because I
know I've been trying to write a lot of UI tests for a lot of my applications but sometimes it
seems like a lot of work to do, but kind of can simplify it
this way, which is very nice. >> Yeah. >> So, I'll put all the source code and all the links in the show notes, you're going to be a PR, correct? >> Yeah. >> Awesome. >> You'll see it all in, I will go bug David, and ask him to merge it in. >> Put a bunch automation ideas. >> Yes, indeed. >> Awesome. Well, thank you so
much for coming on the show. >> Awesome. >> Yeah awesome. Well, thanks
for everyone for tuning in. Again, we'll put all the links in the show notes and all are really cool frameworks into the code but
also to UI test documentation. So that's going to do it for
this week's Xamarin show. Until next time, I'm
James Montemagno, and thanks for watching.