React, TypeScript, and TDD


ReactJS is wildly popular and thus wildly supported. TypeScript is increasingly popular, and thus increasingly supported.

The two together? Not as much. Given that they both change quickly, it's hard to find accurate learning materials.

React+TypeScript, with JetBrains IDEs? That three-part combination is the topic of this series. We'll show a little about a lot. Meaning, the key steps to getting productive, in the IDE, for React projects using TypeScript. Along the way we'll show test-driven development and emphasize tips-and-tricks in the IDE.


Today's workshop is going to be me trying to convince you about an idea and that idea is about developing your react components test first, writing a test before you write the code, writing a test as the way to continue developing the code and the component. And only at the very end when you need to see what it actually looks like do you go to a browser. This tutorial has associated with it something you can follow along on. So you can follow along on this URL slash web storm slash guide that slash web storm slash guide if you click on tutorials you'll get to this tutorial and you will find in this tutorial that I'm kind of cheating every single thing has the write up that I'm going to talk about it as the code that I'm going to show and it even has a video which is mostly correct let me cover that point real quick about the yes I can I put it in discord but you're right I should have put it over oh someone else did all right all right Gabrielle thanks for doing that every single thing I have is kind of cheating and putting it in here but there's a reason for this I want you to be able to follow along and play around and not worry about every single thing I say if there's something you didn't get there's something you want to follow up on I can be easily easily replaced by a URL to a website and I should also know that each step in the tutorial has a link to working code for that segment of the tutorial so what we're going to do is we're going to go through this I'm going to try and make the case for this way of doing development as I go through building working code we will try to do a stop maybe like an hour and a half from now or something like that take a five minute break so I've got my timer set for that we will also be talking in chat so I will try to get both the discord channel and the let me make the zoom chat a little bit bigger so I won't make a mistake on it all right excuse me for a second apologies I wonder if my microphone picked up that sneeze we will be taking a little bit of break we'll be following along on all these things and if you get stuck that's okay because the link to the working code for each step will teleport you into a magical future where everything works correctly one last caveat before beginning I am a developer advocate for our ides so a jet brains for this it would mean web storm or any of the other ides that include the web storm plugin I'm not going to really over promote web storm on this it will be I use the word IDE because then it will apply to other smart editors that can look at structure instead of just the strings of text but at the same time as I do this tutorial I get really excited about how the tooling can help us how the tooling of testing and the tooling of typing can make us have a better development experience and stay in the flow so with that in mind let's begin this is the sequence we're going to do setup and clean up and then jump right into testing we'll do a little bit of debugging to show the benefit of sitting in an IDE and then straight into a number of things about writing react components this is up to date as of create react app last week so I updated all the code for this I didn't update the videos there are a couple of places where the videos are out of date on using a just selector for roles but we're all smart we can work around it I don't know how far we will get through all of this today but again I'm easily replaceable so if we don't get to the end you can just watch the video on your own time and see about these last couple of things they're pretty interesting topics and they really do show off how far you can go with test first all right let's begin so I'm going to go to project setup and I'm going to get us a sample application and we're going to show three kinds of running things in the code we're going to show running the kind of development setup the build your final site setup and the test setup and along the way we're going to start introducing a little bit of things about the IDE so with that in mind if you want to follow along on this page that's fine I also have it in the background so I can cheat I'm going to go over to my IDE I'm going to start on the welcome to web storm screen I'm going to create a new project now I could if you don't if you're not using web storm that's fine you can type this so I'm going to create a new project it's going to be a react project it's going to be a react project I'm going to call it create react app and it's going to prompt it's going to tell me some of the things it's going to be using by default let me make sure I haven't I got to scroll yep we're good there we're good here I'm using oh god I think node 16 yeah 16.10 thank you web swarm for answering that question for me and it's going to be using npx to get create react out so let's see if you have IntelliJ IDEA ultimate then you have access to the node js plugin and if you've installed node js you have access to all of this all right a little disclaimer about this I'm going to explain as if some things for some of you might be new but I also realize that some of you do know what npx is I won't dwell on it because it's all really well explained elsewhere in the world of node js when you're creating a project a project you can use the npm command to install packages but what if you want to install like a application something that you're going to run which will then create a package there's a thing called npx which says okay go get the latest version of this put it in a temporary environment and run it so you see a lot of these command line tools like liners and formatters and scaffolds like this create react app using npx so that you're always getting the latest version what is the latest version of create react app which is the scaffolding tool that we want to use it's 4.0.3 and finally I want to make a typescript project because typing is an important part of this okay with that in mind let's go a little bit off the end I should have I'm going to go back and make a new one because I did well I will go and delete that that's in scratchpad all right okay and then I'll come back my apologies I should have deleted that so new project react I'm going to call it cra and I'm going to ask for typescript support say create new project and web storm is putting on my external monitor so let me resize this over here and then so so what web storm did was it created a new quote-unquote project in that directory and ran some things that it knows how to run such as create react app which is creating all the software and then installing all the dependencies so that's what you see right now is the output of create react app as if I was doing it on the command line uh yes next.js in fact we're getting more interested in next.js my colleague Ebenezer Don has a long blog post about MDX and next.js that we've published recently all right so this is going and getting I mean let me talk about create react app for those of you who don't know it it is a scaffold to generate the best collection of supported software for a modern react app what that means is add-on packages you might want to use and tooling that you might want to use like lenders and stuff like that it's going to be over a thousand maybe fifteen hundred packages that it installs and this is just madness it's so hard to keep all this stuff in your head and then as it changes like every single day this will break that create react app is doing us all a really big favor by taking ownership of what software should you use and what versions of what software should you use and they will say we will support all of that so this is a really important thing to be doing for create react app and that's why i'm using it as the starter point oh look we have co-workers here together all right and yes jun you're correct there are always a hundred options to do the same thing for everything especially in the front-end world i think you all know that okay now at this point all of my software has been installed i'll resize all of this and i want to run something i want to run something that's in my package.json file i suspect that font is a little bit small let me make it a little bit bigger okay create react app generates a package.json with some things in it but what's interesting is it's moved a lot of the configuration and a lot of this scripting over into software that can be updated later without you having to change your package.json or the dependencies or anything like that now i could go ahead and start this using the terminal and i will i'll say npm run script start and this is the way you're probably used to doing it is opening a terminal and then let's see you opened chrome i'm going to go and change my browser to be firefox first listed yep that's good so this needs to come over here all right i wanted you in firefox but that's all right we're good npm start runs a developer server okay thank you for posting the links about the calendar entry and how to get in here and let's see it's it's true that next.js has become very popular but i believe if you go to react's pages itself they still point at create react app so i think the react project considers create react app kind of as the official starter and next.js adds in some things related to routing and other things that make it a little bit more opinionated so we run npm start and it's running a webpack dev server it's doing all of the things in a window and i can prove that it's doing in a window and i can prove that it's doing what i want it to do by going to app.tsx which is in src and if i change something like here to be exclamation you see that it's going to reload it's going to update and when i go back to chrome i will see this live and if i had enough room on my screen switch to 720p i had enough room on my screen you could see that these are actually happening side by side now that's all great but you don't have to run in a terminal we are an ide ide's have some automation to get to integrate your development environment so if i wanted to integrate my development environment i could do a couple of things i could run oh by the way i have tabs turned off i will turn them back on so that it looks a little more familiar to you if you wanted to though you could run our npm tool and get a browsable list of things to run and then it will run it in a tool window for the id uh chris we are on project setup which is the first link under show me a page so we could use this npm tool which exposes all the scripts in your package json which is the way i used to do it all the time the way i do it now though is i just leave my package.json around and we have these gutter decorations that let me run scripts not just run them i can also run them under the debugger which is also useful so i'm just going to run this here and what i get instead of the terminal window is this run tool window which is dedicated for the ide to capture output and let you do certain kinds of things with it all right let's see alexis hi alexis we are currently there here now same kind of thing you'll see it we're running the same thing underneath if i go back to web storm and then go to my component and i will minimize this and remove this and put the period back and save it it does the live reload so under the hood it's still the moral equivalent of npm start so that brings us through project creation show me a page we're running the script for start that's not the only thing we're doing we can do though what we're running is a development server it's not the build production quality it's not minifying the crapola out of everything and splitting into lazy loaded routes and all of the miracles of modern science that modern react gives you what we want to run is the build script and again this is something really nice to create react app has done for us they have a script that they manage in their own package and when they find a bug they fix it and i don't have to go retype something on my side it's in it's managed by the package so if i want to run the build the production build same old same old i come over to the gutter i click run it's going to open a tool window it's going to take a while and my cpu fan is going to light up a little bit uh for the npm tool if you can't find it hopefully you can just do find action to get to it or if you do find files hopefully it will be listed over here if not you might not have the plugin turned on okay thank you sherry i i think i answered the question that was asked if i'm looking at a different question let me know yeah looks like sherry also answered the question there all right and if that doesn't answer the question about where to find it in intelliJ let me know okay so we generated a build directory well what does that mean we generated a build directory that's what it means this is an exported version of my react project ready to be served on a static file server in a very high performance way the minimum javascript all that other kind of stuff and if i look in here i'll see i have an index.html i've got some variations of my logo other things that match what i was getting in the dev server one thing that's interesting about this is the IDE has marked this as excluded which is good i don't want it re-indexing that constantly and giving me two choices to navigate to a symbol or something all right so that's doing builds let's get on to what we want to talk about which is testing another thing the create react app does for us as a scaffold okay all right so i'm showing in web storm but if you go to find files hopefully you have it over here if you don't have it under here then it might not be installed correctly and so what we want to run is this run script for test now what's it really doing again create react app is kind of the official scaffold for the react project and it has made some choices about testing and it has made some choices about testing so what we want to run is this run script for the react project and it has made some choices about testing it has made the choice that jest is the official test runner let's see if i've got yes jest is the official test runner and the testing library that's used for asserts and test automation and stuff like that is something called testing library and they make sure that this version of jest and this version of testing library works with this version of react this is an important thing because that stuff breaks all the time especially when you introduce typescript into the equation and so it's very helpful that someone else is doing that work for us how can i run my tests right now let's see so let me come back over here i could run it from the command line like i did before and it will give us the output or i could run it from the npm scripts or i could do the package dot json thing so i'm going to run it from here it's going to open another run tool window and it's going to launch up my test watcher which is running my tests constantly on every change to see if something is broken briefly i'll go break something and i will let's see in test it wants something called learn react and so let's see yep i save that the test rerun and it says i failed a test put it back save it all right in in this case it didn't run the test again because it's in a mode where it only watches for things that have changed relative to get okay so those are our ways of kind of getting started with npm run scripts in the ide and getting started with create react app and testing so what we saw create react app and testing so what we saw was there's a lot of tooling involved and create react is doing a great job at helping us stay up to date and managing all of that tooling in this next step we're going to clean up some of the things that we got out of the box that we don't need and take a little bit more at take a little bit more of a look at typescript okay let's see all right i think i'm up to date let's go to the next step in the tutorial we're going to go to the project cleanup step i'll take this little moment to take any questions you have or see any commentary you have and offer up some commentary of my own this site is a developer advocacy project at jet brains we have guides for pycharm webstorm dot net go land space intelligi which is doing a great job with their guide and i chose to implement it using gatsby and it was a great first week and it has been a really tough 200 weeks since then all right anybody have any other questions or comments about create react app or the world of react or ids and tooling okay we'll begin we're going to clean up our project a little bit remove some things that we aren't using and along the way kind of show how the ide can help us the ide can help us i'm going to use an expression i'm going to use a couple of expressions in several places i'm going to use an expression called fail faster odd expression intended to be odd and the point being if there's going to be a mistake later show it to me now show it to me right in my face visually so that i know i've made a mistake and so as we go along i'll talk about fail faster a little bit in this sample we're going in this step we're going to look at getting our code reformatted ultimately with prettier we're going to strip down what we got out of the box to include deleting some files that were generated by create react app which we aren't going to use yes alexis gatsby is that smiley face alexis is that a smiley face of love or pain if anybody's a gatsby lover or user that are here i apologize if i've misspoken share your thoughts about gatsby in the channel and let me see what you think so we're going to do some cleanup of some files and see how the ide can tell us hey you're about to make a mistake fail faster we're going to see a little bit about ide goodies how it can warn you about certain problems they can do cleanups for you and a little bit of refactoring so let's begin i'm going to start by reformatting my code and i'm going to do it first and i'll leave package by json open i'm going to start in here and in the ide in mac os it's command alt l you'll see that i've got this tool called a plugin called presentation assistant installed it's for all of our ides and it pops up what keystroke was pressed what action was invoked so i'll do it again that tells you the key binding that you can use on your side the tutorial also has the key binding listed as well in the text yes alexa good point it can use yarn as a package manager it's uh our ides are fairly transparent about that if i go to find action footnote to preferences and i search for npm i can switch between yard and npm good point in the package dot json in the dependencies it actually lists some of the ones that you mentioned the types just are listed here is it i wonder if it's not in my text is that if it's if the problem is it's not in my text then i need to update it but i thought i copy and paste it all that correctly if not i apologize okay back to code formatting i'm in my component i've done reformatting and that's great but that's not what people really are using these days these days people are using things like prettier some other tools like that so instead of the ides machinery webstorms machinery for formatting which is great and has all the tools that you can use to format your code so i'm going to go ahead which is great and has all kinds of knobs to adjust all kinds of formatting stuff if i go to code style look under javascript i see i've got all of these knobs i can hit to to adjust what happens when i do reformat code but you're working on projects that might have continuous integration other people who aren't using our ides you might choose to use prettier so let's get prettier installed i'm going to go to let's see we're doing prettier i'm going to run this one by hand what i could do is go in here oh i see your point you would expect these to be under dev dependencies that's a good point this is a choice by create react app and i agree with you i'm surprised about that all right that's a good point i think it should be yeah hmm okay audience does anybody know why create react app puts things that are obviously development dependencies under runtime dependencies if you have a good answer for that or you think you have a good answer for it type it in okay i was just saying i'm going to go do this install npm i'm going to do it from the command line but one of the cool things you can do in web storm is i could just say prettier here and it will autocomplete and i can choose it and it will do the lookup for me crap i'll just go ahead and do it here all right so now when i save this the ide is going to say hey it changed do you want to do an install why yes yes ide thank you thank you for being so helpful all right yarn installs running going and getting 500 000 npm packages because that's the way we roll in front ends these days aha everything goes into dependencies yeah i got some learning to do on that good point good point uh andy it had the picture up and then it went away uh andy it had the picture up and then it went away um so now i have prettier installed i need to tell the ide to use it for formatting instead of the ide's formatter because i don't want to have to run some other commands reformat my code i don't even know what command alt l is my hands know they do it automatically i just kind of start thinking and my hands type it themselves so i'm going to go to prettier and this is in the preferences and i'm going to say i've got a prettier package installed in node modules now use it you don't have to go get it globally or something and then this is the important part i can check zero one or both of these and i can say uh run prettier whenever i choose to reformat code i could also run it on save i can also go to the tool window for this and do all kinds of interesting things this was introduced in introduced in the last release i believe 2021.2 so back in prettier i'm going to do it the simple way i'm going to say on reformat code and now watch what happens you see that single quote i'm going to reformat code and because prettier has a different opinion than the ide it thinks things should be double quotes when i reformat code it's running prettier all right so that's great we have prettier running let's do a little bit of cleanup i'm going to change my top level component to be super simple okay and i'll run prettier get some indentation on it and i'm going to put a little heading in there to get it to say uh let's see hello react and i'm going to use emit to do this uh i'll get rid of this as well so i cut and paste it and cheat it but i could say div dot h1 tab and then say no that's not what i wanted uh oh yeah sorry it made a class name for that and then tab have that h1 okay div h1 i have messed this up up i won't belabor that i'm obviously typing something wrong here and i will say hello react all right oh okay no space that's what oh yeah you're right div h1 no div h1 yes tab oh my apologies that's something i do all the time i don't know why my hand didn't automatically understand it okay so we have now a very simple react component that will form the basis for our testing later but we see that we've got some problems in our code now uh in fact we have two and let's see logo is defined but never use i could go back up to the top and just delete this but that would mean stopping what i'm doing and breaking out of the flow instead i do optimize imports and that's the key binding for it and that will remove any unused imports and it will uh resort my imports combine my imports where necessary without moving my cursor and that's a great great thing for me optimize imports or reformat code i do all the time now other cleanups i can do i'm not using app dot css or load uh anymore so i can delete that line and then i can delete these two files since i'm not using them anymore so that's logo svg and app dot css i'm going to delete that but this is smart delete it's going to say do you want to go look for anything that might be using it i'll say sure great and nothing was using it now let's take a look at if i deleted something that was being used like okay well if i'm deleting css let's delete some more css uh oh wait something's using it what is using it oh the top level thing is using it let's not do it all right and then some other things if i uh keep that line out in some cases if you don't uh in older versions of react or depending on how you set up your project just like pre-react 17 you had to import react if you were doing jsx and then the ide would give you a little warning and say hey um you need to import do you want me to import it for you and you say yes and it does the janitorial work for you it's interesting create react app still generates this import even though we're clearly beyond react 17 all right great all right we've gone through some of these cleanups let's look at uh we talked about this ide goodie where if you are on earlier version and you delete uh the import of react then you will get this warning that you're missing an import and you'll get an alt enter which will be a friend of ours during the course of this workshop as a help and then you choose the action and it generates it for you let's do another thing let's say that app is such a boring name i want to change it to my app well what we could do is go look around everywhere in our project and find all references to app hope that we found them all and change it or i could refactor i could refactor rename and say my app and you see as i type down on the bottom it's changing that reference and when i'm done i hit enter and it does even smarter than just finding references in the world of react there is a convention a single responsibility principle that you name the file the same name as the default exported component so if the ide is helping me saying hey remember there's this style guide you might want to change the name of the file yes in fact thank you ide i do want to do that now when i go look at the usages of this like the index.tsx top of my app its import is now different it's importing from a differently named file and it's importing a differently named symbol my app is still in good working condition because refactor rename went everywhere and did the right thing for me including in my test code test code let's say i then though decided oh no that's dumb because everybody names it app if i name it my app then no one will know that that's really the top level component hey ide can you put it all back the way it was can you change that function name to app can you change the file name to app can you change the get reference can you change all the things that point at it all you have to do is an undo and it's going to undo everything that was done in that action so the file name is back to app get is back to app and the things that reference are back to using app that's a really handy thing for all of our refactorings that you can do and undo and put things that entire unit of work you can put it back the way it was before okay next up we're going to do actual testing the point of this workshop now that we're all set up i will pause for a moment anybody have any questions i see reggie talking about optimizing imports in vs code least mac os and that's again this is about ids in general smart editors this isn't focused just on webstorm let your tooling do the janitorial work for you which also means spend a little bit of time learning your tooling you're a professional get good at your tools leave time during the week to brush up on your old skills and learn some new skills the 10 minutes or 20 minutes that you spend will pay off during the course of a year all right thanks dylan by the way dylan is my audio too loud or too quiet i have a habit of talking loud all right thanks jen and sherry i agree with you about running them as a combo which is something for webstorm at least in the previous in 2021.2 you can have that all happen in a configurable way okay over to testing i call this test first instead of test driven development because what i want to convince you of is it's not eat your vegetables no one okay you have a choice am i going to eat the dessert or the broccoli you're going to eat the dessert instead i want to convince you this is a more pleasurable and joyful and productive way to work to start in a test i'm not trying to convince you quality uh quality is good but the point here is what's the best way for me to work right now and we're going to show it from the from the perspective of testing all right so as you come through this again all the code is linked from here just is the test runner that the world of react seems to have adopted it's also from facebook i believe and ids such as webstorm and others have great integration with just and for our ids our ids all have a consistent ui atop any test runner so you learn one you learn them all across all of our ids and just is wired into that so let's run our tests the way they are right now but under this pretty face that we put on top of just uh jun you are correct that you will run into some errors um what you can do though is have your stub code just return dummy data to stop the errors as you're filling things in but as you'll see during the course of this uh because we're doing really fine grain small components fine grain small components you can point the test at this very small thing and ignore the rest of the universe and so you're only getting a couple of errors which is happens to be the thing you're thinking about at the moment so jun ask me again in like an hour and a half and see if you you disagree with this approach so what i want to do here is i want to let me get myself set up on the other monitor what i want to do here what i want to do here is um get a pretty face on my testing and this is in this segment pretty just if you're following along so what i want to do is be able to walk up to a test and in this case my tests are in app.test.tsx and just like package json i get these icons where i can run things directly from the gutter and it will run just this one test or i right click somewhere in the editor or i right click somewhere on the tab and i can run everything in just this file so i'm going to do that i'm going to run app.test.tsx test driven development test first development in the world of react is a little slower really actually in the front end world a little slower than other languages such as python because you have the whole transpiler cycle you got the whole typescript compiler cycle to do before it can actually execute the code so in this case we got a pretty face on our test output we have a tool window dedicated to testing with a little tree that shows all the files that ran and then within each file each test that ran and some little icons that tell you what failed what passed and in fact it goes back into the test code changes the gutter icon to show you that it failed and puts a little red or a little squiggly letting you know that a test failed and why so you don't have to go to the tool window you can stay in your editor and stay focused on text output now we know that this failed because we changed it during cleanup so it would no longer say that what we can do though is set up a run configuration that has all of our correct options that runs all of our code rather than walking up to a single test i actually find walking up to a single test to be the way i work most of the time but sometimes and this comes back to what june is saying sometimes i want to run all the tests to see if this change here broke that thing over there so let's create what in our ids is called a one configuration test i'm going to manually create a run configuration based on just and i'm going to say all tests our our just one configuration knows about just it knows certain things that you're going to want to do with chess in fact it knows that not only are there just options they give you the placeholder text that tells you what some of the options you might want are and in fact that's the option i'm going to choose i'm going to choose the dash dash watch option now when i my my drop down for the available configurations list the thing i just ran which was the single file and then this new configuration called all tests and when i run it i'm going to get kind of the same output but i'm going to get the same output but it's still running so that if i came over to here and i see oh it's hello react i need to fix my tests as soon as i save it's going to rerun my tests i don't even have to do the action to run my tests i just have to type and save and it will do the rest so i've now fixed my tests they're all working lucien i'm getting to that in the next segment yes is it the next segment or yeah down here all right that is the way i do is a split windows approach so let's get into a little bit more of tdd in action where i do something that fails i kind of know it's going to fail and i see the failure and then i look at some of the things i can do and then i fix it so i'm going to put in this code here and see a little bit of autocomplete in action i'll make this a little bit smaller all right i'm going to say what i call that actual expected const actual equal one const expected equal two i could put those on the same line i'm going to write a test assertion about this these values that happen to be embedded in the test but that's actually okay as you're doing a test first approach and i want to expect actual to equal and that's how i'm doing autocomplete there i don't have to type the entire thing to equal expected complete the statement save and my test fails and it tells me exactly why my test fails expected and actual were not equal and again if i come back change save didn't type the action it's watching and it reruns the tests that's an interesting question chris at the top of this just before you joined i used create react out 4.0.3 and then everything is the same since then which i mean i believe it means it got its own typescript but that wouldn't affect this so i don't know if for some reason you got a earlier version of um oh yeah okay i suspect it's because hello react is different than this make sure those two things are the same i hope they are the same because otherwise i'm gonna have a hard time debugging this man all right we just did test driven development we wrote a test it failed and then we saw that it failed and we fixed it and along the way we saw that the ide will help us fail faster by putting bleep in our face red squiggly on this assertion it failed gutter icon changed to red letting you know which test failed down in the test runner output one test failed one test passed or whatever and you can do all these different ways to navigate to your successful tests and your failures in that overlay let me go back to that overlay make this test fail again i'm increasingly using this as my entry my window into test running i just put my mouse over that it tells me what happened and most importantly i can click that and it will launch the test in the debugger it'll run just under the nojs debugger which is integrated in web storm and it will stop on that breakpoint and i can step around and see what values are and i can even say things like expected expected expected plus one etc and then when i'm done running the tests the debugger shuts down and it removes that breakpoint so this is a pretty rich way to develop and i'll go to the end of the story i never went to the browser all right tdd basics this is what uh let's see lucien was talking about this is the way i develop it appears to be the way lucien develops as well i don't like distractions i like focusing on the thing that i'm currently doing and i'm a man of a certain age i can't be bothered to remember 500 tabs and i need something to trick my mind into getting into the flow of testing getting into the flow of working slowly deliberately joyfully under control and so the way i do that is i hide the project tool i actually turn off tabs i go to the action tab placement that symbols oh sorry actions tab placement none i choose that so my tabs go away and i split my windows this is all in the text by the way and so then i have my code on the left my test for that code on the right and my test output constantly running on the bottom and i work and i fix things and i implement things and it's all on the screen now sometimes when i'm on my big monitor i take this test window and i turn it into a window that i can move to another monitor and then i really can concentrate code on the left actually no you're i'm backwards for you code on the left test on the right and in this case test runner output on another monitor all right let's make a change in our code that will break this i'll go ahead and delete these three lines save my test run okay my test run okay the other one that i just closed wasn't in auto run mode and if i change something in my implementation and then my tests break that's great because i'm i'm looking at this i'm sitting on it i don't have to go to some other tab or open some other file everything i need for my code my test and my test runner is on one screen so congratulations you just did tdd you just made a change that caused things to fail i will revert it back save things will be fine we remove those lines you may have seen that bumping that jumping of the icon on my big monitor over here i got a desktop notification saying that my tests passed so really i could even hide that tool window and know i'm going to get a desktop notification telling me something about my tests all right i'm going to pause here let's see we've been going for an hour i'm going to pause here and see if we have any questions chris is interesting to see what this is going to be chris is interesting to see what this is going to be i see that has enzyme in it and we're not using enzyme and that's react 16 so it's kind of old chris did you use the latest and greatest create react app i think it's 4.0.3 to generate your project all right let's see all right the question about let's see lucyan do you put your do you do it the other way do you put your code on the right or do you put your test on the right chris i apologize that is obviously my fault i thought at every step of the way that i correctly updated um the package dot json's so obviously i left some stray artifact in there so that is my fault i apologize uh can you tell me um which tutorial step you were on and what was the can you tell me um which tutorial step you were on when you clicked uh get the code from the repository was it the first one project setup so is it here you went here and you clicked here project cleanup oh man i gotta clean up the cleanup god it's hard to keep this stuff in sync i apologize seriously um okay we're going to get into testing and debugging we saw it briefly so i won't belabor the point uh back over to anton in this question about enzyme that's a good question i was a big fan of enzyme and the original version of this tutorial used enzyme but then create react app i don't think it ever bundled enzyme but they started bundling react testing library which is created by kent dodds and kent uh had a great article explaining why he wrote it what problem it was solving and it really resonated with me versus enzyme his philosophy is write the tests that mimic the behavior of the user don't treat it like software write it treat it like people will use it kind of the public interface of the rendered output but you're right enzyme was more familiar to me as well uh but i think it's pretty clear all the energy is now behind react testing library because facebook kind of anointed it as the bundled one it was i'll admit it was weird for me to switch um like for as an example there isn't a matcher for id which killed me when i did an update later in this tutorial and i really needed something to match on and so i just kind of artificially put a title attribute into the an unneeded title attribute into the tutorial so that i would have a matcher okay oh fighting words okay thank you for that link about uh adam thank you for that link about uh writing tests and it looks like all right so lucy and does put his test on the left okay in this step we are going to uh go over debugging i probably won't demo it since we already did but the oh wait no actually i have to do some uh development in this so we're going to do a little more clean up we're going to parameterize um our component a little bit which will then generate some test-driven development and we'll let the ide help us with alt enter and then we're going to show creating a problem and solving it through debugging okay let me get myself set up all right i will begin by getting it i'll act like i walked away from the project came back to it get things kind of reloaded into my brain um and it needs to say hello react so i save it and i will bring up the test runner output and my test run my test pass okay good i'm back in the flow i'm back in the testing flow what i want to do is parameterize this app component and so what i'm going to do i'm going to break the rules i'm not going to do test-driven development i'm going to write the code and write the test second then later when you see the reverse you'll kind of see why we do it that way all right i'm going to write a function called label this is a component this is just a uh like a helper and it's going to return hello react um and then i'm going to come down here and call it and when i say everything's great nothing breaks in the test because we haven't really changed the public interface of this but what i haven't done is written a test for this function so i will come back over here write a test test that it generates a label i guess that shouldn't be capital g this is an arrow function this is an arrow function and the arrow function will first get something some output to test so i'll say result equals label i'll do this mistake on purpose and then i will expect result to equal uh hello yeah complete statement and when i save it will fail why will it fail because label hasn't been imported i can let the ide do the janitorial work for me walk up to this hit alt enter and have it generate and have it generate the import when i save the test rerun and my test passed so i kind of did a little bit of tdd on this um and what's pretty fun about this is this is testing just the javascript function it's not part of react it doesn't have a dom or component or anything like that so it was pretty easy to do that uh let me go back over to the tutorial and so in this we just did this and we want to make their function a little more dynamic it just says hello react we want to have it be parameterized so you can say hello world for example or do something like capitalize the thing that was passed now we're going to do test driven development we're going to change it to break so i'm going to change this to react all upper when i save it fails adam is right uh right it says exactly as a user would interact with it that's kent's big point which then i think at least encourages writing small components so that you keep your velocity up so my test failed now i have to go to the implementation and fix it i need to implement the behavior that i'm testing and so what i want to do is come over here and accept the parameter called name and then i want to change this to a template string thank you ide and i want to say name dot uppercase now you see i don't get any help from the ide on this it doesn't know what type oh wait yes i will now when i save in the test run in the test run test fail because i'm not passing an argument in and it's null so what i want to do is change my test to pass in a value in this case the i'm failing faster the ide is giving me red squigglies saying you violated the contract on react i didn't even have to run the test to know that i failed much less ship it into production and have my users tell me you forgot to supply an argument here so now when i supply the argument test run and let's see label yeah i'm not supplying a value down here either the other place that i'm using it so my test here passed my test up here didn't i'll go ahead and fix this one now by putting in react now my test pass but i'm getting a warning in my ide what's this warning this is where typing comes in this is where typescript comes in typescript is telling me hey we're a typescript project you didn't put any type information on this function parameter i could go type in the fun the typing information or again ids are good at this kind of thing maybe they can help you i'm going to do alt enter and i'm going to say infer and the ide in this case or maybe the typescript language service looked at my code took a good guess at what name was supposed to be and provided the type information for it so that worked out pretty well i've got a i wrote a test i wrote some implementation i cleaned up some of the typing information i have confidence remember i never went to my browser i stayed in the flow in my tool so the ide gave us an alt enter we fixed the typescript problem but let's say that we do something that we just can't figure out we're like tired we've been staring at it all day we know it's a stupid dumb obvious problem i can't figure it out i'm going to pass in 42 all right and my test is going to fail now again fail faster i've got a red squiggly this is where the combination of typescript and test first really helps me but in this case let's say i'm not even looking at the squiggly i'm like what is going on i can't figure this out you know what i'm going to do yolo i'm going to run it under the debugger i'm going to poke around kind of interactively see what's going on and and see if i can stumble across the problem so execution has stopped in my test this is another good thing about if you want it right left or left right but in this mode where you've got your code your test and your test runner output it's all very familiar where the bodies are buried on this line in my test and i can step through the code in this case i think i'll step into i'll just step into the code execution jumps into label because we called label and the next step was to jump into label and it puts my cursor here i get to see the value of name i get to see the closure i get to see the globals all these things i get to see the stack trace if i want to like go up higher and see what everything was higher up in the stack and i get to poke around so i could say all right and what is going on with name it's 42 huh all right let's see two uppercase oh gosh that's the problem i passed in an it i didn't pass a number i didn't pass in a strain that's what my problem is so i was able to poke around see what the problem was realize my mistake and make it a string when i save at the end of that little poking around session find the solution to the problem rerun my test everything's green i'm good so we use the combination we actually just use a really cool combination we're writing components and we want to write components and stay in the flow we don't want a context switch between an editor and a terminal and a browser and where am i and i combined test first i combined typescript and i combined debugger to have an experience that made it really easy for me to get into just the spot i want to be in and poke around no console.log statements all right so we stepped into our code we saw what the problem was let's kind of put things back where they were we got out of the debugger we'll close the debugger tab put it back to being working correctly and we're good our test pass we can go on to the next step i will stop here for a second take a look through some of the comments uh let's see steven's got a good point that and that was what resonated with me was with enzyme i was thinking of my tests kind of like implementations and i poked at the insides of things and not only was that not valuable to my customer who didn't care about it it actually created this huge maintenance burden because whenever i would change the internals i'd have to go fix all these tests that were broken for reasons that didn't really matter um there's this other strategy of you know making sure you understand tests are both good and bad they're like this weight that you're dragging around on your project and when you refactor things you got to go change a whole bunch of tests let's get a link for the guy and i'll paste up to the top of the guy where you can see a bunch of tips all right so that covers that let's see if there's anything in here yes inferring the type information is really nice um that's a good question about mocking in the world of python mocking is kind of controversial uh sometimes people call it a smell uh i would be interested in others who are doing testing here do you use just dot mock very much uh i know in gatsby i do uh therapy sorry okay back to this i i'm going to i'm gonna skip over this segment because it doesn't add anything new to the important part which is teaching about test driven test first development just understand that if you have a need you can execute your tests in the browser's engine or i should say to execute your you can debug things in the browser's engine uh i stay away from doing that but uh web store makes it really easy to do that i suspect that other tools do as well and so in this case what i will it's all written here you create a run configuration that is about that and then we wind up talking the chrome dev protocol to remote control chrome's javascript engine and we execute the code over there but it looks and feels over here exactly like you were executing under node js and you can step through code step into code see your test fail all that other stuff and what you have is over here you have a private chrome window running under its own profile so it doesn't mess up your personal chrome usage and then at the end of your test session it closes that chrome window blows away the profile so it can start from scratch next time it's actually pretty slick i just prefer staying in node js which uses js dom currently question to the audience has anybody seen any rumors about replacing js dom which is the implemented in node js javascript browser simulated browser replacing js dom with that other thing that i can't remember the name of all right looks like uh people are using mock good makes a lot of sense in browser applications to replace fetch and axios and things like that all right onward we're going to look at using some features in tsx and ecma script 6 and seeing how the ide can help complete things for us and keep us on the right track we're going to clean up our code and tests a little bit make sure that your test configuration is running i'm actually still running my web server my dev webpack dev server i'm going to stop it because you know what i haven't gone to the browser in a long time i've been writing components writing functions writing tests never go to the browser exactly the way it should be baby yes uh let's do some cleanup let's put app dot test dot tx back to its kind of original state i'll get rid of this and i'm going to get my component back to just having that so hello react get rid of this reformat code optimize imports because i do that a thousand times a day okay okay alexa is saying that he does like running things in the dom uh headless and i guess that's you know karma is big about that in angular alexa i would ask you would you would you prefer using cypress for that instead of just and say just have two basically parallel test suites one that is about testing/talks">unit testing and one that's about kind of browser testing okay there you go cypress cypress for everybody unit tests in cypress okay all right all right i learned something today i learned uh okay back over we're back into a blank slate spot and that was my timer for giving us a little bit of a break we're one hour and 20 minutes into this audience poll do you want to break put yes for break no for no break it's 50 50 it's 50 50 so we will do half a break we will do a three minute break so i have it is basically 20 minutes after the hour at 23 minutes after the hour we will break okay so i'll type it in both 23 minutes after our we resume i will get some water also all right be right back you you you you all right so that's a good point i like to say about not testing visibility susan the uh uh postman for apis is pretty cool uh we uh our ids have this htp files thing which lets you write in a file the request that you're going to issue and then it feels a little bit like um you're in an ide and an editor it's actually kind of cool paul just a note your zoom chat is stuck with dm so just make sure you switch to everyone oh my zoom chat is stuck with oh gosh thank you sherry so okay we will begin or we'll resume we will resume uh what we're going to do is uh we're back we've got it back into a working condition um all right and what we want to do is start doing sub components refactoring because that's what react is all about making big rocks into little rocks and we will do this refactoring kind of in a test first way so that we will work with confidence but we will stay in the flow because we don't leave our ide we don't have to go and look over at let me turn off the ding we don't have to go look at the browser all the time my apologies for the dinging so i'm going to make a sub component but i'm going to go to my test first and i'm going to write a test that will be broken but that's okay i expect it to be broken because i'm still in the process of writing the implementation so here we go let's actually do test driven development i'm going to sit in app.test.tsx i'm going to write a new test let me make sure that i'm good that question about cypress five minutes ago i would have said yes but alexa is trying to convince everyone that uh that we should be using um cypress for unit tests alexa got to get you to come on a webinar with us for web storm and show this to everybody including me okay i'm going to render the heading renders a heading and i'm going to make an arrow function i'm going to start using the react testing library a little bit i'm going to say const i'm going to i'm going to destructure this is an esx thing i'm going to destructure the results of rendering and grab one thing out of it a closure called get by text and this is going to be running render like we do above and like we do here and so i'm going to be in this case rendering heading which smart people will see doesn't exist okay and then what do i want to do with this text i want to go grab something out of the out of the fake document so i want to grab a link element like i do kind of above get by text and i'm going to expect it to be this regular expression again and then i'm going to do my assertion expect link element link element to be in the document now when i save what do you think happens it breaks because heading doesn't exist yet what we want to do is make a sub component out of this this and what would i do normally i would go up here i'll go to another file i would start typing our ide is smart it can help us with these janitorial tools so i'm going to say hey ide can you help me refactor this by uh extracting this to a component sure what would you like to name this i don't like this heading do you want it to be a class component or function component function is the new sexy so we're going to have a functional component and it took that it made a new function it replaced the play it did everything i would have had to do myself it it put a call to that function here i will it even did prettier for me gosh you're so smart thank you um now when i save my tests still fail because i haven't imported it but that's okay fail faster red squiggly to me it told me there was a problem so go and get that import for me let's see oh it can't import it because i didn't export it so now i can generate the import it generated the import for me i no longer have something called label oh that was left over i removed that test but i didn't clean up my imports so now i did test-driven development to extract a sub component i wrote a failing test i went over to the parent component i found the thing i wanted to extract i selected it i asked the ide to do a refactoring it did the refactoring for me i had to add an export and i went back and generated an import i will show again how to let's say i want to convert that to a component so this answers the question how to trigger extract component you bring up the refactor menu so on mac it's control t i'm about to hit it and watch in the bottom of the screen if you want to see the windows for windows key binding so refactor and then i chose extract component and i did that by typing speed typing i could have hit zero i could have used the mouse whatever so i brought up the refactor menu and i chose extract component now i've got this entire thing selected i don't have to i can just click on the symbol and initiate it from there all right let me come over and look i see there's a beautiful conversation about in zoom about why is it awesome about about testing that's all great stuff now i'm violating single responsibility principle so i've got a sub component heading in the file of the parent component app so what i think i'd like to do is extract this to its own file and then write its own test for it can the ide do the dirty work for us probably otherwise i wouldn't be making this point right now so bring up refactor move i should say i didn't select all of this i just put my cursor on the symbol refactor move then i'm going to get a dialogue where would you like to move it too look what it did it filled in the file name for me the exactly way i wanted it to be it gives you some choice about some members to move later we'll see how the props the type that we use definition we use for props can go with it i'll go ahead and hit refactor it opens it asks me to add it to get i've got this here and look what i have back where i was where i was and import replaces the definition that i have clever folks will see that my test didn't get dragged along into a new file i suspect that probably is asking too much of the ide so i would like to move this let's see okay i don't think i can extract this no i can't all right so i will take this and i'll make a new file called heading dot test dot tsx paste this in there notice when i paste it pasting has the habit of generating the imports that i need for me okay and then i do have a little bit of leftovers back here a symbol that i don't need from the import because i'm not i'm not testing heading in this file app dot test dot text anymore i could delete it or i could say hey ide clean up on aisle five go run optimize imports and now that import is gone this test file single responsibility principle it's about app this test file single responsibility principle it's about heading save everything one more time keep my cpu fan going and all of my tests and all of my files run okay good and let's see yes beauty of unit test is speed speed of execution a second benefit to this i wonder if lexie would agree with me that a secondary benefit is not hauling around the universe when you're refactoring a unit test should really focus on a unit so that if something else changes you don't have to go to 100 things and remember try to remember what you were doing six months ago so okay so we've done the heading sub component we did the refactoring we did the extraction and it's in its own file now let's see i think i did it yeah i did it out of order i apologize so what i want to do is bring back arguments and add defaults so that my heading is parameterizable so i'll take this test i'll go i'm in the heading test file and i wrote a test so that we could pass a prompt called name to our heading and i haven't even run the test runner yet and i know it fails because i got read squiggly because of time script time scripts telling me what my problem is but i'll go ahead and run it anyway let the test fail and we kind of saw what was going to be happening over here we need to put in a parameter in this case though since it's going it's a function we're not going to pass name as an argument we're going to be getting props and we need to destructure the prop name from it and so i'm going to say name which allows me to here say am i doing the two uppercase no i'm not i will save and this test will uh let's say i need uh all right i'll slowly but surely uh go through some of these things and fix them so that should be oh dollar sign duh i'm not in a literal problem okay so this test passes this test fails because i now have a required prop i've done a refactoring which broke the contract and other usages of it are telling me that the contract was broken now i didn't have to run the test to know that i failed because i got a red squiggly for that so what is the solution for this we get into props and typing now the first stab at this will be to inline the prop type information i save that and typescript is happier about some of this but i don't have a solution to this yet i want to be able to use heading without passing in an argument the first thing i'll do though is instead of inline type information just about everybody puts the prop types in a standalone symbol in typescript for the longest time i used interface i still think most people use interface i saw a good article saying use type not interface because type is more limited and the typing information you should put that you put on type on props should be limited so i could extract this and go start typing type blah blah up there come back type some more stuff here do you think i could extract an interface do you think i could do refactor and something about interface why yes i can oh got to be inside so let's see and i'm going to call this heading props and you'll see what it did up here it created something called interface heading props let's see i want i said extract to an interface on this so all that preaching i just did about types you know etc so i'll leave it as interface because i think that's what i have in my tutorial do i now let's see that's what i wanted to do okay okay already formatted so i've extracted the inline type information about my props i extracted it to a standalone type and then referenced it and this is so easy to read that's really cool to see all right now i still haven't solved the problem about the default prop value what i want is to satisfy the old contract by using an es6 default argument so let's go do that let's fix this so that hello react still works and i would do that by putting a default argument here but something else is going to go weird here run my tests and my tests pass i'm green i'm green i'm green i'm green i'm green but typescript is mad at me typescript is mad at me on this lie why is typescript mad at me let's hover over it i think one of you has your microphone on we can hear some background noise typescript is telling us exactly what the problem is telling us exactly what the problem is it's in heading props and it's saying that something is required name is required but it's not being provided here so what i need to do is tell typescript that name according to this contract is actually optional because we have a default argument save that test still run typescroller typescript compiler is happy we're all in a good spot on this and if i would have done that in the very beginning of this refactoring i wouldn't have had that broken test if i would have said okay optional you don't have to pass a name to a heading all right and i went over the single responsibility principle already we already moved the type the component subcomponent to its own file what i should point out is well i will do i'll pretend to say subheading it's going to refactor and extract component extract um anyway when i brought it up it would have given me the option to take not just the component but also the type definition and move the symbol to the new file so that's a pretty smart approach to the refactoring take the subcomponent that you want to create and all things that it depends on and move it to the new file we are in good shape from a single responsibility principle perspective uh i think i'll skip over this a little bit the jsx and the tsx um about i think most of you know that if i say class it's broken in uh in jsx tsx because that happens to be a reverse reserved name in javascript and typescript the class statement so react tells you you have to name it class name and you get a lot of help for these jsx tsx things thanks to typescript that can pop up these really meaningful error messages about this isn't allowed on that in fact that was the thing that kind of got me in trouble in the rewrite that's still there in the videos you can't use the label and four elements on spans which i was using they're only on input elements all right so that lets me skip covering that last part what we showed in this was a combination of two things that help us fail faster and stay in the flow test first development and typing typescript and the combination of the two you don't have to ship it find out you failed you don't have to run it in a rouser go sprinkle console log 50 places hope you trip across it you don't even have to run your you don't have to write a test you don't have to write a test and run it to find out you failed you can get a decoration in your ide saying you broke the contract all right we'll go on to the next step and let me set the timer so i'll be in good shape here i will take any questions i will look through some points from the chat feel free to tell me that i'm going too fast or too slow talking too loud whatever um let's see i think i'm up to date on all of this this point about uh testing the contents of a child isn't relevant that's a good point that's actually i think something from enzyme right shallow versus mount uh that took me a while to stop thinking about when i was switched over to react testing library mocking callbacks these are all great points about mocking child components um let's see that's a sherry that's an interesting point about the ide you know i'm i'm python and i'm web and javascript those things weren't written they were written to be so simple you didn't need an ide but now with bigger systems and where the things like react with sub sub sub components and things like that the tooling can actually help um and and i hope that smarter editors and ide's can really deliver some productivity gains on this uh alexi good question about get by text and alexi do you find yourself or does anybody find yourself using the data dash test dash id escape patch in testing library whenever i do that i feel like i've done something wrong good question about code coverage i'm much bigger about coverage in python than i am in javascript i don't know why it makes no sense but it just wasn't part of my culture to do coverage then in in fact the ide makes it really easy to get coverage output integrated right in your in your editor i should do that more uh good point steven about recommendations on which assertion library query thingies to use uh i guess async factors into that a little bit uh 88 that's just a great number why not um and so brandon uh we were talking before about it a little bit that uh on what to test how much to test and that react testing library is really changing people to not test the implementation but test the way people are going to use the implementation and so as you detect copass like oh this component is not going to show the heading if this evaluates to faults then write a test for something like that uh don't just test one state of a component storybook anybody using storybook because storybook really helps promote that idea of all the variations of a component oh look some storybook fans out there all right okay let's switch over to class components just for fun uh to kind of set us up later for talking about state we've been doing functional components right now currently anton's building a project with learn and storybook all right that's a good combination learn has been around for a while i guess learn is looking over at yarn two saying uh-huh come back to me when you when you get this story straight yarn two uh class components with props we're going to do something similar what we just did a prop but that was with the functional component this time we're going to see the similar kind of ideas about type information for prompts but in the context of a class-based component i will admit i'm not a functional programming zealot if if there's something that i feel expresses itself fine as a class i do it don't hate me we're going to make a new file we're going to be making a counter i've already the name of the component already gives away where this is going there's going to be some state and we're going to use local state in the component rather than redux or emmer my new faint my new best friend and so i'm going to write a test first let's save some time cut and paste cut and paste for the win over on the test side i'm going to create a new file counter dot test dot t s x look how fast paul can type test is broken and typescript is mad for obvious reasons wow doesn't exist but that's again fail faster typescript told us that doesn't exist we will get a starting point here again i will cheat and not type this we're going to be doing a lot of typing in this as we go through this so that's fine i would like to remind you especially if you jumped in a little bit after the beginning i don't have to run all the tests i can walk right up to just this one test and run it or run just the counter tests by doing this all right we want to resolve the import now that it's there oh actually as soon as i pasted it did it for me thank you or it detected that it was there thank you ide so i have a counter and it is rendering a label and a counter it's a span with a title this is the evidence of me finding out that react changed its or react typescript typings decided to disallow label and four on spans so this is the public contract there will be a label with a value and then there will be another span that has the actual count and i'm testing both of them the label and i'm testing the count let's see if there's anything npm audit yeah yeah i guess i kind of did trust yarn one's audit and i didn't trust npm audit but that's a good point i wonder if there's any progress on that does anybody know if npm 45 is ever going to have audit capabilities okay there's a question about checking to see if count to to test instead of in the test instead of in the document good question i could be checking to see if the value just checking that um i guess at this point i don't want to over test and if i change my mind my test break and you know if i say this count this test will still pass but if i tested the actual value it wouldn't and i guess i've kind of made my decision i don't really care what it says but you got to have a label like if you localized it to have a different word for count okay we're good we're going to show with class-based components how to do a prop and we're going to do it using this consistent process we've been doing write a failing test fix the new dumb component and then go to the thing that calls it which we don't have anything calling again and make sure that that uses it correctly so we're going to add another test for the case where we're passing in a label think you know how this movie is going to go it's going to break pretty fast so cut and paste i'm still in the counter tests it failed pretty fast why did you fail and i haven't even run the test yet why did you fail oh you're telling me exactly why you failed because label is missing all right but i will run the test anyway just so that we can see that the tests also fail wait no the tests don't fail because i'm pat and it's a typescript failure this isn't a runtime failure all right so what we want is more typing on our component we have our component here and we want some typing here and what we want to say is we saw this before as well in line typing of the props and when we do that some things change it's optional the question mark so this still passed but we accept the passing of a label so this still is fine with typescript but what we want to do again is we don't want that type information in line so we ask the ide to extract it to a standalone type and i choose type alias and i'm going to say counter and it makes a type definition for me that has the optional label so typescript is happy just as happy i'm happy component is what's called a generic and for the class of a component and we've moved it to a standalone the type definition says label can be optional can we have a default value though and this is trickier now because before when we had the heading we were passing in to a function the value called props which was an object that could be destructured and es6 destructuring supports this but we're not in destructuring unless i have a constructor or something i don't know if i can do it for that so where can i say a default value for the label prop so what i'm going to do is start here and i'm going to say in my render i'm going to do destructuring again which then lets me have a default value which only kicks in if the props this doesn't have a label otherwise the thing that's passed in is used and so then i need to do this i'll just come back over here now when i save run my tests all my tests pass and i have a default value for the count so using the locals for render let me take a look over here and see all right lexi has used data test id lexi when you use it do you always have the feeling that i'm doing something wrong this should be done a better way elena i think there were answers to your question about the localizing um adam gives a response from it but this tutorial is not about uh accessibility and and localizing um all right thank you elena okay now we need to wire in the ui it's not actually in our application yet because our parent component isn't using the counter so we need the parent component component to use the counter i'm going to go to app.tsx and i'm going to add it just after this do i need to stop and go to the top and add my import and then come back where i was try to remember where i was try to remember what i was doing no ids these days type script language service can automate all this for us so i want to result in a counter with that label i can just start typing and it's looked in my project it's already indexed my project actually so it knows where all the bodies are buried and i can just choose counter it knows the props so i can choose label and i will say what's my current so it generated the import for me when i did the autocomplete so we're in good shape we now have something using our counter but our tests didn't break because the app test didn't really even expect that to be there we should have written the test first before we added this all right let's do that so my test pass but i want to test in app to see if the label is in if they i'm only going to see if the i'm only going to see if the component is in there not every single thing about the component the sub component because uh it's not really necessary so they render oh i'll just uh take the whole thing cut and paste it it's doing a better job of testing anyway so this is the top level app we want to see whether that text is in there we want to see if our component counter is in there and so we're doing to do the same thing we just had in our counter test this thing we want i just really that's all i did was i cut and pasted this to here it's failing pasted this to here it's failing because i went back in time and pretended that i did tdd and i haven't put it in yet so now when i put it in i see did i implement this correctly well sure i did because my tests pass yay so now i have a test that proves my counter class component component is in the parent app component so that's good news we are all good so far and i think that's a typo no no it's not a typo it's encouraging me at long last can we finally take a look at what it looks like in the browser so i'm going to go back to my start script fire it up it's going to generate the browser or generate the bundle dev server etc and i actually see the counter component styled poorly because it's two spans showing current and one all right i will go get started for the next part stop take some questions take a look at time stop take some questions take a look at time and we have one hour left we're going right on time okay lots of plus ones for storybook yay alexis typing in discord so i'll go back over to the um zoom chat susan uh hopefully i got it right it's not susan uh correctly poking me about not putting a test first you're right should have done a test first um let's see all right we're up to date on that uh alexis asking write an integration test first to make sure the app is using counter i think that's similar to what susan was poking me about that i should have done that first before pasting it in wonder if i did it right in my text let's say my text nope i didn't my text didn't my text broke the rules i should swap that and that and put the test first note to self i will never remember that note all right let's see what else we got get my title is expecting two to three arguments you got it working what was it done what was it that went wrong with it uh alexis right that now that i've got kind of the integrated tests if i change the inner structure of counter then the app test will break and the counter test will break and so the question of on parent components with child components should you test the structure of the child components or should you just see if they are in the document alexis my name is the document alexis am i saying correctly the point you're making that's really a question of yeah yeah so there you go uh yeah i guess what you would do for that is there a react testing library selector that says a component is in a tree i guess there wouldn't be what you would wind up doing is on the counter you would put something on here that said hey i'm you know class name title or what some selector that was visible data test here we go yeah data test uh uh let's see i restructured get my title oh yeah okay destructuring bit you huh all right and did you get any warning from the typescript language service dylan when you did the destructuring wrong should you have how good all right you got red squiggly do you fail to faster great all right some comments over in discord visual testing i'm interested in something like that as well kind of like that i've seen some things where they can snapshot essentially the pixels of a page and then compare later and see if your css layout changed i wonder if you're talking about something like that uh i believe it's florian but also mentions that you can do some of the computed properties to see if things are in the position that they think they are i suspect that's a cypress thing though it's not going to be a js dom thing cypress does that june says uh all roads lead to cypress right all roads lead to infinite energy consumption when running your tests all right i'm going to move on and we're going to go back to this is why we switch from a functional component to a class-based component so that we can have easy local state this case account we're going to make a very simple class component it's going to have state and then that state needs some type scriptification on it so that we get red squigglies and autocomplete but it's going to get a little bit weird which will then make you think i'm going to go back to functional components and hooks okay uh always start with a test we're going to write a failing test first do the implementation wired into the parent blah blah blah uh we want counter encounter so i've got counter over here i want counter dot test over here and i will shut you off and just have my test runner we're going to write a new test this is going to be about the state not about the presentation and we want our counter to start at zero so i will cut and paste this and then save it which makes it run and it fails because we don't start at zero we currently are at one but that's not an actual that's not an actual stateful value it's just a character on the screen so this test failed correctly now we need to go into the implementation we have a class-based component i'll move this out of the way for a second i have a class-based component which has a type definition for props maybe it needs a type definition for state okay and what we're going to do this time i don't you know i could have done the same thing inlining it and then extracting it but there's just something about state that makes me want to reason about it separately from the component implementation and so i'll go ahead and type this out i'm going to go make a new type i'm going to call it counter state and it's going to have what i call that value count count that's a number and the id is telling me you're not using that yet i know that and where do i put this in my class statement inside the generic and that lets me then say i'm the first argument to the generic is the prop information the second argument to the generic is the state information in fact look at that the pop-up tells us with p and s the ever helpful p and the ever helpful s that is the order of the arguments inside the generic june i'm uh i don't know i'm i'm i'm okay with class-based components probably because i learned them first and the world of python isn't as big on functional programming as the front-end world has gotten okay but i mean there's there's a place for local state local component state so now i've got the type information correct i need to get the actual state and so i'm going to do this in iterations and learn along the way about some mistakes i'll be interested to see if what i call the best way is uh is wrong if there's a a bester way these days because things always change i'm inside the class now and i'm going to add some like a class attribute field thingy i'm going to give it type information and say that the state is of type this and here's the initial value so that's good and then that lets me do this so i will replace the one with this dot state dot look at that autocomplete yay all right i'll save let my tests rerun look at that it went green and i got a little pop-up on my desktop saying that my test passed so i now have a stateful component that internally decides that it starts at zero so i am so happy that y'all are are discussing it with each other about the place of class components versus functional components i could participate but i would probably get it wrong because it's very much a style thing so we added a second generic for the state alongside the prompts and we put in some initial state as a class variable which gave us some benefits but as you know the big problem with this is immutability you're not supposed to just assign to that object you're supposed to use the set state method to get there what if you don't what if you don't what if you're like this dot state dot count plus one plus equal one wouldn't you like it if the compiler could red squiggle that if typescript could detect that something was read only and you were assigning to it you can do it and so we're going to do it we're going to replace our type definition with this we're going to set a module scope value for the initial state with its values and i'm going to do this weirdo type definition we had counter state before we see it here and so what it's saying is it's using read only as the type that's a built-in keyword and typescript that's why it's not imported and in the generic we're going to say that the shape of this thing that is read only is this and so once we do that we need to use initial state now instead of our kind of manual definition it's going to change it to also use the read only prefix so read only and now if i wanted to do something that changed the value we'll see in a second that we can i'll go and do it now what if i wanted to say in here this dot state dot count equals nine look at that awesome anyway back to what we're supposed to be doing which is incrementing the count i'll pause there and look over here that's a good point elena have the opposite problem that's funny it's rich actually i think i agree with you more than the position of who was it that was saying the opposite okay so let's get back to having a starting value so the outside world can tell hey go make me a counter but use this as the starting value change in behavior change in promises and contract means a new test right so and take this test go back to counter hey red squiggles for the win i'm breaking the contract of course i'm breaking the contract there is no start prop all right and we'll save it so the test will run one test fails because of 10 not being the value but typescript fails because start isn't a prop so we'll fix the type definition encounter to also allow i'll type it but all right so now that red squiggle went away the test is still going to fail because i haven't implemented starting point yet how do i want to implement starting point aha things get tricky here a little bit read only can't plop this in in the beginning so i'm going to use a life cycle method and in this life cycle method i will then have access to the props the past in value and from that i can get a starting point so in component did mount i have access to props so come over here add that method it's run once if a prop was passed in if i have a prop i'm going to call set state this time rather than just doing the manual assignment i will save see if my tests run and my tests all ran let's make sure that they actually ran because it ran all screen all right starting point so i've done something on the starting point which didn't work i passed in start as a prop if props.start this that's that's i wonder if this is because the test doesn't have access to life cycle level can't be done all right i will put in a debugger statement why didn't why didn't i put read only count number so matt i was trying to model the entire state instead of just the count i could have done you're right i could have had just the count the idea being later i might add other things to the state but you actually have a good point you should be as specific as possible and not try to adhere to an infinite contract all right so i'm starting at zero this prop start zero so i should let's see so anybody see my problem all right this dot props dot start should evaluate to be true so i am setting state and i guess this is just a case in my test i'm not actually doing the component mount life cycle all right note to self on fixing that maybe angela is about to give me the correct answer on this all right now we got to do the third step we talked about all three steps we've written a failing test we did an implementation now we need to go to the parent and wire it into the ui so i will start with app dot test dot t s x i'm just doing all three things in one big jumbo test probably not the smartest thing to do all right this will run and i don't actually need to do anything in the code because i was including the subcomponent and i was peeking into the subcomponent oh i think is is the f for florian i'll guess and say it is i just happened to choose something that was still going to be in the document oh you dummy so if i would have said 99 it would have failed so because 110 still has 10 in it i'm tired maybe that's what i'll blame it on okay it's so fixed and we have a counter component that can be pass props pass state is configurable from the outside you can give it not just the label but you can give it the starting point and it will keep track of counts and we've got that all wrapped into type information which does some kind of attempt at mimicking read-only and i will agree with i can't remember who it was that said it i will agree with you that instead of modeling any anything possible i should be more specific and say what is this component's contract good job is it florian is that what the f stands for or am i projecting frank okay sorry all right all right carl's roux right do i remember that correctly good all right onward onto some fun stuff and you can see we're getting close to the end of the movie and we're doing pretty well on time before i go into this as a note things about to get real so let's take a little pause any questions any advice on rewriting this tutorial if i do so in the future any any things you seem presented that you've got your own ideas about use oh that's that looks like an interesting workshop i'm going to go ahead and click on that link suzanne thanks okay no points we will go ahead and continue we have a counter it keeps track of nothing so we have no way to increment it except for a test we haven't wired it into any event handling let's add to our counter component handling clicks to increment and show how we're going to model this in typescript and then how we're going to work with this and simulate clicks in testing this one's a fun one i'll also be interested to see if some of you pros out there have a good latest and greatest set of suggestions we're going to do the same same old same old we're going to write tests going to get squiggles we're going to do our implementation etc this time though we're actually going to fire up a browser at the end and do some clicking i'll take this moment to note how far we've gone without really looking at a browser isn't that cool we can do react development without type type type tab to a browser hit reload click the universe go to the console console lock some things go back to your editor type type type oh god just killing me we're going to write a first failing test encounter and this is going to be a incrementer an event clicker thingy and you'll see we're going to get another import from testing library fire event that looks sexy so i'm going to copy and paste this go back over to counter hide this and add a new test i will need an import so hey thank you ide go do that import for me i'll optimize imports reformat code like pavlov's dog and what's happening here is i'm going to write a test for the starting point of the counter and in this case i'm looking at this thing it's matching on this attribute title current count i'm getting its value its text content and i want it to go from zero to one and i want to do that by simulating clicking on that element so let's walk through this a little bit i've got a counter component and i'm going to render it and i'm going to extract some closures that let me peek at it in rich and interesting ways such as finding elements that match a title so i'm going to go find an element which matches a title let me mouse over this it is an h of type html element that's what's returned by get by title and then i'm going to fire an event on it the click event i'm going to fire on that element that html element that i located and then i'm going to assert hey you increment it now so we're good all right so we walk through what all that does and look it failed obviously because it's still zero the element is still zero it didn't firing the event on it had no effect because we haven't done an event handler user event and fire event i don't know oh alexi how about this just tell me tell me that's correct and i will believe you i will i will open a tab uh react no just testing library and you're saying uh user event events are you saying it's more specific and it better matches the actual type script type that is being used i see and i see user event and good docs for it it's a more advanced here we go it's a more advanced simulation of browser interactions than fire event today's winner goes to alexi for getting it right we have two alexis so let's say with a y okay which means i have to change my tutorial again i'll wait till react 25 we need a handler an on click handler because the component doesn't handle clicks let's go do our implementation we wrote our failing tests let's make the test pass so i'm going to go over to my counter here i probably want it on the span for the number i guess i could put it on the div but i'll put it on the span for the number i'm going to get it to say this for now now it's going to be an arrow function it's going to be an arrow function and it's going to grab this and call step state okay but this is a little bit problematic my test now passes but this is problematic because you're discouraged from putting arrow function definitions as event handlers why because all of this is going to get reinterpreted and recompiled whenever this thing is re-rendered it's running in the render cycle it might be 60 times a second that it's redoing all of this compilation so we want to move it out of the event handler and i'm going to put it into kind of a class method and that also helps me do test isolation i can test the counting of something without needing to go through a render and then this on click handler can just say this for those of you that are about to complain to me that's the point i'm walking through variations of this to get to the right thing okay and you know obviously i can do autocomplete all right when i save that i'm getting you know my test pass and what i want to point out is that i think i actually said method this isn't actually a method so there's a method we would get into the problem of this this is actually a field or property or attribute or whatever you want to call it that's an arrow function which then gets the binding of this correct so that it isn't tied to an event as this the component is this but it is uh i misspoke it is still getting the event passed in we're not using it and it's going to be the this isn't the event that this is the component we are though getting an event passed in so let's model that correctly and then it'll get mad because it says it's any and so okay i will just shut you up time script compiler now you're happy aren't you well we still get some warnings about they're not an unused event we'll get to that in a second but if my tsconfig.json turns off the ability to have any i'll get some complaints so i'm cheating by saying any i'm just shutting up the compiler let's do it the right way and let's prove that doing the right way has its benefits that type information can solve can show us problems okay and i'm going to get back over here to having my uh yep good the discord open all right my first tab edit is going to say that it's a mouse event and mouse event is a generic for the kind of thing that was clicked so i'm going to say that right good and then i'm going to you start the process of using this information by saying what we want to eventually get to is did you press shift click if so we're going to increment by 10 and that's why we want to get access to the event as we want to handle the shift click usage so i'm going to come over and start the process of making some mistakes all right so this is my first attempt at it and i'll save see what happens with the test running test failed because it doesn't have the right answer in it something is going wrong what went what went wrong by the way the end of the story is i always get the ternary wrong can typing help me see when i got the ternary wrong okay i can't do a plus on a number or number in boolean so this can be either a boolean or a number why is that i'm saying one and i'm saying 10 here it's a number it can't be a boolean so i'll go on to the next stab at this type script told us the problem let's set the type explicitly and say huh i know better than you i'll shut you up and say you're a number well that red squiggle went away but that wasn't our goal our goal wasn't to move the squiggle our goal was to eliminate the squiggle what's what are you mad about now same thing it thinks the right hand side of the equal can be either a number or a boolean so let's keep looking at this a little bit more and we finally realize that i've got the order of the ternary wrong that it's if this then that otherwise that and type script helped flag me the whole way because i decided to take the extra step and put event information type information on the event it was able to help me autocomplete it was helped me is able to tell me that that evaluates to a boolean all of that stuff and june is correct there it squiggles all the way down right the typo shift key is boolean it just says you see where it says boolean at the end here you see where it says boolean at the end here it just says whether shift was pressed or not for this event was shift pressed alexa does that answer the question all right cool all right with that in mind i will i will save and see what happens my test pass all right i have a shift clickable counter yay do you see any shift in my test no do you see any shift in my test no so we need to handle the test for that advanced by 10 with shift click okay testing library has some event firing i wonder if this is even true anymore is user event bundled whoever it was that told me about user event oh alexa is it bundled or i still have to do this i'm going to presume i still have to do this i only thought i wanted user event for cases where i couldn't use fire event but it appears like fire event is the better thing to do at all times oh look yeah yarn i should have typed yarn just then oh look yeah yarn i should have typed yarn just then okay while you're running i will type the import manually on this so that we can focus a little bit as we do this okay and i'm going to write a new test that basically clones the last test and then we'll walk through it and we want to increase the count by 10 by pretending to hold the shift key when we click on the count how are we going to do that up here we did fire event this time we're going to do user event okay i i see your point yeah it's all part of the same package namespace but it's unbundled this time though when we click we're going to pick a target just like we picked a target but we're going to pass in modifier information the other parts of the event object that we want to simulate in this case shift being true this is kind of the moral equivalent of doing shift is false up here and what we want to prove is that by doing this we go from zero to 10 and here i explained that we switched from fire event to user event so that we got that richer interaction and when we did it look at that our test pass already because we already did this implementation in our event handler i would like to point out i'm testing increment counter via render i could come over here and write a test which calls increment counter and then looks at the state to see if it was incremented and i could simulate an event object that i passed in and it would feel very much like just normal javascript testing not dom rendered component kind of stuff and those tests they're faster and they fail in a more reasonable way okay all right that's an interesting point about extracting into custom hooks and easier testing some of the things that we're doing in this workshop are do a little bit extra work now to give you a level to give you a level of granularity that's easy to test just that thing easy to modify and refactor in the future and that's a good example andre of doing a little bit extra work now to create a custom hook because then i can just test that damn thing and it's packaged up a set of decisions and the outside world doesn't have to know anything about it usually we do that for components with child components it's neat doing that with state as well so that little parts of your global state can be treated logically different okay we are getting to the end uh the last step in the tutorial before i do i will pause for a moment and see if we have any questions or comments okay all right we will continue what we're going to do in this step is refactor this to be the way you're supposed to do it for presentation components child components or container components and dumb components and what we want is the counter to get a lot dumber it shouldn't keep track of its state and it shouldn't really have the logic about what to do on the event the parent should do that and pass it in and make it available to the child what we want to do is see a testing strategy for this as we go through the iterations of refactoring and we also want to see how to model this in typescript information um okay we will start with the counter state we're going to remove the state from the counter component if we're going to remove the state from the counter component we're probably going to want to turn it back into a functional component so i'm going to start by making this be the props where i remove count since passing a starting point won't matter anymore since it isn't keeping track of the count so i'll come over to my counter and here we start i will get rid of and then i'm going to change the counter component itself to be a functional component i'm going to leave in this thing about the initial state now because i'm going to have to go put that somewhere else later and i should have it around so i can reason about it okay and let's see oh wait no i need to i need to add count that's right see i got red squiggled count is now a prop which is being managed by my parent and passed into me and as it changes in the parent i will get it repass as a prop and re-rendered and all that stuff all right juni i'm interested in your thinking on that um you know sfc uh was stateless functional component and so my impression was in the beginning uh functional components were introduced to model components that didn't have state and in the beginning you were encouraged to only use class space components when you had local state i wonder if people will disagree with me about that okay so now our counter um is a stateless dom presentation component and and um we can delete the import of component or use the ide to clean up on aisle five and get rid of it for me in fact you know these days we can i believe get rid of that but i'll leave it because it was generated by create react app let's fix the two tests the first two tests in the counter to see if we're in the ballpark and if we can pass in a starting point so i'll just cut and paste these my tests are going to get a little messy as i do the refactoring on this because i'm changing the contract radically so do these two tests pass i won't really worry about the others okay these two tests do pass so i'm in good shape i mean i am in the ballpark the counter component doesn't control the starting value anymore so these two tests about start at this place start at another place we can remove them so uh let's say that passes let's see that passes should start at another value and should start at zero we will delete those two tests these ones about event firing we would like to keep around now we want instead of the counter to handle the logic about clicking we want the parent to handle the logic about clicking so i'm going to put this bad mama jama on the props definition and then explain it might be easier over here i'm passing in a callable now a function that will expect a first or should look like increment counter right pass in a first argument that is a mouse event on an html element and it's not going to return anything because it doesn't need to return anything it's just going to operate on the state and what we want is to unpack that prop in the local scope of the new counter we want to well let's just go ahead and unpack all of the props so we're going to unpack whatever label was passed in the initial count and the counter increase so i'm going to take all of that paste it reformat and so what we see is we have the label that came in as a prop we have the current count that comes in as a prop and we have a click handler which comes in as a prop and all three of those and their type information are expressed on this type definition so that's an interesting point about if the hook application has made people rethink the presentational and the kind of parent child dumb component thing i haven't seen that meme yet but i haven't gone to a boot camp recently and it's been a while since i wrote this i think this tutorial predated hooks now our tests though we've got compiler problems in our tests because we have a contract that's broken the count is required and the counter increase is required the count is required and the counter increase is required so what i need is let me say count is right yeah the first two pass and the second two fail so we're going to fix these two tests because we're not really testing click handling right now we don't care about the clicking there just needs to be something there we're going to make a fake click handler and we're going to pass it in as the along with an initial count as the two props that are currently missing so now typescript is happy on that one let's see i'll just cut and paste the whole thing so i think i got a stray something because of oh no sorry i need i'm supposed to be fixing the one above yeah these are the ones that the tests are passing but it's typescript that's mad so what i'll do is i'll go back and do this again typescript is mad because i'm passing an account but i'm not passing in a handler let's make a mock and then i can use that as the uh handler and now typescript is happy on that one i'll do the same thing here okay and so the test will run and these two tests pass again and they have no typescript problem and let me go see what alexis saying about uh makes it hard to uh alexi when you say definitely makes it harder to test react components which way makes it harder react components which way makes it harder hooks the new way or the old way of presentation child okay hooks all right got it okay so we are in good shape with those two tests and we got about five minutes so what i will do in in the rest of this instead of typing it in i'll just talk through it and then we'll wrap up event handling is a little trickier because sure your dumb presentational child component isn't going to be doing the work but we at least want to see if the function was called and was it called correctly so what we're going to do in this case is change the third test we're going to delete the last test we're going to make a handler we're going to pass it in we're going to do the clicking and then this handler thing we're going to be to call an assertion on it to make sure it got called did my component call the function when it was clicked pretty smart easy concept of the contract but how do i write a test for it like this i make a mock i use that mock or spy is the thing passed into the dumb component do all the work and then look at it and say hey spy did you get called correctly that's really easy and when combined with fire event and use event and stuff like that it's a really nice i mean how else would you do it you go to the browser click the universe see if everything worked correctly we can make the dumb component a little bit smarter because it's having a interface between the parent and the child is expressing some things that could be moved maybe a little bit to the child what we have now is the on counter increase function passes the entire event but we know that the child doesn't care about the entire event it's only interested in shift click so we're going to say hey call me with an argument about whether shift was pressed so that's the first change and then in the implementation we're going to make a callable which then does the counter increase with the value of the shift key and then that will be the handler used by the child because the parent has access to the entire event we're not going to make the child have access to the entire event i'm sorry i'm in the child sorry so i've got this handle click function that is doing that then we can go back up to the container component sorry the the test is now written to be able to look at just that one thing about false because that was what the handler had and then just to wrap this up a little bit we can go up to the parent component component i said that we were going to leave these lines around in the counter that's so that we can copy and paste them up into the parent where the contract is and let's see i think uh yeah i need to change that it's no longer a class component then on the parent we're going to do an increment function that gets passed in and this is where we get the whole i'm sorry this is the thing that's called by the child and it's going to be passed back up the shift information which we then use we don't have to parse an event so going through all this we can write a test that does everything for the app state that includes some clicking on the counter component now i will start the process of wrapping up taking any comments and things like this i would like to point out something i've said it a couple of times but i'd like to end with it we almost never looked at the app in the browser we were able to do all of this work whether it was rendering whether it was props whether it was state whether it was event handlers all of this stuff we were able to do staying in our tools staying in the flow being able to debug getting good trace backs clickability refactoring all of these other things and that ability to stay in the flow and work methodically and not feel like you're overwhelmed that is a really good feeling for development you're working with confidence you know that because of tests you know that everything is working correctly but because of tests you also get to focus on the problem so i'll stop there for a moment let's go ahead and wrap up any input any questions any feedback any observations about your feelings about testing maybe even about typescript as well so i'll look through some of the comments in in the chat i will have to keep an eye on the impact of hooks on the way people are splitting components and about writing tests and stuff like that so jun thanks for bringing that up and let's see the typescript in the last two years you're right i i follow the typescript roadmap they do a great job running that project and they do a great job of keeping their roadmap up to date and sometimes they have a bullet on you know what's coming or what just got implemented and they're using words that i don't understand because they're like really into type theory now they're really trying to move huge parts of framework development can be expressible in types type information typescript is evil ian unfortunately the license for web store and license for intel j are separate we do have something called the all products pack which lets you get access to all of our ids and alexa your point about not leaving the ide do you feel like this is a way of development that you would like when i can have the discipline to stay in this mode it's just so calm i don't feel frantic maybe that's not the right way to put it yep about styles well thank you dylan i appreciate that maybe i'll see a presentation by you one day and i'll learn some stuff from you all right i think this is most in the comments yeah june what you're saying really is that the thing that got me into this is i don't know maybe or maybe it's just me but the the millisecond
174 min
12 Oct, 2021

Watch more workshops on topic

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career