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
The structure of a page is called Page Objects, but the classes you create don’t need to be entire pages, they can be sub-pages as well. In this video we will show you how that works.
Learn More
No cheating
My subpage Object
class Invitee {
constructor(element) {
this.element = element;
this.locators = {
editButton: By.css('button:first-of-type'),
editNameField: By.css('input[type="text"]'),
removeButton: By.css('button:last-child'),
confirmedCheckbox: By.css('input[type="checkbox"]')
}
}
changeName(name) {
const button = this.element
.findElement(this.locators.editButton);
button.click();
const textField = this.element.findElement(this.locators.editNameField);
textField.clear();
textField.sendKeys(name);
button.click();
}
// ...
Usage
homePage
.findInviteeByName("Jennifer Nordell")
.changeName("Craig Dennis");
-
0:00
Now that we've got our home page all set up,
-
0:02
it quickly became evident that we have a bunch of repeated elements.
-
0:06
Well, mainly those invitees.
-
0:07
All of them have very similar properties and functionality.
-
0:11
Now, we could write methods on our main page object, but that would require us to
-
0:16
continually pass the name of the invitee to each of our new methods.
-
0:19
There's probably a better API that we could design.
-
0:23
It's important to remember that just like how you take your time to
-
0:26
design a software, you should also do the same with your automation and test code.
-
0:30
You should always follow best practices and create clean, understandable APIs.
-
0:35
You want other people to be able to not only read your code, but
-
0:38
also being encourage to reuse it.
-
0:41
Remember, even though this pattern of abstracting away knowledge
-
0:44
of the structure of a page is called page object,
-
0:47
the classes you create don't need to be entire pages.
-
0:51
They can be sub-pages as well.
-
0:53
Let's model our invitee as a sub-page.
-
0:56
Okay, so first things first,
-
0:59
let's think about how we can get a handle on each of these little invitee blocks.
-
1:05
So we've kinda done that already, haven't we, with our locator function here, right,
-
1:08
this removeButtonForInvitee.
-
1:10
It basically just goes and it only gets the button, though.
-
1:14
So why don't we do one where we get the invitee by name.
-
1:17
I'm gonna leave that one there for reference, and
-
1:19
actually I'll duplicate that.
-
1:20
So make a new one of those.
-
1:24
And what we want is we want invitee,
-
1:27
I'm gonna get ahold of the invitee element there.
-
1:30
So we'll say inviteeByName.
-
1:34
And just to be clear,
-
1:35
we'll change our parameter from being called invitee to be called name.
-
1:39
And we'll pass that in here, to name.
-
1:43
And instead of going to the button, let's just go to the parent there.
-
1:46
So that will get that li, won't it?
-
1:49
That li is this here.
-
1:51
We go ahead and we inspect this here.
-
2:00
That's this li, this is the parent that we're gonna get from that.
-
2:04
Okay, awesome, and
-
2:06
then let's give our page a way to get a handle on those elements.
-
2:10
So I kinda like the way that Selenium API works when you call find element.
-
2:14
So why don't we add new method to our homepage.
-
2:17
And we we'll kinda follow the same structure, this is pretty common.
-
2:20
So we can say findInviteeByName.
-
2:28
And that takes a name.
-
2:30
And then what we'll do is we'll get an element,
-
2:37
and we will do this.driver.
-
2:41
We'll say findElement, and we will pass in
-
2:46
this.locators.inviteeByName, which we just created.
-
2:51
And we'll pass in that name, awesome.
-
2:53
So then we have the element.
-
2:55
And then we'll say, return, so we wanna return a new Invitee.
-
3:00
And we haven't built that yet, so let's be careful.
-
3:03
So we're gonna pass in the element to that, cool.
-
3:06
So what we'll do, Keep that function there.
-
3:11
And we need to define what a new Invitee looks like.
-
3:14
So we'll just build one right here.
-
3:15
We'll say class Invitee, and we know that it's gonna take an element.
-
3:21
So we need to pass that into the constructor, right?
-
3:23
So we'll say, constructor, we'll pass in an element.
-
3:31
And then we'll just store a reference to it in the instance, right?
-
3:34
So when this is called it will have a reference to that element, awesome.
-
3:38
So this is much like we did here with the constructor when we passed in the driver.
-
3:42
But this is going to be built and it's gonna be given an element.
-
3:47
So this is where things probably differ a bit depending on your
-
3:49
programming language.
-
3:52
Basically we only really want our HomePage class here
-
3:55
to create these Invitees, right?
-
3:58
And we want to convey to users of our API that our invitee class shouldn't be
-
4:03
created.
-
4:04
Now maybe in your language you would mark a private or protected class.
-
4:08
Or maybe you would tweak the accessibility of the constructor.
-
4:11
Over here in JavaScript Landia, we simply won't add it to our module exports.
-
4:15
So nobody can see it, which is more or
-
4:18
less a private class since you can't import it elsewhere.
-
4:21
Great, so now that we have our specific invitee class,
-
4:24
we can now refactor the removeInvitee bit, right?
-
4:29
So we have this removeInvitee bit that we had.
-
4:32
So let's take a look at what this locator looks like.
-
4:37
So if I press Command here I can click it.
-
4:40
So let's go ahead and let's grab this off.
-
4:46
And let's go and let's add a new locators to our invitee.
-
4:49
So it'll be specific to this class.
-
4:56
So let's call this removeButton, right,
-
4:58
cuz that's the Remove button in that little block there.
-
5:01
Let's take a look at what it was, it was just button[last()].
-
5:05
So, you know what, let's switch what our locator was there.
-
5:10
So we'll say removeButton is a By.css.
-
5:14
And we'll say, button:last-child, right?
-
5:17
Cuz it's is gonna search within element is what we'll do.
-
5:21
So now that we have that removeButton we can use it in an element.
-
5:24
And so, instead of saying remove invitee, we can just say remove, right?
-
5:28
Cuz you'll have a hold of the Invitee and we'll just call remove on it.
-
5:34
And we'll say this.element, right?
-
5:37
Instead of using the driver, we're gonna search from within that element.
-
5:40
We'll say findElement and then we'll say this.locators.removeButton.
-
5:47
And then we wanna click, beautiful.
-
5:52
Okay, so let's get rid of this
-
5:56
removeInvitee here cuz now that is not the responsibility anymore.
-
6:01
So, let's see.
-
6:06
So we've got this invitee form and we're gonna do findInviteeByName.
-
6:10
So it's usage is gonna look a little bit different in index.js.
-
6:13
So here, before what we we're doing, we were removing Shadd.
-
6:17
We're gonna get rid of this, and we'll say homePage.findInviteeByName.
-
6:24
And we're gonna pass in David Riesz.
-
6:30
And then we're gonna call, that's what's wrong.
-
6:36
You gotta put the dot at the front of each one of these lines, .remove, there we go.
-
6:43
So first, we're gonna find it and then we're gonna method chain and
-
6:46
do a remove, sorry, David.
-
6:50
Now, let's get insider of here.
-
6:52
Now that we've got this little invitee, I feel like we're on a roll.
-
6:55
Let's get this little checkbox working, okay?
-
6:58
So let's add to our invitee sub-page.
-
7:02
Let's go over to our invitee sub page.
-
7:05
And let's add the confirmedCheckbox.
-
7:11
Now, these finders start getting a lot easier, right?
-
7:14
So is there anymore, there's only that one, right?
-
7:17
There's only one checkbox on there.
-
7:19
And it's, let's see, it's an input type of checkbox.
-
7:25
So, let's just do that.
-
7:25
Let say, By.css, and we'll do,
-
7:30
input [type='checkbox'].
-
7:34
And I use the single quotes there because they were double quotes.
-
7:37
And I'm gonna actually fix this, cuz I accidentally typed single quotes there.
-
7:45
Cool, so we now have a confirmedCheckbox.
-
7:48
That it's complaining about cuz there's no comma, there we go.
-
7:52
And then let's go ahead and let's use it.
-
7:54
So if you get ahold of an invitee, you can toggleConfirmation, right?
-
8:01
So what we'll do is we'll say this.element, findElement,
-
8:07
search within there, and we'll do this.locators.confirmedCheckbox.
-
8:13
Awesome, and then we'll do a .click.
-
8:16
So that will check that box for us from inside.
-
8:19
And then in index.js, let's use it.
-
8:24
So let's see, so we'll do homePage.
-
8:28
We'll do findInviteeByName and let's see, if this is a treehouse party,
-
8:35
if anybody's gonna be there, I know that it's gonna be Jennifer Nordell.
-
8:41
She's got something like 100,000 points or something.
-
8:44
You've probably met her in the forums.
-
8:45
She's an amazing moderator.
-
8:47
So let's do that, she's gonna come, for sure she's gonna come.
-
8:49
So we'll toggle her confirmation true.
-
8:52
And thanks for all your help and dedication, Jennifer.
-
8:55
And thanks for RSVPing so promptly through this app.
-
8:59
So let's do it, let's give it a go.
-
9:01
So I'm gonna close that existing one that I have.
-
9:04
And let's open it up again, and here we go.
-
9:09
She's confirmed, and we click hide those that aren't there, so there's Jennifer.
-
9:14
And let's make sure that David's gone.
-
9:17
Yeah so we had to kick him out of that party.
-
9:18
He just kept talking about Java and algorithms.
-
9:21
We just [LAUGH] had to kick him out.
-
9:23
Okay, our new API is feeling pretty good.
-
9:27
Now I could imagine how you'd do the rest of these actions, right,
-
9:30
the rest of these ones that are left.
-
9:32
I could kinda see how you'd do edit, right?
-
9:34
Cuz edit comes in and you can change the name.
-
9:37
Actually, that's a good idea.
-
9:39
If you wanna challenge yourself, go ahead and give changing this name a try.
-
9:44
Now I've dropped how I did it in the teacher's notes, no cheating.
-
9:49
One thing that I noticed here, is that this page is a little weird, right?
-
9:54
The line up of these buttons is a little strange.
-
9:57
I was thinking that maybe I should share this in a screenshot to my designer.
-
10:01
And I thought well, maybe I can make this screenshot myself.
-
10:04
But get this, Selenium can do it for you.
-
10:07
But first, we're gonna need to be able to get access to our file system.
-
10:10
So that is a node thing called fs for file system.
-
10:15
So we'll require fs.
-
10:17
And what we'll do is we'll make Selenium take the screenshot.
-
10:21
So we'll go down here to the bottom, half of this is all done.
-
10:24
Let's not toggle this off, we wanna be able to show everybody on there.
-
10:29
So we'll say, drive.takeScreenshot, okay?
-
10:34
And that's thenable, that gets returned, right?
-
10:37
So, and we'll do then and
-
10:41
that expects a callback that takes in an image and an err if it didn't work, okay?
-
10:46
So our function will have an image and it's kind of a blob there.
-
10:51
So we'll say fs.writeFile and we'll just call this weird-layout.
-
10:58
Those buttons aren't lining up.
-
10:59
We wanna show our designer, she loves it when we send screenshots.
-
11:04
Because that's the nice thing about this, right?
-
11:06
You could set this up, and because those names were a little bit longer,
-
11:09
we saw that the thing was breaking a little bit.
-
11:11
So let's send this over to her so she can see it.
-
11:12
And finally, it takes an error, a method that takes an error.
-
11:18
So we'll just drop a new function here that says err.
-
11:21
And we'll log out to the console if there is one, log in that error out.
-
11:28
Okay, so there we go.
-
11:30
So it's complaining about something.
-
11:32
I forgot this and this, there we go.
-
11:41
That's not quite lining up.
-
11:43
I have an extra, so that closes the then, this closes the function.
-
11:48
And I've got, this closes the right file, cool.
-
11:52
All right, so what will happen is it will write out this weird-layout.
-
11:57
And it will push the image in there.
-
11:59
So let's do that, let's go and drop this here.
-
12:02
Let's run it one more time, and then we'll, should, when it all said and done,
-
12:05
we should see a new file pop in here.
-
12:08
Cool, so there's this weird-layout.png.
-
12:11
And look at that, we can just show them right here.
-
12:14
Show our designer that these buttons aren't lining up when you have
-
12:16
longer names.
-
12:17
This Gonzalo Torres del Fierro has broken this here.
-
12:21
And I'm sure that this is not the first time that he's witnessed this,
-
12:24
right Gonzalo?
-
12:25
So there are actually quite a bit of things that Selenium can do at the browser
-
12:30
like this.
-
12:30
Now why don't you take a quick break and then come back and
-
12:33
get ready to practice your new skills and pick up a few more.
You need to sign up for Treehouse in order to download course files.
Sign up