1 00:00:06,540 --> 00:00:08,130 - In an angular application 2 00:00:08,130 --> 00:00:12,780 a component's HTML template can contain child components. 3 00:00:12,780 --> 00:00:15,390 Typically, those child components are relevant 4 00:00:15,390 --> 00:00:18,030 to us when we're testing our component. 5 00:00:18,030 --> 00:00:20,340 We don't want their HTML to interfere 6 00:00:20,340 --> 00:00:23,190 with what we are trying to test from our component. 7 00:00:23,190 --> 00:00:26,250 So, how can we test a parent component 8 00:00:26,250 --> 00:00:28,830 without having to try to predict the HTML 9 00:00:28,830 --> 00:00:30,570 from all our children? 10 00:00:30,570 --> 00:00:34,170 Well, the actual answer is to stub those children out. 11 00:00:34,170 --> 00:00:36,060 So they don't actually render anything. 12 00:00:36,060 --> 00:00:39,150 That means you can just focus on your component instead. 13 00:00:39,150 --> 00:00:40,920 So we're gonna see how to do that, 14 00:00:40,920 --> 00:00:43,410 how to stub out child components, 15 00:00:43,410 --> 00:00:45,240 so they don't interfere with us 16 00:00:45,240 --> 00:00:47,100 when we're trying to test our component. 17 00:00:47,100 --> 00:00:50,580 Example, it's lesson 12 example one, 18 00:00:50,580 --> 00:00:51,810 the demo application there 19 00:00:51,810 --> 00:00:53,460 is actually the same application we've looked 20 00:00:53,460 --> 00:00:57,120 at over the last couple of videos. 21 00:00:57,120 --> 00:00:58,080 So here it is. 22 00:00:58,080 --> 00:01:01,080 If you remember in there, quick reminder, 23 00:01:01,080 --> 00:01:04,590 I had a component called toggle switch 24 00:01:04,590 --> 00:01:08,187 which displayed a button that was on or off. 25 00:01:08,187 --> 00:01:12,360 Its selector was app toggle switch. 26 00:01:12,360 --> 00:01:15,360 And then we had another component called banner. 27 00:01:15,360 --> 00:01:16,620 It displayed a message. 28 00:01:16,620 --> 00:01:18,175 I could click on it to make it uppercase 29 00:01:18,175 --> 00:01:19,803 or lowercase. 30 00:01:20,760 --> 00:01:24,420 Its component selector was app banner. 31 00:01:24,420 --> 00:01:26,760 So those are two children components. 32 00:01:26,760 --> 00:01:31,260 And I embed them inside my top-level application component. 33 00:01:31,260 --> 00:01:34,200 Here's my top-level application component 34 00:01:34,200 --> 00:01:38,760 and doesn't contain much data, but the template, 35 00:01:38,760 --> 00:01:43,447 app component HTML, if you scroll down to line 353, 36 00:01:45,330 --> 00:01:49,200 would you believe it renders an instance of my 37 00:01:49,200 --> 00:01:50,520 toggle switch component? 38 00:01:50,520 --> 00:01:53,190 And it renders an instance of my banner. 39 00:01:53,190 --> 00:01:56,640 Under normal circumstances, that would work absolutely fine. 40 00:01:56,640 --> 00:01:59,340 In the module, for our application, 41 00:01:59,340 --> 00:02:01,260 it knows about all those components. 42 00:02:01,260 --> 00:02:04,680 It knows about the AppComponent, and the banner, 43 00:02:04,680 --> 00:02:06,120 and the toggle switch. 44 00:02:06,120 --> 00:02:09,480 So when the application starts and when angular 45 00:02:09,480 --> 00:02:12,180 sees these tags in a real angular application 46 00:02:12,180 --> 00:02:14,940 it'll know which components to instantiate, 47 00:02:14,940 --> 00:02:16,740 and everything's fine. 48 00:02:16,740 --> 00:02:20,670 I could open up a command window, go to lesson 12, 49 00:02:20,670 --> 00:02:24,150 example one demo app, do an NPM install 50 00:02:24,150 --> 00:02:26,640 if you haven't already done so to install the libraries 51 00:02:26,640 --> 00:02:30,180 and then do an NG serve, to serve the application. 52 00:02:30,180 --> 00:02:31,710 So I've done that already. 53 00:02:31,710 --> 00:02:33,930 And this is what it looks like. 54 00:02:33,930 --> 00:02:34,763 Here we are. 55 00:02:34,763 --> 00:02:36,240 So there's the toggle switch component, 56 00:02:36,240 --> 00:02:39,180 which I can turn on and off. 57 00:02:39,180 --> 00:02:41,940 And here's my banner, which I can click to 58 00:02:41,940 --> 00:02:45,390 display in uppercase and click to display in lowercase. 59 00:02:45,390 --> 00:02:48,360 So when we are running the application full-speed 60 00:02:48,360 --> 00:02:51,420 everything's fine, because our application module has 61 00:02:51,420 --> 00:02:54,450 all the components at its disposal and it can render 62 00:02:54,450 --> 00:02:55,980 the entire webpage. 63 00:02:55,980 --> 00:02:57,270 Okay. So that's what I've just done. 64 00:02:57,270 --> 00:03:00,480 Basically in my top level AppComponent, HTML, 65 00:03:00,480 --> 00:03:03,960 I rendered an instance of both components. 66 00:03:03,960 --> 00:03:08,760 And when I do an NG serve, those components are available 67 00:03:08,760 --> 00:03:10,563 in my module and everything's fine. 68 00:03:11,970 --> 00:03:14,850 I run the tests, however, then it's not so good. 69 00:03:14,850 --> 00:03:16,080 Have a look at this. 70 00:03:16,080 --> 00:03:21,080 I'm running just the test for AppComponent spec TS. 71 00:03:21,210 --> 00:03:24,030 Okay. This is I've tested my top-level component 72 00:03:24,030 --> 00:03:27,150 which contains those other two tags. 73 00:03:27,150 --> 00:03:30,780 My top-level component contains the toggle switch 74 00:03:30,780 --> 00:03:32,460 and the banner. 75 00:03:32,460 --> 00:03:34,714 The trouble is the test doesn't know 76 00:03:34,714 --> 00:03:36,810 about those other components. 77 00:03:36,810 --> 00:03:39,270 When you're testing component A 78 00:03:39,270 --> 00:03:42,240 it doesn't know about child components B, C, or D. 79 00:03:42,240 --> 00:03:45,150 It just knows about its component itself. 80 00:03:45,150 --> 00:03:48,993 So if you run the test, you get an error message. 81 00:03:50,190 --> 00:03:54,600 When the application was, when the component was rendered, 82 00:03:54,600 --> 00:03:58,950 my application HTML, it had a app toggle switch tag. 83 00:03:58,950 --> 00:04:02,070 And basically it's saying here, in my test environment, 84 00:04:02,070 --> 00:04:05,370 it doesn't know what app banner is. 85 00:04:05,370 --> 00:04:09,360 When it saw the app banner syntax in my HTML template. 86 00:04:09,360 --> 00:04:10,320 Basically when it 87 00:04:10,320 --> 00:04:15,320 when it processed this in my application component HTML, 88 00:04:15,360 --> 00:04:17,220 it didn't know in my test environment. 89 00:04:17,220 --> 00:04:18,990 It didn't know what that is. 90 00:04:18,990 --> 00:04:22,200 Is it a component or is it regular HTML? 91 00:04:22,200 --> 00:04:23,403 What is this then? 92 00:04:24,780 --> 00:04:27,720 So we get these error messages being displayed. 93 00:04:27,720 --> 00:04:30,390 App banner is not a known element. 94 00:04:30,390 --> 00:04:32,490 Is it an angular component? 95 00:04:32,490 --> 00:04:34,110 In this case, in this this case 96 00:04:34,110 --> 00:04:37,890 you should basically notify in your test module. 97 00:04:37,890 --> 00:04:40,080 You should mention this component. 98 00:04:40,080 --> 00:04:43,890 Maybe it was a web component, some kind of HTML element 99 00:04:43,890 --> 00:04:46,383 in which case we should register it as well. 100 00:04:46,383 --> 00:04:49,500 Okay. And it's complaining as well about app toggle switch. 101 00:04:49,500 --> 00:04:51,450 It says, what is this thing? 102 00:04:51,450 --> 00:04:52,440 You didn't tell me about this. 103 00:04:52,440 --> 00:04:53,551 When you set up the test module, 104 00:04:53,551 --> 00:04:56,010 you just gave me the app component. 105 00:04:56,010 --> 00:04:57,030 You didn't mention anything 106 00:04:57,030 --> 00:04:59,490 about toggle switch or banner. 107 00:04:59,490 --> 00:05:00,390 Doesn't know, 108 00:05:00,390 --> 00:05:02,520 doesn't have a clue what we're talking about. 109 00:05:02,520 --> 00:05:05,400 So clearly we have to fix that. 110 00:05:05,400 --> 00:05:06,690 In our test, 111 00:05:06,690 --> 00:05:09,690 We have a test bed, the test bed compiles 112 00:05:09,690 --> 00:05:12,570 the HTML template for our component. 113 00:05:12,570 --> 00:05:15,840 When it does that, it sees these tags, 114 00:05:15,840 --> 00:05:17,550 and in the test environment, 115 00:05:17,550 --> 00:05:19,953 it has no clue what those tags mean. 116 00:05:21,240 --> 00:05:22,353 So we need to fix it. 117 00:05:23,460 --> 00:05:26,460 So, here is what you do. 118 00:05:26,460 --> 00:05:29,970 You can just be stub out the components that are 119 00:05:29,970 --> 00:05:31,408 causing the problem. 120 00:05:31,408 --> 00:05:35,910 This is my enhanced component spec. 121 00:05:35,910 --> 00:05:40,290 What I've done is I've defined a stub component like a 122 00:05:40,290 --> 00:05:44,820 do nothing component for app toggle switch. 123 00:05:44,820 --> 00:05:49,203 It basically says, here is a, a mock or stub component, 124 00:05:50,070 --> 00:05:53,793 basically anywhere where you see this selector, 125 00:05:55,500 --> 00:05:59,070 then create an instance of this mock component. 126 00:05:59,070 --> 00:06:02,663 Okay. This is replaced in the actual toggle switch component 127 00:06:02,663 --> 00:06:05,100 with a, with a stub implementation 128 00:06:05,100 --> 00:06:07,293 which has an empty HTML template. 129 00:06:08,490 --> 00:06:11,910 And likewise for the app banner, it says 130 00:06:11,910 --> 00:06:14,730 if you ever see app banner, then we, you know 131 00:06:14,730 --> 00:06:17,580 basically instantiate this component 132 00:06:17,580 --> 00:06:20,190 which has an empty HTML template. 133 00:06:20,190 --> 00:06:21,870 That fixes the problem for us now 134 00:06:21,870 --> 00:06:25,710 because when my application component is rendered 135 00:06:25,710 --> 00:06:27,330 it will see, you know 136 00:06:27,330 --> 00:06:30,840 the angular test environment will see these tags. 137 00:06:30,840 --> 00:06:31,950 And what I've just told it 138 00:06:31,950 --> 00:06:34,950 in the test environment is when you see those tags, 139 00:06:34,950 --> 00:06:37,440 basically create an instance of this component 140 00:06:37,440 --> 00:06:40,650 and that one that have an empty HTML template 141 00:06:40,650 --> 00:06:43,320 that doesn't interfere with the rest of the stuff 142 00:06:43,320 --> 00:06:45,450 generated in my component. 143 00:06:45,450 --> 00:06:49,350 So, I've effectively created two stub components here. 144 00:06:49,350 --> 00:06:52,280 I need to add those components into my test module. 145 00:06:52,280 --> 00:06:56,400 So, when my application, when my test is starting up, 146 00:06:56,400 --> 00:06:59,730 in my test bed, I configure a test module. 147 00:06:59,730 --> 00:07:02,910 Here are the components that are required for this test. 148 00:07:02,910 --> 00:07:07,230 I give it my real app component, my stub component for 149 00:07:07,230 --> 00:07:09,870 toggle switch, and my stub component 150 00:07:09,870 --> 00:07:11,430 for banner stub for banner. 151 00:07:11,430 --> 00:07:15,450 Okay. So that means whenever it now knows when 152 00:07:15,450 --> 00:07:17,640 that tag appears to create an instance 153 00:07:17,640 --> 00:07:19,773 of that component or that component. 154 00:07:20,640 --> 00:07:24,210 And that means our tests can now proceed properly. 155 00:07:24,210 --> 00:07:27,003 If I run the tests properly now, 156 00:07:27,900 --> 00:07:31,650 then it'll all work fine without any errors. 157 00:07:31,650 --> 00:07:35,310 I'm actually gonna do that in my real code, just to verify. 158 00:07:35,310 --> 00:07:39,060 So in my real code have a look in app component spec. 159 00:07:39,060 --> 00:07:40,380 What I've done here is I've got 160 00:07:40,380 --> 00:07:42,150 I've got these statements commented out. 161 00:07:42,150 --> 00:07:43,960 So I'm gonna un-comment them now 162 00:07:47,040 --> 00:07:49,620 and un-comment that one as well. 163 00:07:49,620 --> 00:07:53,280 So import the component decorator from angular, 164 00:07:53,280 --> 00:07:58,050 set up a stub version for toggle switch, 165 00:07:58,050 --> 00:08:00,633 and a stub component for banner. 166 00:08:01,980 --> 00:08:05,040 When my test sweep starts, 167 00:08:05,040 --> 00:08:10,040 set up a test module and declare my real app component, 168 00:08:10,620 --> 00:08:14,160 and then the stub versions of the other two. 169 00:08:14,160 --> 00:08:17,880 Okay. So, basically, un-comment those two lines. 170 00:08:17,880 --> 00:08:19,050 And then what I'll do is I'll get rid 171 00:08:19,050 --> 00:08:22,141 of the comment as well, because well, who needs comments? 172 00:08:22,141 --> 00:08:23,160 Okay. 173 00:08:23,160 --> 00:08:27,780 So now, my app component will render these stub components 174 00:08:27,780 --> 00:08:30,000 which have empty HTML. 175 00:08:30,000 --> 00:08:33,750 So, they aren't going to interfere with what gets rendered. 176 00:08:33,750 --> 00:08:37,623 Okay. And these tests now should be, should work fine. 177 00:08:39,120 --> 00:08:40,230 Okay. So when I run the tests 178 00:08:40,230 --> 00:08:42,270 now we don't get any error message. 179 00:08:42,270 --> 00:08:43,230 So that's what you can do. 180 00:08:43,230 --> 00:08:44,610 This is a common technique. 181 00:08:44,610 --> 00:08:46,890 When a component has children 182 00:08:46,890 --> 00:08:48,360 you can define stubbed versions 183 00:08:48,360 --> 00:08:50,280 of them with an empty template. 184 00:08:50,280 --> 00:08:52,440 That means that the only HTML you get 185 00:08:52,440 --> 00:08:54,410 is the HTML from your component. 186 00:08:54,410 --> 00:08:56,163 So you can unit test it properly.