 So, before we start, how many of you have worked with WebDriver, used WebDriver? How many of you have used Java language, apart from Java in any other language? Anyways, majority of you are using Java. That's great. That should be a nice foundation for this, okay. So just to set the context right, let's quickly go through some basic things. So you know you have WebDriver. So this presentation by Selenium, I mean only WebDriver, we're not going to talk about Selenium 1.2. So Selenium WebDriver is abstraction for our multiple browser implementation, or instead of writing tests or automation scripts for each browser, you just write using WebDriver API, and then you can run it on any of the browsers. But ideally, there should be a implementation of WebDriver for the specific browsers. So at this time, people write their automation scripts, write directly using WebDriver API. So is it a good thing or not so good thing? Then we have this famous thing. If you're using WebDriver API directly in your automation scripts, you're doing it wrong. Same as to what? So there's a link to that in Martin Fowler's Blinky. So what is the problem here? Anybody? It leads to a lot of rework, fragile tests, et cetera, right? So this is the context we are mostly familiar with. Let's try to see another context as well here. So here, say the automation scripts are written in JavaScript using WebDriver.js, which in turn talks to Selenium server using JSON wire protocol, which in turn talks to the browser. So that's how you can bind any language libraries into WebDriver. Another possibility is like the system in which you're running the script and the system in which actually the browser is running, they are different. So you want to send automation commands to another system, again through JSON wire protocol. So if you look at this point, so one place developers are using the API and you have multiple implementations of that and you have also other language bindings trying to use this API. So it's kind of doing multiple jobs here. So anytime when you design an API, the common issue you run into is the level of abstraction, whether the API has to be fine grained or the API has to be coarse grained. So what are the benefits or disadvantages with that? If you go for coarse grained APIs, developers will have to write a lot of code, right? So step one, step two, step three, step four, like that, you'll have to do that repeatedly. On the other hand, if you go for coarse grained API, it's good for developers for writing the automation scripts, but implementations of the WebDrivers will become complicated. They'll have to implement more. Or you might not be able to expose all the capabilities of the browser through the APIs, because it's slightly at a higher level. How do we solve this problem? Let's just take a look at here. So here you have the, you know, this side it will become more and more complicated if you make the APIs more coarse grained. On the other hand, developers will want a very API. So this is the problem. So how do we solve this problem? That's a very famous saying, right? Any problem in compute science can be solved just by adding another layer of indirection. So instead of everybody directly relying on WebDriver API, you develop a small library on top of WebDriver, which could help developers to write better. Okay, let's quickly start with a simple example of usage of WebDriver. Then let's see how we could implement that using JEP library. Then slowly let's convert our code to more idiomatic style of JEP, how you should be ideally writing JEP code. And then let's build upon that, adding more, you know, patterns into that like page object and see how something, I mean, how the entire environment has to be developed. So let's quickly go through this. This is a simple WebDriver script. So I'm not using anything related to JEP here. It's totally a WebDriver API usage. The differences I have written this in groovy file, not Java, just to make things simpler. You would see the usage of APIs, WebDriver and, you know, I believe what we are trying to do is very much evident from the code. Just to note here, at the top you would see grapes, grab, et cetera. So instead of, I mean, to run this program, you would need the Selenium jar. And here I'm trying to use FirefoxDriver, so I would also need the FirefoxDriver jar. So instead of creating a Maven palm file and putting the dependencies there, I'm directly putting that content over here. So you would see at grab, I'm exactly giving the, you know, the Maven group artifact and the versions here. So what it will do is it will download these libraries or jars and make them available in the class file. Let's just run it. So it executed real quickly. I mean, I don't have any assertions or anything like that. Just usage of WebDriver. I mean, so far things are fine. Now, what's chat, please? Everything is in directly in my code. I don't have to, you know, create another middle or something like that. If you have script one and script two, if you're running them independently, you'd have to mention it. See, if you're using script one, and from that you are accessing script two, then you don't have to. So wherever you're starting, you have to mention that. Oh, no, no. I'm not, say, whenever you are running your entire test suite, so you'd be using some dependency managers and all. So here everything is in one file. Just to make the demo simple, I'm using it. Say whenever I run a single script or some simple code like this, I always use Grape. But if I have, say, hundreds of files, then I could use Maven or Gradle or anything like that. You could use still, but I would say this is simple, right? It's like hard coding is okay when you have only one file, all right? You want to demonstrate something to your friend. Yes, do that. That's what I'm trying to do. So let's try to introduce Jeb here. So what's bad about that? What's bad about WebDriver? We already discussed that, so let's just try to generalize. Let's take a simple example. Say you meet your friend in the conference and you ask him, how did you reach here? So what's the answer will be? You can buy public transport or bike or whatever, something like that. Instead if he answers like, okay, I opened the door, front door of my house, I stepped out, then I stepped, I mean, I climbed down the staircase, then I got into road, then I walked till the bus stop, then I got a bus. How do you feel about that? Not so good, right? Is it the way we interact with it? No. It's in the same way we, the developers, want to interact with any APIs at that high level. We don't want the APIs to be so dumb, that too in 21st century, right? So that's the problem we are trying to solve step by step. So let's see how Jeb could help. Let's introduce library Jeb here. So Jeb is an open source project which is written in Groovy language. Groovy is a dynamic language on JVM which compiles into class files and later you can execute them on JVM. And also it's Apache V2 license. So you could grab them, make your own changes, commercial friendly, right? And the latest version of Jeb is 0.9.3, it's very close to 1.0. So 1.0 should be out somewhere this year. And the API is quite stable and typically not much changes are expected in 1.0. So we have been using WebDriver. So the gateway to WebDriver API is WebDriver class. So you get an instance of WebDriver class and then you start using it. Similarly, the gateway to Jeb API is BrowserObject, which is in Jeb.browser which wraps around WebDriver. So instead of talking directly to WebDriver, now you will talk to Jeb and Jeb in turn will talk to WebDriver. So this is how you could do it. So you create a new instance of BrowserObject by passing a DriverObject. Then you want to go to visit some URL. So you can say browser.go and you could give a URL. Now hard coding things is not so good. That's what we just, I mean the people, told about. Because if you want to use a URL, I mean a Driver in multiple places, you want to use the same Driver, not the different, different Drivers, or say you want to change the Driver. Instead of Firefox, you want to use Chrome. You would want the change to be in one place rather than in multiple places. So this is how you do it. The configuration file is named jebconfig.groovy and you put them as a groovy DSL Driver and you could create. So here I'm creating a Firefox Driver. So any customizations there you could do. Here I'm trying to make sure that when the Firefox window opens, it's maximized. Then I return the instance. Similarly, you could create a Chrome Driver and return that, okay? Now, previously I created a new browser passing a DriverObject. Now I don't have to do that because it will be taken from the config file. So here I can say browser.go directly with browser, just a new browser. Then browser.quit can be used to terminate, I mean, stop. Now let's see how you could access elements in jeb library. So at the top, the commented code shows how you could do it using WebDriver API and below you can see how you can do it in jeb or using jeb. So browser.you call the dollar method and you say name is j username. Now once I got the element, I want to set some value into that text. So I can use the left shift operator and I can pass the value. So again, you could see the WebDriver version and jeb version. Then suppose you want to read the value present in the text field. You could say the field.value which will return it. So I'm just trying to print it here. So let's see that example. So my configuration is already present in jeb config which should be placed in the default package. Now here you could see additionally I am including the jeb core library as well in addition to Firefox. Then I'm creating an instance of browser. The actual instance will be taken from the config file and I say go to login.html. That's a URL and then I enter the username and password. Then I click on submit and finally click in this. Okay, that's it. Come. Yeah, please. Right. Exactly. You're right. So this is not the end result. We are just starting. So instead of directly giving you, this is the perfect way to write jeb code, I'm slowly transitioning you from WebDriver API to Jeb API. Now let's see how you should ideally do it in jeb. So this is just to get you familiar with jeb. This is what we do. This is a very ugly code. Right? Why is it so? I'll come to that. Yeah. Apart from that. Just from the API usage perspective. Yeah. I could do that. I'll come to that later. That's fine. Apart from that. So every time you'd see browser, browser, browser, that's a bit irritating, right? When you speak to someone, say your friend, say Raj, hey Raj, how are you? Hey Raj, did you do this? Hey Raj, like that. You don't say that, right? First time you say that, then you stop that. Again, we want our APIs to be intelligent enough, not so dumb. So once you tell that this is what you have to use, browser object, you want it to understand that. That's not so good. Apart from that, another one. Here I call browser.quit. What happens after that? Can I, the browser object reference is still available, right? Can I use that? If I try to say browser.go once again, what would happen? It will give some error. Right? It's, I mean, illegal state sort of exception you will get. So, but still you can do that. That's not so good thing. So how we could improve that? So again, the API provides a static method called drive, wherein you can pass a block of code. So drive will create an instance of browser and run the code block within that context, within the context of the drive. So once quit is called, you don't have the browser reference anymore and you can't do any silly things there. So does it look better than the previous? Okay? Or no? Okay. So this is exactly the point he mentioned. So we have hard coded the URL. We don't want to do that. So we may want to run the test in multiple environments where the base URL could change. So you put the base URL in a chip config file and when you say go login.stml, it will be appended to base URL. Yeah. Yeah. It's exactly done using with. But in that case, I have to create an object, say new browser object. Then I should say the browser dot with and I could pass this code block. So what would happen is after the code is executed, still you would have the reference to that browser object. So we make that construction part private, which happens internally. Then comes the assertion. Once we have the, I mean, we have seen how we could set the values and read the values. This is how we could assert, say I'm getting the value of H1 and which has some text value and I'm checking if it is dashboard. So that's just an introduction of how we would use it. Now let's get into bit more details of the navigator APIs, how you could access elements in the page. This is the syntax. So does it sound familiar, the dollar one, anybody? Have you written dollar selector somewhere, jQuery? How many of you are familiar with jQuery? So you already know how to use jQuery, most of the web programs. So instead of remembering web element dot by ID, by so many classes and that, doing jQuery selectors or CSS selectors is easy. So that is the power Jeb gives you. So you could write CSS selectors or jQuery selectors using the dollar method here. So first argument is the CSS selector. Then you could say index or range, we will see more examples and some attributes also. Let's get into the example. So this is the page snippet you have. So you have a bunch of H2 elements. So I try to select H2 and say get the text. So there are four H2 elements here. So dollar H2 will select four elements. And dot text will get the text, the content of the first item in that. That's how your jQuery API would also work. I'm trying to give a index value here. So I would say dollar H2 and one, so which gets the first one, zero and five. Now I try to get the size of that. How many H2 elements are there, gives four. Now I want to fetch multiple ones, not just one element. So I can provide a range operation here, zero dot dot two, zero, one, two. Three elements will be accessed. So which returns a list of that. That's a bit of a trick in Groovy here, I use star dot, which is equivalent to iterating and getting that value and collecting the result and returning it as a list. Here I have added the duration attribute and I'm trying to query by where duration is five and there are two elements in that. Here I'm trying to get an H2 element where text is something. So I'm not going by ID or name or anything by the content, that also you could do. So it's similar to attributes. So whenever you give text as an attribute, it will take the content, not the attributes. Also you can use sort of, you know, regular expressions. So there are some built-in options available like a contains here. I try to get all the H2 where text contains O. You would see the first two contains O there, page objects where O is uppercase. So if you want to include uppercase as well, you could do I contains. Here again duration contains five, so you would get size as three. So finding the child elements, you could do by I'm selecting, you know, div dot languages which selects the outer div. Then I'm trying to find all the elements with class dot jvm. So what would be the result, anyone? So two elements have jvm class. Next filter, again similar to jquery. So I'm trying to filter from the current list. So I get all the languages and filter with jvm is, this is an including filter. So if you want excludes, not containing that, you could use not. There's a most discussed item, a topic in the conference, I believe, page object. So let's see how we could use page objects. So this is the code we just saw previously. Let's just ensure that it works before we try to refactor, okay? It's complete, so first thing is we need a page object. So let's create a page object, say log in page, so which has to extend jv dot page. Now what do we do? So here I'm telling go to log in page. So now, instead of telling here, I should tell go to log in page. So how do I do that? I should put the URL here. So URL, I make it internal to page. So even if the page URL changes, the change has to be in one place. Next, what do I need to do? I have to move all of these elements inside the page. Which I can do, say, I say username. I use the same selectors, but I just move it inside the page. Submit that required, you could put. Now, what should I do? Should I access username, password, submit within my code here or something else I should do? That will be still, it will be kind of a getter setter. So it will eliminate that problem of URL changing and you want your code, I mean you want to change only one place in your code. That problem is solved, but still it's tightly coupled. So instead, what I can do is, I say log in. So now, instead of doing this, I say log in. Does it look good? Any questions? So what I did is, I created a page object, log in page. And I specified the URL there. And I moved the elements inside the page object so that it's encapsulated over there. And I'm just providing a log in method which I can use to call that. I mean, to simulate that. Anything you see? Call. I need not be using method two, sorry. When you're using page, you are supposed to use two instead of go. So yeah, that's what you could do. Now, when you log in, the page changes to another page, right? So let's just create another page object. Here, we want kind of verification if it is really at that page or not. So I can remove this part. We just move to dashboard. So I say add, so that's complete. So the assertion is now moved to the page itself. Similarly, I can move this text also. I can put a placeholder similar to username password. I can say some heading or something. Then I can say heading or text. We could do that as well. Any typos? Anyway, that's, that's, that's, that's. So we have seen a basic page object in action. Let's get into modules. So, page objects are logical representations of a page, but there could be some content, some section repeating across pages, right? So how do we handle that? Let's see a demo for that. So here I have taken dashboard, you may have the heading same, the search, you may want to use it across the pages. So let's see. So for the reusable section, what I do is I create a module by extending module class, and similarly, the way how I created a page object. Similarly, you create the content for your module. Then the similar way I have provided, I provided a login method within the page. I provide a search method here, wherein I pass the query, which will send the, set the text in the text box and click enter, press enter. Now, how to use it in the page? This is the page where I want to include that module. So within my content, I say search bar, that's the variable what I want to use. And I say module and the module name, is it clear? Then this is a result page I'm using. So I say I go to dashboard page, then I call the search on that. Then I just assert that the page is actually moved to next page, that's the search result page, where you see search result, you can run that, okay, complete. Any questions? I have a question. So here, my dashboard page has a page title, and search result page as well as a page title. Here I say assert page title equal to search result. How does it know which page title to be called, in which page? So in the previous example what I did is, in the page demo, right, we said go to login page. Then here we said at dashboard page. So browser object what we saw earlier, that maintains which is the current page. So here when you said login page, it knows you are in login page. Then when I call login, there is nothing called no login method within browser, right? It is present in the page object. So browser knows which is the current page object, and it delegates that responsibility to the current page object. So login is delegated to current page, that is the login page. Now when you say at dashboard, it calls this verification. So now it knows that dashboard is the current page, right, or instance of that. So when you call next heading, it should go and call the heading of dashboard. But in this example, I have not used it. I have just commutated. Then how does it know? Look at the module definition, I created search box, along with that I specify two and a page object. That means when I click on that, which should be the page you should move to. This is one of the practices people use, right? A page object should return which is the next page object upon click, right? So due to this, it automatically knows which is the current page object. Out of one, you could pass multiple values as well, you could pass a list as well. So what it will do is, now you set two search result page, it will call the at assertion on that. So if title is not dashboard, something else may be due to an error, it will skip that and go to the next element you passed here, that's allowed. So it will go one by one from the list, and it will check this at assertion. If it is true, it will set that page as the current page object, otherwise it will try to get the next one. So whenever you say at, there is an explicit assertion made. So there is no page object, something like that, it will fail. So move back, that's one of the example where we saw one content repeated across pages. Let's get into another example. Anything repeating here? The rows are repeating, it's the same, structure is same, right, list of some values. So you could use modules to solve this problem as well. This is how do you use it. So record represent a single line or a single row here. And here I have created a kind of template which using the groovy closure. So I pass an index and the row is what is, you know, everything what is in the row is will be in a TR type. Within TR you have multiple TDs. So when you search by TD, you would get multiple TDs by default. But my navigator allows me to specify an index as well. So if I pass 0, I would get the first one, if I pass 1, I would get the second one. I need the columns of that. Say I am trying to get here product code and price. I just call this with multiple different index, right. Column of 1 will return the first TD, column, sorry, it's the second one. First one I just put the serial number. Column of 2 will return the, so it just, so I am just index 1 and 2 is what I am taking. And I am trying to convert it to integer. Now how do you use it in a page? So I have a page called a product page which has a URL as usual and within content. So previously I gave a variable name then I told module and the module class, right. Here I gave module list and I gave the module class which is here. And then this is the row selector. If there is only one, you don't have to give that also. I mean if you're directly, if this is directly selecting, you don't have to give anything. In like, in my previous pages there was only one search box. So if I dollar, I give you some idea of that search box, it should find it. In this case, there are multiple rows. So I need to tell that module which is the current row, right. So this will select all the TRs and put it into a list called products. Let's just see how you can get the values actually. So you say you go to product page and product contains all the rows. So I say products.each, I'm getting product.product.code and product.cry. So a product is a variable I give here itself while iterating the current element. So any questions here? That's how to use cases of modules. So one content repeated across multiple pages or same content repeated within the page. Next thing is how to wait? Why do we need wait? Anybody? Why do we need a waiting? So you may have an Ajax request which may take some time to get the response. So until then you want to wait to get the value of the result. Consider this example. You have a div whose ID is dynamic. There is no content. Say there is a button upon clicking that an Ajax call is made and the response is populated here in our text. These are all the ways that provides ways of waiting. So you use wait for method and you pass a closure here. So here it is I say by ID dynamic and get the text which is a kind of predicate. So it will wait until this div contains the text. Not infinitely it will use the default timeout which is 5 seconds and retry interval is by default 100 milliseconds. So every 100 milliseconds it will check if that text is present in the div. If it presents it will return. If it is not present it will wait till the timeout. In the second case you are explicitly saying I want to use 8 seconds timeout. And the retry interval is set to default again 100 milliseconds. The third example I am saying that I want to wait till 8 seconds with I do not try every 100 seconds instead retry only say half a second. Next one is you could pass a text also. So what does that mean? So in your config file you could have a preset. So under presets you could define multiple presets. I have defined a preset called slow which says timeout is 12 and retry interval is 1. So if you want to use this across your application in multiple tests you could use it as slow. You could categorize say some faster jacks calls maybe fast category. Slow means say slow category like that. So then slow previously which was 10 seconds now you want to reduce it to 8 seconds or you want to increase it to 15 seconds something like that you just have to change it in one place not go and change in every place. So waiting is real real simple here. Let's see we saw how the JEP API can be used from the trivial example to a very practical page objects, modules and weight and so on excuse me. And now let's see how you can really integrate this in a say continuous integration environment or so. So JEP provides these integrators. So typically you may want to write your test in J unit and call JEP API could be or these are the options available J unit 3, J unit 4 and test NG is available and also SPOC is also available. So I'm going to just give a demo of SPOC API so if you are using Groovy typically you would end up using JEP which is quite a good you know testing framework which is again on top of J unit 4 runner. So this is a sample SPOC specification similar to J unit you can consider. So JEP provides a base class JEP reporting spec so it helps you to capture the screenshots. So I just create one called sample JEP spec so this is how you define the specifications here in a very you know descriptive way or specification not test so you can give the description here. It need not be like a regular method and then I say when here I use the JEP APIs so I'm not saying browser dot anything like that or I'm not saying browser dot drive anything because this already creates an instance of browser and it provides to me. So whenever I'm doing here it's always within the context of browser that context is already available. So we say to login page we repeat the same thing what we did here but there is no browser explicitly mentioned here so I hope any questions here I mean the syntax should be pretty evident. So then when then that's the expect those are the syntax let's see a demo of that some using gradle here that's a failure right so let's see what is that this is where you would get the screenshots as well as the HTML file at the end of each test that is by default it's taken now we just want to see the test report so one failed we saw so the error is shown here so the page title is actually you know result result one search result one and search result that's a so this is left side is search result showing right side is the search result one actual is search result but I'm expecting it to be search result one let's just fix that and rear so it passed now everything is passed let's say you want to take the screenshot in the beginning also right now if you go here the reports you could see the dashboard and next one is the search result those pages are available you could see there is a page before also which I just put it in one place so wherever you want you can just use report or you can use a pass a string which is the group so it will create a folder and that kind of and I'm using the Gradle here I can run it with the multiple tests by configuring it in Gradle I'll say you can add any browser so that is controlled in the Gradle file so you could add which drivers you want and you may want to add some dependencies and so there are few these are the templates I took directly from the JEP there is a sample repository there is a sample Gradle there is one for May 1 also there is one for Grails if you're using Grails that's much easier to do than this and I have all the patterns what we learned that's how you could define one more point I missed here is I used stepwise so that the tests are executed in order so I may want the login to be done first and then the rest of the things in this order or say you could also put it as I mean say before running the entire test you do a login that's also possible depending on your how your use cases you could configure that so you know you have setup and tear down for each test so setup is executed before each test tear down after each test and setup spec is executed once for the entire spec and tear down spec after all the tests are run so by default what happens is the browser session is maintained for the entire I mean if you stepwise for the entire spec it is maintained otherwise all the cookies and all will be deleted after every test so your login session will not be retained so you could customize it the way you want so in summary what does jeb really provide to you so web driver API is available to you you can still you can get the instance of web driver and you can customize if you want in addition say 80 percent of the case you use jeb and some specific case you really want to control through web driver that is still possible nobody's preventing from doing so you still have the power of web driver you know learning jQuery selectors is pretty easy compared to learning any selectors API so in no time you can learn that all people would already know that so that's another part of it and page object patterns are set right away so you don't have to reinvent the wheel then the power of groovy so if you know bit of groovy still you can you know say in a complex situations you can write a lot of templates and more reusable code something like the closures we used in that rows and all so that would be a another benefit you would get so with all these jeb should be a very good you know candidate for developing test automation so I mean I'm not telling that everybody has to use jeb or something but using plain web driver might not be a good idea so you have to develop something on top of web driver so jeb has all the good practices of that so most of the cases jeb should cover pretty well so any questions I have the references are put and all the code examples what I've used I've already you know put in the github and presentation slide will be available in my slide share yeah yeah I'm sorry right you're right so what happens is from the performance point of view if you can put everything in the CSS selector that would get executed in the browser and it will return that will be faster compared to getting everything and then you are doing a filter so it's like you know you make it work and then you can make it better that's usual cases even if you use groovy selectors the attributes still it would work say a few milliseconds here and there will not make a difference but say if you really facing some performance problems or if you want to improve it further you can always try to move it to CSS selectors the first argument else last minute well thank you