Bummer! This is just a preview. You need to be signed in with a Basic account to view the entire video.
Start a free Basic trial
to watch this video
To develop complex scripts, or even just a large library of scripts using Selenium Webdriver, eventually a more abstract way of approaching the interface between the script and the page will be needed. In this video we will take a look at page models and how this design pattern can help us create scripts that are easier to create, maintain, and understand.
Learn more
Other Languages Handling of Locators
In many languages, you would store locators as a static
property. These are sometimes returned to as class properties
or class level fields
.
-
0:00
The functions that we created to add and
-
0:02
remove invitees do a great job of having us not repeat ourselves in code.
-
0:07
Meaning we don't need to write code to find the form, fill it out, and
-
0:11
then click the Submit button over and over.
-
0:14
We just call the function and pass it a name.
-
0:17
It also provides another benefit,
-
0:19
it abstracts away the need to know what is actually required to add an invitee.
-
0:25
As a user of this function, i don't need to know how the invitee is added,
-
0:29
I just know it happens.
-
0:32
This way of thinking should feel pretty familiar if you've done any
-
0:35
object oriented programming, or OOP.
-
0:37
Where you keep hidden or encapsulate the information that you don't want your users
-
0:42
to worry about, and you expose what you want them to use.
-
0:46
Well users of our automation code should have that same sort of respect and care.
-
0:51
We should be able to say, this is the homepage, and you can add invitees, and
-
0:55
remove them.
-
0:56
Don't worry how it's done, I got this.
-
0:58
Now, over time, best practices have evolved on how to do this, and
-
1:01
a pattern has emerged, it's called the Page Object Model.
-
1:05
Now note the word there, object, the first O in OOP.
-
1:11
So languages have different ways of doing OOP.
-
1:14
And while we're doing this in JavaScript,
-
1:16
you can imagine this extended to whatever programming language your code base is in.
-
1:20
So what do you say we go about creating our first page object?
-
1:25
Okay, so we have a pretty good start here already.
-
1:28
And the way that we built this code up is actually pretty common.
-
1:31
First you work on your selectors, next you work on your abstractions.
-
1:35
So what we wanna do now is build a new place to store page-specific information.
-
1:41
So in JavaScript land, we'll make a module.
-
1:44
Now this is equivalent to packages or namespaces in other languages.
-
1:47
So what I'll do is I'll come over here ,and I'm gonna make a new folder,
-
1:52
and I'm gonna call that pages.
-
1:55
And I'll add a new file to this folder, and
-
2:00
I'm gonna call it home.js.
-
2:03
Our app only has one page, and it's typical to name your main page home.
-
2:09
Okay, so you might not have seen this before, but
-
2:12
in the later version of JavaScript, they introduced a new class keyword.
-
2:16
It's syntactic sugar for how you build objects in JavaScript.
-
2:20
I'm gonna use it here because it's the most language agnostic way to get
-
2:23
the point across.
-
2:25
Please don't let it trip you up, more information on the teacher's notes.
-
2:28
So we are gonna create a class called HomePage,
-
2:31
and we'll add a constructor method to our class.
-
2:35
Now, this is method that's called when the new object is created or constructed.
-
2:40
So it's common to pass the web driver into the page object, so I'll say constructor.
-
2:45
And that's how you do this in JavaScript, it's called constructor, and
-
2:48
then this is what is expected.
-
2:50
And then now I can use this, right?
-
2:52
So we'll store a reference to the driver in our instance.
-
2:59
Okay, and
-
3:00
now let's explicitly state that this is the class that we wanna have exported.
-
3:05
So the way that you do that in Node is you say, nodule.exports,
-
3:10
and we're gonna say HomePage.
-
3:12
So this is specifically saying hey, if you import this file, you can export HomePage.
-
3:18
So now, let's go import it, so in our index file,
-
3:23
we'll come over here and we'll say const HomePage = require,
-
3:31
So in the current directory, pages/home.
-
3:35
Cool, so now we have it, right?
-
3:37
So now we have the ability to create one of these, so that's our class definition.
-
3:41
And then after we build our driver here,
-
3:44
what we'll do is we'll pass it into our HomePage object.
-
3:47
So we'll make a lower case of homePage here, right?
-
3:50
So we're gonna make an instance of that page, HomePage,
-
3:53
and we're gonna pass in driver.
-
3:56
Now we move page-specific stuff from index js into our page.
-
4:01
So it's a common approach that your page understands how to navigate to itself.
-
4:06
So let's do this, let's cut this driver.get, we'll cut that from this file.
-
4:13
And we'll come over here into the HomePage, and
-
4:14
what we'll do is we'll make a new method called open, okay?
-
4:20
And in here, we will paste our code.
-
4:25
Now, normally you wouldn't have to use the dynamic process.env,
-
4:30
right, URL from the command line, but that is because ours is dynamic, and
-
4:33
I want this code to work for everybody.
-
4:35
So the thing that we need to remember is that we need to use this.driver.
-
4:40
Cool, so now we have a method that we can call on our instance, so
-
4:44
we can say homePage.open().
-
4:47
And see, it knew about it there, pretty neat, right?
-
4:50
Okay, so let's keep these invitees here.
-
4:53
I'm gonna collapse this, invitees, there we go.
-
4:56
Now, this doesn't really belong here, does it?
-
4:58
If we take this locators out, this really belongs in the page object.
-
5:03
So I'm gonna cut, and I'm gonna come over to my page object,
-
5:09
and I am going to paste in the constructor,
-
5:13
paste in here, this.locators.
-
5:17
Cuz I wanted to be a property of this class.
-
5:20
Now different languages handle this a little bit differently, so
-
5:23
check the teacher's notes for more information.
-
5:26
Go head and semicolon there, okay and check this out, we're using this By, so
-
5:31
we need to do our imports over here.
-
5:33
So let's go ahead and let's bring in
-
5:37
let's bring in this, both of these.
-
5:42
Or actually, what we could do is we could just say, let's do this a little proper.
-
5:48
That's one way of getting very specific about what it is that you need.
-
5:53
So we just need the By, so we'll say By = require("selenium-webdriver").By,
-
5:58
there you go.
-
6:00
And we don't have to bring in Selenium over there, cuz we're not using it,
-
6:03
it's not in the namespace.
-
6:05
Okay, so back in index.js, let's grab our functions that don't belong here anymore.
-
6:11
So I'm gonna grab the function, the removeInvitee and the toggle right here.
-
6:17
So I'm gonna grab all these functions, and I'm gonna cut them out, and
-
6:21
I'm gonna come over to my home.js.
-
6:25
I'm gonna come down in here, let's get this up here a bit, and I'm gonna paste.
-
6:31
And you'll see the squiggle,
-
6:32
says that the function doesn't belong here inside of a class.
-
6:35
So I need to get rid of all those.
-
6:38
So what I'm gonna do is I'm gonna use the multiple cursor shortcut
-
6:41
in Visual Studio Code.
-
6:42
And it's kind of one of those killer features that when you need it,
-
6:46
it's exactly what you need.
-
6:48
Here, check this out, so I'm gonna turn on a little key tracker so
-
6:51
you can see what I'm doing here.
-
6:53
So I'm gonna turn this on, and I'm just gonna press Cmd+D, and I get all of them.
-
6:59
And I see there's a cursor on each one of them.
-
7:02
I'm gonna select the word function up until the function there, and
-
7:07
then I'm gonna delete it, bam.
-
7:10
And then I'm gonna press Escape to get rid of it, there we go.
-
7:13
And now we're back to a single cursor, but I'm gonna move over here and I'm gonna get
-
7:17
each one of these drivers, because the driver needs to access this driver, right?
-
7:22
So I'm gonna highlight this one, get all of them.
-
7:26
I'm gonna go to the front, I'm gonna type this dot, and press Escape.
-
7:32
We have the same problem with these locators, don't we?
-
7:34
So I'm gonna go here, and I'm gonna do locators,
-
7:38
get all those locators, jump over to the front, and do this.locators.
-
7:43
Wow, let's take a moment and just appreciate how amazing that feature is.
-
7:49
Okay, now let's flip back the index.
-
7:51
[LAUGH] This is looking pretty great, isn't it?
-
7:54
So this is our whole file now,
-
7:57
we've got the home page here, it can fit on one screen.
-
7:59
So let's do this, first things that we need to do
-
8:03
is we need to change the calls to use them currently, right?
-
8:05
So, let's see, let's flip this back really quick, so it's more clear.
-
8:08
So forEach invitee we want to call homePage.addInvitee and
-
8:16
then pass in the invitee.
-
8:19
And just a little JavaScript free hint here,
-
8:21
you can still do what we were doing before where we just passed in the method right?
-
8:26
So we could just say homePage.addInvitee.
-
8:29
But the problem is that when it calls this function,
-
8:33
it doesn't know what this should be.
-
8:35
So that's what the second parameter here is,
-
8:37
it's called thisArg, see that up there?
-
8:40
So it needs to know what this is, and
-
8:43
this in the case is homePage, here we go.
-
8:48
All right, and before this Shadd call,
-
8:51
what we wanna do is call homePage, we'll call that method.
-
8:57
And we also wanna do that for our toggle, so we can say,
-
9:01
homePage.toggle, awesome.
-
9:08
Wow, this looks great right?
-
9:09
Not many lines at all.
-
9:11
So let's go ahead and give this a run.
-
9:14
I'm gonna close this existing one, let's give that a run.
-
9:22
Make sure everything's still working, sure looks like it is.
-
9:26
Okay, so let's say that we wanted to click this
-
9:31
Confirmed check box here for a specific invitee.
-
9:36
Hm, we already have one for our remove invitee function, but
-
9:41
that's not exactly great, isn't it?
-
9:44
It means we'd have to build a function for each one of those new,
-
9:48
parse the invitee and each time for that.
-
9:50
I don't really wanna do that for
-
9:51
each of this interactions that the invitees can do.
-
9:54
So now that these things are in classes, we could probably do a better job of
-
9:58
returning an invitee and modeling that as a page object model.
-
10:03
Common misconception of this page object pattern is that you
-
10:05
need to make a page object the entire page only.
-
10:08
But you can for sure make them a part of the page only, a sub page, if you will.
-
10:13
Now this ends up feeling a lot like web components.
-
10:15
So let's do this, you're doing great, you're cruising through this content.
-
10:18
Why don't you take a quick break, do some stretching or jumping jacks, and
-
10:22
get the brain juice flowing.
-
10:23
And then come back and we'll build the page object just for
-
10:26
this little invitee thing here.
-
10:30
Sound good?
-
10:31
See you in a bit
You need to sign up for Treehouse in order to download course files.
Sign up