Best Practices for User Interface Automation | The Xamarin Show

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
>> 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.
Info
Channel: Microsoft Developer
Views: 10,269
Rating: undefined out of 5
Keywords: channel9, Xamarin, UI Testing, xamarin.forms, user interface automation, automation, testing, ios, android, uitest, visual studio
Id: i0UNQvfXZhM
Channel Id: undefined
Length: 40min 5sec (2405 seconds)
Published: Thu Dec 20 2018
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.