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