Nx After Dark: Integration testing an Angular feature using Spectacular

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey all welcome to nx after dark it is not quite after dark here in denmark yet but the sun has set so it's dusk right now uh a quarter to nine pm today we're going to stop for a second on the implementation of the co2 forecast feature on the energy insights angular app using an nx workspace because we have covered it quite well with unit tests and now it's time to look for the integration tests as if you've been following since the beginning we actually removed cypress which is the default end-to-end testing framework so let's see what we can do with integration testing instead we're actually going to be using the angular testing library together with a testing library for angular integration testing that i have created called spectacular but those two work hand in hand at least for the feature testing api of spectacular so let's go have a look at that here is our energy insights app and the code as always is on github just find me on github and should be good to go we're working still in this co2 forecast feature let's have a look here at uh nx dependency graph let me find the browser this is what it currently looks like we're still missing these implicit dependencies between the assets and the styles workspace libraries but we are starting here to see the layers of our application the app project right here the forecast feature which then depends on the main interfaces the data access layer which has the component store and the http client inside of it which then uses a utility library for date times so what we're going to be testing or rather the feature testing api of spectacular looks at a what's known as a feature module from angular a routed feature module rather and takes that as the kind of the scope of what do you want to test here's the place where we cut and a feature module in angular would contain yeah the module is kind of the i can say that like the code splitting boundary for an angular application so the the feature module will really give access to everything below this project in the dependency graph so also the data access and the domain and the utilities all of that we can exercise in our spectacular feature test the integration test but it stops there we're stopping everything outside of these projects so either we were well we're actually putting it inside of an application but not this application a testing application um using the test bed or rather using the angular testing library together with spectacular to set up the angular testbed so it's being bootstrapped as if this feature module was everything there was available in that that application then we can interact with the application through the the dom we can click buttons we can inspect elements we can route navigation all of that um but we will stop at when we reach a request to the server for example hcp client which is down here hello jordan nice of you to join even though you you used to hate videos [Laughter] um so so yeah so this is where we have a decision to make should we continue or allow our http client inside of this data access library should we allow that to send an http request if yes then we could let's say the http request goes here just to demonstrate or visualize it so here's the server like a real uh in this case it's it's an external api but a public one that we're calling the energy data service in denmark so we're going to intercept that request here we could use for example the the library called mock service worker or msw and with that we could we could set up kind of a testing http server i guess it's installed as a service worker hence the name i think uh tim describer who's who's the creator of the angular testing library is also supporting helping support the mock service worker and has created the angle-like samples for that but anyways we could use this to actually allow our app to send real http requests but intercept them in the kind of the pipeline the http request pipeline but another option and and one that i mean that's what you would want to do if you were doing an end-to-end test either you'd use mock service worker or maybe like in cyprus there's a way to intercept http request as well in the when we're using the test bed which angular testing library spectacular and other angular testing libraries behind the scenes they're all calling the test bed so we have this angle testing module which means we can replace certain services with what we call as a stop or fake or spy or a mock service that is only for the purpose of testing so we could do the same here inside of this data access library we have our own http client that calls this energy data service api and we could replace either that service but then we wouldn't be testing the code of that service which is our code so maybe instead we could choose to use the http testing api from angular so those are the kind of decisions we have should we use the should we use the http testing utilities from angular they're kind of kind of a not very they're a bit complicated to use um so an easier option would be to replace the kind of response from the htp client our own http client for the co2 uh prognosis emission data set but then we wouldn't be touching that code and exercising that code in the integration test so it's it's a bit of a trade-off the third option would be to use mock service worker but since i don't know how to use that i'm not going to to do that today because i want to focus on what i do know today which is spectacular and the angular testing library so yeah we'll we'll have another look uh once we we have the tests to see where we're going to stop out a dependency or say this is the the boundary that defines what we want to test and what we want to replace with fake code this is the spectacular package is in the ng worker names or namespace or npm organization this is the open source group i'm a part of that also has the lumberjack logging library for angular and a few other projects in the making uh for example we also well we also have the angular versions action for a github action for trying out things with cert certain versions of angular similar to the setup node task or action from github it's themself we have the angular versions action which allows us to for us it allows us to test um lumberjack with many different versions of angular every major and minor version since 9.0 and all the related typescript versions we also have it set up for many node versions and so on and that's the same thing i i want to give that same level of confidence for spectacular but the angular testing action or angular version action is not does not support nx workspaces yet it only supports angular cli workspaces which is why spectacular is still in version 0 to 0 because i haven't verified that it works with uh other versions than angular 11 but today we're going to use angular 12 so at least we'll know but i'm pretty sure it'll work with many versions of angular but i i want the pipeline to be able to say it for sure like have verified support and for that we're going to sort of need support in the angular versions action for an nx workspace because spectacular lives in a monorepo using the nx tool chain so this is the the one of the testing libraries for angular we're going to use my testing library and the other one is the let's see here let's search for it the angular testing library this is part of the testing library family of libraries uh it's created by kent c dots and tim of the ngrx team is maintaining the angular flavor of that so this is the package name add testing dash libraries forward slash angular and here's the github repo there's also there's a discard server for all the testing libraries and there's a channel for the the angular flavor where you can come and say hi to tim and me and a few other people uh so yeah there's not a lot of documentation in here because very very little of this library is angular specific um a lot of it is depending on the core library here the dom testing library but what is angular specific here is these three that normally in other frameworks you would import them from well from the dom testing library or the react or whatever so i guess it's the same here from the angular testing library and what's special about the angular version is this render function you pass it a component and then you're you're going to have some angular specific options here such as the component properties the input properties and then uh yeah we're we'll we'll cut to this but basically then we can we can fire click events we can inspect uh elements on the screen uh so all of this is is that's exactly what this library is for but as you can see it's focusing on a single component so and and isolating the world outside of that component but what i wanted to be able to do was test a whole feature like a whole area of an application and say yeah i want to test this whole domain behind this angular router angular feature module with all the components all the services everything inside of that feature not just this one component so spectacular sits as a thin glue layer on top of angular testing library well it's not really wrapping the angular testing library but what you'll you'll see uh very soon uh it's helping to configure the testbed behind the scenes by by passing some options um from spectacular to the angular testing library so it's not really a hacky way it's just should never say just because to me it's simple because i i built the library right but um it's passing some special options it's registering some routes for the router testing module it's registering some some modules it's registering a component that will be the root component for this testing application and it will have a router outlet so that it's able to render all the routes inside of that feature so so not just one route not just one component but a whole chunk of the application basically everything that would be inside of a lazy loaded chunk that's what you're we're going to test and now that we're starting to see that that we have an application it's still like it's still very early for for this feature but it's enough that we can already start to see how this could be helpful let's quickly fire up the app here to see just and just remind ourselves what we have and what we don't have because the next step was actually to as it's not done yet um the next step was to now we have the raw data and we have displayed it in a very rudimentary html table but we actually want to show it in a graph [Music] so that's the next step implementation for that we made sure that we have covered everything that makes sense to cover with unit tests and now let's see what we can do with integration tests so this is the app right now this is the co2 forecast feature everything we see here inside of this main area so this is our html table with the the date and time stamp the grams of co2 equivalents greenhouse gases emitted per kilowatt hour produced in the danish electricity grid the price area there's dk-1 which is western denmark dk2 which is eastern denmark but for this data set right now the values are always the same because they're actually an average across the two price areas they will hopefully be split out at some point so that you have um the exact number per area here per price area yeah but this this is a lot because it's five minutes intervals as you can see there's a new value per price area per five minutes uh and we're able to see depending on the time of day we're able to see the current day which is may 26th and the following day which is may 27th here and all the way up to midnight uh tomorrow danish time so this is a lot of data right so we want to put that in a chart so that it's easier uh visualized and you can get a good overview and what can you use this for i intend it to be used by private persons to see in which hours or would it be good for me to run my my washing machine my dryer my dishwasher which hours of the night would be the the most climate friendly and those hours would usually also be the cheapest we pay per there's a price per hour in the day nation the european electricity grid so they go hand in hand usually they're climate friendly with that price friendly so yeah instead of having a smart grid you'll just have a smartphone with with an app i'm going to turn it into a pwa hopefully at some point so that you can pull it out your pocket and and maybe maybe go further than a chart and instead just like a message saying which hours would be the best for me to to run my my appliances during the night right and it would say the hours between two and four are the most climate friendly and the hours between four and five are the most economical and so on something like that that would be great so what can we test here we can test that the user is able to see uh yeah all these data points and for both price areas for every minute in the two the two days we have displayed and data available like the current day from midnight and the following day until yeah at the end of that day so five minutes before midnight every time here represents the start of an interval so so this value here applies to the the time between 12000 midnight and 1205 and then another interval starts and from from 005 to 10. so that that's the way it works okay so we will be we will be i can say like stuffing in some test data for say at some point during the day before three pm danish time you we only have one day's data available so so we could give it some test data for one day and then make sure that everything is displayed to the user or maybe just some of it and for both price areas or we can maybe have a scenario where we have data for both days so that would be in the afternoon or evening you would have data for the the following day and we'll see that that data flows all the way through the ui to the user other than that there's not really a lot of interactivity going on right now it's simply presentation well except for the fact that every minute it will ask for new data and it will do it initially as well because if you've been following along you might have remembered that we put in an effect using ngrx component store so there's an effect being triggered when when the service is constructed and then every minute following that where it will be requesting new data because as as you might have guessed these data uh it's it's updated uh well at least every five minutes but in some cases every few minutes even uh all the all the way throughout the day and then at 3 p.m around 3 p.m in the afternoon then we get the data set for the following day and that will also be a preliminary numbers that will be updated because these numbers are it's a forecast right so it's not it can't be precise so it'll be adjusted accordingly throughout the day for example based on the weather forecast based on the trades or maybe a power plant has run out of like uh run out of of production or maybe a power cable has been caught or something that would certainly affect uh these numbers because the co2 emission level is of course based on yeah what's the energy sources is it solar is it wind or are we going to need enough power that the solar and wind cannot cover it so we have to to turn up the the the traditional fossil fuel based power plants uh let's let's just for fun have another a look today on the current numbers here also even though they they were the real numbers what we just saw but here we have the chart for the next eight hours uh so right now we're at 9 p.m and it goes to 4 p.m here um so yeah from four to five right so that would be eight hours um everything below 80 is or 80 max grams per kilowatt uh would be considered green so this is going to be a green electricity night in denmark so time to turn up those washers and dryers anytime here between 11 and 5 a.m 11 p.m and 5 a.m would be good a good interval to run your appliances at home or charge your ev or whatever charge your laptop charge your phones all of that and right now um the the last hour was covered by 53 wind and solar and it's certainly not a lot of solar because the sun has set and even though it's not fully dark yet like the the in in the nordic in the nordics there's not a lot of sun right i mean sun goes down early and the sound is at a difficult angle so unless you have the solar panels that can adjust to the sun you're only going to get much solar power like in in the day daytime hours certainly not early morning or late at night not a lot though okay so this is our domain and this is our app right now this is the feature the co2 forecast feature and um we might have to adjust the app a bit because right now it's it's um it's not really well okay let me think about that for a second right now we have this feature forecast feature and it has a feature module right here or where is it here it is that is exporting the scam so the single component angular module of the co2 forecast container component because right now it is being used here in our application as an element so there is no routes involved um so we might have to turn this into something more realistic more best practice actually lazy loading the feature so that it will be a separate chunk so that's actually what we're going to do first so how are we going to do this um several options uh first for sure is we could create hmm yeah maybe it's time to do a shell or uh that might be 2a too early right but in a domain i would i would have a shell module a shell angular module a shell library and that will contain the routes and the entry point component for this feature but yeah that will come later that's another concept we'll have to dive into at some point when the application grows right now let's um let's see here we're going to need some routes we could do that in a separate routing module but let's just keep it simple right now so we're going to need some routes from angular router and hello mateo thank you for joining i know you have been asking about spectacular and um there is no there's not much documentation right now there's a very basic api reference there's a there's some uh in-line documentation which i think is also important but there's not really a full example i mean there's the there is an integration uh spec that for for a very complicated one even for the two of heroes routing tutorial inside which is inside of the spectacular github repo so that's showing how spectacular works just with the test bed without an additional testing library there's actually also a branch where i was figuring out how to use it with angular testing library so you might want to look into that branch but otherwise yeah there are some advanced use cases inside of there i've done a few videos about spectacular there's one on my angle of the dark show here on youtube there's one with with the the bls show i think and i was also i presented spectacular for the first time in a tech talk with santosh called angular testing but that was more of a like the background for it and there's it was like two and a half hours of how how to unit test angular so that was a nice episode and where i also presented spectacular for the first time and the previous video has been quite useful to get the idea uh okay so that maybe that's the one on angular after dark i hope so but here we'll see from the from the scratch how to to add it to to a workspace with with installing the libraries and everything um probably did that in the other video as well okay so from the router module we're going to need the routes type here and we're going to have some routes that is the type of routes it's an array we have some routes here first one will be empty component and then we are going to import the forecast component or rather the forecast container component here so and when we want to introduce a shell module there would be the first level component here would be the shell component and it would have children and router outlet itself with children for each route or each part of this feature right now we just have one component so let's just keep it simple for now so this is our only route needs a path it needs a component that's it there's nowhere else to go inside of this feature right now so we need now the router module for child and that's it okay so we're not going to need to export the scam anymore because people should not be using the component directly they should rather be using the route they should be routing to this this feature module using some path oh but we need to import this scam so that the component is declared because then it can be routed but we're not going to need to export it anymore since it's now intended to be a routed component and now the app is breaking because it is using this trying to use this container component inside of this template so i think these are the changes we're going to need and yes it was the oh after dark installation setup uh the angle after dark for spectacular or what mateo okay i think this is the change we're going to need inside of our feature module and and in the container component and now we're going to go back to the app component here and instead of our co2 forecast container component we're going to add a router outlet now rather uh and to do to use that of course it's complaining here uh it doesn't know where to get this uh element from or or which component to map it to that's because we need to add it in our scam we're going to need the router module to to get that router outlet corrective yeah i think it's actually a directive and now it should be hopefully it's happy up here well maybe not the angular language server has been playing tricks on me in version 12. maybe some dependencies are out of date um or out of sync or i don't know but yeah now it's working after restarting the language server yes good so one last thing here now that we have the router outlet and the the feature module has the router module for child routes we're going to need the root routes and there's also some some nice patterns on how to do this but yeah that's more of an advanced use case we don't need that right now but here in that this case we could also use a shell module there's three kinds of shell modules in show libraries but we're not going to import the routes router module uh hey what did i say here the router outlet that's wrong it should be the program rather module um router outlet is the director okay uh so we're not going to import the router module for root here because that will add some providers this is a scam a single component angular module so it's only intended for setting up configuring uh declarable dependencies so that's the components the directives and the angular pipes so there shouldn't be anything like a service module adding providers there should be no providers either so instead let's go into our app module here which is not a scam but it imports the app scam and this is where we can do like root level um root level configuration there's another older pattern called we could have a root module for also for the core or the root level dependencies but we don't really need that right now our app is not that big and we're also going to be using the shell modules instead besides we already split it the app module into the app module importing the browser module and then the scam here and the app module is then bootstrapping the app component but everything about what's going on in the template of the app app component is managed by the app scam which is also a module but a single component module okay so here we can now import the router module for root and then we're going to need a route type again going to initialize the routes here and now we need a path the path will be let's say co2 and now we need to pass it a module so we'll say low children and we will say let's see import and we can use the path map name here feature forecast then we have an es module here and it exports this feature module that's what we need to return from the promise the module to import okay did i do something wrong or maybe it's um i need to put it in a function yeah that was probably it okay so this sets a code splitting boundary for angular so that this chunk yeah this this is the dynamic import statement or it looks like it webpack is actually turning it into a promise behind the scenes uh so not really at runtime at least and it has some limitations uh for example angular puts its own limitation like this has to be a syntax like so i can't for example unwrap the module by using b structuring and then returning it like so angular compiler will complain and yell at me because it knows best and i have to do it the angle away so yeah it's not really dynamic import just looks like it at least it's not the native dynamic import it's it's being chunked up and served through a promise loaded by webpack all that goodness but it's fake it's webpack angular compiler fake not the web platform so this is now our lazy loaded chunk this is our feature so every time the user goes to any route it begins with co2 it will load this module which will load the modules the feature modules routes which will allow us to see that co2 forecast container component now we need to pass it to the for root here and this will register these top level routes as well as providing uh for example an instance of the router service and it's maybe some related dependencies actually a lot of related dependencies um yeah that's why we use the for root here because it comes with providers you can see it returns a module with providers and there's a bunch of them and in the other module um we were using the for child this is also a module with providers but the only provider that it adds is these routes this array of routes all the services are only being provided here when we're using the for root static method which is kind of a conventional name and pattern in angular yeah so that should be it let's see uh well now the path is co2 so so either we need to make it empty a default route or we can do a redirect here [Music] let's start up here say path empty and then we need to say path match full because by default the path match is actually prefix so a prefix of empty then it will match every route because everything starts with the empty string so that's why we need to say full because it's only if it's exactly the empty string that's the route not if it's empty string co2 so yeah it allows it to skip by if someone actually asked for the co2 route or any other route and final option here is the redirect 2 and then we say co co2 so when we're opening up the app and just saying localhost 4200 or whatever in production the url is it will navigate us over to the co2 route instead which will then load this feature module in all of its routes good now we have all the angular basics in place let's let's make sure here that it works and hopefully it does no something's wrong router module does not have mod property that doesn't sound good if the angular compiler i could kick and it might work again in the meantime you're trying to render your component importing the spectacular feature testing module with feature inside the render options but a strong illegal state could not load the summary for the directive don't know what that is um let me like let me send you a link here in the chat for this um example test spectacular and angle testing library spec in the an example repo and you might look into that for yeah like a basic example i guess this was from the bls show and make sure it's looking similar but yeah it is using um you need to import spectacular feature testing module with feature and then pass it a feature module which should be a routed feature module including routes and then the feature path which should be the same path as in the application in our case it's co2 here um now it doesn't export all the components the important thing is it needs to have routes that's the important thing and then you need to render the spectacular app component we'll get to that as soon as we figure all of this out all right nothing to complain about in the compiler it's the app now working yeah it is okay so it was just the the old angular compiler with the hiccup again getting old angular angular 12 okay so it's working now uh but strange it should have redirected to slash co2 it shouldn't really work uh so what's going on here that is strange i have no idea uh well if i do say co2 then it also shows co2 so why is it not redirecting so it doesn't say co2 up here you probably can't see it but it just says localhost 4200. what did i do wrong here maybe i should say forward slash redirect to or did i not do something i didn't save here maybe that was my bad uh come on okay something broken in angular or did am i not like did something change just redirect okay if you figure out what i did wrong please let me know there's one more thing here and that is this co2 you can see we already have a duplicated two places here and that's what ends up happening in in angular apps you're going to have magic strings for routes all over the place for route path fragments or segments as it's called so let's actually put this in the library as an export so this would be the co2 right well right now this is just one feature of the co2 if we had the shell module the shield library that's where i would put this right now we just had one feature though so co2 uh rock path ts c no not today um export constant it's going to be called co2 route path it's going to have this string and then we need to export it in our public api here which is the index ts this is everything that's available outside of this library that we can import when we refer to the well if we import from here so yeah that's actually what we need right now [Music] um and i'm bad at hitting keys right now here it is now we should see we have the co2 route path so we can put that in here you can put that in here and now there's just a single place to change it is if it has to change and um this is the first part of not having magic strings magic ground string sprinkle all over your app especially also in the templates you you should really do something about that uh for now just for the the route configuration and maybe it helps if i put it down here i don't know i don't know like what is going on maybe booting up the angle compiler again um restarting the the app and just going to the main route and it's not it hasn't finished compilation yet i guess now angular is really slow in version 12 because this machine is pretty fast okay so now it's working but it's not it should be redirecting me to co2 but it doesn't for some reason but co2 route also works now i'm saying slash co2 and i end up the same place just as strange that the the root route when i just say localhost 4200 it isn't redirecting that's kind of throwing me off here anyways now the app is ready we have refactor turn co2 forecast feature into a routed feature module feature module into a router feature module so which means that it's lazy loaded in in this case and i'm just going to jump down the development server i'm going to run my my format tool i have a have a vs code extension that sometimes mangles these import statements which prettier isn't always too happy about good so that's a commit right there now we're set up for success you have seen complaints about speed and discord yeah i think it's angular 12 or it might be nx12 but it's as soon as i'm compiling angular and i'm pretty sure it's using the angular builders so it would be strange if it was nx let's find here or i'm use the nx console and go to the app project look for the build i can click here to get to it inside my workspace configuration and the executor is the angular dev kit build angular browser builder or executor or executor or whatever it's called in nx terminology so seems like it is the angular 12 package that's really slow at compiling for some reason at least on my machine so yeah that's unfortunate let me just have a sip of water then we'll get into the testing starting from scratch [Music] all right now we're not going to start up the app well no let's do it without it because actually when we're testing using spectacular and angular testing module we'll be able to test a feature module without even without an application so basically you're creating a a micro front end of sorts that can be put into any application any angular application host application you don't even need the app project it's kind of exciting as long as you know your way around angular testing and typescript and angular projects and all that okay jordan you're also saying nx is low react throws your machine when first running okay well that's that's unfortunate i think i saw someone today also saying 12 is really slow so i don't know what's going on there because nx 12 has been out for some time came up before angular 12 so that's kind of interesting one thing i do know is that they don't they happen to not test nx on or the performance on windows machines and i'm using windows windows here oh seems like we actually wallaby is telling me here there's one test broken and that's because we added a test to this feature module and now we can see that test is actually working as expected because it's saying um see the error message is that it cannot render this energy co2 forecast component inside of our testing host component because our module is no longer exporting that component so now we need to route instead so we need to change here our feature module test uh let's do it more of an additional way rather than i mean here we could also use spectacular and we'll kind of demonstrate the same thing and then some but let's go with a traditional um setup here sorry it's taking a little while to get to the spectacular part um but the app was not really a best practice app right now uh so now we have imported the browser module so we should have access to the router outlet uh the angular angle language service is still playing tricks on me so it probably needs another restart and we are still in our test here we're still importing this feature module um oh we actually need router testing router testing testing module audio import it please so it's not aware of that um package yet it seems here it is uh so this one is stubbing up some browser dependencies which allows it to run in karma especially but there's also something in there for react because react is not a it's running on node.js so it doesn't have a browser so it's also stuffing out some browser dependencies there okay what's the routes yeah well actually the routes are inside of of co2 right or this feature module but yeah actually this is like in the traditional way um we would do something like this so we would again say here's where we can use the co2 route path for the path and we could do load wait i need an array here children and here we don't have to do the dynamic import we can do the like so and this will work just like um just like lazy loading a module but but yeah this is this works the same inside of a test now we're reusing this route path in our test so that it works exactly the same as in the app well yeah you know what this is going to be yeah i don't even there's more to this test and this is exactly what spectacular is hiding away so i really don't want to write all of this this was the only test case of this spec so i'm actually going to delete that and we're instead going to replace it with an integration test suite instead because that's where spectacular shines it's there's a lot of configuration and setup needed to actually test around the feature modules that's where spectacular comes in and helps us so yeah let's let's focus on that instead maybe they change the config in b12 and disable the incremental compilation well 12 nx 12 was supposed to come with better performance but again that might not be the case on windows they have not been known to test performance test on windows they use mac and linux themselves the developers so and ci and so on but yeah other than that incremental builds incremental serves i have had very little success with that on windows it has not been faster on large workspaces quite the opposite in fact so that that has not been a success for me again because they didn't performance tested on windows might work well on linux on mac i can't really say but on windows it sucks good so we're adding this to previous or no well we can put we can do it in this commit so that it's kind of this commit replaces one test suite with another test suite no removing this removing remove out data test suite feature module test suite because we kind of need a blank git state now because now we need to install the libraries we're going to need for for this test and you also saw that in linux that there's good speed for nx yeah might be another sorry windows users from nx starting to see a pattern here okay uh what are we going to need well we're definitely going to need spectacular so i'm using pnpm here so that would be add save there and the worker ng worker spectacular and it's not it's not spectator that's another angular testing library also a good one but this one is specifically an angular integration testing library so it has a certain fee a certain set of of certain um certain set of very focused testing apis for specific things that are hard to test in angular oh so we also got a new version of nx cloud apparently that's interesting okay so that was spectacular we're also going to need the angular testing library which is add testing library forward slash angular now i'm thinking i wonder if there's an ng ad for that but first of all i mean we could try it but when using nx you can't run just ng ad or nx ad you have to have to first install the library and then if there is an ng ad schematic or generator as it called in in nx we have to run that manually afterwards so that would be nx generate generate testing library forward slash angular and then the name of the generator or schematic which would be ng dash add that's how ng ad works behind the scenes so we can do the same thing here okay there's no generators it seems or it doesn't support nx let's have a let's have a quick look here just to make sure uh ad testing library angular doesn't have a collections json nothing here about schematics or a collection no there is no ngap schematic for angular testing library so now we have these two libraries we need anything else yes there's a there's a nice little um utility or add-on plugin for testing library which is called testing library forward slash user event we're also going to add that and that's what we're going to need so yeah let me show you here so these three ng workers spectacular testing library angular testing library user event that's what we're going to need all testing libraries good and now we're ready to start setting up the first integration test suite and we're starting here with the forecast feature so we're going to like here we see that the spec files are next to the class or whatever they are testing so same thing that's kind of the angular convention and we're doing the same thing here so we're going to say co2 forecast and then we could say spec.ts but i'll actually call it and this is you can you can call it whatever i'll call it dot integration dot spec and i might to able be able to filter out or in the integration test suites when i'm doing a test run because they will be slower than the unit the isolated unit test because they will be testing a lot more code so it'll be slower to run slower to start up however not as slow as end-to-end tests and that's kind of one of the benefits here of angular testing library and spectacular they're using the testbed and the testbed is quite fast at least compared to end-to-end testing frameworks or most of them so that's that's the idea behind spectacular the the concept from end-to-end testing frameworks the concept of testing as a user that's also the kind of concept of angular testing library so test as a user but then also having the balance of the speed and the flexibility of the test bed which is optimized for angular so it's trying to get the both of both worlds um without too many trade-offs so yeah let's see so co2 forecast integration spec it didn't like it didn't you don't have to put in this that integration the important thing is still dot spec dot ts because that's what our tooling is set up to to pick up on but i'll call it.integration.spec.ts because then i can run only the integration tests with some work i mean i have to set up the tool chain for this but yeah let me have some water and we'll start writing this good goodness what are we going to test we're going to test the co2 forecast integration or forecast i mean you could say feature but just co2 forecast that is the feature and um i'm still well running here uh can see for the camera there it is wallaby js which is a paid tool a vs code extension but there's also an extension for other editors like webstorm and atom so it's a paid product i'm not paid to advertise but i just love it i've been using it for years and you can see here i'm getting inline feedback in my tests uh that the test is actually failing because it doesn't have any tests or test cases so here i would need to add a test case so an an it function call with a callback and now they are green here i can see in the cutter this is wallaby telling me that now the tests are running and passing and the same down here the whole workspace has 19 tests they're all passing okay now we're going to start with this setup okay let's see here mateo is saying um that i have told you mateo that the feature module is cast by the compiler but then it won't be as fast as spectator yeah the like angular has been optimizing the speed of the test bed ever since or starting with angular 9 iv iv allowed for some optimizations the testbed had been really really slow especially because it was for every test case it would have to read all the files with the components the templates the style sheets and then recompile the whole thing but then they started to add a caching layer so that the compiled output would be cached and they have been optimizing on that ever since yeah angular 9 was released in february 2020 so today it's it's actually pretty fast and we'll actually see that in wallaby will be showing us the test execution speed as we go but keep in mind that this is an integration test so it's going to be slower but it's certainly not going to be slow like it's going to be fast enough that it's it's enjoyable to work with um or maybe so i don't know about spectator here or if you're actually asking about spectacular spectator is the other angular testing library which is also great but focusing on other things um so i'm not sure what the question is here okay you're saying follow follow up sorry oh hey circa hello uh faster than end to end but still testing a lot more code and unit test yes it it is spectacular is is trying to sit between somewhere between the void between isolated unit tests and end-to-end tests where you load the whole app in the compile compile bundle and so on and in a real browser so spectacular sits here between the two it's integration tests so it's loading multiple classes first of all not just one component it's also trying to not fake too many classes instead it'll say something like every time we're interacting with the server of course we'll fake that somehow and then the question is where how close to to uh like the the the implementation do we want to replace the angular's http client our own http client or do we want to send in an actual request but intercept it for example using mock service worker because you would be able to do something similar in an end-to-end testing framework so yeah spectacular since it's using the testbed will be faster than end-to-end tests not because of spectacular but because of the angular testbed and you will be comparing the execution times nice i love to see those numbers and you're welcome mateo yeah so yeah right now spectacular i'm sorry to say doesn't have a very good documentation it only has this it's not very good on the npm page it only has this api reference where every part of the public apis are mentioned by name and like what is it what type is it and a little description all of this will be available in the inline js docs as well so when you import something you can read the same descriptions but it doesn't really have like a full example in the documentation simply because i haven't figured out how to add a docs website yet uh certainly something on my roadmap the like the most important things actually right now on the roadmap is um verifying compatibility with multiple versions of angular that would actually when i have done that i would be happy to put it at 1.0 it's very stable today i'm just not sure which versions of angular it supports i don't want to to make that promise yet although i think it will support many versions of angular and the other thing is documentation because um the previously most important thing was figuring out how to how it can work with angular testing library because that's the best library for test as a user but without end-to-end tests so yeah i figured out how to do it and i didn't have to change the library because i had already implemented in in a way where i thought i would be able to integrate it with the angular testing library and that was a huge success so the next step of course is then documenting how to do it i've been doing some example repos and videos like this one next thing is setting up a doc's website for for this and adding some some full examples because your only help right now is going in and finding the example test suites like here we can see the three apis of of spectacular um the feature testing one is the one we're using today so it has this integration spec for the crisis center from the two of heroes routing tutorial so we're using that as a feature module or feature excuse me feature library and testing it without an application but using a spectacular and here in this test i have created my own uh testing unit utilities which are wrapping the test bed um but i really don't want to like i didn't want to make something like this part of the library because that's exactly what angular testing library is doing very well already so i would rather integrate with that library than having to reinvent the wheel in in spectacular so spectacular is more focusing on the configuration of the router testing module and the angular testing module and then adding some convenience service replacements on top of that or service extensions for specifically for the router and the location service from angular but anyways here you can see how to use it just with the test bed created some helper apis here wrapping the test bed but really should be looking into here i have the branch called spectacular something with a testing library angular testing library and then you can go here find the folder angular testing library and see where i wrote i think most of that same test suite but using the testing library so here you'll have a really good example let me put it in the also put that in the chat because that's a like a much bigger example than the other one i sent you here this is a really complicated test suite actually it's the the angular routing tutorial so it will have almost yeah a lot of different features from the angular router um well i see that i didn't implement the whole test suite but enough to to like have confidence that yeah that how it works so this is what i i need to describe and this is what we're going to be doing right now but here's a more full example where i put it in the chat now but it's in the repo and you worker monorepo and then this feature brand spectacular angular testing library but this was to figure out whether i needed to change spectacular that wasn't the case that was very nice back to the tests yeah it's working good now now we need to uh maybe i should take that file myself right um or that url here yes so we're going to need some setup so we're going to have our before each and then we're going to be learning some angular testing library apis and but here most importantly how to use spectacular for the setting up the angular testing module the testbed so we're going to have a shared variable i'm going to call it result um because of the type that it's going to hold here is uh something from the uh the testing library forceless angular called render responder result render result and then whatever component it's testing and in our case it will be the spectacular now we need to import from spectacular add ng worker spectacular and then the spectacular you can see here there's a bunch of um public uh things inside of spectacular but the one we need right now is the spectacular app component that is a root component for testing purposes so that will be similar to a component fixture from testbed yeah that will be the root component of the tests so to get that result we're going to need here from the angular testing library the render function this is the most important one we're going to say result equals render and then you need to pass it a component and then some options so the options will be here and here we need the component and this is where we're actually taking this spectacular app component and making that that's subject under test or the component under test as far as as far as angular testing library is concerned but really it's a very similar to an app component well it actually only holds a router outlet in its template that's almost everything it does so it's just a convenience component so that you don't have to create one yourself for this but in this case usually when you use angle testing library it's the component here that's the important one but here that's the unimportant one that's just a testing host component or testing root component actually and the important thing is down here in the options so now um we're going to because um this will be set up with a scam declaring it and when when you're using a scam a single component angular module with uh angular testing module you need to pass this option exclude component declaration because by default when you pass in a component to render it will be added to a declarations array of the angular testing module by angular testing library because that just for convenience but when you're using scams you already have a component declaring that component or sorry you already have a module declaring that component so you don't need also angular testing library to declare it for you so instead you would be importing it here so say we had a spectacular app scam and we actually do as you can see here but that is um it's it's also imported by the one we're really going to need here um which is the spectacular i can't even spell it right now spectacular feature testing ah go away toolset spectacular spectacular feature testing module dot with feature and then some options so this will behind the scenes also import the scam for this spectacular app component that's why we need this exclude component declaration option as you do with every other scam when you're testing so with feature and here we need to add two options for spectacular uh one is the feature module so that's the routed feature module which is the scope of this test and in our case it was the co2 uh forecast feature now what was it called let's find the name here should be right next to it here this one let's see if auto import works it doesn't so that's why i couldn't find it so import from relative path here it is okay so that's the scope for our test this feature module and that's all we need to tell spectacular and angular testing module to import everything that's behind the boundary of this routed feature module so all the routes all the components all the services used they will all be included um so yeah that's really nice that's what i was going for that you're basically saying much more much more than this is the module i want to test and you take care of all the routes and all that we need one more thing and this is we need the same feature path as roo or the same feature route path as is used in the application so this is where we are going to need this constant that we created again the co2 rock part here it is going to use the same thing here the reason for that is um that this these route paths are usually sprinkled all over component templates especially so it will say co2 slash this you to slash that inside of router link directives and so on so we really need to make sure it's the same here in the test as in the real app or otherwise those links will not work when you click them okay [Music] oh okay so yeah render is async so i need to await it and then i need to make the function i think there we go so this is everything you need to pass to spectacular's feature testing api to at least when working with the angular testing library to so these two things are the important bits here and then also this option basically everything you see here that is the important uh setup for spectacular when working with the angular testing library mateos starting to remember the library for documentation dr servers yes that's also the one i'm going to be looking at um and there's an nx plugin for that and and spectacular isn't in the next workspace so yeah um i was i've also been working on other things for these past months so yeah that's on my very near the top on my to-do list right now is adding documentation for spectacular and hopefully someone can add documentation for lumberjack as well yeah okay so this is the important things about setting up um a test suite an integration test suite using both spectacular and the this is the angular testing library right here there's another option for spectacular it can also work with angular component harnesses maybe we'll get into that some other time or the third option like i did in the test suite for the test suites for spectacular itself you can also use just testbed but it's a bit more verbose which is why we have all these angular testing libraries in the first place mock providers features stores effects added to the render yes here we can add providers we can add modules with providers everything you need so for example here say provide say say a hero service you could say use class and then click hero service or maybe it was a stop service or something like that or maybe you're using nd2 marks or auto providers orders by what they're all called but since this is an integration testing library we want to write integration tests so we really want to replace as little as possible when doing integration tests so there should really be very little need to add mock providers and features but you have the option to do so it's just not maybe not the best approach well depending of course on your setup but well yeah okay so maybe your feature module has some features state or feature stores from ngrx yeah then you would need a router or sorry a root store but for that i actually use the real root store sometimes in tests because why would you need a fake one it will be put in the context in the real app of a real root store so you don't really need a fake one that's for another time we should mock http request yes that is definitely one place we do need to step out the requests as soon as there's an hp request and we've been talking about these different options of doing that we can replace the angular http client we can use mock service worker or we can replace our own http client here but then we wouldn't be testing that http client and it has somewhere here it actually has a lot of logic so it would be good to also test that as part of the integration test suite so but yeah different options you do have the option to replace everything here in imports and providers but you should be thinking let's not stop this out we want to test as much of the real code as possible and does this work with wallaby or is it a false positive it's working there's just not anything in the test right now so yeah it is working with wallaby wallaby works has zero configuration for nx karma jasmine mocha what we have just uh create ragna view cli angular cli all of these just work by saying wallaby start or if it shouldn't be looking at the root directory of of your repo you have to say select configuration and then choose a sub directory maybe there was a directory inside of here called nx workspace or something but in most cases do well restart and you're good to go it can take a little while to to spin everything up because but that's because it's keeping the tests hot in the background which is why we get this really fast feedback it's not restarting the whole test suite every time so there's some magic going on you do real use the real store too but mark the service response is yeah yes yes so http responses those are what we should be stubbing or mugging somehow but yeah then the question is which which method to use so yeah that's good that's the the right thinking um also if there was a web socket of course we should replace that maybe if there was some local storage we should also stop that out with test data uh any kind of i o like that um yeah good so now we have the setup here for how to configure spectacular and angular testing module for an integration test suite so testing this whole feature module the routed feature module remember it has right now it's just one route but like the same goes for no matter how many routes are inside of this product feature module we will have access to all the routes and then because of that all the components that are kind of behind the boundary of this feature module yes so yeah that is it for now except uh yeah we're going to need we are going to need some mock marker stopped providers of some sort but let's see that when it happens well okay so first yeah let me already add the http client testing module because i don't want my computer to send requests to the api because it will be doing it a lot when every time i restart this test so just for the sake of not hitting the real api and bombarding them with requests so now it will never receive a request or a response for an hp request when it uses the hp client from angular until i tell it what it's going to receive so yeah that's good enough for now okay one more thing that i usually use when when using angular testing with the testbed this result object from from from angular testing library it has the component fixture in a property here called fixture and then i said auto detect changes call that then i will have to do less of fixture that detect changes but other than that the angle testing library is already doing this a lot for us every time we click a button it will also be trying to detect changes and when we use other interactions it will also be running the tech changes so it will work most of the time we're also going to pass it through because then that will be the the on init the initial change detection cycle so i use this with the test bed if it was the testbed here i would have a component fixture and i'll call detect you know auto would have the same auto detect changes true so when using angular testing library it's hidden behind this property the result object then fixture one more thing to point out here the the more of the convention for angle testing library and the other testing libraries i think is doing a destruction like so rather than putting in a variable called result we can say oh i need the picture i need the screen maybe no that's not in here we have a of goodness yeah all these queries helper functions debug elements um yeah but i am let's see yeah i'm putting it in here because then i'm sharing this setup um i'm storing it because i'm sharing this setup between all my test cases so this is just my way of of of doing doing it you can still do it this way if you want to the most important one here is the navigate function especially for integration testing so i'm doing it this way i'm storing this result object from angular testing library and this will be available between all the test cases rather than having to pass all of this in every test and then destructuring good so our now we're ready for our first test okay jordan how is it how is it working with zoneless the angular test bed is in a zone so you can't really do some list there for soundless i mean i'm not 100 sure but i have been reading the code where it seems like it's always inside of the zone i'm not sure there is a way to disable the zone for a test bed maybe there is an injection token i don't think so so what you would need to do is use an end-to-end test basically or maybe i don't know cyprus has this component test api and there's there's stable ones for react and view the angular 1 is the angular component test for cyber is still in beta i think and has been so for quite a while years i think so might not be fully working yet maybe that's maybe that works i don't know i don't know otherwise you're going to have to use end-to-end testing frameworks for zoneless or maybe not i'm not 100 sure because maybe when you're detaching from the zone at least when using something like rx angular templates some of those then you're probably also detaching from the test bed so um in that case you're like are you going to have a hard time no because something like rx angular template would be calling detect changes whenever there is an update in the dom so it's more of a question can you disable the ng zone in testbed i haven't figured out why i am pretty sure pretty convinced that it's always running with the ng zone the testbed but let me know if you find out otherwise okay the first test case we have all this good setup done and this will be basically the boilerplate for integration tests then the the things that are going to be different is well of course which module and which which path for the route which lazy learning path but especially like the providers if there is anything providers being stepped out that will be things that can vary between equation tests yeah well let me know it know if you you try something with soundless uh that'd be very interesting to know okay okay first thing um place a title or a heading that's a simple thing right how could we do that he would start by saying result.navigate and then we would actually say well we could use this again the co2 route path and now we have navigated in our test app to that route and that route has been activated this route here which activates this the co2 forecast container component so this so what what should we expect as a user what should we expect to see now let's have a look in the in the component here well this is a container component so it's it's template will only have the presentational component and some data bindings and sorry i'm using async i should be using rx angular template instead that's a lot nicer but async will also do the job in some cases it's just not very ergonomic and doesn't take everything into account so let's go on to the presentation component instead oh i can't go to definition maybe that doesn't work for inline templates yet that's too bad so i have to find the com where is it forecast oh here it is co2 forecast dot sfc that's for single file component i'm i am doing something unconventional here i have the component in one file i have the styles here too i have the templates here too the component model even the freaking scam ng module here is also in the same file and look at that it's still a reasonable amount of lines of code so what do we expect we expect to see a heading an h1 here with the title co2 forecast now you're missing ish navigation industrialization uh yeah that like um okay so yeah i'm trying to remember there isn't a feature navigation initializer in spectacular but i think i left it out when you're using spectacular in this way for the for the angular testing library purposes because you really want to use the navigate function from angular testing library because it has some patching behind the scenes and replacing some things but you could you could still use let's see here feature router there's a service called spectacular feature router you could still use that from here test that inject or we could do result fixture or debug element what's deeper what is that i don't know so the debug element we could do the injector get so that would be the angular testing library way of doing it but we can also also call the testbed directly here that would give us the same so here feature router and using either one of these these two techniques here let's go with the angular testing library one read property injector really of null so the debug element is null that's not nice okay let's use to test that inject instead okay so we rather than resolve navigate from from the angular testing library we could also use the feature router what the feature router does from spectacular is it has navigate and navigate by url but it allows this special symbol here the tilde character which means feature relative so when i say tilde or tilde slash or both of them it will navigate to the default route of this feature module so that i don't have to say co2 raw path or if if there's a nested route i don't have to say like i can say like this instead of like this so i don't have to keep mentioning this co2 and the co2 rock path everywhere so that's just a convenience service by a spectacular that will also work we could even take the angular router angular router that injects the router give me the router i could also use that that would also still work uh what happened though oh still good navigate by ravi no angular router navigate my url q2 details if there was a details route right we could also use any any of these will work but when you call the one from angular testing library uh yeah we're just making sure that like it's aware of that navigation so if there's something special it needs to set up or replace it will be able to do that because it it wouldn't if we would use these other apis but um yeah based on my experience they still work you can use them instead of this one but let's stick to the convention here which is the navigate function but yeah they will all work um yeah so router like routing initialization that that will work if you're using it will navigate to the default route if the default feature route if you're using spectacular with the testbed so not with angular testing library uh why i don't want to have a dependency on angular testing library in spectacular so because of that i'm unable to call this navigate function myself inside of spectacular so you're going to have to do this yourself so so maybe we could do it as part of the testing setup um if we wanted to could do it like so and this is async probably yeah so we would have to wait that now we're starting on the default route in every test case but when we start to have more routes we'll have to navigate away anyways so it won't help us too much but when you're using spectacular with the testbed it will do this for you basically do you need to wait for when stable no i don't think so this is what one of the things that angular testing library is taking care of when you're using a testing library and when you're using spectacular with the test bed uh in that case you're using the create feature harness from spectacular it looks like so and then the same options here basically the same options yeah when you're using it this way it is doing that initial navigation it is also waiting for like when the app is stable so after navigation has occurred and all that that is part of spectacular when you're using the spectacular feature harness but now you don't have the ways of interacting with the dom that we're going to be using now from the testing library so you'd have to do all of that manually using the testbed api which is kind of a inconvenient so yeah the harness has the harness can also accept some providers also except some imports so similar to angular testing library and most other libraries harness object has inject which is exactly the same as calling testbed.inject so it's just for convenience purposes and it has the location the feature location service which has path so it will return a feature relative path for example it would say details like so and it has the one we just saw here which is the feature router which has the navigate and navigate by url here we could say details to navigate to the this would be the same as in our facing co2 details is there anything else in here yeah there's also the root component instance and the root component fixture just in case you want to and you're going to need that for the for the angular component harnesses but that's for another time now we're using the angular testing library because that allows us to the next thing we need to do here is inspecting the dom so get rid of all of this mess let me enable this hero which sorts all these imports and gets rid of unused ones but it's not always agreeing with prettier that's where i go wrong um if your component is calling store on in it um [Music] yeah good luck with that testing the store is not nice uh yeah but i tend to actually use the real store and not the mock stores for my testing um but yeah you need a lot of experience to figure out when to do what but i'm basically an ngrx noob so maybe i'm just too inexperienced but i don't use fakes unless i need to and i don't inject the store directly in a component so i don't have to replace the store for unit testing a component okay also i switched to njx component store so that's a lot easier um so we want to just test or verify that it displays a heading so now we need let's see the screen and we can get that here from uh the testing library for angular screen based on what i've read it's better to use this screen here which has all of these queries and so on it's better to use the screen global rather than even though they're also available here result and then all these query thingies i read a best practices blog post by kenzie dodds and he's the creator and maintainer of testing library so i'm counting on him to know best so use screen instead what do we need now okay so angle or the testing library has a lot of query functionality here which one to use let's go look at what's called the cheat sheet so we're going we'll be going there's nothing specific to angular testing library uh about the queries and stuff except that we should import it from testing library angular the screen object rather than from testing library dom which we don't have installed but it uses the same api so we can go to dom testing library which is the core library we can go to the cheat sheet here which i always do and here we can see in this matrix which of the occurring apis we need so we want to look for one element this one and uh oh no um okay so it's more like if there's no match so if it doesn't find the the element what should happen should it flow should it return a null value uh well all by is looking for multiple elements i'm only looking for one so it should be one of those three here but do i want it to throw or return a null value i want it to fro if it doesn't find a title okay so it's one of these two get buy or find buy and what's different okay so one is async and the or this one is async find buy and the other one is synchronous so let's see is my test case async not right now so right now let's go for the synchronous one this one get by and get by is just a prefix of the name there's a lot of get bias here there's get by label text gets by placeholder text get by text get my display name a lot of different things and in common is it's kind of this testing as a user approach so it's it has accessibility in mind if you're familiar with html and website accessibility so it would be get by and then it would it would probably be the role and here the uh the text right the text so what would be the text c o to forecast and then some options where we can specify role no no i guess the role is sorry i have this backwards the role is it's either header or heading trying to remember this is the area role or the html accessibility role header or heading okay so here it's saying let's open up wallaby saying testing library unable to find an accessible element with the role header okay so it is probably heading there's also a place to look up these role names but i can't remember right now but search for it and you'll find um i'm not sure it's in the dom library documentation but yeah it's something about html right so you should be able to find it also testing library will be helping you so if you do if you spell it wrong it will say ah that doesn't work there's also like i don't remember how right now but there are some helpers to oh that's probably the debug function that can help you figure out which roles are available right now in the view but anyways seems that it can find a heading so i have to specify now the name the name really means what's the text of this h1 element so here co2 forecast uh okay but it says it's not able to find that okay did i spell it wrong or oh that's right that is the right one okay what if i don't have the name and it's happy okay uh okay let's make sure that it can actually find it so first i will do the not so accessible way so not the best practice way when working with testing library find my text and then just co2 forecast is there any a name with the text co2 forecast if so let me just check by adding rubbish oh get by text so that it grows okay now not an element with this text what about the real text still no okay so did i forget something is the question hmm okay this is certainly a question for the that discard server for testing library there's a channel for angular where you can the angular testing library or you can ask tim or someone else but i'm sure tim will answer when he can there's not a lot of activity so sure he'll be able to tell you for sure whether you can specify a custom data test id attribute because the default one is the default one is data test id so uh let's say this this h1 we had the uh heading for example or my header or something right and that's the default one and you're looking to customize it with a label or something and yeah i don't know if if angular testing library is able to do this um maybe let's make sure i have spelled it right here oh it's with a lowercase f so i'm just stupid yeah okay so at least there is an element now i'm using the more generic um occurring api but i should be thinking accessible the user is not interested in seeing any elements in with the text of co2 forecast it's they're interested in seeing a heading because then it's accessible to screen readers and people and people driving their car and using a screen reader or whatever so yeah now it was just me with a spelling mistake right so let's add some gibberish here and it will fail again good so it's failing now it's processing with what we actually expected that's our first test after two hours we have one integration test there you go are you convinced yeah it is actually getting late uh but let's add one more let's at least add one more does it support area level uh well it supports okay area level is that for headers let me look for that yeah well let's uh let's try let's try it out i mean that's the purpose of testing library is taking excess billions into account so i would expect it works that way but let's find out for sure let's even delete it here yes it's still working stop breaking as expected and then working as quick so yes it uh it does work hello julian nice of you to come out of the lurking in the shadows okay yeah so uh okay let's let's get the real heading back but yes it does take accessibility into mine so it does support area attributes as well uh that's nice okay so i know this is not very convincing right just creating some some element here uh so let's try to get into something more one one more test case and that will be more advanced right but the whole like the whole purpose of this is is seeing how to set everything up and then hopefully you can you can use your imagination to see like how can this be useful um or you can watch the other videos where i'm like like with tech talks with santosh or the bls show where i'm explaining more about spectacular uh but yeah i think we'll only have time for one more because it's getting late here it's probably late with you too some of you at least uh yeah let's okay i'm going to commit this because now we have our first working test the integration test here and did i change something probably just some formatting yeah that's my extension here messing up or fighting prettier let's run the format again and it will probably go away there we go okay so test oh what did it install well probably some formatting again right go away okay add youtube forecast integration tests like so first commit down okay nice so there is a way to to configure customize the testing id attribute okay thinking back on the like what do we have here uh okay first first thing i want to see i want to see a date time value representing the first five minutes of the current day that's actually a pretty complicated use case and the most complicated part is we're going to test all the code basically in this this repo at least everything everything here in data access everything domain everything utilities everything in feature forecast all of this code is being tested in this one next test case of course also in this one but yeah yeah even in this one but we could still pass that test by removing this table so it's not really verifying that all that data loading behavior and rendering it to the table and all that so this is probably where we're going to need that test id so we'll say data test id i'm just keeping with the conventional name here although i personally prefer this so whatever uh date time sell oh okay so now like how does it act if there's multiple elements with the same test id can you still query all of them with the same test id i hope so otherwise a more conventional way or classical way of doing it is you can say give it a class call it qa date time cell or test date time cell and yeah we can query on the class instead let's let's see if if it doesn't work like so so we're going to we're going to query for the first date time cell element and verify that it what would it output let me just see here if i can find the actual app oh i don't have that running anymore so let's start it up i'm sure i'll have time for some water because something is really slow in angular 12. boom it's done okay so now we should have the app running again let's open it up here so we want to see basically this but really this is what we're interested in uh well also the like ideally like the current day i just don't want to go through the hassle of of formatting a date value right now so in the first test case here we're just going to be looking for this string or this text just trying to keep it somewhat simple so that we can do this quickly and then wrap up it displays the first five minute interval of the current danish day the test uh expected next until i come up with a better name expect expect the time and so time and offset yeah forward okay so now now timing starts to play a role here and also we now we have to provide it with some data um because it like right now it's trying to send an hp request so we have to give it some something back or it won't render anything and in that case the only thing we'll see is this co2 forecast and maybe the header of the table here but not these actual cells because there won't be any forecast so this is our setup we can do our aaa here just for can be explicit explicit about the faces we have i i don't add the comments usually but i'm trying to get you familiar with these these terms this terminology and sometimes we have some extra special teardown here as well uh sometimes we even have like we we should try to avoid that but in some cases it makes sense to have act number two our assert number two and so on usually just one of each because you want each test case to be asserting only one thing most of the time even for an integration test okay let's let's figure out the query because we can set that up already it will be screen and then something maybe similar to before right get by it's definitely a get by because that will look for the first and if it doesn't find one it will throw then the test will fail so get by test id yeah and then what did we call it i think it was date time cell make sure here that oh date test id that's not real right should be the data test id my bad sorry that would have caused me some trouble eight times sell date time sell is there any options or something yeah some something's here oh uh what else what else this is where i'm kind of what does it do when it finds multiple cells well right now it's complaining that it doesn't find one at all it's because none are rendered how about if we put in let's put in a row before any data is loaded just to make sure that it can find this i should be able to find one and it does okay good okay so this would actually return the l element here there's no real options we need to no there's no options we need so from here we could say this was the cell we wanted yeah let's even put in this just to see how what that would look like um cell to let's see if just has some nice matchers for html elements i don't know let's see to contain expected time and offset okay sell the text content yeah so if this was the real cell that was loaded by the data this is what our assertion needs to look like it should be to contain because it will be part of that that whole text okay so now let's get rid of these fixed this fixed row and let's look for the actual data points when data becomes available so now it's failing until we do do things right here and there is actually no act because that is implicit because we we did this thing right we navigated to the the route that has this forecast feature so we don't have an act here but setup is where we need to do something so we did already use the http client testing module um so we could use that the angular http testing api which we already have been using for testing this http client of our own but the the responses here are a bit like there there's a lot of nesting going on but yeah the trade-off is if we instead replace our own http client this one if we replace that in the test we won't be testing this class and we would really be wanting to test all of the code inside of this feature or as at least as much as possible the real classes the real functions the real everything so let's let's use the http client testing module even though it's very inconvenient uh if i knew how to use mock service worker i would probably use that but i still need to to learn that so let's go with this one that i do know okay so arrange we still need some setup here we're going to have an http controller inject hcp control testing controller maybe just call controller because we don't have any angular controllers anymore so let's call it http controller so well i guess in the act would that be the right place to make a response no it's in the setup we're setting up the environment so the environment will respond with expect one [Music] now the url should be able to find that well the url there's a long query string parameter called sql with a long prosperous sql query inside of it believe it or not you'll have seen this if you've watched some of the previous episodes so let's instead do a matcher here so if we have a request the request url starts with and then should have the oh that might not be public that might not be a public property anywhere watch the url here it is i don't think this is exposed inside of this library so it's not something we have access to in the other library and we shouldn't i mean needed for the test but that's not a reason for exposing it um so it's not in here and it shouldn't be it's an implementation detail but since now we're integration testing we do need to take into consider to consideration which apa api endpoints are being hit because we need to create these these fake responses so the url should start with this and the method should be yep didn't find any okay so maybe let's just expect anyone let's expect any request with that work no okay so so it's not being triggered so i'm wondering if there's a provider missing somewhere uh but i don't think so um the container component is probably providing something here the store right and that's hopefully the only service we have here yeah it is so that's not the issue so it could be timing like some time has to pass before the the request starts to fire oh oh there's also the timing of when we need to set up the request in the http controller but i think it is i mean i can i'm going to look in this working test suite but i think it is after the request have been sent then we can call httpcontroller expect1 to say oh you should have one request queued up that matches this these conditions here and in in this case we're saying that any request you should match any request right now let's see what it looks like in the test suite for this service this http client because here we do have all of this set up properly i did call the controller how terrible of me so yeah i'll also do that here be consistent so we should have another assert down here approval verify which will verify that there are no outstanding hp request http requests we didn't take into account okay so the timing here let's copy something in here because that was working oh except we don't what's found except we don't have this string here so let's get that this should be working because it is in the other test and then we just need to flash the response but it's already failing here so that's some time needs to pass and uh one way i what are you seeing here mateo is there a way to print where i am in the test like the current route here the current route that would be the location service from angular so you could inject the location service and then say dot path and you will get the current routed path the active route path you're not getting your element there's also there's a debug function on this uh i don't know if it's on the screen or the result or both but if you call this debug it will print out sure it will print out um let's see let me just activate only this test because this should print out to the console oh oh we need to pass it an element what about screen that debug instead also need an element okay uh so do we have a root element this one is pretty printing the current html that's also pretty nice um so let's see what could we do we could do result fixture no container that's an element so this should actually work maybe wallaby is filtering something out i need to put here i'm not sure if wallaby is filtering out some console logs here or something this should be calling console log itself right yeah it doesn't return anything okay i can't remember something like that it will out pretty print the dom oh here it is yeah here it is so it should also be showing out here no [Music] well at least here it's showing up right so this is the dom of the whole the root component with everything that's currently active right so this is a good utility screen dot debug then pass it in the container component the root component here empty router outlet yeah so something's not quite working maybe a guard yeah yeah that's another thing like you might want to replace your guards in the tests um depending on where are you then testing the guards but yeah if there's like a login guard a route guard or something disable that for the purpose of the test except if you're specifically testing the login functionality so that's that's where the flexibility of the test bed comes into place and then that's another benefit that you don't really have in the same way with end-to-end testing frameworks in that case you need to have like a macro of some steps to log in before the test case or something like that so yeah that is what happened a route card so you can replace that by using the providers then provide and give it the name of that broadcard and then use class and then a route guard that does nothing i think so yeah so yeah just to show you um here providers here this line it would look something like this here you would have your your route guard class then you would give it a fake route guard that does nothing or no up route card and of course you would need to set that up like as a real route guard with the well a rough guard just needs to implement a function right so just you just have that or a method so it should have that method but doing nothing right i'm pretty sure that that would work yeah so provide your route card name here use class and then a fake one or no op route guard and that hopefully that will work but isn't it also interesting that you can test everything including the route guards in your integration test without the end-to-end test right because what's the alternative you can unit test a route guard you might even integration test the route guard by passing some some fake urls and route configurations and all that but here you can actually test the route guard fully step by step like what's going to happen i'm i'm going to try to route or navigate then i see a login page then i click login or enter my credentials click login and now i should be at the real group you can test that with an end-to-end test but now you can also test it with an integration test using the angular testing library and spectacular so yeah i think that's really nice like that that's where it really shines where you're doing a multi-step test case a very complex one that would be pretty difficult to do like in in testbed without some of these helpers here and it would be easier to do with end to end but then it would be slower and you couldn't have the flexibility to replace individual services or maybe you want to remove some of the route guards and focus on just one of them or something like that and again the speed of at which it happens so wallaby here is telling me right now that this test case is milliseconds um did i feel um extra speed on this one 81 milliseconds so i think this one has like the startup cost also wallaby is running in a special way so these numbers are not always trustworthy but yeah it gives you kind of the idea about it's definitely slower than an isolated unit test but still it's pretty fast right like below 100 milliseconds for test testing all of this code and basically all the almost all the code in my repo that's pretty good okay so here back to my issue it isn't firing a request it seems so i think my issue is that some time has to pass before that request is sent the effect says the effect says zero seconds so that effect should be triggered initially but still it like um it's happening outside of the first vm turn or something so trying now to use the fake async helper from angle core testing see if that can help me out then i need from tick zero to ten no that's not it okay so now i'm in trouble because now i don't really know what's going on um okay so one thing i could do right now is just trying to debug here so i could do the the angular um http client uh except if that one is replaced by the hp client testing module and i'm not sure but i don't think so i think it's some of its dependencies being replaced but i oh okay so i kind of have an issue because i wanted to replace this with a spy or spy on it before it was called right am i thinking right now um i'll delete this one by the way to do that i would have to provide it up [Music] here yeah okay so now yeah now i'm actually going to look into whether this my own htp this one my own hp client whether that is ever called it also has a method called get so in our integration test we let us replace it now hopefully temporarily see if it's being called at the time i expect here so provide provide what's going on uh this one oh that's actually yeah okay so here's an issue that one is not exported i kept it internal to my data access library so actually wouldn't be able to replace that so i do have to replace on the hp client level unless i exported it from this library only for the purpose of testing i would like to avoid to do that okay whether you're saying mateo the mark is not taken into account um yes um the spectacular feature testing module is not um it's not setting up any providers except for these two spectacular feature router and spectacular feature location those are the only well does it well it's also configuring the router testing module so you shouldn't be doing that yourself um that's the whole purpose of that one but yeah the providers as i'm trying to do here the providers for render um that that should be picked up by your test and let's see if i can make that work so instead i'm going to replace the http client then use value and i'm going to make a really http client here http spy um which will be a partial of the hp client uh yeah else does it needs it's unhappy why is it unhappy url some options oh also this should be just again yeah okay so if i provide that instead of the real hp client um by angular i should be able to leave this up one up temporarily and then i can't inject the controller but i can should be able to see now or wait i have to have to store this in a shared variable first http spy which is a partial http client and then sending it here instead okay i was just thinking whether or not any of this is async but it's not so no okay now i can check here whether hp's buy but get to have been called no it hasn't been called so http client hasn't been called so now i'm kind of i am sorry this was this was blocking the view a little bit and down here hopefully it didn't miss anything because i was working up here um yeah so it's saying actually that it we expected it to have at least one call but it hasn't been called the get method on the hcp client the angular hp client has not been called right now so what's going on i have no idea i have no idea right now uh there is something like i actually don't know um so okay there's one thing i think that wallaby can help me out here um it has this thing called the testing story i can click that and it will walk me through it will show me here every piece of code that is called by that whole test this test case i think including the setup so every code that has been executed as part of this test so it starts here even with the imports of well first here in the integration spec and then this forecast module the container component the index of this forecast store the forecast store has some imports so it goes all the way right let's go down to some code here let's get down to some actual code rather than import statements uh okay here we are store it's just initializing some variables in the class um here now we're in the forecast component is initializing some a component class sending a scanner here or is it actually calling it okay so oh so we're inside of the container component it's importing the scam for the forecast component that's why we're getting into this file now we're back in the container component um to finish declaring its class now we're at the routes in the forecast co2 forecast feature module and it's looking for the path co2 route path here it is it found it um now finally we're getting to the test suite here we're now defining our shared variables calling like the setup function here setting up the test cases and here we go yeah so now we're getting to the executed test code we have our before each that's our test setup so it's calling render it is now creating this http client now it's creating the angular http client which should be our spy instead of the real one now we're in the danish date store to set the initial state to the start of the current danish day now we're in the co2 forecast store initializing an initial state and this is requesting or resolving the our own http client this one and we're calling the effect here uh is there some code now we're in the forecast component okay so it is requesting so it is now requesting the forecast state property from the forecast store okay so now we're at now we're at the test now we're at the arrange test step of our test case and everything failed so we didn't get to the to trigger the effect yet which is this one we have been where it's actually passing and observable to this effect so this seems like yeah today we're getting today from here hmm yeah but the effect hasn't like um we should get further like we should get down to the switch map calling the http client so we haven't really gotten into the effect yet at this point and now i i don't really know let's try to step to the next one but it will fail rather it is failing so i can't i can't step oh here step over okay so now we're here where it will be failing right can't do anything more than this but i can take the wallaby tools so now i sh you know like i can see the http spy here here it is with our mark and the mark has zero calls okay so it definitely hasn't been called yet ending this test story with the debugger and mateo you're wondering if you can do uh can you do everything with the harness that you can do with the feature testing module yes the create feature harness from the function from from spectacular it's imports the feature testing module and does some more work like well it's initializing um by by navigating to the default route of the feature module and then it's waiting for the whole thing to stabilize so that that's what it does when you use it the create feature harness instead of the feature testing module directly but when you're going to combine it with other libraries you're going to probably going to need to feature testing module um at least with angular testing library yes uh yeah well one muffin one more thing that the crate feature harness does yeah it does bootstrap the whole app and uses the spectacular app component as the root component uh so yeah it does some of the same things as angular testing library but then you you're you can't you don't have all the helpers for interacting with the dom and querying the dom so you're going to need to use testbed directly for that as you you might have been used to from angular component tests using the test band so but yeah it can work without angular testing library without component harnesses it can work on its own with a angular testbed and just to create feature harness function and maybe a tick to let the effect be executed yes that was what i i tried before making using uh we can try to do both um pick and we can do rush and the whole thing is i don't remember right now which one is doing what um still no success yeah yeah i do i do highly suggest that you use spectacular together with angle testing library or angular component harnesses from cdk and material but you can use it just with the test bed it is a independent library but it integrates well i'm talking about spectacular here the feature testing api it integrates well with angular testing library because it will never have all these nice apis for working with the dom and the testing library has been evolving over years so why reinvent the wheel in spectacular instead spectacular is focusing on setting up the testbed for working with a whole feature module all the routes all the services and components represented by that routed feature module okay so it's definitely getting way past my my bedtime now so i can't really figure out what's going on here why that component star is not triggering its effect yet there's something i'm missing right um i mean i can i can try to find the store i can go into store if i can find it co2 store and like i can do well we saw that this was being called so if i open up wallaby down here and i do say i should turn up here right before before effect in it after yeah it has been called a few times after and even if i focus only on this test uh this is a wallaby feature could do the same thing by writing it only or f f it or fit but when i do it with wallaby i'm not leaving traces in the code so i'm not committing something accidentally that disables other tests so i can click here focus and now that's the only test being run so when i see the console log outputs here it's from that it's because of that one test so what could else do i could also go in here and say tab now i could use a nice debug operator who was the person that created that one from the community i can't remember right now but values values so whenever this is trigger and i can actually see here from wallaby that we never reach this point of the code it's grayed out meaning it was not touched by any test running right now so we're never getting to this point so what if i disable this assertion and go all the way down here is the code then trigger no if i disabled visa surgeons no you never get to executing this code it seems so yeah i have no idea is it this timer is it this timer that's not being started uh do i need a test scheduler or something um oh well i'm glad to be of help matteo i knew you have been asking about spectacular so hopefully this can give you some inspiration and then another video that you can go and look at and of course this is let me push it now the working test and the setup is also in the energy insights repo in this feature branch for the co2 forecast so yeah i don't really know where i'm like maybe it's a i need a test scheduler for rx for this timer to work or or is this something special i need to do with um the component star it's it's a little strange because wasn't that effect working no i guess it wasn't it wasn't working in the other test because there was like the container component test um i was providing the store why was it providing the store by the way it is already provided here so that's oh because i was testing it as a container component i was calling create component uh so i was basically testing it without any dom but even in this even in this test i think i was controlling the state of the component store uh here by calling set state on it rather than oh here i'm doing tick zero uh yeah i was controlling the internal state um directly rather than work uh waiting for any effects to to do http request so here i was kind of stubbing the the store not using how the store actually works not like the effect i was kind of ignoring the effect and doing the setup myself hmm so i mean i could do the same thing here inside of this test and go and give the co2 forecast store some some data but then it wouldn't be much of an integration test i mean then i would be testing the component again but not the store with the effects not the http client so yeah it would still be an integration test because it's testing multiple components and all the way to the dom of them but and navigation as well but i would be leaving out a huge portion of my code this youtube forecast store with the state and the effect to call the hp client and my own http client so i really want to cover all of those classes with these integration tests so that i'm testing basically everything as close to as close as possible to how it would be used in production so without replacing any classes with fakes and stubs as much as possible so yeah where is this going wrong i don't i don't really know i mean i i had been thinking about um that maybe i'm let's delete this whatever i put in here i've been thinking about that but this is not a good way to initialize an effect from a testing standpoint because i i would like to be able to control it more granularly like not starting the effects or starting the effects when i say so uh so so yeah i don't know maybe there's a pattern for this in component store maybe not and one thing i have been thinking about is what if i gave it like an initial i can't spell but like an initialize function here uh that would actually initialize the effect of course i would need to do something like this then of course this would need to be called in the application and in the test how could i do that i could use an application initializer maybe but still like yeah still thinking about whether that's a good idea also in this integration test it shouldn't be necessary it should just work as like in the the app so i shouldn't have the need in the integration test to control when the when the effect is actually triggered that should just happen as in like seamlessly as in the real app it shouldn't it shouldn't be necessary to touch these things but maybe it is this rxjs timer that i need it needs a test scheduler or something um yeah i'm not sure i'm going to have to sleep on it or maybe ask uh some some clever people some smart people for help on this rxjs testing thing but it might be i need a rxjs test scheduler or something it's definitely like how can i how can i get to the next point in time to start triggering this this timer and this timer is not being triggered and and this next step in the observable pipeline is not reached until both of these observables have emitted at least once and we we saw that the danish today observable that we get from here that has emitted uh but yeah the timer seems to be the issue combined latest wage for uh at least one emission from both of these before going down the pipe line here so yeah probably the trick the timer of rxjs is the issue here but we have seen this timer working in its test actually we have seen it here i'm still i think i'm still filtering out on this test now i'm running all tests again so the test for this store we are actually seeing here that we can control the effect uh using fake async and then tick here it's tick zero then the initial effect is running which i'm like why doesn't this work in our other test here i'm not sure and here it's tick and then a minutes worth of milliseconds and then we can see that http get spy has been called again so here we have actually seen this like the and then this discard periodic task but here we have seen the effect running in the test controlling the time in the test by using fake async and tick so why is it not working in here oh wait wait wait this fake async is it getting it from the right place yeah it is okay good from angular core testing but this should be enough this is the same as i had here in the forecast or test did i have anything special inside of the setup function oh yeah okay oh oh well we're like it should of course receive something from hcp but um like i'm still wondering this timer should trigger no matter what then it should go down here and then it needs to respond from from http our own http so it still seems like the timer is not being triggered what if i run through the test story of this one let me see what that looks like let's go down here now we're at this point of the test story let's actually go to the next line check oh circle back okay step step um if i step over and then step into what's going to happen okay so this take 0 is triggering the next step in the observable pipeline the map here and then it goes on to call the http client this is what we're not seeing in the in our integration test suite for some reason take 0 triggers the effect okay let's try to get into our setup and see what what's going on here step into configuring we're getting our http client which is getting the angular http client okay we're done replacing it with a spy the get method then we're injecting this door so then at that time it's being created which should uh start start the effect very soon oh this is the date store danish date store so i'm looking for the co2 forecast store here it is it's now being initialized here's constructor oh and now okay now it's creating the effect property and i'm looking for oh here it is yeah now it's being initialized inside the constructor of the co2 forecast store so to do that it is getting the value here from the danish date store and now we're back from the setup and getting to the tick yeah this is what i expected but why is it not happening inside of here that's my question hmm well you did say uh something about your providers not working so am i like am i no that's not my problem here uh because the effect is never triggered that's my problem and i really don't know why i mean this this integration test is using a lot of other things that was not used in that unit test for the co2 forecast store this one is using spectacular it's loose using the angular testing libraries there's a lot of things going on here routing as well okay well i definitely have to sleep on this and figure out like what's the the issue here so yeah important things today we saw how to now i've messed it up a bit in the repo you'll see how to set up like the spectacular with the angular testing module goes something like this this bit here that's the setup something like the setup you're going to need for integration testing with spectacular and angular testing library so for this integration test it's testing this routed feature module from an nx feature library for the angular app we have here and we're giving it the route path which is co2 so it's the same as is being used in the application which gets rid of some issues and then we can test so yeah i'm going to add back some of these things here yeah so that that's the most important learning we saw how to use angular testing library for every basic thing here and now we're getting into some some issues with the the router or sorry the engine our njx component stores i'm having to i'm going to have to to do some more experiments here some other time unfortunately this was my last episode i have now used up all my free stream string yard streaming minutes and i will only get more uh three weeks from now the 17th of june so this is a cliffhanger i'm sorry very sorry for that um i'll be working on some other things until then and then i'll see you again in three weeks time so that's it for today annex after dark i hope you learned something or anything from any of this uh hopefully some inspiration to look into some some of the different technologies here and uh have a great day or a great week depending on your time of day see you bye
Info
Channel: Lars Gyrup Brink Nielsen
Views: 156
Rating: undefined out of 5
Keywords: nx, angular, spectacular
Id: d7zUnVpuBL8
Channel Id: undefined
Length: 182min 37sec (10957 seconds)
Published: Wed May 26 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.