 Hi all, I'm Ravi. I'm joining from Bengaluru. Namaskar. And uh, with me, uh, have panty is quite familiar with them. Uh, attention panda, then Andrew, he's here with us talking about the fundamental. That's a web driver and it's a web driver. And he's talking about web driver using Python. Yeah, let's welcome Andrew right. Yeah, it's all for you. Sure, man. Thank you. And hello, everyone. Thank you for being here today. She'll know I'm Automation Panda, Andy Knight, also Pandy. You can check me out on Twitter at AutomationPanda, AutomationPanda.com. I'm just Google AutomationPanda. You'll find me somewhere. So today I'm going to be talking about my favorite programming language, Python. Yay. Awesome. What I'm going to demonstrate for you today is a Python project using Selenium WebDriver. This is Selenium.com. How many of you probably know I love to use Python for testing. I think Python is one of the best languages for test automation. I find it to be fairly accessible syntax. It does a lot of things for you. It's just nice to read. It has a lower learning curve than some other languages like Java and C sharp and JavaScript. So it's easier for folks who are new to not only automation but new to programming to get into. And thankfully Selenium WebDriver has Python bindings along with Java, C sharp, JavaScript, Ruby, PHP. So I'm going to end this project here today and I'll dump the link in the chat again to the GitHub repository just so everybody has it. You can follow along. Boom. So I'm not going to be giving a talk in a traditional sense of like I'm going to have slides. I'm going to like walk through concepts. This is all I'm going to be hands on. I'm going to be walking through this project with you together to show how I would structure a test automation project with Selenium WebDriver in Python. And what's really cool about today is not only that but I'm going to be showing how to do it with the screenplay pattern. Somehow you have to model your interactions like when you log into a page and you navigate and all that stuff. So Selenium WebDriver calls, which is what a lot of like demos and quick articles do. More commonly people will use page objects, where you have your locators and your methods to represent a page or component of a page. But I strongly believe that screenplay is a much better pattern for modeling those interactions. And I, in my previous projects, I've used, I should say, in my, my previous team, we developed a screenplay implementation called build constrictor but that wasn't net. Recently I've done a very small bare bones basic implementation of screenplay in Python, which I will be demonstrating for you today. And this is actually the first time I have publicly shown the Python screenplay package. So let's dive in, shall we? In the project here, I've got it open in Visual Studio Code. Fairly standard Python projects. You put all it, I should, I should also back up. Not only are we using Python with Selenium WebDriver, we're also using PyTest. PyTest is the most popular Python test framework. It is not part of the standard library, it's a third party package, but still it is by user share the most popular. And it's excellent. It's, you write your tests as functions. You don't have to write big honky classes. It has a really nice reasonable way of handling something, clean up called fixtures that we'll look at in a second. So in a project when you are using PyTest as your framework, you'll put all of your test cases under a folder called tests. And so here I have a module named test underscore search.py. And that's what's shown here on the main screen. This is the main test case. Everything will come through here. PyTest will search for test modules with functions named test underscore something, treat those as tests, line them up as dominoes, and run through them all. So in our test search module, we have some imports here, which I'll explain a little bit later. The main test case is this one test dot go search. This is a plain old Python function. And in it I have the basic steps of the test case and I have them arranged in the arrange act assert pattern. I'm hoping y'all have heard of arrange act assert. So this is a great way to structure your test cases, whether they're unit test cases or end to end test cases, they keep your test focused on individual independent behavior. If you're familiar with Gherkin or BDD, or given when then, given when then is essentially a range act assert. So this is how I structure all my functional test cases. The test I haven't explained what the test is yet. The test here, what it does is it performs a basic search using duck duck go. Duck duck go is a search engine just like Google, Yahoo, Bing, whatever. Why did I choose that one? Because I had easy locators. Truth be told. So one of the steps to a duck duck go search test. To set it up. We are going to load the search page. Now there's this thing here this actor attempts to this is where the screenplay pattern comes in in screenplay pattern. Like I said it's a pattern for interactions. Screenplay is in screenplay actors use abilities to perform interactions. Right versus the page objects which are you have pages with locators and action methods. With screenplay we separate concerns further actors use abilities to perform interactions. The actor is the initiator of all the interactions. So I have an actor objects here, and that actually came from a fixture, essentially a setup function that was dependency injected here. And I'll show you what that looks like in just a moment, but just take it for granted right now is constructed in a and like a setup and given to us. So we have an actor. And anytime an actor wants to do two tasks, we say actor dot attempts to right because they're attempting to do something we don't know if they're going to be successful yet this is a test case. So actor attempts to perform an interaction. And so here the interaction is to load a particular web page with a given URL. So I have an interaction named load. It's called search page. And it passes in search page URL underneath of that selenium web driver is there. Selenium web driver is an ability, because it in the ability of selenium web driver enables the actor in order to load a page. And so the screenplay brings us all together so I can have a very readable step actor attempts to load search on the page. And that's my arrange as part of the act portion of my test. Actor attempts to what's the main action what's the target thing what's the main behavior being executed here. Actor attempts to search dot dot go for a given phrase. Right, I could be searching anything it could be panda, Python, parakeet, whatever. That phrase is coming in through a parameterization of our test case. So here the pie test test case function is literally just plain old function with test underscore on the front, but I can parameterize it with different inputs. So here I'm parameterizing a phrase. I'm choosing three different search strings, panda, Python, parakeet, and I'm injecting that into the test case so that can be used here as a string variable. This test will actually run three times because of this once for each phrase. So I'll be searching one time for panda searching one time for Python searching one time for parakeet. So then in the, what once I do my main action I need to verify that it was successful. So there's a couple assertions that we want to do and that's all part of the assert base. So what do I want to check after I do a search I expect that the result pages loaded has links and all the good stuff. So actor attempts to verify result page input value is the phrase. So the top that input value is there. Actor attempts to verify result page title contains the phrase as the page title like in the tab or whatever. And then finally actor attempts to verify that the result links include whatever my phrases I want to make sure they want to search for panda I see links for pandas and not for parakeets. So at a high level, we have our test case here. This is almost like reading plain English. That's one of the powers of the screenplay pattern. So let's start to actually let's let's run this real quick just to show how it works. And then we'll dig a level deeper into our into our project to see how this magic is happening. Right because at a high level you can see oh well these are words that indicate things but how does the code actually work. So let's run the test. We can see right now set up using Chrome. So it's doing the test three times once for each of those phrases, and it is pretty quick, but you can see Dr. Go the browser pops up Dr. Go page load, navigate verifies. And so I was able to finish those three seconds for three tests about 10 seconds. Pretty good local machine here. So, let's see. So let's now dig deeper into what is going on in this code. So let's look at the setup of what's going on here. So as I said there was this actor that gets injected. So you're using py test that you do your setup and your cleanup using something called fixtures. A fixture is another function that will build objects that you can call in the signature of the test case functions and py test will automatically resolve that and get that to you. So when it comes to things like your web driver object, any inputs into automation, and this actor object for our screenplay pattern we want to be able to construct those using fixtures. We put those in a file called comf test dot py. This is the standard name I did not get to choose his name pie test will look for files of this name in the test directory automatically and then use that. So there are actually three things we want to settle. There's the config of the configuration for our tests. There's the browser, which is going to be using our Selenium web driver, and then there's the actor to use for screenplay. Excel this real quick, give some more room. So the config here is actually something I've created in the project directory in the root level, I have a file called config JSON. This is how I'm choosing to pass inputs into my test automation. Things like, hey, what browser do you want to use? Do you want to test Chrome? Do you want to test Firefox? Do you want to test headless Chrome? I want to be able to specify that because all the tests should run the same with any browser. Also, I'm tuning an implicit wait time for Selenium web driver. Selenium, we know we can do implicit or explicit weights. Since this is a small project, I'm going to be okay with an implicit weight. If this were something I'm trying to scale, I probably want to bake explicit weights into my screenplay calls. So here I have the setup. I like using JSON with a Python project because the Python standard library has a JSON module that makes it really easy to read. And so back to CompTest, my config fixture, which has session scope, meaning once for the entire test run, what it will do is it will open that config JSON file and read the JSON data into a Python dictionary. Beautiful. Two lines right here, and I can read that config file. Then what I want to do is I want to make sure that the values in that config file are good because if there's a problem in there, you want to catch it before any test run, before you start wasting time and resources executing. So I want to make sure that my browser config is one of the supported browsers. I want to make sure that my implicit weight is an integer and that implicit weight is greater than zero. If that looks good, what my config fixture will do is it will return that dictionary so that tests can access it, and even other fixtures. So once I have my config, the next thing I can do is I can use that config to help build my WebDriver object. So here we have another fixture called browser. You can see it takes in the config. And what it does is it looks inside the config to see, hey, what browser do you want? If you want Firefox, construct a Firefox driver. If you want Chrome, construct a Chrome driver. If you want headless Chrome, construct a Chrome driver with headless options. Otherwise, if it's not recognized, fail. Then we're going to set the implicit weights for that browser based on the input we were given. And then we are going to not just return the browser object but yield. Yielding is in Python, if you're not familiar, it makes something called a generator. When it comes to pie test fixtures, the way it works is anything before the yield is like the setup portion. Anything after the yield is the cleanup portion because Python execution will automatically come back in here after the end of the test and perform cleanup operations. So we've initialized our WebDriver, yielded it. Then automatically after the test, we want to come back here and quit our WebDriver so we don't have those zombie processes. So then finally, the third fixture we have for setup is the actor. That's that screenplay thing, the initiator of all the interactions. So the actor will need the browser and how we created us like this. We say A equals actor, we created new object. We could give him or her or a name. We're choosing not to. And then to inject the ability for the WebDriver, we say actor can use and then pass it in. We're calling the ability browser and we're giving it the objects with the variable browser. And then we're just going to return that. We don't need to do any cleanup here. So that's how we do our setup. Very clean. We can use it for any test. It's very, very reusable. It's very nice. So that's what we have here. And again, so when the test case called the actor fixture, you know, it was doing that actor setup, but that required the WebDriver. So it would automatically do that by dependency. And then the WebDriver needed the configuration to be read. So it did that. Boom, boom, boom. Everything comes through nicely. So now let's dig into our screenplay calls here. So what I have done is I have actually created a test library package up here. I created a test library because the test directory is not meant to be a Python package, meaning no init, no imports or anything. I put all my tests live in a package that can be read. This could be in the same project and different project, whatever. But I have two things. I have interactions and pages. Let's start with pages. Typically for familiar with page object model, you might think like you have classes with locators and action methods. When you use screenplay, the recommended practice is that you will still have page classes, but only for modeling structure, not for performing interaction. And so what I've done here in this class is I have created a search page and a result page. And they have nothing but locators and possibly a URL. So here my search page, I want to model the search input field. So I create a locator. It's a tuple with the type of locator as well as the query for it. So I'm getting this by ID. Result page, I had two locators. One's a CSS selector, one is an ID. And so I can call these universally. I don't have to construct the page object and inject the web driver. So these are essentially kind of like static classes you could almost think of, universal accessible, creative one time, you don't have to create duplicate instances of it. And these are meant to be incredibly declarative, you know, the just model structure so that our interactions can use these locators. We hop over to the interactions class. This is where we start constructing some of those, those, those tasks that we saw in the main test case. So for example, when we said actor attempts to load the web page, here's the load task. What it does is it is part of the Python screenplay package this, this task comes from a screenplay, or from screenplay pattern import task. So we make a subclass of task. And actually, it's actually in Python it's an abstract class. What we do is we want to, when we construct this class, we want to pass in a target URL so that's saved as an instance variable. And then every task implements this performance method, it gets injected with the actor. And so from the actor we can then get the web driver object using the browser ability, and then we can make standard Selenium calls with the browser so things like browser.get. And so that's ultimately what's happening under the hood, just a little bit more verbose, little, little more self documenting. Or for example, my search dot dot go task. I passed in a phrase inside the performance. I got the browser object, the web driver object, and then I did browser find element for that search page search input there's that is located from that page class, and then search input send keys, I type the phrase, and hit enter. And that's how search was performed. So you can see how we can construct these, these interactions these tasks to do things with screenplay Then I have my other tasks here you know verifying the result page, whatever stuff you know make performing assertions in these tasks here. I also have a different kind of interaction called a question that will, whereas the task will just do something a question will return a value. So here like if I want to get the input value of something, you know I can find an element, get its value attribute return it, or if I want to get the title to page I can return browser dot title. So right now the Python screenplay package here is very bare bones. In the C sharp implementation I worked on bow constrictor we actually provided out of the box interactions tasks and questions for basic web driver things like, do you want to get the text of an element do you want to get value do you want to click it. We haven't done that yet in Python, all we have is core screenplay. So all of things, all the basic things like this input value of text list for title load, those should all be things that would be in a Python screenplay package given to you you shouldn't need to implement those what you would need to implement would be your custom tasks like search dot go or verify your result page input. Yeah, so in a nutshell, that is how you would construct a Python test automation project in Python with Python test using the screenplay pattern. I believe we're out of time now. So if you have any questions I would love to chat with you in the hangout. I believe that's where we're going next is that true. We, we can take one question. Okay, what's the question. The question is screenplays something specific to Python or open for the languages as well. Now so screenplay is just a design pattern. It can be used in any language like I said I've done it here in Python at my previous company we did it in C sharp. The serenity BDD project has implemented screenplay in Java as well as in JavaScript. And if you're in some other language, you can you can implement the pattern yourself. And we have one more question coming in. When we, when we use the screenplay pattern for large projects, we should have multiple interactions class. Yes, yes, you would, you would end up writing multiple interactions in a large projects, though, perhaps not as many as you might think in my previous projects with both constrictor because both constrictor had the basic interactions in the package itself. We found that we, we didn't have to write too many custom interactions. There were certainly a good set of them, but not. It wasn't like in the thousands or anything. Yeah, those are the two questions. Thanks, many for giving that quick just about those three than the three years with screenplay pattern. Thank you. Thank you for being one of the contracts.