1 00:00:00,340 --> 00:00:05,590 We found our element to interact with but our locator was way too specific. 2 00:00:05,590 --> 00:00:09,510 Any change to the page can potentially break our ability to access that element. 3 00:00:09,510 --> 00:00:13,020 Now detailed knowledge about the structure of the layout of the page 4 00:00:13,020 --> 00:00:16,240 is definitely an automation anti-pattern. 5 00:00:16,240 --> 00:00:19,910 You want to be as specific as you can be, but not as rigid 6 00:00:19,910 --> 00:00:23,930 as to require the entire structure of the document to remain unchanged. 7 00:00:23,930 --> 00:00:25,370 If you fall into that trap, 8 00:00:25,370 --> 00:00:29,800 any change to the layout of your page breaks the locator strategy. 9 00:00:29,800 --> 00:00:33,560 This how do I be specific about an element without 10 00:00:33,560 --> 00:00:37,380 relying on the page structure problem is actually quite common. 11 00:00:37,380 --> 00:00:39,230 We see this a lot in both CSS and 12 00:00:39,230 --> 00:00:43,030 JavaScript in the DOM, or document object model. 13 00:00:43,030 --> 00:00:47,380 We want to be able to specify the exact element that we're talking about. 14 00:00:47,380 --> 00:00:51,670 Now a typical solution to this is to add an identifier to your element. 15 00:00:51,670 --> 00:00:54,360 In HTML, we do this with the id attribute. 16 00:00:54,360 --> 00:00:58,150 Then in CSS, we can reference it with the id selector or 17 00:00:58,150 --> 00:01:01,270 we could use get element= by id in JavaScript. 18 00:01:01,270 --> 00:01:05,080 So the good news is, most of the time, the page you are trying to automate is 19 00:01:05,080 --> 00:01:08,610 already setup to have easily locatable elements. 20 00:01:08,610 --> 00:01:13,400 Because others have needed to access things either for style or interactivity. 21 00:01:13,400 --> 00:01:15,260 Selenium allows you to leverage that work. 22 00:01:16,500 --> 00:01:19,530 Why don't we take a look at accessing these elements by their identifier? 23 00:01:20,970 --> 00:01:23,980 Okay, so let's start by looking at the layout of our page. 24 00:01:23,980 --> 00:01:25,685 Well first, is your server running? 25 00:01:25,685 --> 00:01:28,230 [LAUGH] It's sounds like that old prank call, doesn't it? 26 00:01:28,230 --> 00:01:29,770 You better go catch it. 27 00:01:29,770 --> 00:01:31,910 So mine isn't, so I'm gonna click Continue Working. 28 00:01:31,910 --> 00:01:33,370 And I'm gonna choose Reload. 29 00:01:33,370 --> 00:01:38,340 And this should be enough to start our preview up and running again. 30 00:01:38,340 --> 00:01:44,730 All right, so I'm going to flip back and let's go back to our ripple. 31 00:01:46,210 --> 00:01:48,600 And we'll say, node get that up and running. 32 00:01:48,600 --> 00:01:50,720 And I'm gonna again press the up arrow. 33 00:01:51,740 --> 00:01:57,870 Let's bring in Selenium and let's also bring in By over here. 34 00:01:57,870 --> 00:02:02,370 And then we will go ahead and might as well set our url. 35 00:02:05,460 --> 00:02:08,100 And let's get the driver built, so 36 00:02:08,100 --> 00:02:11,420 we're gonna build the driver using the builder pattern there. 37 00:02:11,420 --> 00:02:13,570 And then we are going to, 38 00:02:13,570 --> 00:02:17,510 and you saw it pop up behind there, let's go ahead and open up our page. 39 00:02:18,950 --> 00:02:22,260 Okay, now let's try to see what sort of id we have. 40 00:02:22,260 --> 00:02:24,330 So we're looking again, we're looking at this text input. 41 00:02:24,330 --> 00:02:29,200 So right click and Inspect, okay, I'm gonna look at the Elements tab here. 42 00:02:29,200 --> 00:02:34,550 I'm gonna close this, let's go ahead and bring this down here. 43 00:02:35,830 --> 00:02:39,450 And I'm gonna pop this up for visibility purposes. 44 00:02:39,450 --> 00:02:42,560 Okay so we've got an id, not on the input tag, but 45 00:02:42,560 --> 00:02:45,710 we do have one on the form tag here, so it has an id. 46 00:02:47,130 --> 00:02:50,940 So, let's see what that looks like, so let's flip back over to our code here. 47 00:02:50,940 --> 00:02:54,280 So what we'll do is we'll make a new variable called form. 48 00:02:55,460 --> 00:02:59,950 And we will use the find element method of the driver. 49 00:02:59,950 --> 00:03:03,770 And our locator strategy this time is going to be using By. 50 00:03:03,770 --> 00:03:11,510 And there's another method here, named id, and it takes the id. 51 00:03:11,510 --> 00:03:16,620 And again, that id, let's flip back real quick and make sure that id was registrar. 52 00:03:16,620 --> 00:03:22,716 So we should be able to get a hold of that by ID registrar. 53 00:03:22,716 --> 00:03:26,850 Cool, so now we have a form element. 54 00:03:26,850 --> 00:03:29,550 Well, eventually, remember this is a premise. 55 00:03:29,550 --> 00:03:34,190 But it is in our field, so we can't just send keys to the form, but 56 00:03:34,190 --> 00:03:36,699 what could we do with this element, we have a hold of it. 57 00:03:37,770 --> 00:03:39,870 So this is a great time to look at the documentation. 58 00:03:39,870 --> 00:03:47,121 Let's do a search for Selenium WebDriver API. 59 00:03:47,121 --> 00:03:50,660 And I'm just gonna throw on a JS there just to make sure 60 00:03:50,660 --> 00:03:51,965 we get the one that we're talking about. 61 00:03:51,965 --> 00:03:54,250 Cuz remember, there's a bunch of different languages for it. 62 00:03:54,250 --> 00:04:00,370 So I"m gonna click this selenium-webdriver one right here, awesome. 63 00:04:00,370 --> 00:04:04,990 Let's open up these modules here, and if you click the selenium-webdriver, 64 00:04:04,990 --> 00:04:09,100 this will show all of the documentation here and they're pretty great. 65 00:04:09,100 --> 00:04:14,220 You can see here that if you scroll down, we have this WebElementPromise. 66 00:04:14,220 --> 00:04:15,490 And that's what we have, let's click into that. 67 00:04:16,490 --> 00:04:19,440 If we scroll down, you'll see that it has some methods, right? 68 00:04:19,440 --> 00:04:24,840 So, you can cancel or click or find, get an attribute. 69 00:04:25,980 --> 00:04:28,470 So, let's see, which one we can do here? 70 00:04:28,470 --> 00:04:31,750 Here's getTagName, let's go ahead and if we click it will open up and 71 00:04:31,750 --> 00:04:32,560 will tell you what it does. 72 00:04:32,560 --> 00:04:39,370 So it says it schedules a command to query for the tag/node name of this element. 73 00:04:39,370 --> 00:04:40,470 Awesome, so that's the tag name. 74 00:04:40,470 --> 00:04:43,400 So the tag name should be form, right? 75 00:04:43,400 --> 00:04:47,610 But let's look, in this case, this is saying that it returns a Thenable, so 76 00:04:47,610 --> 00:04:49,800 that's a promise, okay? 77 00:04:49,800 --> 00:04:52,090 And it's probably like you're usually accustomed to. 78 00:04:52,090 --> 00:04:57,910 So, what happens is you call the function this getTagName, and it returns a promise. 79 00:04:57,910 --> 00:05:00,740 And see how it's a Thenable of type string. 80 00:05:00,740 --> 00:05:03,010 So that string is gonna be the name. 81 00:05:03,010 --> 00:05:07,020 So, to get access to that value, you need to call and 82 00:05:07,020 --> 00:05:10,310 then provide it a function, so let's do that. 83 00:05:10,310 --> 00:05:14,120 So we're gonna get the tag name for the form that we got. 84 00:05:14,120 --> 00:05:16,390 So let's come back to where we're at, here we are. 85 00:05:16,390 --> 00:05:22,520 So we're gonna say form.getTagName, okay? 86 00:05:22,520 --> 00:05:25,010 And again, that returns a promise. 87 00:05:25,010 --> 00:05:27,530 So a promise has a then on it, okay? 88 00:05:27,530 --> 00:05:31,770 So after it's gone and gotten the tag name, it's gonna call a function for us. 89 00:05:31,770 --> 00:05:34,340 Now we're gonna use the arrow function syntax. 90 00:05:34,340 --> 00:05:36,650 If this is new to you, check the teacher's notes. 91 00:05:36,650 --> 00:05:41,060 So the function expects a string called name and 92 00:05:41,060 --> 00:05:42,110 then we're just gonna print it out. 93 00:05:42,110 --> 00:05:47,931 We'll say console.log("Tag 94 00:05:47,931 --> 00:05:52,096 name is " + name)). 95 00:05:52,096 --> 00:05:54,980 Make sure we close that out properly, awesome. 96 00:05:56,670 --> 00:06:00,280 So tag name is form, cool, there's our value. 97 00:06:00,280 --> 00:06:02,500 So let's look at another one really quick, let's flip back to that doc. 98 00:06:03,520 --> 00:06:11,010 So let's say, get Let's see, there's text, getSize, that's fun, so let's do this. 99 00:06:11,010 --> 00:06:16,520 So it's Thenable that returns an object that has a height and a width. 100 00:06:16,520 --> 00:06:19,890 And it computes the size of the elements bounding box in pixels. 101 00:06:19,890 --> 00:06:23,260 Well, that's pretty cool right, so let's try that. 102 00:06:23,260 --> 00:06:30,640 Let's go back to our form, we'll say form.getSize. 103 00:06:30,640 --> 00:06:33,320 And again, it returns a promise, it's a thenable. 104 00:06:33,320 --> 00:06:34,670 And the size object, 105 00:06:35,820 --> 00:06:37,750 it's gonna be an object that has a height and width on there. 106 00:06:37,750 --> 00:06:41,070 So we'll say console.dir(size), cuz we'll wanna spit that out so 107 00:06:41,070 --> 00:06:42,160 it looks a little bit prettier. 108 00:06:43,620 --> 00:06:49,000 So then, and look at that, so, the size of the form is 54 by 520. 109 00:06:49,000 --> 00:06:51,792 It looks like it has some other information in here, it's not filled out. 110 00:06:51,792 --> 00:06:56,460 Okay, so we still need to get to our input field though, right? 111 00:06:56,460 --> 00:06:59,630 We need get here, how can we do that? 112 00:07:01,040 --> 00:07:04,180 Well, you know what, I do have access to that source. 113 00:07:04,180 --> 00:07:06,353 Why don't I just go in there and add my ID, right? 114 00:07:06,353 --> 00:07:07,750 I mean, what could go wrong? 115 00:07:07,750 --> 00:07:09,120 So I am gonna come in here. 116 00:07:09,120 --> 00:07:15,673 Here's our input type I'm just gonna go ahead and I'm gonna say id="invitee". 117 00:07:15,673 --> 00:07:21,510 Cool and then if I come back here and I can just go get that, right? 118 00:07:21,510 --> 00:07:25,680 It looks pretty easy so we'll 119 00:07:25,680 --> 00:07:30,330 say const field = driver.findElement. 120 00:07:30,330 --> 00:07:34,020 And again, we want to find it by id, and 121 00:07:34,020 --> 00:07:36,180 the id that we just added is called invitee. 122 00:07:37,840 --> 00:07:42,560 So it should fail now, right, because the document's open, so it can't find it. 123 00:07:42,560 --> 00:07:44,980 So wow, that failed really hard. 124 00:07:44,980 --> 00:07:47,750 So it says, no such element: Unable to locate element. 125 00:07:49,130 --> 00:07:50,110 ID invitee. 126 00:07:50,110 --> 00:07:51,230 Ok, so, it can't find that, so. 127 00:07:52,460 --> 00:07:56,980 Let's go ahead and, I'm gonna go ahead and, see, left this thing up and running. 128 00:07:56,980 --> 00:07:59,730 And these will start piling up here. 129 00:07:59,730 --> 00:08:02,050 Let's go ahead and let's close this. 130 00:08:04,316 --> 00:08:06,270 And I'll start things up again. 131 00:08:06,270 --> 00:08:08,110 Boy, we need to do something about this, don't we? 132 00:08:10,090 --> 00:08:13,045 Selenium and we're gonna go ahead and 133 00:08:13,045 --> 00:08:17,390 build the driver we need to make sure that we get by here. 134 00:08:18,650 --> 00:08:24,760 There's our by, and then we need to do the builder, we've got the builder already. 135 00:08:24,760 --> 00:08:31,520 We need to get the url which we haven't set yet, so we need to set the url. 136 00:08:31,520 --> 00:08:36,560 Now we can do driver.get (url), okay, so now our page is open again. 137 00:08:36,560 --> 00:08:39,038 And I wanna try and find that field, there we go. 138 00:08:39,038 --> 00:08:42,920 Field = driver.findElement(By.id"invitee"));. 139 00:08:42,920 --> 00:08:45,760 And it should be there now, because the page just refreshed, right? 140 00:08:46,930 --> 00:08:52,470 Okay, so now we've got the field, and let's do our trick there. 141 00:08:52,470 --> 00:09:01,210 And we can say field.sendKeys("Found by id"), boom, we did it. 142 00:09:01,210 --> 00:09:04,260 Now, before we go celebrating too much, 143 00:09:04,260 --> 00:09:07,810 I kinda led you down a path towards a bad practice. 144 00:09:07,810 --> 00:09:10,580 Adding specific attributes for automation purposes 145 00:09:10,580 --> 00:09:14,620 only is a common trap that people just getting started tend to fall into. 146 00:09:14,620 --> 00:09:18,060 So I wanted to walk you through it, sorry for misleading a little bit. 147 00:09:18,060 --> 00:09:19,620 But let's think this through, 148 00:09:19,620 --> 00:09:23,210 we don't really wanna add an id to every element, do we? 149 00:09:23,210 --> 00:09:26,975 First off, you might not have access to make the modifications to the source, 150 00:09:26,975 --> 00:09:27,923 like we just did. 151 00:09:27,923 --> 00:09:31,750 Maybe you're on a team that doesn't have the ability to make those kind of changes. 152 00:09:31,750 --> 00:09:37,290 And second, it's a lot of work, imagine all those ids that you'd have to create. 153 00:09:37,290 --> 00:09:41,797 You'll find that when working on a team that relying on ids that you created 154 00:09:41,797 --> 00:09:46,667 might mean that people using them for CSS won't understand what they're for and 155 00:09:46,667 --> 00:09:47,902 [SOUND] remove them. 156 00:09:47,902 --> 00:09:52,117 If you need another reason to avoid using ids just for locator purposes, 157 00:09:52,117 --> 00:09:54,700 this will probably seal the deal. 158 00:09:54,700 --> 00:09:58,000 One thing you might not realize is that elements with the id 159 00:09:58,000 --> 00:10:00,875 attribute actually pollute the global name space. 160 00:10:00,875 --> 00:10:04,080 Here, let me show you real quick, so I'm wanna go ahead and 161 00:10:04,080 --> 00:10:06,940 open up, let's full screen this. 162 00:10:06,940 --> 00:10:12,050 I'm gonna go ahead and open up our Tools, I'm going to Inspect this element. 163 00:10:12,050 --> 00:10:15,807 I'm gonna flip over to the console here and close this. 164 00:10:18,380 --> 00:10:22,970 So, you probably know that already, with JavaScript, 165 00:10:22,970 --> 00:10:30,460 we could say document.getElementbyId and it has an invitee right? 166 00:10:31,940 --> 00:10:38,990 Check this out, if I do window.invitee, look at that. 167 00:10:38,990 --> 00:10:41,890 Also, it's available on the window. 168 00:10:41,890 --> 00:10:46,270 That means that a variable was created just to store that element. 169 00:10:46,270 --> 00:10:49,800 And because window is in the default scope, 170 00:10:49,800 --> 00:10:53,500 we also just have a plain old variable called invitee. 171 00:10:53,500 --> 00:10:56,990 Just available, yeah, there is, 172 00:10:56,990 --> 00:11:01,990 let's remove that id and be a good teammate and a good JavaScript citizen. 173 00:11:01,990 --> 00:11:03,890 So I'm gonna get rid of that id that we added. 174 00:11:07,022 --> 00:11:11,852 Save that, now in order to get at that unidentified input element, 175 00:11:11,852 --> 00:11:16,430 we're going to need to explore a few more locator strategies. 176 00:11:16,430 --> 00:11:18,740 Let's do just that right after this quick break.