1 00:00:06,600 --> 00:00:11,100 - When you configure your Jest test environment to use JSDOM 2 00:00:11,100 --> 00:00:14,220 as we've seen, Jest creates a document object 3 00:00:14,220 --> 00:00:17,190 as if your test was actually running in a browser. 4 00:00:17,190 --> 00:00:19,890 You can then use the regular DOM API 5 00:00:19,890 --> 00:00:22,110 to access the document object. 6 00:00:22,110 --> 00:00:24,420 As far as your test is concerned, 7 00:00:24,420 --> 00:00:26,580 the code is running in a browser. 8 00:00:26,580 --> 00:00:29,160 It really isn't, it's running in the JSDOM 9 00:00:29,160 --> 00:00:30,780 emulation of the browser 10 00:00:30,780 --> 00:00:33,240 but that doesn't affect your code in any way. 11 00:00:33,240 --> 00:00:35,700 You just use the regular DOM API 12 00:00:35,700 --> 00:00:38,040 as if it was a regular web application. 13 00:00:38,040 --> 00:00:40,350 So we're gonna start looking in this section 14 00:00:40,350 --> 00:00:43,410 at how to access the DOM content 15 00:00:43,410 --> 00:00:47,010 and to test that our code updates it correctly. 16 00:00:47,010 --> 00:00:49,360 So it's in this folder, JSDOM_AccessingContent. 17 00:00:51,139 --> 00:00:53,910 Okay, so that's where you want to go. 18 00:00:53,910 --> 00:00:55,740 And if you open that folder 19 00:00:55,740 --> 00:00:59,160 in a code editor, it looks like this. 20 00:00:59,160 --> 00:01:00,750 I have a couple of tests, 21 00:01:00,750 --> 00:01:03,480 a simple test just to get us started, 22 00:01:03,480 --> 00:01:05,820 trying to figure out how to navigate the content 23 00:01:05,820 --> 00:01:08,490 of the document, the header and the body. 24 00:01:08,490 --> 00:01:11,250 And then example two is a bit more ambitious. 25 00:01:11,250 --> 00:01:13,050 We're gonna start actually adding content 26 00:01:13,050 --> 00:01:16,140 to the DOM tree and verifying that it's correct. 27 00:01:16,140 --> 00:01:17,254 In all of these tests, 28 00:01:17,254 --> 00:01:20,520 we're gonna basically be running in JS DOM mode. 29 00:01:20,520 --> 00:01:22,860 Okay, so this Jest, config JS, 30 00:01:22,860 --> 00:01:25,200 it says all tests will be executed 31 00:01:25,200 --> 00:01:27,870 in the jsdom testEnvironment. 32 00:01:27,870 --> 00:01:32,220 Therefore, Jest will create a document object 33 00:01:32,220 --> 00:01:34,233 that our tests can execute against. 34 00:01:35,100 --> 00:01:36,870 Okay, so there's just a reminder. 35 00:01:36,870 --> 00:01:41,870 We've set the JSDOM test environment in our Jest config. 36 00:01:42,033 --> 00:01:45,327 Okay then, so here's our simple, first test. 37 00:01:45,327 --> 00:01:46,740 And on the right hand side 38 00:01:46,740 --> 00:01:49,710 I've drawn a little picture just to remind you about 39 00:01:49,710 --> 00:01:51,630 the structure of the document. 40 00:01:51,630 --> 00:01:56,520 This basically is the default content that JSDOM creates. 41 00:01:56,520 --> 00:01:59,943 It creates a document object with an HTML element, 42 00:02:00,986 --> 00:02:03,330 this is called the document element. 43 00:02:03,330 --> 00:02:07,290 Okay, so the document node is document. 44 00:02:07,290 --> 00:02:11,340 The document object has a property called document element. 45 00:02:11,340 --> 00:02:12,960 It's kind of like the root element. 46 00:02:12,960 --> 00:02:16,120 HTML is the document element or the root element. 47 00:02:16,120 --> 00:02:19,770 And then it has a head child and a body child, 48 00:02:19,770 --> 00:02:23,370 all of this content here is created automatically for you 49 00:02:23,370 --> 00:02:25,890 by JSDOM as a starting point. 50 00:02:25,890 --> 00:02:27,540 And on the left hand side, you can see 51 00:02:27,540 --> 00:02:29,160 I've got some code here, 52 00:02:29,160 --> 00:02:34,160 which tests access to that little document object structure. 53 00:02:35,070 --> 00:02:36,420 Okay, so I've got three tests. 54 00:02:36,420 --> 00:02:38,100 Let's have look at the first test. 55 00:02:38,100 --> 00:02:41,430 The first test, I basically grab the document object 56 00:02:41,430 --> 00:02:43,162 and I'm hoping that it exists, 57 00:02:43,162 --> 00:02:46,590 because I've configured JSDOM as my test environment, 58 00:02:46,590 --> 00:02:48,000 it will exist. 59 00:02:48,000 --> 00:02:49,740 Therefore, this test will pass. 60 00:02:49,740 --> 00:02:52,140 The document property does exist, 61 00:02:52,140 --> 00:02:54,551 and it'll give me this object here. 62 00:02:54,551 --> 00:02:56,490 Okay, what about the second test? 63 00:02:56,490 --> 00:02:59,220 In the second test, I take the document object, 64 00:02:59,220 --> 00:03:01,340 and remember the document object 65 00:03:01,340 --> 00:03:04,323 has a property called document element, 66 00:03:05,190 --> 00:03:06,360 which gives us this element here. 67 00:03:06,360 --> 00:03:08,490 Document element is a euphemism 68 00:03:08,490 --> 00:03:11,340 for the root element in your webpage. 69 00:03:11,340 --> 00:03:13,230 It's the HTML element. 70 00:03:13,230 --> 00:03:15,390 So this will give you back a pointer, 71 00:03:15,390 --> 00:03:18,030 effectively, to the HTML element. 72 00:03:18,030 --> 00:03:22,710 I can check that the HTML element is not undefined. 73 00:03:22,710 --> 00:03:24,450 Okay, so it does it exist. 74 00:03:24,450 --> 00:03:27,150 I can also check that the document element, 75 00:03:27,150 --> 00:03:32,150 in DOM every node has a property called node name. 76 00:03:32,430 --> 00:03:34,200 Like basically, what's the name of the element? 77 00:03:34,200 --> 00:03:35,910 What's the name of the element? 78 00:03:35,910 --> 00:03:39,210 I'm expecting it to match this regular expression. 79 00:03:39,210 --> 00:03:41,010 So in other words, I'm expecting the document 80 00:03:41,010 --> 00:03:44,700 element's name to be HTML case insensitive. 81 00:03:44,700 --> 00:03:47,370 You gotta be a bit careful with JSDOM 82 00:03:47,370 --> 00:03:49,911 because these elements, 83 00:03:49,911 --> 00:03:53,040 I think it generates them with capital letters. 84 00:03:53,040 --> 00:03:56,580 So if you're doing matching on element names, 85 00:03:56,580 --> 00:03:57,600 you probably want to be always 86 00:03:57,600 --> 00:04:00,930 using a case insensitive comparison. 87 00:04:00,930 --> 00:04:03,210 Okay, so what about the third test? 88 00:04:03,210 --> 00:04:04,800 Let's have a look at this. 89 00:04:04,800 --> 00:04:07,110 Grab the document element, 90 00:04:07,110 --> 00:04:09,690 that would be the HTML element there. 91 00:04:09,690 --> 00:04:11,700 I'm gonna use query selector, 92 00:04:11,700 --> 00:04:14,670 that's a standard DOM API. 93 00:04:14,670 --> 00:04:18,390 Query selector, you can give it a CSS selector. 94 00:04:18,390 --> 00:04:21,630 This year we'll search for an element called head. 95 00:04:21,630 --> 00:04:26,499 Does my document element have somewhere 96 00:04:26,499 --> 00:04:30,150 a child element, or descendant, called head? 97 00:04:30,150 --> 00:04:32,820 And does it have a descendant called body? 98 00:04:32,820 --> 00:04:34,110 Yes and yes. 99 00:04:34,110 --> 00:04:38,970 When you call query selector, this here is a CSS selector. 100 00:04:38,970 --> 00:04:40,530 It could be the name of an element, 101 00:04:40,530 --> 00:04:42,660 like head, or body, or div. 102 00:04:42,660 --> 00:04:47,070 Or, it could be a CSS class like '.important', 103 00:04:47,070 --> 00:04:49,167 or it could be an ID, like '#myID.' 104 00:04:50,130 --> 00:04:53,100 So you can use any CSS selector. 105 00:04:53,100 --> 00:04:55,800 This will check that the head element exists 106 00:04:55,800 --> 00:04:57,780 and the body element exists. 107 00:04:57,780 --> 00:04:59,790 Okay, so that's basic navigation. 108 00:04:59,790 --> 00:05:02,040 It gives you an idea of the content that we get 109 00:05:02,040 --> 00:05:07,040 for free using JSDOM and how we can access the content here. 110 00:05:07,260 --> 00:05:10,623 If I ran that test, then it works. 111 00:05:11,580 --> 00:05:14,130 Okay, now what about the second test? 112 00:05:14,130 --> 00:05:17,880 The second test here is a bit more ambitious. 113 00:05:17,880 --> 00:05:21,780 This is in example two, test JS. 114 00:05:21,780 --> 00:05:25,498 So in here I'm gonna have a look 115 00:05:25,498 --> 00:05:27,780 at several different tests, 116 00:05:27,780 --> 00:05:30,000 just to kind of illustrate how 117 00:05:30,000 --> 00:05:33,300 to create content in different ways, right? 118 00:05:33,300 --> 00:05:35,100 So we're gonna have a look at three different ways 119 00:05:35,100 --> 00:05:39,540 of creating content in my kind of pretend webpage, 120 00:05:39,540 --> 00:05:41,220 via the document object. 121 00:05:41,220 --> 00:05:44,693 So I'm gonna use JSDOM, create some content in the document 122 00:05:44,693 --> 00:05:48,450 and then write some tests to check 123 00:05:48,450 --> 00:05:50,790 if the content is correct. 124 00:05:50,790 --> 00:05:52,980 So, first of all, in the first test 125 00:05:52,980 --> 00:05:56,043 we're gonna create an element in the webpage. 126 00:05:59,588 --> 00:06:03,030 So basically, whenever you wanna create content in DOM, 127 00:06:03,030 --> 00:06:05,100 you always go back to the document object 128 00:06:05,100 --> 00:06:06,780 and you say, "create element." 129 00:06:06,780 --> 00:06:08,940 You give it the name of the element you wanna create, 130 00:06:08,940 --> 00:06:12,870 and what that does, it just creates a node. 131 00:06:12,870 --> 00:06:15,480 So I'll create a node, like an element basically, 132 00:06:15,480 --> 00:06:20,010 a div, doesn't have any content yet. 133 00:06:20,010 --> 00:06:21,210 So the way you set the content, 134 00:06:21,210 --> 00:06:22,140 or one of the ways, 135 00:06:22,140 --> 00:06:23,490 is you can say take the element 136 00:06:23,490 --> 00:06:26,130 and set this inner HTML to be "Hello." 137 00:06:26,130 --> 00:06:29,370 Technically speaking, that actually creates a sub-node, 138 00:06:29,370 --> 00:06:33,900 a text node, that contains the text that you just specified. 139 00:06:33,900 --> 00:06:36,510 Okay, so technically we've got two nodes there, 140 00:06:36,510 --> 00:06:39,993 the div element, plus it's child content, the inner HTML. 141 00:06:41,130 --> 00:06:44,010 This test doesn't really go too far. 142 00:06:44,010 --> 00:06:46,890 It just checks that the element isn't null, 143 00:06:46,890 --> 00:06:49,487 well of course it isn't because I just created it. 144 00:06:49,487 --> 00:06:53,790 And it also checks that the element in the HTML is "Hello." 145 00:06:53,790 --> 00:06:57,330 And of course it is because I've just assigned it there. 146 00:06:57,330 --> 00:06:59,340 So that's like a starting point. 147 00:06:59,340 --> 00:07:01,530 To take it a step further, what we'd need to do 148 00:07:01,530 --> 00:07:04,740 would be to integrate this content into our actual webpage. 149 00:07:04,740 --> 00:07:06,870 So let's see how to do that. 150 00:07:06,870 --> 00:07:10,740 So, first of all, this is my second test. 151 00:07:10,740 --> 00:07:14,506 On the first line there in red, I've created a div element, 152 00:07:14,506 --> 00:07:16,713 so here's mydiv element. 153 00:07:18,316 --> 00:07:23,250 And then we set this inner HTML to be ID, at "Hi" even. 154 00:07:23,250 --> 00:07:28,250 Okay, so basically there's some inner text there, "Hi". 155 00:07:28,380 --> 00:07:32,250 I've set this ID, nodes have an ID property. 156 00:07:32,250 --> 00:07:35,400 Okay, so I'll kind of draw its ID here, 157 00:07:35,400 --> 00:07:37,620 technically speaking as an attribute. 158 00:07:37,620 --> 00:07:40,733 So the ID attribute is now set to be mydiv. 159 00:07:42,300 --> 00:07:46,060 Okay, so that's the kind of idea 160 00:07:47,040 --> 00:07:48,120 that you want to have in mind. 161 00:07:48,120 --> 00:07:49,830 So at the moment I've created a div 162 00:07:49,830 --> 00:07:53,370 but I haven't kind of integrated it into my web content. 163 00:07:53,370 --> 00:07:55,440 So the easiest way to do it is this. 164 00:07:55,440 --> 00:07:58,830 The document object provided by JSDOM 165 00:07:58,830 --> 00:08:00,690 has a property called body, 166 00:08:00,690 --> 00:08:03,150 which automatically gives you back the body element. 167 00:08:03,150 --> 00:08:06,120 And in that body element, I'm appending the div. 168 00:08:06,120 --> 00:08:10,263 So there'll be a body element in my webpage. 169 00:08:11,100 --> 00:08:13,623 There'll also be a head element, 170 00:08:14,580 --> 00:08:17,340 and there'll also be an HTML element, 171 00:08:17,340 --> 00:08:20,910 and there'll also be a document property there. 172 00:08:20,910 --> 00:08:23,670 Okay, so that's the basic structure that we've got. 173 00:08:23,670 --> 00:08:25,560 When you say document body, 174 00:08:25,560 --> 00:08:29,610 it automatically gives you access to this node here. 175 00:08:29,610 --> 00:08:32,250 And in that node, I've just appended the div. 176 00:08:32,250 --> 00:08:34,680 That's the easiest way of adding content. 177 00:08:34,680 --> 00:08:37,950 At the end of my body, as its last child, 178 00:08:37,950 --> 00:08:39,120 append this div. 179 00:08:39,120 --> 00:08:42,386 So mydiv is now part of the webpage. 180 00:08:42,386 --> 00:08:45,120 Right, so if I go back to my document, 181 00:08:45,120 --> 00:08:47,280 so that's basically going back right up to the top here, 182 00:08:47,280 --> 00:08:50,610 so this is going back up to the document node. 183 00:08:50,610 --> 00:08:55,440 I can say, find the element whose ID is mydiv. 184 00:08:55,440 --> 00:08:58,050 So this is a genuine request, this is effectively 185 00:08:58,050 --> 00:09:00,300 like a mini pretend webpage. 186 00:09:00,300 --> 00:09:03,000 And find the div whose ID is mydiv. 187 00:09:03,000 --> 00:09:04,830 It should give me back that div, 188 00:09:04,830 --> 00:09:06,420 if this is all properly integrated 189 00:09:06,420 --> 00:09:08,880 I should get back a pointer to this div element. 190 00:09:08,880 --> 00:09:11,820 So this should be he element that I found. 191 00:09:11,820 --> 00:09:13,890 Check that I have found it, 192 00:09:13,890 --> 00:09:17,100 and check that its inner HTML is "Hi." 193 00:09:17,100 --> 00:09:18,210 Okay, so there you go. 194 00:09:18,210 --> 00:09:20,250 Create elements like this. 195 00:09:20,250 --> 00:09:24,032 This code would probably be in your actual web page, 196 00:09:24,032 --> 00:09:26,040 this real JavaScript code. 197 00:09:26,040 --> 00:09:28,710 And then this is how you can check that the content exists. 198 00:09:28,710 --> 00:09:31,530 Find the element in the document 199 00:09:31,530 --> 00:09:33,660 and then check that it's content is 200 00:09:33,660 --> 00:09:35,661 what you expect it to be. 201 00:09:35,661 --> 00:09:39,180 Okay, so creating elements manually, one by one, 202 00:09:39,180 --> 00:09:43,260 create an element, set its HTML, set its ID. 203 00:09:43,260 --> 00:09:46,650 You can do this for each individual element, one by one, 204 00:09:46,650 --> 00:09:50,340 but if you wanted to build a complex list, for example, 205 00:09:50,340 --> 00:09:53,550 it would be quite painful creating each list item 206 00:09:53,550 --> 00:09:55,140 as an individual object, 207 00:09:55,140 --> 00:09:57,840 and then adding it one by one. 208 00:09:57,840 --> 00:09:59,520 An easier approach, sometimes, 209 00:09:59,520 --> 00:10:03,720 is just to formulate an entire string of HTML 210 00:10:03,720 --> 00:10:06,510 and just add it to the document directly. 211 00:10:06,510 --> 00:10:08,820 And it builds the DOM tree accordingly. 212 00:10:08,820 --> 00:10:10,020 So here, what I've done, 213 00:10:11,040 --> 00:10:15,050 I'm using JavaScript these days, we have a back tick. 214 00:10:15,050 --> 00:10:18,123 Back tick is called, like a template string. 215 00:10:19,500 --> 00:10:23,010 It can span multiple lines, it's a multi-line string 216 00:10:23,010 --> 00:10:24,450 and that can be quite handy 217 00:10:24,450 --> 00:10:27,510 if you wanna formulate some lengthy HTML. 218 00:10:27,510 --> 00:10:30,408 So here it's just a string at this stage, 219 00:10:30,408 --> 00:10:32,940 an unloaded list of items 220 00:10:32,940 --> 00:10:36,000 that you might take on a ski holiday, for example. 221 00:10:36,000 --> 00:10:38,010 This HTML, or this string, 222 00:10:38,010 --> 00:10:41,640 I'm assigning to the body of my document. 223 00:10:41,640 --> 00:10:44,730 This is the easiest way of loading content 224 00:10:44,730 --> 00:10:47,940 into your document object, so that you can test against it. 225 00:10:47,940 --> 00:10:50,130 So again, remember what's going on. 226 00:10:50,130 --> 00:10:54,093 There's a document object provided by Jest, or by JSDOM. 227 00:10:56,250 --> 00:11:01,050 It had an HTML child, 228 00:11:01,050 --> 00:11:03,120 that's the document element. 229 00:11:03,120 --> 00:11:08,120 The HTML child has a head child and a body child. 230 00:11:09,330 --> 00:11:13,350 And then what I'm doing here, in one single fell swoop, 231 00:11:13,350 --> 00:11:15,810 I'm saying, take that body and set this entire 232 00:11:15,810 --> 00:11:18,030 inner HTML to be that. 233 00:11:18,030 --> 00:11:21,989 So that will automatically, basically add the unloaded list, 234 00:11:21,989 --> 00:11:26,989 plus three list items, list item, list item, list item. 235 00:11:28,500 --> 00:11:33,500 Each list item will have some text: skis, boots, goggles. 236 00:11:33,750 --> 00:11:37,830 Okay, so just by assigning HTML like that, 237 00:11:37,830 --> 00:11:40,230 to the inner HTML of the body, 238 00:11:40,230 --> 00:11:44,130 you're effectively creating the document structure 239 00:11:44,130 --> 00:11:46,590 that you want to test against. 240 00:11:46,590 --> 00:11:49,260 You can then write tests against that document structure. 241 00:11:49,260 --> 00:11:50,580 And that's what I'm doing here. 242 00:11:50,580 --> 00:11:53,790 I'm saying query Select All, 243 00:11:53,790 --> 00:11:56,700 that will give you back a collection of all nodes 244 00:11:56,700 --> 00:12:01,110 of type L I, it'll give back a node list, 245 00:12:01,110 --> 00:12:04,757 containing three list items: skis, boots, goggles. 246 00:12:04,757 --> 00:12:07,920 I called that L I S, as in list items. 247 00:12:07,920 --> 00:12:10,590 Check that it's a node list, 248 00:12:10,590 --> 00:12:12,450 check that the length is three 249 00:12:12,450 --> 00:12:14,820 because there were three items added. 250 00:12:14,820 --> 00:12:17,550 Get the first element, 251 00:12:17,550 --> 00:12:19,530 so this will give me back a point there 252 00:12:19,530 --> 00:12:21,300 to the first list item. 253 00:12:21,300 --> 00:12:24,663 So that would be that one there. 254 00:12:25,860 --> 00:12:28,470 Check that it's inner HTML is "Skis," 255 00:12:28,470 --> 00:12:29,970 and then the second one is "Boots," 256 00:12:29,970 --> 00:12:30,960 and the third one is "Goggles." 257 00:12:30,960 --> 00:12:33,420 So hopefully you can see how this pans out. 258 00:12:33,420 --> 00:12:36,030 Basically, the document body property 259 00:12:36,030 --> 00:12:38,010 is the key point here. 260 00:12:38,010 --> 00:12:40,320 You can just give it a whole chunk of HTML 261 00:12:40,320 --> 00:12:42,210 and that sets up the document structure, 262 00:12:42,210 --> 00:12:45,120 against which you can then write your tests 263 00:12:45,120 --> 00:12:48,543 to see if it's updating the document structure correctly. 264 00:12:50,580 --> 00:12:52,380 Although it's quite a simple example, 265 00:12:52,380 --> 00:12:53,910 it's also quite a realistic example 266 00:12:53,910 --> 00:12:56,850 of how we're gonna be going on for the rest of this lesson. 267 00:12:56,850 --> 00:13:00,453 So just need to run that test and it works.