I know it's after lunch and it's long 90 minute talk and I don't want anyone to get sleepy. So let's start with some video. So how many of you did actually notice that black gorilla? Like while counting the passes? Well okay, it's okay we haven't noticed that one but in our day to day life we do that right? We find such non-obvious things which might get crept into production and as a quality get keeper we do that job, isn't it? So I think we all deserve a clap for ourselves because we find such non-obvious things and we save those production crappy nights for us, right? Cool. So I am Priti. I have been working with ThoughtWorks since last almost four years now. I have worked on complex web application. I have contributed to different open source project as a part of Peeler 3 activity in ThoughtWorks and now I am into mobile domain and presenting something to you. I don't know how useful it might be for you but yeah I am trying to present my learning. When it comes to work one thing I keep striving for is automate all the things. I mean you feel it what how can one automate all the things? Well that's what I do. I sort of introspect my day. I check that what are the things I have repeated and is there any way I can automate that, save my time, improve efficiency and learn some things along with that. So that's about me and let's start with some questions. How many of you have worked on mobile application? Okay, not many. Okay. And how many of you had more than one platform involved in your project? Okay. Okay. So you had multiple platforms that was cross-platform I can say because was it similar functionality across the app or it was completely different? There is some delta. Right. So that's exactly my project is it's famous biggest US airline and we have been supporting these many platforms. But of course the active development is only on Android, iOS and mobile web because that's what give the more benefit to business. During project journey what we realize that whatever new functionality is coming it's coming for these three platform mainly. And whenever there would change it was coming for all these three platform. We realize that okay we are repeating our self because what we had to do any change is coming. Oh go and implement on three platform. Any new functionality is coming do that on these platform as well. And we ended up inventing Kalatrava tool which is very similar to PhoneGap these days but it was way ahead in time. The Kalatrava which was developed by ThoughtWorks as a innovation in this project. And that means what we have is we have different combination of screens in our app. We have pure native screen. We have pure web view sometimes. And we have sometimes native embedded into web views and vice versa. But our business is very particular about native touch and feel. So of course we have kept followed those standard UI style guides which any platform would suggest. For example in Android you will see navigation and drawer. In iOS you will see that tab bar. So we have those hybrid. It's an hybrid app but at the same time we have maintained that native touch and feel of the platform. Okay. And how many before you raise some hands right about mobile project. Apart from that we all do write functional test right. And why we write functional test. It's not related to mobile is what I want to ask for. Like why do we write functional test. Okay. Whether it satisfies the requirement or not. Functional aspects of it. Okay. Let me help you more in this one. Yeah someone was saying something. Okay. Early feedback that's very valid point. But when we talk about functional test right. Where the fit in our pyramid is the top of the one. You will see unit test then integration test which will consist of many aspects. Like it can have component integration API level test. And what you will test that functional is just the flow. Like my end to end user journey is working properly or not. Right. And yeah it and why why we write it. Because we don't want to write same test again and again. So it saves time. It act as a quality get keeper right. Because it catches bugs if there is any problem in your journey. That will give you early feedback. So this is very important point. It represents what your domain is isn't it. Because in my team at least we follow this practice. Whenever any new team member joins whether he's a dev or he's a be a irrespective of that. We tell him to go through different scenarios we have written. That help him to understand that okay what are the flows present in my application. Like this is the screen from which screen from which flows I can come to this screen. Is what helps to identify that is what functional test helps to identify us. It plays very important role in terms of domain right. Of course we do run it regression suit and it helps in that as well. It gives us it gives us quick sanity and we can take a decision that whether my build is good to go in production or not. And documentation well some people will agree with this point and some might not agree. But again if you write a cucumber level feature it can very well act as your documentation instead of having those typical documentation for legacy project. Okay so these are the advantages of my writing functional test right. And whenever I'm writing in a new automation what kind of things I should keep in mind. Like what are things you should keep in mind rather. Whenever you are writing in your automation framework or whenever you are about to write new automation framework. Can you be a little loud. Test scripts yeah. Easy to maintain that's very very important point. Yes readable yeah yeah okay yeah. When it goes beyond the maintenance then you need to think of those aspects. Reliability. It should give same result when you run in number of times it should not be flaky yeah. Code reusability that's very important aspect. Well let me summarize for you. Reliability is okay maintainability include other aspects as well. Like you want to maintain your logs reports where your test is running how you want to put it in your CI that all aspects will come. But reuse ability is something towards the clean code right. That's the principle sort of we can say. Yes okay from that aspect yes right. So I think almost all points we have covered I will just go through it. So we said that automation test should help us to which saves our time right. So when our automation framework is ready it should take minimal time to add any new test. It should not take like okay longer time than for adding any new test right. Change is an integral part of any application and what is your automation framework if it doesn't accommodate change fastly. So very important point as he mentioned that change it should accommodate change very fast. Reusability you already talked about it. Well that is the point which I think most of the people get like most of the people ignore this point. Why because we don't have that mindset of continuously factoring and using clean code practices in our automation code as well. So if we keep that thing in mind reuse ability and clean code that is going to help us in our automation. Promote high level thinking is something I would like to talk about. When it comes to automation right it's very important that it should represent your domain as I said earlier. And let's say your scenario is written in such a way that you're saying okay click on a drop down. I select this check box it is not going to help any end user who is reading this scenario for the first time. Rather if I say oh I'm just feeling a form it's going to make sense at this scenario level. So it should allow you to write in terms of higher level domain and it should promote to think in terms of that. The most important aspect is keep it simple and we tend to ignore this fact because we want to achieve some things at the same time. And keeping it simple will make our life simpler. That's what I can say. Again I have repeated it but it's very important point and hence. And we'll be taking one example in the next remaining time and what I'm going to do is I'm going to present a problem statement to you. And we will solve it together. Let's see how it goes. The example we'll be taking is a food app, a general food app where there is a food items present. You can place the order then you will enter the details like username, address. There will be a payment option either you can opt for you know cash on delivery or you can go for the credit card one. And if you opt for credit card you will enter those details and then the summary will be shown to you. Simple example and we'll be referring this to for the remaining time. So I am the product owner of this app and what I have decided is I will be starting with Android but I want to reach out to multiple customers. So what I'm thinking let me launch for iOS and mobile web as well. I just don't want to launch Android alone. That's what my business strategy is and that's what we concluded for. So the platforms we'll be having is Android, mobile web and iOS. And I don't want to repeat myself in my development one. So I will be using something which is like phone gap or I want to reuse my code in development. That's the simple thing. So what I will end up having is I will have the native screens as well and I will have the hybrid screens right. And there is no and coming towards the automation point now we'll be focusing only on automation. This is what the product owner so I'm the product owner and I'm telling you that this is what we want to launch whenever we will be going live. And as a QA we want to decide the automation strategy for this one right. Because we know that these are the platforms I'll be supporting in future. So I have to keep these points very well in my mind. All tell with me cool. And currently so now I was product owner now I'm a QA and what I'm doing is I want to decide the automation strategy for that right. But there is no single automation tool which is available which can be used for all this platform right. For mobile web for iOS and for Android. And here we come this is the problem statement to you. What we want to do is we want to build a generic automation framework which can work for all this platform. Given that there is no single automation tool. But also we need to keep in mind the ground rules like automation expectations we have seen before. Like it should be easy to add test, reusability, change and simple very well. Okay and whenever we face any problem what we do. Yeah that's it. We Google right. So I Google it as well. And what I found was some solutions. Let's go through existing approaches right. This is the kit of link which you can like go into detail later. And this is by Calabash. They have suggested this under cross-platform best practices to be used for functional test. I will tell you the gist what they have done in their implementation is they have used different pages for iOS and Android. When I say pages it's yeah. So do I need to tell about page object? Anybody want to talk about it? I mean we had a nice session like at just before this one right. Screenplay pattern and page object we saw that. It's like a perfect example of encapsulation right. You have a data, you have services. Those services will work on data will give you some result right. That's what the page object is. If I have to tell in layman terms how it will be. Okay this is my screen and this is how my page object should be. And we will do refactoring if it goes long and all these things. But in layman terms that's what my page object is right. Going back to the Calabash approach what they have done is they have used different pages for iOS and Android. And each page implement the respective contract. And lateral implementation detail they have done it conditional loading. So if I am running the iOS test iOS pages will be loaded. If I am running the droid the droid will be loaded. Whatever examples I saw and I googled right. I saw they have done they have done solutioning for two platforms. iOS and Android. But in our case we have another like we have to consider three platform which is mobile by additionally to this one. This is another one which is strategy pattern. I would say a simple inheritance. What they have done is there is a base page and Android page in iOS page is extending from that base page. And your base page will define a contract. So in our case if it is food app then it will be order food or place order and check out right. So these this will be present in our base page and both platform will implement that. In our case it will be third platform right additional. This is another one which is similar to what other two like previous two we have seen. It's this screen object pattern they have called. They have referred the tool Calabash iOS and Calabash Android and the respective pages are again inheriting from that base page. Now if we combine these all three approaches and let's see how it looks for our web one right. Because we have three platform how it will look for us. So this is how it going to look for us. We will have one feature file. We will have one step definition and we will have three different pages for three different platform. I like the solution like how do you think? Do you see any problems in this one? Or we are like good then we can go ahead with this one ok. So that's what my solution is right. What's harm in that? Maintain ability ok. That's the principle like automation expectation we have said before and this one is violating that maintain ability. So to add to his sorry somebody is saying something. Oh it's like cucumber size something I am using and cucumber generates the reggae step definition right. From where you can call the page of your business layer sort of that I am talking about. So the maintain ability right somebody mention about that. So if I have to add any new test how would I do that? It's a new flow right. So how I will be implementing that ok. Before going to the other approach right let's talk about the problems here. If we don't see any problems we are good to go with this solution. If we find the problems then we have to search for alternative right. So maintain ability is something I am going to add to. So if I have to add any new test how would I be adding? Exactly right. So you got it very correctly that what is said is if I have to add any new page right. Sorry new test then what I need to do is I need to add three different pages is what he is trying to say. So I will end up adding though the user action is same like login or order food. I will repeat that for number of platform times. And similar is applicable for any change as well. Ok before jumping towards change what kind of changes you would expect at functional layer. What I mean is at functional level test. Ok I sort of got it. Ok let me answer that one. So at functional level test right only two kind of changes you can expect. If there is any change in UI the locators I am using is going to change. And if there is any change in flow right. So for example I have introduced earlier in my food app earlier there was only option of cash on delivery. But now I am introducing a new flow which is credit card one right. So before my page was going from A to C directly. Now with the new change I need to go to credit via credit card to purchase summary. So there is a navigation change like A to B to C. Yes very well. But what I am trying to say is at functional layer you can expect only these two kind of changes right. And if that change I have to implement in with this approach then what I will end up having is using my code right. I have to repeat it for n number of platform times. So definitely these automation expectations which we have seen before are not getting satisfied by this approach. And if I look at the root cause of this problem I see we have different pages for each platform. Isn't it? So what if if we have a single page which will represent all the platform possible? Exactly. So let's analyze this approach with the expectations which we have seen before. So if I have to add any new test I just need to update one page. So it's true for any kind of change right. In a way I am not repeating myself. So I am achieving reusability and let's see how this journey goes. Let's go with this approach and let's see because this seems to solve our this seems to meet our expectations which we have seen before. But I see some concerns here and what are those concerns? I have different automation tool and that's my important concern. Because I have there is no single tool right now available which I can you know make it applicable for all these platforms. There are different UI actions because there will be different API different tool there will be different API and there will be different UI action. And we refer to these action like touch and click those are different right. As he said that there are different locators as well because the platform ecosystem is different at all. The way of identifying locator on each platform is different. And of course navigation pattern each platform suggests some UI style guides to follow. And if we end up following those style guide we will have different flow in our app. I feel these are valid concern but single page seems to solve meet our expectation. So let's do object modeling exercise for this one right. So I am starting with page so what my page is going to have is some ID and some name right. And what behavior like it will be a service on that page. For example it will be a food if it will be a food app right. It will be order food can be service checkout can be a service. So this is my page my name can be any string which I can refer it like it's a English plain English name. What my ID is which help me to identify this page across the app uniquely. And in our case it's a combination of platform and a locator right. So how we can specify simply like this where I will have my key this is simple hash map if we can relate to. Where my key will represent the platform and my locator will be my values. What I want to do next is I want to check whether this ID is present on my page or not. So how I am going to do is it visible from backside like can anybody tell what is it what it is doing. Yes exactly so we have if an else or switch case rather and we are because there are different automation tool. What it is doing is if it is Android it will check existence for that ID on Android. On iOS it will do the same and on mobile web it is doing same. And in software world we say that whenever there is e-file slatter add an abstraction layer and delegate to that. We can do the same thing right. So page will have page ID and we can delegate this behavior to this driver. This is very important concept here. So this driver what the what this driver is doing. This driver tells that okay I am an Android driver and I know how to perform exist on Android. I do not care about other platform. And similarly I can have for iOS and for mobile web right. Okay and here we have solved our first concern already which is we have that we have different automation tool. By introducing a driver yes. Yeah but even though we have APM right with limited reading of APM what I know is there is no single API which we can use for the there is single API for iOS and Android. But if you combine these three platform because the mobile web driver and all this action sorry. Yes that actions will be different you will not end up having similar API. Yes yes exactly. So instead of checking that every time right what we are going to do is we have introduced this driver here and which is going to talk to your automation tool. So if I am using APM driver, a driver will do that exist check by using APM tool. Let's say tomorrow I want to replace it with Calabash. I just have to change the driver code and I am done right. So it does not have to relate with the tool is more around how you modularize your code with your requirements and that is what we have done. Okay so what else page has? Page has elements right different text boxes, different check box and radio button. So in our object modeling diagram this is how it will fit right. Page has element. I will represent my element again element is a combination of my platform and a locator right. So I am going to specify I am going to create a new element class and I will specify that this is my platform and this is how specify my locator on different platform. Now that element is going to take care of different providing different abstractions for locating your elements. And there is an action which is click right. On element you can perform different actions like click, set text, get text. Again we have to do by switch case like if there and we have solved this problem already. Whenever there is a if-else in case of your platform you will delegate that to your driver. So what we will be doing we have page has elements and each element action will be again delegated to driver because driver knows that how to perform different UI action on my platform. Okay and we will not just have one element right. There will be different element and their behavior will be different. So very well we can use the inheritance where check box, text box and drop down table. They will have their special behavior and they will each one will delegate to driver. So this is how it going to look end to end where we will have one feature file, one step definition. We will call some service on my page instead of now if we go back to the approaches we have seen instead of having three different pages we just have one page. What we end up having is three different driver. So very well we can say that my number of drivers is equal to number of platform. So tomorrow if I have to introduce any new platform I just need to plug in my driver and of course I need to update my pages as well that you can that anyway in any case you will have to do that. So this will be my feature and what I will do is I will perform some action from that step definition and page will going to execute that action. And here we have solved another two problems which are different UI actions and locators by introducing element. So what element is going to do? Element is going to delegate all the things to my driver. If we go back right I would like to talk about certain analogy here. Anybody know about I think everybody know about OSI layer right TCP, IP OSI layer. So there is physical layer, there is data link layer, there is a network layer. Physical link layer does their job and give data back to data link layer. And data link layer is aware about physical layer but physical layer don't know that ok there is something data link layer exists. Similarly if you go up every upper layer knows about it's below layer but physical layer doesn't know about network layer. And that's what we have used here right we have layered architecture where element knows about driver page is aware about element. And my test does not know that what I am doing I am just delegating things and internally all things are done by driver. Driver is again giving back response to element and then your test is deciding whether my scenario is pass or fail. That decision is ultimate to your test ok let me move forward. Tell now all with me is it too much? Yeah. So in so you are going to answer your question ok I am going to ask you certain questions. So if it is my login page what service my login page will have? So it will let's say it will be login and login method will look like username dot enter username password dot enter password and submit button dot click right. So I will not repeat this code in my three different pages but what I will do is I will define a wrapper over existing automation tool let's say enter text right. Which is and which knows how to perform that enter text if it is droid if it is iOS and if it is web. So obviously I have to repeat some things but it will be just at one place right. I will not repeat at my page level not exactly wrapper but yes. I think before moving towards let's look at some code so you will understand ok. So this is my feature file and what I am doing is I am these are my items I am ordering dosa filter coffee I know we all are sleepy we need coffee. So what I am going to do this here I am going to enter into my step definition and what I am doing is let's look at one simple page rather ok. This is my user details page how it is going to look I can show you in the app so it will be easy for you to relate. So this is filter coffee I am adding it to cart I am going here I see that ok it is added to my cart I do check out and here I am going to enter details. It is very similar to what login is right I am going to enter name address and I am done. So this is let me get them all you know single ok. So this is how it is going to look this is my username here I have defined that ok it is a text box. I specify that for well it is this is what the locator for web is this is what the locator for iOS and Android. And what I am doing in my service is I am doing username dot enter text here again address dot enter text and I am clicking on a button. Now let's look at the element part right. So if I see enter text I will see three variations of this one because I have three drivers for a droid iOS and web. So this is a simple overridden or polymorphism you can see and if we go to any of the enter text this is how I will be doing. I am extracting the particular locator for the particular platform and what I am doing is calling the respective API for respective platform right. Does your question answer now? I think we can this is hosted on GitHub so you can maybe very well go later and dig deeper and check. Yes that's what the crux of these framework is yeah ok. So I got your question I will answer that. So here if I if I see the look the very important point of my application is look and feel is same. So if I see the text box on Android it will be very similar text box on iOS as well right. Yeah one thing can I answer his question first and then maybe we can come to your part. So my application look and feel on each of the platform right it is very same. But if you so in that case what I will do is I will write a different flow for each platform rather if it is adding too much complexity. What I what I am achieving from this automation is look and feel is same my flow will be same and I don't want to repeat. So if it is a text box here and if it is let's say some radio button or table I will not try to fit into this framework. Because it is it is adding it will add complexity as you said menu bar yeah it will not fit. Yes yes yeah ok yeah. So we we had that problem and we take we have taken a call case by case basis. So it's it's your wrap it's your driver right it's whatever you call if your team is if you are happy with writing a swipe ok. So let me take a minute if it is a swipe right what I will what I will do is I will have different actions in my driver. So in my way the swipe action will not hold true whereas it will hold true in Android and iOS right. But the swipe action can very well be done by the button if there is a button and my intent is I want to cover my user journeys. All that minor level details will be taken care by unit test or integration test that is what we have followed. And the interesting problem we are going to see next is about the different navigation patterns which we see in our framework which is menu right. So this is a Facebook screen shots I have taken. I just he didn't mention actually he mentioned actually the UI gestures and all this part gestures and all these things. But here the point is you have different way of representing your menu right. In your Android this will be your menu in your iPhone you will call this is your primary menu. In mobile web this will be your menu where you will click and the menu will appear like that. But in iOS there is one more way you can have the menu where you will click on the more one and you will have a secondary sort of secondary menu we can say. How and this was the problem we face and what we came up and we started thinking that ok can I define my menu as a page. Well my menu will have ID what will be ID of my menu what will be name and what will be elements of my menu. So menu items menu items are obviously elements of my menu page and what will be my ID is this one where I click on menu item. These menu items will be shown and very well I can have this abstraction in place where menu is a page itself. Again in our diagram this is how it will be shown I will have a menu. Menu has menu item menu is a page so it will have ID name and elements as we have seen before. What menu item will have is menu button and a type. Type defines that whether it is a primary menu or a secondary menu. If it is primary menu it will be continuously visible on my screen. But if it is secondary I need to do some extraction like click on the more one and open the second navigation part. So here we have solved the navigation different navigation pattern problem as well. We will see in action that how that how we have abstracted our menu. Okay so single page for all platform seems to solve our all the concern. But in later case we face this problem where I order the food and I go to user details page right. If it is success of course and what I will have is my back. What I will have is we proceed there is act there is service defined on order food. I will click on order food button then I will wait for user page to load and I will return new page. This is what I will be doing in any case of my click right. And that is what make our application flaky because what we do is we do not handle such weights and if let us say wait for user page to load will be different for one page and for another page. Then we will end up having the weight problem in our automation soon. And what is going to happen is I will the action which is repeating is click on some button wait for next page to load and return that page. These three steps will happen on each and every navigation in our application. And we saw that okay we can abstract it out this logic as well. And let us see so in our object modeling diagram where we can fit this one. Can I specify can I have this logic in my driver? No because driver is only responsible for UI action right. It should not know about higher level things what is happening at my higher layers. Similarly I cannot put it in element because every element click action doesn't lead to navigation right. So I need something which is very similar to element what about having a transition of your element. Which knows more things like which knows transition in addition to the locator. We will see that how we have done that in our diagram here it is going to fit. And this is my transition element where my locator this is something we have seen before right. I am specifying my locator and for different platform. I will specify my transition like this where 2 is the key and user details is my page. So I can go from if I want to order I want to check out page card page I can go to user details page. This is very similar to specifying a success transition in your application right. So you know so transition will do this transition of your element will do more than one thing. So what it will do is it will click and it will check that okay I have certain transitions given to my I have certain transitions with me I need to check which transition like the which is my current page and I will compare with the transition array I have and I will return that state to my page layer and then page will take care of further things. And let's say in some cases we will have multiple transition right. So if I click on a payment option what I will have is I will have a credit card page and I will have a purchase summary page depending on the payment option I choose. And we can specify those transition in our array very like this. So it is like my success callback so if my transition is successful I will lead some in a way element is telling that if my success transition is successful I can go to either of these pages and if I go to any other page than this one then definitely there is an error right and that error has to be taken care in your scenario. Well in some cases in some cases you might have an error right. For example let's say whenever any transaction is successful we show a dialogue box and whenever there is any when the transaction is unsuccessful we are showing another dialogue. Let's say it is user error dialogue right. So I will specify and I want to differentiate between my success and error. How will I differentiate by specifying two different callbacks for that. So I will have a two which is success and I will have an error which will represent my error transition yeah sorry yeah. Now this is an interesting scenario if there is bug in the code right and I basically what I am doing in my functional UI test is I am checking the flow. So there is a bug in the application and I lead to a wrong page. Who will check that because my transition array my transition to and error might very well have those transitions specified right. Yeah but who will do that that is something already we have seen the transition element is doing one of the pages right. So what happened is in my success transition there were two transition specified A and B huh but there is a bug in the application code that flow can very well go to A page and B page but in that scenario I am expecting that it should go to B page. But it landed on A page right. So whose responsibility is to check that yeah right. So here what point I wanted to make is your transition element should not be aware of this logic because what it should only do is it should check the state and return whatever state is present to your test. The OSI layer which we have seen the layered architecture and this is how the code is going to look. So what we are doing here we have we will get success transitions and we will get error transitions we are looping through those we are looping through those transition and we are checking if there is any match we will be finding for these success or error come out of this loop and we will return that state to next layer and that the next assertion part will be taken care by your test. That is what this logic is doing and of course we are looping for certain amount of time so that we do not go into indefinite loop. So little implementation detail how we do is we require specific driver we have taken this from Calabash as Calabash loads that specific pages for the platform specific test you are running we load the specific driver for specific test and of course if there are so many pages we end up having page registry which will manage all these pages you can and you can very well have that business layer in place where you will delegate that to business layer page registry will just is going to manage your pages. Interesting part is we have written RSPEC unit test now you will say that ok we have it is in a way that test for a test but because we had such a complex logic in our framework the transition part and such other things we have written unit test for this one. You can refer to the Github repo I will give you link in the next line and some things we have automated of course if you repeat you should look for opportunity to automate and similar way we saw that ok I am I need to write that code for web iOS and droid for each of the element and ID. So we have created a red task for that one we will see that in the demo part and these are some learning keep looking for the refactoring and take the use case solve that use case and go ahead if you have another if you have use case which is and if you have solve one use case and it is conflicting with the next problem you have take a look back again do refactoring and build solutions on top of this. These are the links I was talking about yeah so to add any new platform what you need to do is you need to define the driver but at the same time you need to update the locators as well and let us say you are forecasting that change that you will be going to support that search platform you can abstract out again the element part where it will accept multiple as many as platforms you pass and anyway whatever approach you go with you need to update the locators so that you cannot avoid. What extra and what less thing you will have to do is you need to define that driver wrapper and you are done you do not have to bother about services at page level that is what you will do it is a it is a hash map yeah yeah we can do that in cons of each one it will remove the readability purpose so if I come to this page and let us say I want to update only Weblocator then I need to remember the sequence oh first one is web second one is iOS and third one is drawing that ok that will be like additional refactoring if you have to do but I will not to be often change then yes we may look out for separating locators from your page but if I know that ok whenever there is change it is going to be applicable for all the pages I will prefer to keep in my same page so what we are going to do is a short demo let us look at the folder structure how we have is we have app which will have page pages and page registry page registry will manage those pages framework will have different elements we have seen element base class it will define a factory for element so you need to just call that ok give me a text box and it will give you a text box and it will provide you interface for that one what platform specific code you will have is iOS driver environment.rb because I am using cucumber very well but if there will be any hooks any specific things you want to do before and after your test for specific platform you will have that code in your iOS like platform specific folder so the code which is specific to platform is only in iOS the other pages and framework is common for all the platforms right the flow we have seen before is food then we will place the order then we will enter the details then there will be payment option and depending on the payment option I will go to summary page or I will go via credit card page so I have one flow already in place I have written it already the flow we are going to automate is this one and we will see that how it is easy to add any new flow and new page new page into the existing framework so I am going to close all the pages so this is my cash on delivery feature right what I will have is similar feature I am copying right now for the sake of time and I will have credit where I need to change is I choose to pay by credit card rather than cash right the other flow will remain same this is undefined so I will create a step definition I will use the existing one so earlier if I go to earlier step what I have is payment preference here I will have is pay by credit first I will go to payment preference I will add that method and I have already locators with me so I will be taking those locators for all the platforms ok this is important aspect let us look at this in detail let me get all these elements into one view ok we need only this one so we have seen the flow right earlier I was going directly to purchase summary now if I click on this button I can go to the new page which we will be creating which is credit card and there I will enter the credit card detail and then I will go to purchase summary so for that I need to specify here multiple transition which is let us say my user details which is something we will be defining now no not user detail credit card detail and this is undefined now so we will be defining that page we will show you the rec task which we have created for creating this page so it ask me that ok what is your class name and the class name we have entered is credit card details only name something which we have seen that every page has some name right so I will have is credit card enter folder name let me check the folder name is its folder food and they are asking me that to which page I will be going to so this page has just one transition so I will be going to purchase summary and I am done so here if you see the new page is created right and what we need to do is we need to add ID define transition define the service method and we are done for this page as well I have copied the locators so very well we can I am copying them credit card details I will have two text box one for entering credit card number and other is for CVV I am going to copy all those locators as well and this is my done button which is defining my transition yes what service we will have on credit card let's define that service first so I will have is enter credit card details for example in the same service I will be specifying here I am just defining constant for my credit card number CVV and the wrapper we have written is enter text which for text box and I will just define it so here I am done so my scenario so what we wanted to do is we wanted to do pay by credit card if I proceed I will pay by credit card and then I will enter credit card details and of course I will see that I see the complete purchase summary so the transition assertion is been taken care of you that's all that's all I had let's run the test do you want to run that test do you want to see things in action okay this is the web application so I am running for Droid and iOS here you will see that okay it will work for good oh iOS is just started so meanwhile we said we had set some automation expectations for us right it should be easy to add test it should be easy to change reusability and keep it simple and that's what we have achieved through this so if any test any flow I need to add if the page what I need to do is just define a page add a flow and I am done very well you can do refactoring on top of this you can have business layer in place if it is data in your feature file you can put it in your test data you can define model or you can define the builders for those data but this is what the crux for cross-platform automations yeah in our case also what we have is we have very light so we have android and iOS they are very similar but in mobile web we have very less functionality because we wanted to keep mobile web very light so what we do is whatever is there similar you define the same feature and same page for that but this is not restricting you to define a new page for just one platform in that hash if you just specify web it is going to work for you so that is what the similar question he has asked before right so the UI is different then do not add complex but if for some screen let say your UI is different then do not add that complexity of making that same throughout your single to achieve the single page for that one very well you can have different pages for that write different scenarios or if you see there is an opportunity to abstract it out and it is working well do that yeah if it is not going to work just do not try to fit in that that is all that is what I can say yeah because environment.rb is something which is getting loaded first time right and I want to do certain actions for my platform if you have if you do not have any like in my application what I am doing in my environment is doing that apk I am installing in my simulator I have that is what I am doing before running android test similarly the same action is doing for iOS so if you have certain hooks certain actions you need to perform for each platform which is different then you can have different environment.rb that is something oh I miss here sorry my bad so in environment.rb right what we are doing is I said that we are loading conditionally if I am running android test I am loading the android if I am running the iOS I am loading iOS specific part so that is what I am doing in environment.rb and apps like not for driver for pages so what we just did is we created a new page yeah you can you can do that no I just wanted to you know give single response to each environment file so you will very well have one file which will call three file internally differently right instead of that I had three environment.rb which will do different things for me and app life cycle hook is what I talked before it is doing the before and after part so before test I am loading certain applications I am cleaning data that is what I am doing before and after so that is let me let me go to code that might give you clear idea so this is for droid I am checking that before install the app and after shut down the test server because android internally I am using calabash for this one so it starts the test server in the app itself so I am shutting down that server so it will recreate that server whenever I am running a new scenario oh it is not like that we just I think ruby is a scripting language and there are advantages of ruby and disadvantages as well and when it comes to automation oh you will not able to see that and when it comes to automation right you end up writing a script and for that we prefer ruby over java but there is no in java there are other advantages because it is statically type language right you will get that those auto suggestions which you will not get in ruby because you can do meta programming and make and that will make your life worse but yes if you are familiar with the language meta programming is something you will go for I would say defining sometimes it was challenging for us to define you know correct wrapper for each of the driver yeah but otherwise it worked well for example scroll scrolling actions scroll to and all these things I think what we ended up doing is we defined so there was some existing framework and we built on top of that so if we do the refactoring of that existing one this would not have happened in our case because that was the case that was most this is the part which is most painful but the day we make all these driver api consistent right that problem will be solved thank you if anybody has any questions we can take or otherwise I am done these two people like we three together paired a lot for this framework and of course one of the learning is dev qa pairing helps a lot like you get that different perspective which you might miss sometimes that's what my learning was thank you