Rogelio Guzman - Jest Snapshots and Beyond - React Conf 2017

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey everyone my name is Raquel you lose money I'm part of the Jets core team and I work as a front-end engineer at Ducker so I love testing but I often find myself not testing enough so how is it that if I really like something I feel then do it a lot of it has to do with the problems and the number of tools that we have to stitch together when we think about testing which brings me to the idea that I might just like the idea of testing so abductor we were having this problem where we were not writing enough tests and it was mainly because our tests were taking too long which make that really slow for us to iterate on them so I was trying to motivate our team to test and write more but it's really hard to start doing that when the tools are not working on your favor and if you don't have an environment that makes it really easy to write tests then you end up writing not writing them so when the effort of writing tests is really high you write less tests and the same is true for when the effort of writing tests is slow you end up writing way more time so at this point at docker we were using a combination of tools that were not providing us with a cohesive experience and a lot of it was not the fault of the tool that we were using on the contrary there were all great tools but we just never took the time to optimize how they work together which means that we ended up with this really slow testing solution so this was around like halfway through 2016 and at this point I have heard a couple of things about just I've seen that it has any type it has had a couple of good releases so one day I just gave it a shot and just like what it would take to my Gradle our test to judge and surprisingly the transition was fairly simple like after like theyõre to all of our tests were migrated and we have removed several dependencies from our code rings but most importantly it meant that every time that we hired someone new they wouldn't have to think about all these dependencies button but they would just be thinking about this single dependency for testing which means that it reduces a lot of the cognitive overhead that comes whenever we were hiring someone and wrapping them up so after my grading suggests our tests started running in about the 6th of the time and running a single test what went from taking about five seconds to being almost instant which means that our feedback loop was way tighter and this means that we ended up writing more tests and last but not least we were able to start using snapshot tests which we're going to be using a lot today okay so what does it take to set up just it's actually fairly straightforward I have this project where the only thing that we need to do is to adjust the set of pendency and after we're done that's the only thing that we need to do and I also have this really trivial sum function that would add up a and B and I already went ahead and creating it and created a corresponding test file for it so let's launch just in watch mode and see what happens when we launch it we see that it will already found the file and it already figured out that it doesn't have any test so let's write one this one is it adds up to numbers and it expects that the sum of one and two will be equal to three like nothing really exciting so we run it Jess will pick up the change it will rerun the test and this case are passing but if we change it to be a four they will fail and every time that we're saving something Justice Reata matically rerunning all of our tests this is great I know that it was not super exciting but we actually didn't do much work to set it up and we already have all that environment working so by the way all the code that we are going to be working with in the talk is going to be available later at the github repo so that you can use it up reference so are some example was great for setting up just but for the rest of the talk we're going to be using these other application it's called emoji cinema and it's basically a type-ahead where you can start typing the name of the movie and you're going to get the emoji representation of that movie back so for example if you type frozen you get a snowflake and address if you type Finding Nemo you're going to get a lens and a fish so let's dive into how this application is architected it basically has this movie list component that takes in a query AC prop and renders a set of movies and if we dive into this movie list component we see that the core of our application is this function called search movies which also takes in a query and returns an array of movies for example if we have the letter F it will return as all the movies that contain the letter F so let's see how that search function search movies function is implemented it takes in a query it has a de mogi map it filters it filters through it and returns the movies that match that given query and our emoji map looks something like this where we have several movies like Kingsville panda and harry potter and et cetera so how would we test something like this so our initial approach would be to do something like okay we just expect our search movies of F to match some set of movies right that sounds like a good way of starting so let's write a test for it it returns two movies that match the query and let's start writing our expectation but halfway through like where we're writing it we realize that we don't know what are all the movies that match the letter F and even if we did know I don't know if you guys have tried pasting some emojis into your editor it gets really weird and if they have like more than one unicode character and just guess even worse so we should do what we always do right like we just come into doubt we come to login and perfect and after console logging ed we see that it's frozen Kung Fu Panda and Finding Nemo perfect so we just go ahead paste that into our test and rerun it and now perfect we have a passing type saturate but now let's imagine that protein 2 comes along and you're like oh really so you you modify all your remove all of your emoji map and you modify your application and then you rerun your test and then you're failing you're like okay this makes sense it's because I haven't added frozen 2 to my test so we go and we do the same exercise we just copy over the emojis from the output of just and we add it to our test we have a passing test now perfect so now so what would happen if our search movies function started returning more than just a title on emoji started returning more metadata let's say the year so if you go ahead and add the year to your emoji map and all of that and run your test they're going to fail again and it's a similar type of error right you go when you copy over the year of all the movies and you're ready to go that's great but you might have realized that we're in this manual clunky process of having a failing test and then manually verifying that that output is the expected behavior of our application and then copying it over to our test pasting it rerunning our tests and then having a passing test now which we could generalize these to we have a failing test we manually verify an updated test and then we rerun it so there must be a better approach of doing this because this has a couple of problems right it's a manual process it doesn't really adapt to changes because right now it was only one test what Faline but let's imagine that instead of that we have a set of like 300 tests that are affected by our code change so these just prevents us from either doing a really big refactor that is going to break a lot of tests or from testing so that we can do our a big reflector and then we just don't test so this makes it really hard to maintain and to solve this just has this approach called snapshot testing which we can think about it as the same thing that we have been doing except that instead of us doing all the manual work of verifying the output and copying and pasting it we're going to delegate that to just and we're going to automate it so let's see how that would look we're going to go back to our trivial sum function and our first step to converting this to a snapshot test is going to be to extract the hard-coded assertion that we have there and by doing that we're going to be telling Jeff hey I want to delegate you all of this just by saying to match snapshot so let's see what Jeff is doing in reality when we're doing a to match snapshot so it will grab the output of a function and it will compare it and it will save it in a snapshot file so this is where jess is going to be managing the states of each snapshot and then the next time that we rerun our test is going to do the same thing it's going to figure out that it already has a snapshot save for that given test and it's going to compare it it's going to say ok 3 & 3 are the same perfect your test passes then if for some reason our sum function returns before then it's going to fail it's going to give us an error telling you telling us hey one of your snapshots failed and whenever this happens is because of one of two things we either change the behavior of our application and our tests need to be updated to reflect that or we introduce the bug in our application and we need to fix it when and so just just so that we can press you to update our it snap shots if we want to do too so this has several benefits because it's an automated process we're not doing anything and it really adapts to changes which means that it doesn't matter if we're updating one snapshot or 300 the effort of doing so is the same which makes it really easy to maintain and scale so let's see how this would look for our same sum function so again we go and we change it from a we change it from A to B equals three to a two-match snapshot oh it's not taking here so we change it to a two-match snapshot and this generates this file which is our snapshot file and they tell us that the output of that test was three perfect so now if we go and change our sum to something that returns for our snapshot is going to fail and it's going to tell us hey these snapshots do not match so that's kind of like all the effort that we need to do in order to deal with snapshots so like let's take step back and let's see how all of these plays with our emoji cinema application again remember it has a type a head where it returns to you all the movies that match that letter okay so let's go back we we were here and we only had frozen Finding Nemo and food Panda so our first step is going to be to extract a hard-coded value from our test and we're going to do that and replace it with a to match snapshot so we run our test and now just tell us like oh perfect you have one snapshot that was written okay and now our the way that it works is that Jess will compare the snapshot and it will save it into a snapshot file and that snapshot file is going to look like this which you can see that he actually looks fairly similar to what our test had it's actually just the same representation but just did all the serialization and the and will string defy it so they will save it in a file and so you don't have to do any of that and now let's see what the process would be if and to came out so we change all everything in our application we do the same thing we rerun it and we get a similar error than before but this is slightly different because now it's telling us that these snapshots do not match this was because just compare the output and it figure out that something has changed so we can just press you and Jess will update the snapshot and we should be ready to go and now our snap should look something like this so you can see we achieved the same thing but we didn't update anything on our own so this good but there's just something that really annoys me about this snapshot and it is that there's a lot of noise you can see that it has an array and an object and it has a like emoji and the title keys which in reality I want my snapshot to look more like what we have on the right hand side because that's also what our application looks like so how are we going to do this so to do this there's just come to this concept called snapshot serializers and we can think about them as what should the snapshot look like right they define how the snapshot is going to be see realized and then string divide so how do we adding a snapshot serialize er to do that we only need to have an object that has two functions a test function and a print function we can think of the test function as a function that returns a boolean and it basically decides whether or not this specific serializer will serialize this value right in this case it's only going to be serializing movies which we're going to define as something that has a title on an emoji and then there's our print function which tells you how the snapshot for this specific value is going to look in this case for each of the movies we're going to concatenate the emoji and the title perfect so once we have this how do we use it in our application that's the best part like we don't have to do almost anything with our tests we just put it on top of our test file and jeff's would figure out that it makes you use that cereal aye sir and that's it you can see like we didn't have to touch any of our tests to use this cereal Iser now it just obviously tells us that something failed and that's because our snap should our snap ship doesn't match the previous one which is exactly what we expected so we press you just update updated and now our snapshot file looks like this perfect which is kind of what we want and then if we rerun our test there packing perfect so we've been really deep into our application but let's take step back and go into our movie list component remember that's like our main component of our app and it takes in that query that we mentioned renders all the movies so how would we test this our first option is well we simply don't write like testing UI is hard and it's weird so we just don't test it our second option is okay we're going to like pin up a browser set up selenium but this also comes with some problems because it's kind of flaky and it's slow and whenever something changes in our application the maintenance cost of it is really high and not surprisingly the third option is going to be snap shot so we can think of our movie list component as a function right things up like thanks to how the render method works and react we can think about it more or less of a thing that takes in props and render it's a set of react element which in this case are going to be eventually rendered as done in okay so we know that every time that we want to use snapshots we want that thing in this case a function or a component to match a snapshot right so that's probably a good place to start okay so we have render service and we expect the component to match the snapshot but how do we get that snapshot and sorry how do we get that control well react already comes with this test renderer module which we can think about a something that will get a component and render it into memory and then we can just pass that to jazz in a to match snapshot and it will sterilize that and string to fire it into something that looks like a dumb representation of it but wait how does it know how to get the component and serialize it appropriately to look like a dumb well that's where snapshot sorry where serialize ER is coming to place just comes with a set of Serie lighters already built in for example it knows how to serialize react elements into what looks more like a dumber presentation so if we run our tests they will pass and it will tell a new snapshot what's written and if we look at it like yeah that looks pretty similar to what are our type-ahead would look like again so let's imagine that frozen 2 comes out and we're like ok let's make the same changes that we always do we rerun our tests and we get a pretty similar exam a pretty similar failure it's actually not it's telling us that the snapshots do not match it's not telling us that you we did an arrow we just letting us know hey you probably need to update your snapshots so we press you just updated and we're again ready to go wait so at this point you might be thinking hey you totally forgot to mention enzyme because I do test my components but I don't use like snapshots or anything I use end time to test them so like how does that play here so we're going to be using serialize earth again so let's go back to our main test where we're saying that we want our component into that snapshot and there's already a serial icer that will serialize enzymes component or like components i've got render with enzymes into a snapshot which need to install enzyme to jason and then we can use this serializer you can see that our tests are still passing and that's the beauty of snapshots because we totally swept how we are rendering our component but because snapshots are only interested in what the output of that function is our tests are still passing because like there was no behavior that change in our application we just went from using the react s renderer to enzyme and we can do something similarly if we want to use shallow renderer and it will also work so we've been thinking about our application and and about our test as a single static thing but the truth is that our application is not like that every time that the user is typing something our application is transforming and the out the the UI of it like every time that we type letter we get different results so it would be bright if we could capture all of these transformations of a given object over time so how could we do that let's go back to the test that we always have and we're simply going to iterate on a couple of like key up set of like characters in this case let's imagine that we're typing frozen to and we type F and then at some point with high F R o and then at some other point we typed frozen too so you can see we added two more snapshots one for effort oh and one for frozen - but the complexity of our test did not go up right like imagine if you were doing this without snapshots the complexity of your test will be going up because for each of those takes you need to know exactly which movies are matching that snapshot at that given time right so but here didn't go up which is really interesting and Geoff's will add two snapshots which will look like that and you can see they're both a representation of how our UI looks at that given time in this case one is for when we have fr OS a query and the other one is for when we have frozen to sa query so all of these object transformations over time we can think about them as a movie right where each snapshot is just a frame in that given movie that it's like telling us a whole story of how the user is interacting with that given object and I'll imagine if we start adding tools to visualize how that given object evolves over time and we can use parts of just to create those tools so I've been working in this guest movie tool that I wish I'm probably gonna be able to share it with everyone in the next couple of weeks but it kind of looks like this you can see it final it found this snapshot file and then it also found what it calls a movie which in these cases are renders movies test and notice that it has three frames and you can we can use the arrows to go back and forth so we start moving through the frames we can see that the second frame doesn't have to loop and an Finding Nemo and the third one which is when we were over in typing frozen - it only contains frozen - it also comes with it like disc mode where we'll compare one frame versus the previous one or like one snapshot versus the previous one right so it knows that the second snapshot does not contain the two these two movies and the third one is not contained in this one there was contained in the previous one so this is a great way of visualizing how our application is evolving over time which brings me to the point that just is more than a testing framework just is a testing platform so right now we have been thinking of just as this single package but the truth is that it's composed of many other packages which can be used independently to adapt to your tools and to just be used for whatever you find most useful for example we have just snapshot which is a standalone snapshot package that will encapsulate all the logic of how to update and add and manage all the snapshots which you can use without even using just at all we also have like pretty format which is what the serial icers are using to know how to serialize all of the data so you can also use that to integrate it into any of your tools and be able to like pretty format any of your either Nate like built-in JavaScript types or just start to create like new serializers for your tooling it also has like just validate which is the tool that validates all the configuration arguments that come from the command line and it gives you like all sorts of like validation error and deprecation warning this is actually what like prettier is using for validating their command line arguments also they're not that they're just using their like just validate package so what's next right that shuts it's an open area of research to be honest it's just the beginning of snapshots and I really believe that a lot of food could come in new ways that we can start thinking of snapshots for example like I don't how many of you end up testing your like web pack config right like we don't do it that often because it's hard to test but it still dictates a lot of how our application is going to be bundled there's a lot of logic of how we're going to bundle it in production versus in development so what if we could do stuff like oh just give me a snapshot of my current web pack config and we can serialize out some values that we don't want to be in that snapshot so there's a lot of like really interesting things that could be done with snapshots outside of just testing anyway I invite everyone to contribute thanks for listening I'm more than happy to help out with anything please feel free to come to me or the brague or just send me a message on twitter i'm thanks for listening um or the have table [Applause]
Info
Channel: Facebook Developers
Views: 44,936
Rating: 4.9741268 out of 5
Keywords: react conf 2017, jest, jest snapshots, tests, testing, react
Id: HAuXJVI_bUs
Channel Id: undefined
Length: 26min 34sec (1594 seconds)
Published: Thu Mar 16 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.