 I run the Israeli Selenium Meetups. So this talk actually started as a discussion where we talked about page objects. And everybody says they want to implement it in a different way. So I just put it in writing what people think they should do. And what I wanted to present to you is the questions and the pros and cons for every decision you can make when you decide and you create your page objects. OK, so let's start. So about me, well, I did a lot of stuff. I always thought it was non-related to test. But apparently, everywhere I worked, it was test-related even with IBM. So it was how I helped the testing. The cadence, that was the language specific for the hardware verification. And obviously, I helped, I know a lot about web, but I thought nothing about testing. And I helped with the weeks with the test automation a bit, and then found out there's no UI verification tool. So I ended up in Apple Tools. They have a great UI verification tool. Should try it out. Now I'm trying to solve the challenge that everyone wants to solve for the last 30 years, which is the Recode Playback Tool. So let's start. So I'm going to talk about page objects, why and not, and how to remove all your slips, that everybody that's the source of all evils. There's a different talk about locators. You should probably check that out. And we're not going to talk about retries, which you can see in single-page applications. You see it on Angular. You should probably use more advanced techniques. So the page object is just a simple design pattern. So it's funny because what developers do, the architect usually, he takes the model of the application and he needs to transform it into a UI. And it's funny because now we have to take the UI and we actually want to transform it into the same model again as the user sees it. So it's almost the same. It resembles the model that the architect saw it in, that you have in the back end. But now you have to reverse engineering. And so what we're going to talk about is software design. How will you use? You use objects, you use classes. People like to use it so you can reuse using inheritance. Some people prefer delegation. You can use all that. So let's start with page object and see what it is. Everybody knows it by different names. When I started it at Wix, like 10 years ago, people called it drivers. There wasn't any documentation. And it's not just pages. It's not just for a specific page. Every component should have something that some kind of driver that you can interrogate the component have. And actually what you want to do is separate between the implementation and the model. You want to have it as a service. You expose a service, actually, at the model, which you can interrogate and drive through. So I think someone says that Simon said that if you're using in your test, you're using the selenium. So you're doing it wrong. So I hope I didn't misquote anyone. So we'll start with the basic login, which is very simple and kind of interesting. That's the thing, the Google login. And after you remove all the CSS parts that related, you basically get just two text boxes and a button. And usually people start with a test, who actually looks like this, you just, OK, if I want to do a login, I'll enter some text to each text box, and then just click whatever I want. And now after I log in, I'm going to try, I'm going to wait till something loads up. And I'm going to do some assertions. So usually every step is why you start in a state. You use Tim Stimley to go to another step, and you do some assertions. So OK, so Simon says no. Please don't do that. So let's see what can we do. We want to split between the business logic, between what we're actually testing, the application itself, and remove and change it to move to the side, or the implementation part. And I saw it in action at Wix. They asked me to help around with the test automation. The guys started out really, really bad. Now Wix has the best automation in Israel, probably. But there's great guys there. But they started out with exactly what we said you can do. So the first thing I did was, OK, let's separate. I wrote over the weekend interfaces for the entire application. And I gave it to the tester and said, OK, use those interfaces. Now you can write tests. You have the business logic. Everything a user can do, everything you can do with your click, and your test, and your scenarios. You can write now. It's interfaces. But now give me two Wix. And I implemented the application so I can easily implement the drivers. So I separated between the business logic and the implementation that worked out great. The tests were, after two weeks, the test were the minimal code they wanted to test that was over. And we implemented it. So that worked out great. So let's see how we can do that in exactly with the login page. We do want to have something representing the login page and make a connection, a simple login action. Now the question starts. So when we do this presentation is in Java, but the same question applies to all not just the static languages like C-Sharp. I think the question is about architecture. So the same decisions is similar in PHP, Ruby, JavaScript. So what do you think, maybe we should ask you guys. So what does the login has to return? Let's say the login brings us to the gallery page. So there's two options. Let's go to let's return void or let's return the gallery page. Who says let's return void? Who says let's return the gallery page? OK, so let's go through all the options we have. So the first option is void, which means it has an advantage. So that's what you'll do. You'll do a login, but then you don't know where you are and you have to wait till the page loads. And there's an advantage here. And the only advantage is it says, OK, the login deals with the login. That's it. It doesn't have to deal with anything else. So why should I deal with something? The return, where should I go? I don't have the login. I don't know where I'm supposed to go. But it doesn't handle any of the other issues we want to know. Did the login succeed? Where are we now? Are we at the login? Is the login failed and we're back to the login? Are we at the gallery page? We don't know where we are. Is it ready? Should we wait more? So the second option, I don't think it's improved, but probably should raise that. So it's a different option. The different option is let's return the gallery page. So when we get that, the nice part about it is that, OK, I return the gallery page and now I can use it. Now, of course, with a small timeout. That don't worry, we'll deal with the timeout. So the source of available for me when you start writing tests is there's one thing is that's the random sleep. Nobody should, everyone, when he first writes his own test or program, writes a sleep. But nobody should ever use sleep. But we'll get to that in a second. But the first question is, we need to find out. There's an asynchronous, that's the difference between unit testing and end-to-end testing, usually, is that you have asynchronous calls. You're doing the login and it's going to take some while. You're not sure how much, maybe there's hundreds of VMs on one machine, so it's going to take forever. So we're not sure we need to deal with that, but the first thing we need to decide is where to put it. Should we keep it exactly where it is right now in the test? Should we keep it in that side of the login? So let's see what we got. So the first option is, OK, let's add it to the login. And before we return the gallery. And so we wait. The nice thing about it is that you get your test seems like synchronous code code. Yeah, it looks great. It looks like unit tests. Give me the login and do the login. And now I can do something on the gallery. So, wow, it looks cool. Well, actually, if it's something, if we need to wait till the gallery is ready, maybe we shouldn't do that inside the login. Because the login page doesn't know what's the gallery page, it's got nothing to do with it. So maybe if we want to wait for the page, well, let's give it a name. I wait for a page. Let's put in the gallery page and have the same code, the same sleep in the gallery page. So that could be a good option. And if we're back to option one, that we have a login. And after we logged in, we can now ask the gallery page, let's add a static method, and said, OK, wait for the gallery. Now, it's going to interrogate the driver. It's going to aggregate the page, the document, and find out when it's ready. The gallery page is the perfect place to put everything related to the gallery. And once it's done, it's going to return an object, the gallery page object, an instance of gallery page. And we can move on. So that's a nice way to put it. And so what we can do is we can combine two options. And in the login, when we want to return the gallery page, we can ask the gallery, OK, I want to return a new instance. So why don't you tell me when you're ready and give me an object and I'll return you? So the login does know where you're supposed to go. So maybe the login is a different, I chose the login because it's very, very simple. Everybody knows it. But there's a lot of situations where inside your page, you know exactly when you're going. So this is great. I'm not sure if the login is the perfect scenario for returning some return time. We'll get to that in a second. So here the login waits. And if the login has the gallery, tell me when you're ready and I'll return. OK, so if every page is asynchronously, so maybe we should add some conformance. I want every page to have some method. This forces the developers to implement such functions. So we can have every at the login, we can have at the gallery, we can have every component. We should have one. So we should probably have it at the base class and have things inherit and extend it. But my computer says no. You cannot have override versus static methods. But what we can fix that very quickly, if we just remove the static, so it won't be a static method. We'll create new objects and then tell them wait. So it's almost the same. But I think in some languages we can even improve that. Because for here you see the gallery, the wait for page. It implements the wait for page signature, which is returning basic page. So that's what everyone does. But in Java you have the flexibility to return something, even not just returning basic page, you can return something that extends it. And it's still considered not breaking the signature. So you can return a gallery page. So when you call the gallery page wait for page, it returns a gallery page. And this is another option. We'll see it in a few minutes. But this is another nice option too. Just let's put it in the constructor. If the same waiting, and it doesn't matter if it's waiting or if we saw wait for a slave, but we can use the constructor. And the first tip I want to keep using the basic page. It's that common reuse using inheritance. So if you have more methods, more things that is common to all pages, you just add it there. So we'll reuse via inheritance. So people start asking, OK, how do I support different users on different pages? So we can see what we can do. So if you want different users, OK, let's add a user and a password. That could work, right? Sounds simple. But OK, then so we get to the first challenge. And it's that the login, we can log in with the correct password and then the wrong password. And as you can see, the wrong password will lead me back to the login page. And a good password should lead me to the gallery page. So that's these two different places. But when you try to write this code, it's called overloading. And overloading gives you, when you have different signatures, you can use different methods, right? Different codes. But in Java, for overloading, it has to be the name or the parameter. So you can't use overload only with the return type. So you can't. This is going to give you an error. It's going to say, no, no, those are not free. Those are three different functions. You can't overload. So you're stuck. So what you'll see in most cars usually is login as incorrect, login as admin. So different users get, which point to different pages, you'll probably see this. So that's Java. So it won't happen. You can JavaScript or Ruby, you can do that. So that's the invitation. But the next question is, username is in the password. Why do I have to add? I don't want to use a username and password. And that depends on what you want to do. Because when you have the login page, the page object, you have two options. You have two different scenarios. You have one scenario that you use the login to get to the gallery page, and you want to test the gallery page. That's one thing. And there's a different scenario when you want to test the login. You want to test it with a bad username, a good username. So there's two different scenarios. Well, the first scenario when you want to have it as a setup for another, for testing a different component. I don't need any problems there. Because I don't care if you do the login. I just want to log in. I just want to get to my component. So I don't care. I want it as simple as that. I want to have every developer doing the login page dot, and then the ID will automatically say, OK, you have a login. That's easy. That's it. Simple as that. And the implementation can vary from cookies to Google Docs, Google Accounts, and real user and password. I don't know. We don't care. But if we want to test the actual page, the actual login page, so here we do want to have a different API. We do want to have a, the recommendation is usually, OK, had a method called login with the username and password. But there are some people that prefer having references to the implementation, which is usually less recommended. But there's kind of people that do want to have this kind of thing, so they can do unhover effects or something to mimic the user and have it do something similar as they manually do it. So it depends. So should we put everything together? Because we have the simple login, and the straightforward one, and more complicated. So OK, again, this is the login page very, very simplified. So we have two methods. But you can have 20 methods for each one. So the question is, should we put it together? I guess the question answer is yes. Yes, I do want to have it all together. That's all the code is related to the page, to this login page. But if you want to purify it, so if you want to make it simple, you can actually have two interfaces. The one that has the login, one that has the simplified logins, one that has the more complicated way to interrogate the application and drive it. And you can have one method to bring you one from one to another. And the implementation actually, they can be both in the same class that we have interfaces for. So you can use interfaces to expose only the simple API. And if someone wants to, you'll get the more collaborative API. But he can move that only if he needs to. So you can have a convention, getting the driver, and every component will have a driver as well as the simplified API. So when you start implementing page objects, you'll probably find things like you'll try to get reference to an element. So usually you'll start when getting a reference when you want to use it. So in this example, only when you want to do the login, you get the reference and then use it. But usually you'll need it in several methods. So you say, OK, I'll put in the constructor. Then I have reference and I can use it a million times. So you probably had added to the constructor. And then you notice, OK, it's really repeating itself. And every element I need to find in the page is actually repeating itself. So is there anything I can do to remove all this glue code? And actually, yes, there's a page factory. Does anyone here use this page factory? Yeah, cool. So page factory gives you exactly that. You can tell it, OK, initialize everything for me. I just have web elements. And all I want to do is I want to have references to the page. So you can even simplify that and add it to your member. Even the constructor will say, you can add the weight, the weighting to the constructor. So if we do all the weighting until the page is ready, the code for the login at the constructor, OK, after it's done, we can call the page factory and tell it to init itself on us. And that's it. We have everything ready. So sounds great. And actually, what the page are for some people that don't know exactly what happens, what's the magic behind it, he looks for the names. If you have a web element named email, he uses reflection. And he says, OK, you have a field member named email. And he tries to find an element at the document with that ID. If he doesn't find it, he's looking for it with a natural boot name named name that the value is email and so on. So what happens if we have, this is the real example from Google that they use. And the name is Q. So nobody wants a field member named Q. The R&D manager is going to kill us. They added the notation. So you can say, OK, it's called on the page. And the document is called Q. But when I use it, I want to call it search box. So I just want to call it differently. And of course, it couldn't be pre-fied, because there's a shorthand version. So just find by name equals to Q. And you have, they support the ID and tags. And you can write your own custom annotations. That's the best part. You have different ways to find elements. You can write your own code, because everyone's code is different. Maybe yours is extremely different. Well, as for assertion, there's a strict recommendation. It's only one slide. There's a strict recommendation that people tend to go with, so adding it to the test or adding it in some batch of class so you can reuse it. But I did see it in people still using in-page objects, though most the best recommendation, best practices, just either the insider test or insertion classes that you add. But just one more thing I wanted to ask was how do you avoid the random sleeps? I promise to get rid of it, because nobody should use random sleeps. So there's a few, don't worry, don't try to Google the names. I just made them up. And there's a couple of options you can use. There's, I think, those are the most common four. It's four, because the coordinator has two options. And the no smoking without fire, that means that has to happen before. So usually, if you have smoke, probably you had a fire before. So it's a before relation. It happens before. So usually, you wait for an element and you know that loads last. You talk to the dev team and say, OK, which element loads last? And if I know, if I wait for that element, I know the entire page is ready. So that's the first common that people use. There's the take your time idea that you use that just, let's try to click it. It doesn't work. Let's try it again. If it doesn't work, let's try it again. And we'll do that until there's a timeout. So I'm taking my time. I'm going to try a busy weight. And suddenly, I did the implicit weight. So it got easier. People usually start with this and then they get bugs. So I usually don't recommend using it. And the coordinate, that means I'm going to have someone at the application site tell me your ideas I can find out. I want to sync everything between me and the application, not just use weight for random elements. So what you want to do, you have two options. The one is use the first option is I want to wait for an event to happen. So we can do two options. There's a we can, when using the test, what it actually does, the implementation, we'll probably use asynchronously. You can inject JavaScript to the document. But we can add run asynchronously JavaScript. So we inject JavaScript that runs in a loop and checks for something to happen. When he finds out something's OK, when something happened, you can be either he checks for some kind of state. And when he gets to that state, he calls the callback and tells me, OK, you can move on. So on the testing side, it's completely synchronous. It's just sync because we're waiting till he'll send the callback. So usually you have the execute, I think, scrape, which is very simple. It says you write something that runs code. But what it means is it runs JavaScript code that runs the callback. So it looks very, very simple. And it really is simple. But there's a small gotcha, you have to remember, that they provide, you shouldn't wait for the callback as a name. You should probably wait for it. The callback method is the last method. That's what they promised. This is the last method. So you should probably use this kind of code. OK, find the arguments. Take the last argument. And this is the callback. And when you're done, when you get to the specific state, just let us know. They have let the selenium back know. So we're done. But I'll tell you what I don't like about this is that you have, if you use Java, and then you have to write JavaScript code, and you have to ask the developer, OK, come and write in my code and JavaScript and put it inside the, so there's good editors like WebStorm and IntelliJ that can syntax highlight JavaScript. But it's far from perfect. And the question is, can we do something that we can ask the developers to, let's make a contract, very simple contract. It's going to take three lines of code for me and three lines of code for you, but we'll have a contract. And then I can know whenever you're ready, whenever you switch the pages. And actually, three lines of code I'm going to show you. So what do you want to do is, in your code, you say, I want to wait for some test event inside the application. And the guy writing the app, in my case, it's a lot of time, that was me. I would admit an event says, OK, I'm ready. I'm done. And what it looks like is something like this. That's two methods. And the implementation is rather easy, because you use it before you return it. We move the sleep and wait for test event. And the implementation would actually be very, very simple. Usually, in your write apps, you have the application somewhere. But you can have another. If only not in production, just in testing, you can have another element for testing. And people can add elements there. And you're asking me, why? Because what's the best thing about element? What about selenium? What can you do? What's the best thing, the easiest thing to do in selenium? Finding what? Elements. Wait for elements. We got that in selenium. So you can tell the developer on the other side when you're, if you want, instead of submitting an event. So I should write an event. I need to add JavaScript callback. So no, just add an element. And I'll wait for that element to exist. So if we have this, the div with the element with the ID test, so it's very easy for us developers. That's the entire framework. That's it. We need to wait to an element. We're waiting for a gallery-ready event. So we know that the developer will add some gallery-ready element to inside the test. So that's easy to find out. This is the code. That's it. And once I'm done, let's prove of it. And on the other hand, the developer just has to add just one more line on his side when he's done. When he knows, the developers always know when it's ready. They know. Trust me, they know. I don't think they had to add. It's just one simple method. And usually there's a lot of frameworks right now, like AngularJS and Ember. They have routers, which change from state to state. And usually they even give you hooks when changing states. So you can even usually add something that automatically adds this. You won't even need this single line. So when they change the state, they automatically add this element. And the implementation, of course, is very, very easy. It's like two liners. OK, if I'm not testing, right, if I'm production, I probably don't want to do anything. And they're supposed to prefer more pretty implementation. But this is easy to explain. If I'm not testing, then return. But if I'm testing, I should probably add this as an event. Should we add an element with gallery ready as a class? That's it. So I guess what I want to tell you guys is that this is a discussion. You saw there's always two options. And I guess you should decide, every time you ask yourself, why do I make the decision? What's the pro and con for every decision I make? And the best thing about meetups and the conferences is that you talk to other people and they show you what they are using. People here use, there's a lot of more techniques. Some people use page objects as static methods. They don't use the objects at all. They say, oh, what are the chances I'll have two galleries and one page? So there's a lot of techniques. I think the best thing to do is one, talk to each other. And the second thing is when you do something, talk about it. Blog is Dave here. He's talking a lot. And he has a blog. And he keeps on adding common use cases. And I think he has a book right now. He just added everything together and added lots of more things you can do with the commons in Selenium. So what I really think that you should do is just talk to each other. And if someone has any questions, now is the best time. Yes? OK, so the question is about assertions. Why is it recommended not to have the assertion in the page objects? Usually when people try to use page objects, they want to use it as a way to interrogate the object and the component in front of them. Usually it's components. So it doesn't have to say something about the business logic. So the page objects, they deal with implementation. They know, OK, so I have a business logic, the API, which means A, B, and C for login. I'm going to implement it. So you implement the login. But there's a lot of cases when the business logic you want to have on the testing side. So that's the business logic on one side. And it's not something that there's a must. The whole question here is, every language, we don't have to use even objects. Everything we want to test, we can write it without object, without classes. The whole thing is just design patterns. How can I write something that will be easier to maintain, easier to write? So every time something fails or not, I know exactly where to change that or where to add it. I want to make something very simple and find out. I don't have to think, oh, where should I put it? You want to have design patterns that go back in. And then you want to focus on what's important, the testing, the business logic. That's different between every application. And not thinking, OK, should I put the time here and here and spend so much time? So it's a recommendation just because you try to separate between the business logic and the implementation. So yes, why do you? OK, my question is, why won't you know? Because after you landed somewhere, you will find out. So you have some code that his job is actually finding out which page am I on. Maybe this code should ask, the gallery, is that your page? And you should know. And you'll ask the login page, is that recognized? Is this login page? OK, yeah, that's the login page. I'll return the same one. So yeah, OK, those stats are tricky. So in statically-type languages, you can have the base object and then having castings. But that usually sucks. So what you do usually, that's why people use the void convention, returning void. And then in business logic, just trying to find out, having another system, another component, that his job is finding out whose fault is that. Yeah, who's now? OK, it's the gallery. OK, I should probably call that. The page. Yeah, yeah, so that's why I said in the beginning, because things are changing. There's not lots more single page application right now. So that's why I ask in the Q&A as well, is there is going to be some support for the retries? Because every day, the page out usually saves you a lot of code. So now you have to use something, you have to go back to the old way and try to use it as you go along. And usually, you can try to do is wrapping the elements with your own element. And that makes the tries. And if it doesn't work, it tries to find the element again. So you can do have such a custom web element, your own web element that does the retries. So the funny thing is that everybody keeps doing that. So that's what I'm supposed to do. I hope that something like that will enter Selenium and everybody can reuse the same code. So that's what we're going to do. So we should probably add that as a request. And you should probably give it a thumbs up or something. So I see it a lot. And the stale exceptions can happen more and more. And because, you see, there's frameworks now like Angular that if you misuse it, even if you don't go to another page, even if you change the filter, you have like a filter that filter the items, if you use it in a bad way, which beginners do too. And you can have the same element. It looks the same, but it's not the same element because it actually doesn't refresh, which is bad for their performance, of course. But it has effects on the test. So you should probably ask them, can you use this? Of course, Angular can be proven. There's a track by. There's a lot of things you can do to improve that. But until that day happens, we need to do something on our own. So I hope we'll do something that's very nice that Selenium will pull in. Oh. And so, ah, yes. Sorry? The web element, we're talking. Yes? What's the question again? Are you answering his question? No, if you do see someone having a pretty solution that can be used, so if someone knows already, so let me know. OK. But there weren't any, everyone writes their own code and that's something that we should not do. Yes? So you're talking about the option, the second option, that if you return an object, so what happens? It's a similar question, that what if we should return different options? So there is no clear decision on how to implement it for now. So I see a lot of people just returning a base class and not using some kind of someone that they can ask later. And it depends. And usually in not static languages, static-type languages, you don't have that dilemma. So by the way, does anyone here use a JavaScript as the binding language? It's funny, I really hope that I will catch on, because people, the developers themselves, use JavaScript. And so maybe if the testing would be in JavaScript, it could be better communication between the developer and the test automation. And so I do starting to see some improvement on that side. Anyone here knows about Protractor as well? So and the Protractor is based on Selenium, but it gives a little bit better API. The small difference is for better API just for Angular, because Angular has some things that it waits for and does, there's something called dirty checking. It's called asynchronously. So you usually have to wait for some stuff, and he does it for you. So that's a nice implementation in JavaScript for AngularJS. So guys, thank you very much. Thank you.