1 00:00:00,189 --> 00:00:03,520 As you just saw, CSS is pretty powerful. 2 00:00:03,520 --> 00:00:07,125 It does a great job of remaining concise and extremely expressive. 3 00:00:07,125 --> 00:00:08,030 Now believe it or 4 00:00:08,030 --> 00:00:13,200 not, XPath can do even more, but it quickly looses its conciseness. 5 00:00:13,200 --> 00:00:16,780 I want to do some exploration with you because it's so super powerful. 6 00:00:16,780 --> 00:00:19,239 Sometimes you'll need to lean on it when CSS falls short. 7 00:00:20,250 --> 00:00:24,550 For instance, here's one case that you can't do reliably across all browsers yet 8 00:00:24,550 --> 00:00:25,890 with CSS. 9 00:00:25,890 --> 00:00:28,750 We want find an element based on its content. 10 00:00:28,750 --> 00:00:33,835 We want to find one of those invitees by name, so let's do this. 11 00:00:33,835 --> 00:00:39,900 Okay, so first let's get some more students added here to our invitee list. 12 00:00:39,900 --> 00:00:43,090 In the teacher's notes, I've built an array of invitees, and 13 00:00:43,090 --> 00:00:47,840 I'm gonna drop them right here at the top, right under our driver there. 14 00:00:47,840 --> 00:00:48,560 Boom. 15 00:00:48,560 --> 00:00:50,070 There's all our students right? 16 00:00:51,960 --> 00:00:54,290 Look at all those beautiful names, all right. 17 00:00:55,350 --> 00:00:58,062 So, those are in the teacher's notes. 18 00:00:58,062 --> 00:01:03,008 All right, and now I just want to add all these invitees, and since that's an array, 19 00:01:03,008 --> 00:01:05,289 let's just use an array method there. 20 00:01:05,289 --> 00:01:10,727 So we'll say invitees, which is that array there, and we'll say, forEach. 21 00:01:10,727 --> 00:01:15,729 So the way that this works is it takes a callback here, 22 00:01:15,729 --> 00:01:20,732 and a callback expects each one of those elements, so 23 00:01:20,732 --> 00:01:26,210 we'll say invitee => addInvitee(invitee), cool. 24 00:01:26,210 --> 00:01:31,553 So, actually if you look at it, what happens is this is just looking for 25 00:01:31,553 --> 00:01:36,808 a function that takes an invitee, and that's what addInvites does, 26 00:01:36,808 --> 00:01:41,884 so what we can actually do is just do this forEach of those invitees, 27 00:01:41,884 --> 00:01:43,868 (addInvitee) like so. 28 00:01:43,868 --> 00:01:47,983 I'm gonna make sure my workspace is running, and it is, and 29 00:01:47,983 --> 00:01:53,066 then I'm going to go ahead, save this file, and I am gonna do my up arrow and 30 00:01:53,066 --> 00:01:57,225 run this, and watch this get filled out, it's beautiful. 31 00:01:57,225 --> 00:02:01,417 [NOISE] And I clicked the toggle button at the end there, [LAUGH] but 32 00:02:01,417 --> 00:02:04,925 look at these names, I would love to go to this party. 33 00:02:04,925 --> 00:02:07,390 What a great treehouse party this is. 34 00:02:07,390 --> 00:02:11,197 So let's assume though that I was just trying to get a hold of one of these 35 00:02:11,197 --> 00:02:15,005 by name, like let's assume that I was trying to here to get a hold of this 36 00:02:15,005 --> 00:02:16,288 one by Shadd Anderson. 37 00:02:16,288 --> 00:02:20,902 Now he trolled me earlier on Twitter by saying he didn't wanna do it, and 38 00:02:20,902 --> 00:02:26,130 then he said okay sure, [LAUGH] because that's what Shadd does, he is a troll. 39 00:02:26,130 --> 00:02:29,735 So let's do this, let's remove Shadd from the party. 40 00:02:29,735 --> 00:02:32,159 So, I wanna lean on XPath here. 41 00:02:32,159 --> 00:02:37,859 So, what I'm gonna do is I'm gonna go to the elements tab, so let's Inspect. 42 00:02:37,859 --> 00:02:42,834 Cool, and let's bring this down, let's close these new releases, and 43 00:02:42,834 --> 00:02:46,458 let's go ahead, and let's pop this up a little bit. 44 00:02:46,458 --> 00:02:48,340 There we go, and I'm gonna open up the find again. 45 00:02:48,340 --> 00:02:51,540 So, remember you can do XPath or CSS up in here. 46 00:02:51,540 --> 00:02:55,807 So what we wanna do is we wanna do a relative search. 47 00:02:55,807 --> 00:02:57,458 Let's see, what does this look like actually? 48 00:02:57,458 --> 00:02:58,194 What's in here? 49 00:02:58,194 --> 00:03:02,744 Okay, so there's a span and then the name there. 50 00:03:02,744 --> 00:03:07,858 Okay, so what we wanna do is a relative search from anywhere in the document, 51 00:03:07,858 --> 00:03:10,940 and with XPath, you do that with two slashes. 52 00:03:10,940 --> 00:03:14,320 So we say anything there, and then so now, just like CSS, 53 00:03:14,320 --> 00:03:17,150 we specify the tag name that we want. 54 00:03:17,150 --> 00:03:21,352 So we wanna find a span, cuz we're looking for a span. 55 00:03:21,352 --> 00:03:22,636 Okay, so there we go. 56 00:03:22,636 --> 00:03:25,449 So there's 24 spans on this page. 57 00:03:25,449 --> 00:03:27,780 Let's kind of make sure that those are all the names of the people. 58 00:03:27,780 --> 00:03:29,540 There's the Shadd one that we wanna get rid off. 59 00:03:30,650 --> 00:03:32,451 Okay, cool, awesome. 60 00:03:32,451 --> 00:03:35,435 So, we don't wanna grab this first span, and 61 00:03:35,435 --> 00:03:38,267 there's 24 of those available there, so 62 00:03:38,267 --> 00:03:43,180 what we can do is we can do more testing on each of these nodes that's found. 63 00:03:43,180 --> 00:03:46,180 So remember we wanna find a specific text. 64 00:03:46,180 --> 00:03:48,550 We wanna find Shadd Anderson. 65 00:03:48,550 --> 00:03:53,310 So to do that, we do what is known as a predicate, and it further tests your node. 66 00:03:53,310 --> 00:03:58,606 So those are in hard brackets, like so [], and in here, we can check an expression. 67 00:03:58,606 --> 00:04:02,552 So the expression that we're gonna call, 68 00:04:02,552 --> 00:04:07,830 we're gonna call [text()= "Shadd Anderson"]. 69 00:04:07,830 --> 00:04:10,890 Now look at that, we got the span. 70 00:04:10,890 --> 00:04:15,289 Now text gets all of the content in the element and it's checking for equality, so 71 00:04:15,289 --> 00:04:15,876 we got it. 72 00:04:15,876 --> 00:04:17,830 So, but man, how do we get this button? 73 00:04:17,830 --> 00:04:19,140 How do we get this remove button? 74 00:04:20,815 --> 00:04:24,130 So we have a lot of options, but let's work our way there. 75 00:04:24,130 --> 00:04:29,010 First, what we could do is we could go up to the parent, the parent is the li there. 76 00:04:29,010 --> 00:04:30,050 So, let's try that. 77 00:04:30,050 --> 00:04:33,393 So, in XPath, you can reference different axes, 78 00:04:33,393 --> 00:04:37,221 and one access that we can reference is the parent access. 79 00:04:37,221 --> 00:04:42,135 So I can do this, I can say /parent, and then do the axes, you do :: which 80 00:04:42,135 --> 00:04:47,361 a little wacko, but we'll do that, and then you say what you're looking for, 81 00:04:47,361 --> 00:04:51,813 so we're looking for the li above Shadd Anderson, so that is that. 82 00:04:51,813 --> 00:04:55,950 So, now if we don't really care what the parent is, we can do parent::, and 83 00:04:55,950 --> 00:04:58,440 you can just do star, and star kind of just selects anything. 84 00:04:58,440 --> 00:05:01,760 You can actually do that anywhere, star's kind of a wild card. 85 00:05:01,760 --> 00:05:05,830 But this parent parent star has done enough that they actually made a shortcut, 86 00:05:05,830 --> 00:05:08,870 which I think it reads a little bit better, especially in our scenario, and 87 00:05:08,870 --> 00:05:14,780 that's the double period, and that looks like a, kind of like a directory changing. 88 00:05:14,780 --> 00:05:19,384 So there we go, so if you do .., that's gonna find any parent of Shadd. 89 00:05:19,384 --> 00:05:20,960 There's only ever one parent, right? 90 00:05:21,978 --> 00:05:26,024 So now we're in a place where we want to do a new node test. 91 00:05:26,024 --> 00:05:28,015 Here's a point where you get to pick your poison. 92 00:05:28,015 --> 00:05:31,715 What's more likely to change in our current situation, is it the copy, or 93 00:05:31,715 --> 00:05:32,606 is it the layout? 94 00:05:32,606 --> 00:05:35,685 So, I could definitely hard code the text of this button. 95 00:05:35,685 --> 00:05:38,904 The button that we wanna find is the one that says remove. 96 00:05:38,904 --> 00:05:40,013 So, let's do that. 97 00:05:40,013 --> 00:05:42,530 See, inside the button there's text to remove. 98 00:05:42,530 --> 00:05:45,095 So we could try that, so we could just do, like we just learned. 99 00:05:45,095 --> 00:05:46,803 Say button, so that found the first one. 100 00:05:46,803 --> 00:05:52,210 Let's see, it found two, but let's get specific about it we'll say, 101 00:05:52,210 --> 00:05:55,769 [text()="remove"], and there we go. 102 00:05:55,769 --> 00:06:02,070 So that's one way to get it, but what if that text changes to delete? 103 00:06:02,070 --> 00:06:04,902 If this is more likely to happen and the design is to change, 104 00:06:04,902 --> 00:06:06,613 you can of course go another route. 105 00:06:06,613 --> 00:06:09,820 So let's say that we wanted to just get the buttons. 106 00:06:09,820 --> 00:06:11,580 So we could lose the predicate. 107 00:06:11,580 --> 00:06:12,500 So let's lose this predicate. 108 00:06:12,500 --> 00:06:16,104 So we're back to two buttons here. 109 00:06:16,104 --> 00:06:19,935 So layout-wise, it's the second one, so we could use an index. 110 00:06:19,935 --> 00:06:25,915 So we can say, button[2], and I do wanna point out here that in XPath, 111 00:06:25,915 --> 00:06:33,290 it surprisingly is not zero-based, like arrays in most languages, it's one-based. 112 00:06:33,290 --> 00:06:36,580 So we're looking for the second one, and we're actually using the number two, 113 00:06:36,580 --> 00:06:40,400 zero doesn't come into play, unlike typical array indices. 114 00:06:40,400 --> 00:06:43,120 So the other thing I can do is I can also specify that I want 115 00:06:43,120 --> 00:06:45,190 the last button in there. 116 00:06:46,240 --> 00:06:49,266 There's also sibling axes that we could use, and 117 00:06:49,266 --> 00:06:52,445 it's equivalent to the plus sign that we saw in CSS. 118 00:06:52,445 --> 00:06:54,905 Check the teacher's notes for more information on XPath. 119 00:06:54,905 --> 00:06:58,784 But for now let's just use this one in our code, so let's grab 120 00:06:58,784 --> 00:07:04,340 this selector that grabs the last button where it's named Shadd Anderson. 121 00:07:04,340 --> 00:07:08,436 Now, we need to make our locator more dynamic than that. 122 00:07:08,436 --> 00:07:11,824 Different languages have different ways of handling this, but 123 00:07:11,824 --> 00:07:14,402 JavaScript's newer syntax really shine here. 124 00:07:14,402 --> 00:07:17,649 So what I wanna do is I wanna make a locator, and 125 00:07:17,649 --> 00:07:20,245 we'll name it exactly what we want. 126 00:07:20,245 --> 00:07:26,472 So we're gonna say, we want this to be the removeButtonForInvitee, 127 00:07:26,472 --> 00:07:30,481 and what we'll do is we'll have this thing, 128 00:07:30,481 --> 00:07:35,140 this will be a function, so it requires an Invitee. 129 00:07:35,140 --> 00:07:39,930 So you pass it an invitee, and the you'll get back the proper selector. 130 00:07:39,930 --> 00:07:43,147 So what we'll do is we'll say By.xpath, and 131 00:07:43,147 --> 00:07:46,041 we'll pass in what we copied from there. 132 00:07:49,957 --> 00:07:52,452 This has the quote problem that we had seen before. 133 00:07:54,801 --> 00:07:57,272 What we really wanna do, I'm gonna leave those quotes there, 134 00:07:57,272 --> 00:08:00,458 because what we're gonna do is we're gonna change this to be a template string. 135 00:08:00,458 --> 00:08:03,766 So I'm gonna remove this, I'm gonna change this to the tick, and 136 00:08:03,766 --> 00:08:07,385 if you haven't seen template strings before, they're really slick. 137 00:08:07,385 --> 00:08:13,216 So what happens is I can now access variables that are in my 138 00:08:13,216 --> 00:08:18,570 scope by using a $ and surrounding them with these. 139 00:08:18,570 --> 00:08:22,390 So template strings, more on those in the teacher's notes, I'm gonna get rid of this 140 00:08:22,390 --> 00:08:26,320 semicolon at the end here, and let's see if I can't get this fully open. 141 00:08:27,370 --> 00:08:29,666 The font up pretty high for everybody but. 142 00:08:29,666 --> 00:08:34,659 So removeButtonForInvitee, and what happens is, you pass in an invitee, 143 00:08:34,659 --> 00:08:36,609 and then to the function, and 144 00:08:36,609 --> 00:08:41,140 the function will return a finder very specific to what you typed in. 145 00:08:41,140 --> 00:08:45,929 So whatever's typed in here is gonna get replaced here in the string, and 146 00:08:45,929 --> 00:08:49,109 that will return the locator, so let's use it. 147 00:08:49,109 --> 00:08:55,669 So under addInvitee here, I'm gonna say, function removeInvitee. 148 00:08:55,669 --> 00:09:01,910 So removeInvitee will take the invitee's name, and then we'll 149 00:09:01,910 --> 00:09:08,952 say,driver.findElement(locators.removeBut- tonForInvitee). 150 00:09:08,952 --> 00:09:12,709 Now remember this is a function, so we're going to pass in what was passed in, 151 00:09:17,157 --> 00:09:19,332 And then we're gonna click, 152 00:09:19,332 --> 00:09:23,682 because that thing's gonna build the proper XPath for us. 153 00:09:23,682 --> 00:09:28,758 So let's call that, I'm gonna turn off this toggle at the end so 154 00:09:28,758 --> 00:09:34,304 we can see it really quick, and so all the invitees are gonna be added, 155 00:09:34,304 --> 00:09:39,671 and then we're gonna say removeInvitee("Shadd Anderson"). 156 00:09:42,262 --> 00:09:46,310 Cool, all right so, we're gonna pass in, we're gonna call the function, 157 00:09:46,310 --> 00:09:50,546 we're gonna pass in the string "Shadd Anderson" and it's gonna come in here, 158 00:09:50,546 --> 00:09:52,810 It's gonna go into find element. 159 00:09:52,810 --> 00:09:55,980 Find element needs a locator, so it's gonna run this function, 160 00:09:55,980 --> 00:09:58,380 removeButtonForInvitee and pass in "Shadd Anderson". 161 00:09:59,850 --> 00:10:02,810 Here's the definition of the function, this will be "Shadd Anderson", it will 162 00:10:02,810 --> 00:10:06,930 come through and say "Shadd Anderson" and the XPath will find specifically that. 163 00:10:07,960 --> 00:10:11,430 Let's go ahead, and let's run it, and make sure we got things working. 164 00:10:11,430 --> 00:10:12,522 I'm gonna press the up arrow. 165 00:10:12,522 --> 00:10:18,760 I'm gonna close our other one that we had open, and I will call this. 166 00:10:20,300 --> 00:10:21,150 There we go. 167 00:10:21,150 --> 00:10:25,387 There it is, fills everybody out, and it removed Chad from there. 168 00:10:25,387 --> 00:10:28,125 I wanted to show you one more thing in here. 169 00:10:28,125 --> 00:10:33,245 If you come in, just like before in the console, we were able to use dollar, 170 00:10:33,245 --> 00:10:38,160 dollar, we can also, if we wanted to check an XPath, we can choose $x. 171 00:10:38,160 --> 00:10:40,000 So again, let's make one up. 172 00:10:40,000 --> 00:10:45,640 Let's say we wanted to find the form, we wanna find anything, 173 00:10:45,640 --> 00:10:54,500 let's find anything remotely, any type of element that has the ID of registrar. 174 00:10:54,500 --> 00:10:57,390 So that should return the form with that ID. 175 00:11:00,220 --> 00:11:02,047 Awesome, and it does. 176 00:11:02,047 --> 00:11:05,767 Cool and so, again, when you open this up, and 177 00:11:05,767 --> 00:11:09,100 you mouse over it, it shows what it is. 178 00:11:09,100 --> 00:11:12,290 So $x will do any Xpath query, right there, from the command line. 179 00:11:13,470 --> 00:11:13,970 Awesome, right? 180 00:11:15,110 --> 00:11:18,549 I hope you're beginning to see how powerful the CSS and 181 00:11:18,549 --> 00:11:20,130 XPath selectors can be. 182 00:11:20,130 --> 00:11:23,440 Remember to always try and keep things unambiguous and precise. 183 00:11:23,440 --> 00:11:26,160 There are many ways to select the same element, but 184 00:11:26,160 --> 00:11:28,270 you should always embrace the lazy. 185 00:11:28,270 --> 00:11:31,230 Try and focus on what is least likely to change. 186 00:11:31,230 --> 00:11:33,520 You don't want to do more work than you need to, do you? 187 00:11:34,760 --> 00:11:37,660 One thing I wanted to point out was how good the abstractions 188 00:11:37,660 --> 00:11:38,830 are starting to feel. 189 00:11:38,830 --> 00:11:42,042 We were able to say, add invitee, and remove invitee, and 190 00:11:42,042 --> 00:11:46,809 we weren't really even talking about how that was implemented, user interface wise. 191 00:11:46,809 --> 00:11:49,798 What this means is that if things were to change in our app, 192 00:11:49,798 --> 00:11:53,946 we could definitely update our locators and our methods to match the new layout or 193 00:11:53,946 --> 00:11:56,152 interface, and that is pretty powerful. 194 00:11:56,152 --> 00:11:59,138 We've abstracted a way to how. 195 00:11:59,138 --> 00:12:02,701 Currently, we are only dealing with a single page application, 196 00:12:02,701 --> 00:12:05,510 but imagine this across a huge application. 197 00:12:05,510 --> 00:12:09,995 This level of abstracting away the actions you can do on a page would 198 00:12:09,995 --> 00:12:11,525 definitely be ideal. 199 00:12:11,525 --> 00:12:15,683 Well, there is a pattern that emerges pretty quickly during automation of larger 200 00:12:15,683 --> 00:12:18,940 projects that encourages this abstraction for readability and 201 00:12:18,940 --> 00:12:20,880 code duplication avoidance. 202 00:12:20,880 --> 00:12:23,690 It's called the page object model, and 203 00:12:23,690 --> 00:12:25,750 we should take some time to explore its benefits. 204 00:12:26,770 --> 00:12:28,160 Let's do that right after this quick break.