- 00:00:01 hi everyone welcome to this video in
- 00:00:04 this video I'm gonna dive into one topic
- 00:00:06 that a lot of people are struggling with
- 00:00:08 or are afraid of and that is testing
- 00:00:11 your code in this video specifically
- 00:00:13 testing JavaScript code testing can be
- 00:00:16 or should be an important part of any
- 00:00:19 major project you're working on and
- 00:00:21 still a lot of people don't do it
- 00:00:23 because it looks too complex it's too
- 00:00:25 unclear how it works and so on in this
- 00:00:27 video I'll take a look at what exactly
- 00:00:29 testing is why we would want to test and
- 00:00:32 then of course most importantly how to
- 00:00:34 test our code and you will learn that
- 00:00:36 there is no reason to be afraid it's
- 00:00:38 actually pretty easy to get started with
- 00:00:40 testing so let's dive in
- 00:00:45 now what is testing and why would we
- 00:00:48 want to test now testing when you hear
- 00:00:50 it for the first time sounds pretty
- 00:00:52 obvious pretty straightforward we are
- 00:00:54 writing an app we're creating an
- 00:00:56 application and we simply test it right
- 00:00:58 we had a feature we open the browser and
- 00:01:01 we test our application and that is
- 00:01:03 indeed how you will continue to work
- 00:01:05 even if you do add this kind of testing
- 00:01:08 I'll dive in in this video so testing
- 00:01:10 manually still is something that makes
- 00:01:12 sense you want to see your application
- 00:01:13 run so in the end the idea always is
- 00:01:16 that we have our code and we have some
- 00:01:18 expected result so if we write some code
- 00:01:21 and then we go into the browser and test
- 00:01:23 this code we have some idea of what
- 00:01:26 should happen we want to open that modal
- 00:01:28 we want to add that user when we click
- 00:01:31 that button something like this so we
- 00:01:33 have our expected results in mind and
- 00:01:35 then we simply test our application and
- 00:01:37 if we are successful we are fine with
- 00:01:40 that we can continue with writing the
- 00:01:42 next piece of code and if we're not
- 00:01:44 happy with the result well then we can
- 00:01:46 modify our code and fix the issue or
- 00:01:49 adjusted such that it works in the way
- 00:01:51 we want now the idea of JavaScript
- 00:01:54 testing or code testing when you read it
- 00:01:57 like this is that we automate this
- 00:01:59 testing part so that we automate it so
- 00:02:02 that we don't have to manually test
- 00:02:04 everything in our application now we
- 00:02:07 will probably still test everything
- 00:02:09 manually but automated tests can be run
- 00:02:12 whenever we change something in code to
- 00:02:15 see if that affects any part of our
- 00:02:17 application without us having to test
- 00:02:19 everything manually again that is the
- 00:02:21 idea behind automated testing that we
- 00:02:24 can see breaking changes were issues in
- 00:02:27 our code may be introduced by a change
- 00:02:30 in place a in a totally different place
- 00:02:32 of our app that we can see this
- 00:02:34 instantly that is one of the major
- 00:02:36 benefits of writing tests so that is
- 00:02:39 also one answer to the question why
- 00:02:41 would we want to test we want to get an
- 00:02:43 error and CDR if we break our code we
- 00:02:45 want to see that immediately without us
- 00:02:48 testing everything manually we might
- 00:02:49 still do manual testing but it's still
- 00:02:52 worth a lot to have a suit of predefined
- 00:02:55 automated tests that we can run to
- 00:02:58 quickly
- 00:02:58 see did this change break anything well
- 00:03:01 with well-written tests we'll get the
- 00:03:03 answer right away we'll also save time
- 00:03:06 if we don't have to test everything
- 00:03:07 manually over and over again and we are
- 00:03:10 all forced to think about possible
- 00:03:12 issues or bugs
- 00:03:13 when writing our tests we have to think
- 00:03:16 about what do we want to test how do we
- 00:03:19 write a test that makes sense and I'll
- 00:03:22 dive into that in this video already we
- 00:03:24 also can integrate it into our build
- 00:03:26 workflow this is something more advanced
- 00:03:29 but there I mean you could have a build
- 00:03:31 workflow where you push a commit so a
- 00:03:34 get commit to your code repository like
- 00:03:38 github and then you have a workflow that
- 00:03:40 automatically is triggered where this
- 00:03:42 code is then tested in the cloud on some
- 00:03:44 server and if the test succeeds it's
- 00:03:46 maybe deployed automatically so you can
- 00:03:49 build a very complex deployment chain
- 00:03:51 there and tests are then an integral
- 00:03:53 part of ensuring that no breaking or
- 00:03:55 invalid code is deployed so that is also
- 00:03:58 an advantage of tests or something you
- 00:04:00 can use tests or we can also break up
- 00:04:03 complex dependencies and that is also
- 00:04:05 something I'll show in this video we
- 00:04:07 have to make sure we write code that can
- 00:04:10 be split up that is modular because this
- 00:04:12 will make testing easier and ultimately
- 00:04:14 it will make working with our code
- 00:04:16 easier and it improves our code
- 00:04:19 therefore since we are forced to follow
- 00:04:21 certain patterns or to write code in a
- 00:04:24 certain way or at least that will make
- 00:04:26 testing easier we will write better code
- 00:04:29 all together so these are a lot of great
- 00:04:32 advantages but they might still be a bit
- 00:04:34 abstract when you have not written any
- 00:04:37 tests so let's dive into testing soon
- 00:04:40 but not before I try to answer one other
- 00:04:42 question and that is which types of
- 00:04:45 tests do we have I'm talking about
- 00:04:47 automated tests so some code we write
- 00:04:50 that tests our code so code that tests
- 00:04:53 code that is a good description of what
- 00:04:55 testing is or what automated testing is
- 00:04:57 I guess and there we have different
- 00:04:59 kinds of tests we have some tests that
- 00:05:02 test a fully isolated piece of code
- 00:05:04 let's say a function that takes some
- 00:05:07 input and returns some output we can
- 00:05:09 test such a function with a test because
- 00:05:12 it
- 00:05:12 has a clearly defined structure and we
- 00:05:14 can say for input X&Y we expect to get
- 00:05:17 output set and that would be a so-called
- 00:05:20 unit test because we test a single
- 00:05:22 isolated unit of our application we also
- 00:05:27 have some tests that test units with
- 00:05:30 some dependencies so we have no isolated
- 00:05:34 piece of code anymore but we might have
- 00:05:35 a function that calls another function
- 00:05:37 let's say and therefore the function
- 00:05:39 we're testing depends on the result of
- 00:05:41 an average function and that is called
- 00:05:44 an integration test because there we're
- 00:05:47 testing more than just a single unit we
- 00:05:49 test the integration of a feature into
- 00:05:51 another feature so to say we also have
- 00:05:54 the full flow which we can test or the
- 00:05:56 user interface so the full application
- 00:05:59 or a part of the full application and
- 00:06:01 this is a so-called end-to-end
- 00:06:03 or also a user interface test the idea
- 00:06:05 here is really that we do what we could
- 00:06:08 do manually as well in the browser but
- 00:06:10 that we write kind of an automated
- 00:06:12 script that executes a certain series of
- 00:06:14 steps for us and then we can check if
- 00:06:16 the result is the result we expected to
- 00:06:19 get now these kinds of tests have a
- 00:06:21 different complexity unit tests are
- 00:06:23 relatively easy to write because you
- 00:06:25 have a small unit and you know it's easy
- 00:06:29 to infer what you want to get as a
- 00:06:31 result the more dependencies you add the
- 00:06:34 more complex it becomes because it gets
- 00:06:36 harder to differentiate between what
- 00:06:38 exactly is causing an error is it a
- 00:06:40 dependency or the function that uses the
- 00:06:43 dependencies also you might have some
- 00:06:45 dependencies that reach out to a server
- 00:06:47 and fetch data that is also a complexity
- 00:06:50 you have to handle and it will show you
- 00:06:51 how to handle this in a separate video
- 00:06:53 and the full user interface test is the
- 00:06:56 most complex one because there you have
- 00:06:58 to define every step that should be
- 00:07:00 executed and cleverly think about what
- 00:07:02 you want to test and what you want to
- 00:07:04 expect there now all the due to this
- 00:07:07 complexity we write tests in a different
- 00:07:10 frequency we typically have a lot of
- 00:07:12 unit tests because if you test every
- 00:07:15 unit of your application and it works
- 00:07:16 correctly
- 00:07:17 you can kind of infer that the overall
- 00:07:19 application will also work correctly so
- 00:07:22 we will have a lot of unit tests we then
- 00:07:24 have some integration tests
- 00:07:26 to rule out that two individually
- 00:07:29 working units don't work anymore if you
- 00:07:31 combine them and we have a few UI or
- 00:07:35 end-to-end tests to test some steps or
- 00:07:38 some flows in our application in the
- 00:07:41 browser in an automated way so these are
- 00:07:43 the kinds of tests and in this video I
- 00:07:45 will show you all three already
- 00:07:47 and with that I'd say it's enough of the
- 00:07:49 theory let's start writing some tests
- 00:07:51 for that I prepared a little demo
- 00:07:53 project to which you find a link below
- 00:07:55 the video of course and you can simply
- 00:07:58 download that run npm install in the
- 00:08:01 extracted folder to set up all the
- 00:08:04 dependencies I have here I don't have
- 00:08:06 many dependencies I only use webpack and
- 00:08:08 then we have a very simple application
- 00:08:10 here in app J's a JavaScript application
- 00:08:12 front-end JavaScript where I import some
- 00:08:16 bad stuff and then have some code to
- 00:08:18 basically set up an event listener to a
- 00:08:20 button and add a user to a list of users
- 00:08:24 when we click that button
- 00:08:25 I got u tilde s which holds D the
- 00:08:29 functions and importing into AB KS I'm
- 00:08:31 using node.js module syntax here simply
- 00:08:35 because that's a bit easier to test and
- 00:08:36 doesn't require a complex build workflow
- 00:08:39 setup on which I simply didn't want to
- 00:08:41 focus in this video but I use webpack to
- 00:08:43 then bundle this all up and get a main
- 00:08:45 J's file which is the file we then use
- 00:08:48 now what you can do is you can simply
- 00:08:49 double-click index.html I got no dev
- 00:08:53 server and place here or anything like
- 00:08:55 that simply to not focus too much on the
- 00:08:58 front and workflow and if you did double
- 00:09:01 click on that file this is what you'll
- 00:09:02 get you can enter some data and add a
- 00:09:05 user and that is all we can do here so
- 00:09:07 it's a relatively simple app but that is
- 00:09:09 great for starting with testing because
- 00:09:12 we can easily confirm if our tests make
- 00:09:14 sense if they do test something we would
- 00:09:16 test manually as well so this is the
- 00:09:19 application and now let's write some
- 00:09:23 tests now for writing tests we need some
- 00:09:25 external tools we need some tools that
- 00:09:28 help us with creating these tests what
- 00:09:30 do we need we typically need three kinds
- 00:09:33 of tools we need a test runner which is
- 00:09:36 simply a tool that executes our tests
- 00:09:39 and summer
- 00:09:39 the results and gives us some output on
- 00:09:41 the results we can use something like
- 00:09:44 maca there that is a popular test runner
- 00:09:47 we also have assertion libraries and
- 00:09:50 there we define our tests that logics
- 00:09:52 are expected outcomes
- 00:09:54 so these assertion libraries give us
- 00:09:56 tools to define expectations to define
- 00:09:59 comparisons conditions we want to check
- 00:10:02 as part of our tests they are chai is a
- 00:10:05 common or a popular assertion library
- 00:10:08 though what we will use is a very
- 00:10:10 popular library for both running tests
- 00:10:13 and asserting and that is just just as
- 00:10:16 relatively new or at least it was
- 00:10:18 rewritten and not that long ago and it's
- 00:10:21 a very popular library for writing tests
- 00:10:24 because of this Bopha test Runner and an
- 00:10:26 assertion library and it's really
- 00:10:28 powerful and a lot of fun to work with
- 00:10:31 for end to end we also sometimes need a
- 00:10:35 headless browser so basically a browser
- 00:10:37 where we don't have to click manually
- 00:10:39 but where we can use the browser API the
- 00:10:41 Dom and so on without a user interface
- 00:10:43 necessarily because we'll analyze it in
- 00:10:46 code anyways and there we can use puppet
- 00:10:49 here which is a very popular solution
- 00:10:51 for that we need to add headless browser
- 00:10:53 mostly for ant to end testing whereas
- 00:10:56 the test Runner and the search library
- 00:10:57 are also needed for that but also then
- 00:11:00 are the only things we need for a unit
- 00:11:02 and integration tests now let's start
- 00:11:05 with jest and with unit tests and you
- 00:11:08 can simply google for a jest to find
- 00:11:10 just j s dot io t official webpage of
- 00:11:13 chess chairs and there i can only
- 00:11:15 recommend trying that out getting
- 00:11:18 started diving into the official Docs to
- 00:11:20 learn way more but of course I'll also
- 00:11:21 walk you for all the basics in my videos
- 00:11:24 here so we'll start installing just now
- 00:11:27 and for that let's switch over to our
- 00:11:29 project and in there
- 00:11:31 let's run npm install – – save dev just
- 00:11:36 because just will be a development
- 00:11:38 dependency of our project and it will be
- 00:11:41 the tool we use for running our tests
- 00:11:43 and for checking our outcomes or for
- 00:11:45 writing some conditions some assertions
- 00:11:47 as its called
- 00:11:48 so this will now install and with it
- 00:11:52 installed we can
- 00:11:53 right our first test and it will write
- 00:11:55 my test for functions defined in Utah je
- 00:11:58 s and their this first function makes up
- 00:12:01 for a great first unit test it has no
- 00:12:04 other dependencies because it does not
- 00:12:06 call any other function it does not
- 00:12:08 reach out to the web or anything like
- 00:12:10 that it simply takes input two arguments
- 00:12:13 and returns an output and this would be
- 00:12:15 a great example for a simple unit test
- 00:12:18 we can write now to write a test for
- 00:12:20 this function you create a separate file
- 00:12:23 into which you'll store your tests and
- 00:12:25 you typically named it file like to file
- 00:12:27 your testing Guto and then dot spec or
- 00:12:30 dot test is and the name is up to you
- 00:12:33 jest will automatically detect files
- 00:12:35 with dot test or dots back in them and
- 00:12:37 we'll run them automatically once you
- 00:12:39 run just which we'll do in a second so
- 00:12:42 now I have my util test dot J's file and
- 00:12:45 I want to test my generate text function
- 00:12:47 for that I first of only to import it
- 00:12:50 here I will use destructuring syntax
- 00:12:53 here to require something from Yuto so
- 00:12:59 from that you tell file where the core
- 00:13:01 code is stored and then the structuring
- 00:13:03 syntax simply means I pull out some
- 00:13:05 items from the object which isn't the
- 00:13:07 end exported by the util file and it
- 00:13:09 will pull out the generate text function
- 00:13:11 so essentially I import the generate
- 00:13:13 text function into my util test J's file
- 00:13:16 and by the way this is the native way of
- 00:13:18 importing ingest tests you could think
- 00:13:22 that you can also use like es6 imports
- 00:13:26 if you had respective exports in your
- 00:13:28 file of course something like this but
- 00:13:31 this will not work not only because I'm
- 00:13:33 not using es6 Explorer exports here that
- 00:13:36 is also a problem but even if I would
- 00:13:38 use them this is not a syntax natively
- 00:13:41 supported by jest this note is like
- 00:13:44 import syntax is supported by jest and
- 00:13:47 therefore I also wrote my code to use
- 00:13:49 nodejs exports because that made it
- 00:13:52 easier to implement just obviously you
- 00:13:54 can also make it work with es modules
- 00:13:56 like you use it and react or angular
- 00:13:58 apps but there you need a more complex
- 00:14:01 build workflow you need some additional
- 00:14:03 packages and I did not want to spend a
- 00:14:06 lot of time
- 00:14:06 on the setup I want to spend time on
- 00:14:09 testing therefore I use this syntax so
- 00:14:12 now I'm using gel or I'm importing
- 00:14:13 generate text in this file now we can
- 00:14:16 write our first test and for that we can
- 00:14:18 simply write tests here this is a
- 00:14:20 function which is now globally available
- 00:14:22 or which will be globally available when
- 00:14:25 we run our test with just so there's a
- 00:14:28 function provided by just in the end and
- 00:14:30 this function allows us to define a
- 00:14:32 single test now we can give that test a
- 00:14:35 name that's the first argument we're not
- 00:14:37 really a name more of a description you
- 00:14:39 could say something like should output
- 00:14:43 name and age typically you kind of
- 00:14:46 define what you want to test in this
- 00:14:50 name or in this description so which
- 00:14:51 output are you testing for you try to
- 00:14:54 put that in your description ultimately
- 00:14:57 you can put whichever text you want in
- 00:14:58 here but it should be kind of
- 00:15:00 descriptive the second function argument
- 00:15:03 is then an anonymous function which you
- 00:15:05 pass in with just a function jest we'll
- 00:15:08 execute to rerun your test so in this
- 00:15:11 function you add your testing code your
- 00:15:14 code that will be executed and now here
- 00:15:17 we can generate some text by calling
- 00:15:20 generate text and storing that in a text
- 00:15:22 constant and there will pass in max and
- 00:15:24 29 let's say now that is also what I
- 00:15:28 tested here manually entering max in 29
- 00:15:31 added a new item with text max and 29
- 00:15:34 years old now I'm effectively testing
- 00:15:36 that part where this text is generated
- 00:15:39 so not where the whole item is generated
- 00:15:41 but only this text max 29 years old is
- 00:15:45 what I expect as an output of generate
- 00:15:47 text because if we have a look at
- 00:15:49 generate text well then we return a text
- 00:15:51 here where we have to name and then in
- 00:15:54 brackets
- 00:15:54 29 or whatever the age is 29 years old
- 00:15:58 now if we have that expectation we
- 00:16:01 should formulate it here in the test and
- 00:16:03 we do this with the expect function
- 00:16:05 which is also provided by jest now if
- 00:16:08 you would use a different setup with
- 00:16:10 let's say mocha and chai then test would
- 00:16:13 be a function defined by your test
- 00:16:14 Runner
- 00:16:15 whereas expect would be a function
- 00:16:17 provided by your assertion library and
- 00:16:19 Moe
- 00:16:20 search libraries work with the expect
- 00:16:22 function because tests are pretty
- 00:16:24 descriptive in terms of function names
- 00:16:26 we write a test and then we expect
- 00:16:28 something
- 00:16:29 now here we expect that text so we pass
- 00:16:34 the thing we want to look into you we
- 00:16:37 want to compare we expect text is equal
- 00:16:41 to a specific text we do this with a
- 00:16:44 bunch of helper functions that we can
- 00:16:46 now chain on our expectable object here
- 00:16:50 and there you see we have a lot of
- 00:16:53 functions where we could say we expect
- 00:16:55 text to be not a number for example or
- 00:16:58 to be null or just to be and then here
- 00:17:02 as an argument to the to be function we
- 00:17:05 pass the value we expect text to be that
- 00:17:08 could be a number but that could be also
- 00:17:11 max twenty nine years old which is
- 00:17:14 exactly the output we do expect to get
- 00:17:16 because of this day output we can also
- 00:17:17 see here and now with that we have our
- 00:17:21 first tests to find now to run this test
- 00:17:24 with the jest package I will tweet my
- 00:17:26 package JSON file there we have just
- 00:17:29 installed and we have a script up here
- 00:17:32 the test script which is kind of invalid
- 00:17:34 right now here I will just run just and
- 00:17:37 this will automatically search for files
- 00:17:39 with dot test or dots back in the name
- 00:17:41 and execute them or which end with dot
- 00:17:45 test rjs or dot spec j/s I should say so
- 00:17:48 now with that added we can simply run
- 00:17:51 npm test down there in a normal terminal
- 00:17:54 navigated into the project folder and
- 00:17:56 just will automatically execute all our
- 00:17:58 testing files and here we get a
- 00:18:00 beautiful green output it found one test
- 00:18:04 which passed and there we see the one
- 00:18:06 test which passed successfully where it
- 00:18:09 should output name and age and that
- 00:18:11 succeeded now this is great because now
- 00:18:14 if we ever change something here let's
- 00:18:17 say we accidentally output the age here
- 00:18:20 too we changed something in that
- 00:18:22 function and the original function and
- 00:18:24 we break it if we save this and then we
- 00:18:27 run our tests again we now actually get
- 00:18:30 a failed test and that is exactly where
- 00:18:32 tests can help
- 00:18:34 a lot we get a failed test we see which
- 00:18:37 test failed should output name and age
- 00:18:39 and just even gives us some information
- 00:18:41 on what failed there we see that we
- 00:18:45 expect that max 29 years old but we got
- 00:18:48 29 29 years old and this now helps us
- 00:18:52 debug our code and fix our code of
- 00:18:54 course this is kind of a constructed
- 00:18:56 example here but you could have a typo
- 00:18:58 like this you could be misusing some
- 00:19:00 variable or some argument and now if we
- 00:19:03 fix that we can indeed run this again
- 00:19:06 and get that test passed by the way you
- 00:19:09 can also watch with chests you can add –
- 00:19:12 – watch here and now if you run npm test
- 00:19:16 just will actually keep on watching and
- 00:19:19 you can control the watcher with the
- 00:19:21 shortcuts that are shown there for
- 00:19:23 example force a run of all your tests
- 00:19:26 again or whatever you want to do and it
- 00:19:29 also means that now if I do change my
- 00:19:32 file here and I save just automatically
- 00:19:35 reruns my tests so this is great having
- 00:19:38 this run all the time and therefore
- 00:19:39 ensuring that we get errors right as we
- 00:19:42 change something so that is another
- 00:19:43 great option and that is our first unit
- 00:19:47 test here now this is a first simple
- 00:19:49 unit test now before we move on to
- 00:19:51 integration tests just a quick example
- 00:19:53 for a different kind of test that could
- 00:19:56 also make sense we should also make sure
- 00:19:58 that it does not just return the valid
- 00:20:00 response here because we can get this
- 00:20:04 with this trick as well if I copy the
- 00:20:07 output there I can also just use return
- 00:20:12 and then this text here and if I do that
- 00:20:17 then my first test will always succeed
- 00:20:26 if I quickly comment out that second
- 00:20:28 snippet so my test will not always
- 00:20:30 succeed but I have an error in my
- 00:20:32 function and we have a second test we
- 00:20:34 can add a second test where we confirm
- 00:20:36 that this is not the case so let's say
- 00:20:39 we say should output data less text or
- 00:20:45 whatever you want to name it and there I
- 00:20:48 could also generate a text with generate
- 00:20:51 text but I pass an empty string and I
- 00:20:55 pass null as a number here and then I
- 00:20:58 can't expect that text should be well
- 00:21:03 what should it be like it should be
- 00:21:05 basically just a blank and then nothing
- 00:21:10 years old right well let's give this a
- 00:21:13 try if I save Det it fails because I
- 00:21:17 always get back max 29 years old because
- 00:21:19 I broke that function I had a false
- 00:21:22 positive for the first test because I
- 00:21:24 returned the value which I expected
- 00:21:26 there but the value didn't take the
- 00:21:27 inputs into account now I can fix this
- 00:21:30 of course and return to the function for
- 00:21:33 him I had before and now the second text
- 00:21:39 will fail fail because there whoops I
- 00:21:43 should expect null years old of course I
- 00:21:45 passed an all not nothing and now there
- 00:21:47 I passed you and I have confirmation
- 00:21:49 that I don't have a false positive here
- 00:21:51 so we're adding a second test like this
- 00:21:53 might make sense as well to kind of
- 00:21:56 check for the opposite or check the same
- 00:21:58 thing with different arguments though
- 00:22:00 you could do the same in one of the same
- 00:22:03 tests you can have multiple expects here
- 00:22:06 too so you could generate an ax 28 here
- 00:22:11 as well and then simply add another
- 00:22:13 expectation here text 2 to be an ax 28
- 00:22:20 years and now this should all do pass
- 00:22:23 but having such double checks that is
- 00:22:25 the main thing can make a lot of sense
- 00:22:27 to avoid false positives and here I have
- 00:22:30 a double check as well as testing the
- 00:22:32 opposite so what happens if I call that
- 00:22:35 function correctly
- 00:22:36 what happens if
- 00:22:37 has nothing for example well then we
- 00:22:40 would expect undefined undefined here
- 00:22:48 right and that would be a test that
- 00:22:51 could also make sense so I'll delete
- 00:22:53 that for now I'll leave it at this
- 00:22:54 simple unit test but you should be aware
- 00:22:56 of the fact that you can write multiple
- 00:22:58 unit tests for one and the same thing
- 00:23:00 then you can check more than one thing
- 00:23:02 in a unit test and that you might also
- 00:23:04 want to check for false positives or for
- 00:23:06 opposites but now let's move on to
- 00:23:08 integration tests so let's now write an
- 00:23:12 integration test and for integration
- 00:23:14 testing if we have a look at all our
- 00:23:16 code which function could we use there
- 00:23:18 well we got the app.js file we got add
- 00:23:21 user which uses a lot of other functions
- 00:23:23 which has a lot of dependencies so
- 00:23:25 testing this function would be an
- 00:23:27 integration test but this is a function
- 00:23:29 that that doesn't either take an input
- 00:23:30 nor return an output it's that it's a
- 00:23:33 function that really added something
- 00:23:34 that dawn so this is something which you
- 00:23:36 might want to test in an end-to-end
- 00:23:38 testing scenario or in a user interface
- 00:23:40 test but an integration test would be
- 00:23:44 kind of hard here we would have to do a
- 00:23:46 lot of manual Dom interaction inside of
- 00:23:49 our test which you can do but which you
- 00:23:51 might not want to do instead there is
- 00:23:54 something else I can test and that is
- 00:23:56 basically a part of that function you
- 00:23:57 could say in the end what I'm doing in
- 00:23:59 the add user is I do select a couple of
- 00:24:02 elements then I do validate the input
- 00:24:04 and then I generate a text based on the
- 00:24:07 input now we could outsource this init
- 00:24:09 into a separate function and that is the
- 00:24:11 part of writing modular code that I
- 00:24:13 mentioned earlier your forstride modular
- 00:24:15 code which also makes your code easier
- 00:24:17 to manage and reuse though so in you
- 00:24:20 told Jas I can export a new function and
- 00:24:22 let's name it
- 00:24:23 check and generate or whatever you want
- 00:24:26 to do now check and generate will get a
- 00:24:30 name and a age as an input and then I
- 00:24:34 will go to my app J's file and I will
- 00:24:36 grab that validation code and move it
- 00:24:39 into check and generate to validate
- 00:24:41 input for and now that's important for
- 00:24:44 the name here and then there for the age
- 00:24:47 like this and then if we make it past
- 00:24:50 this
- 00:24:51 if block I will return a call to
- 00:24:53 generate text where a pass name and age
- 00:24:56 because that is what I then returned
- 00:24:57 here I returned to checked text so in
- 00:25:01 app days where I'm using this output
- 00:25:04 text is in the end just a result of my
- 00:25:07 call to check and generate I don't need
- 00:25:09 validate input here anymore
- 00:25:11 I don't need generate text anymore I'll
- 00:25:13 just import check and generate this new
- 00:25:15 functional import data and app chess and
- 00:25:17 down there out for text is the result of
- 00:25:21 check and generate I can move that up
- 00:25:24 here and here I can now simply check if
- 00:25:27 not output text so if we did return
- 00:25:32 let's say false here we return false and
- 00:25:36 validation fails so if this is returned
- 00:25:38 and therefore if this is not true ish if
- 00:25:40 it is false for example then it will
- 00:25:42 return an add user to and it will not
- 00:25:44 continue creating that element so now it
- 00:25:47 is this the tweak to add user function
- 00:25:48 and this gives us the check and generate
- 00:25:50 function which is great to use in an
- 00:25:52 integration test so let's write the test
- 00:25:55 for it and I want to test if my validity
- 00:25:58 works correctly and I then get the
- 00:26:00 expected text back so it should generate
- 00:26:04 a valid text output or something like
- 00:26:07 this and then here in this function I
- 00:26:10 will test my check and generate function
- 00:26:14 which I therefore have to import and I
- 00:26:16 can simply create my text with check and
- 00:26:19 generate and I've has max and 29 here
- 00:26:22 and I would expect this text to be equal
- 00:26:29 to max 29 years old so my expectation
- 00:26:34 actually is the same as in this unit
- 00:26:36 test but it's not a simple unit test
- 00:26:38 because the function we're testing has
- 00:26:40 more to it we could fail because
- 00:26:42 validation fails or because generate
- 00:26:45 text fails
- 00:26:46 however generate text is kind of ruled
- 00:26:48 out because we have a separate unit test
- 00:26:50 for this and this is also how you want
- 00:26:52 to write your tests by the way you want
- 00:26:54 to ensure that you drill down like to
- 00:26:56 the smallest possible level and write
- 00:26:59 unit tests for all your units so write a
- 00:27:02 test for generate text would also be
- 00:27:04 worth right
- 00:27:05 one for validate input and then your
- 00:27:07 integration tests really just rely on
- 00:27:10 the unit's being tested and ensure that
- 00:27:12 the units also work together well so
- 00:27:14 desert stand the idea behind an
- 00:27:16 integration test so here I have this
- 00:27:19 test and if I now save this it actually
- 00:27:22 fails now I get an error that Valley
- 00:27:26 that input is not defined here and that
- 00:27:30 is true because I do export validate
- 00:27:32 input I don't need to do that anymore
- 00:27:34 I should instead created or define it as
- 00:27:39 a constant the same is true for generate
- 00:27:41 text so that I can use these functions
- 00:27:43 directly in util J's file and then at
- 00:27:46 the bottom I should also export generate
- 00:27:49 text and assign the generate text
- 00:27:51 constant here and all the export
- 00:27:54 validate input maybe and assign that
- 00:27:56 constant so that I could use it in our
- 00:27:58 files too and now you see my tests
- 00:28:01 passed both tests passed now the idea
- 00:28:04 about the integration test is that if I
- 00:28:07 do change something in my check and
- 00:28:09 generate function for example here I use
- 00:28:15 my validate input function incorrectly
- 00:28:17 so the result of that is used
- 00:28:18 incorrectly now it fails and now this is
- 00:28:22 a great example of why I have an
- 00:28:24 integration test I could have a separate
- 00:28:26 test on validate input and validate
- 00:28:28 input does work correctly I can tell you
- 00:28:30 that but my error is directly here in
- 00:28:33 check and generate I'm using the result
- 00:28:35 of validate input incorrectly by not
- 00:28:37 checking for it being false but for it
- 00:28:39 being true and this means if my name is
- 00:28:43 valid then I actually returned false
- 00:28:45 which is of course the wrong logic in
- 00:28:47 check and generate so even though my
- 00:28:49 units work correctly the combination of
- 00:28:52 the unit's fails because I have an error
- 00:28:54 here and this again shows you the power
- 00:28:56 of tests and why integration tests make
- 00:28:59 sense too and unit tests alone could not
- 00:29:02 be enough because all units could be
- 00:29:04 working if you're combining them
- 00:29:05 incorrectly you still have a problem so
- 00:29:08 now it's working again though now that
- 00:29:11 we had a look at unit tests what they
- 00:29:12 are why we use them and integration
- 00:29:15 tests let's have a look at end-to-end
- 00:29:16 tests or user interface tests
- 00:29:18 for this only to install another tool so
- 00:29:21 I'll quit my chest process here and I
- 00:29:23 will install with safe death puppeteer
- 00:29:27 which is a headless version of chrome of
- 00:29:30 the Chrome browser so it basically is a
- 00:29:31 browser we can use to interact with the
- 00:29:34 dom and so on you can even run it in a
- 00:29:36 version with the head so where we see
- 00:29:38 the browser and we can basically define
- 00:29:40 steps that should be executed in that
- 00:29:43 browser so that we can automate certain
- 00:29:45 processes on our web page and then of
- 00:29:48 course tests a result of these processes
- 00:29:50 as well
- 00:29:51 now this download will take a while
- 00:29:53 because it in the end it downloads the
- 00:29:55 entire Chrome codebase because well it
- 00:29:58 needs that to be able to simulate that
- 00:30:01 browser and once it's done I'll be back
- 00:30:03 so I'm done installing it let's start
- 00:30:06 using puppeteer now and for that I'll go
- 00:30:09 to my utility JS file and I will import
- 00:30:12 puppet here so import puppet here by
- 00:30:17 requiring it from puppeteer like this
- 00:30:20 and I will write a new test now and
- 00:30:24 there I will just write should click
- 00:30:27 around for now we'll fix this later or
- 00:30:30 change this later and in this function
- 00:30:33 which should be executed here I want to
- 00:30:34 use puppet here now how can I use it
- 00:30:36 first of all I set up a browser by using
- 00:30:39 puppet here launch now this will launch
- 00:30:46 a browser with some options which I can
- 00:30:48 define here for example I can set
- 00:30:50 headless 2 to false to actually run a
- 00:30:52 browser with a user interface as well
- 00:30:55 you can set a bunch of stuff here and
- 00:30:57 you can find it all in the official
- 00:30:58 docks of puppet here of course I will
- 00:31:01 also set slo-mo here that will basically
- 00:31:04 slow down the automated operations so
- 00:31:06 that we have a chance of seeing what's
- 00:31:08 happening and I'll set it to a value of
- 00:31:09 AD and we can also set some arcs here
- 00:31:13 which is an array where I can pass – –
- 00:31:17 and then for example windows size to
- 00:31:19 launch this browser with these arguments
- 00:31:21 and windows size allows me to set a
- 00:31:24 width height pair so I can set this to
- 00:31:27 1920 and 1080 for example like this
- 00:31:31 should launch a browser with this size
- 00:31:33 and that of course can be great to also
- 00:31:35 test if certain responsive features are
- 00:31:38 working the way you want so now this
- 00:31:41 will create a browser now actually this
- 00:31:44 will return a promise so we can use
- 00:31:48 async/await here if you want you by
- 00:31:50 placing async in front of this pair of
- 00:31:54 arguments here or this empty argument
- 00:31:56 list and now we can await this to launch
- 00:31:59 the alternative would be to just use
- 00:32:01 then and catch a single weight and the
- 00:32:04 end dust is for you so here I'm awaiting
- 00:32:07 this and storing the result and browser
- 00:32:08 you could say as a next step I can now
- 00:32:13 create a page object by a waiting the
- 00:32:17 browser to create a new page like this
- 00:32:23 now I also need to tell the browser
- 00:32:25 which page to load and I'll grab my URL
- 00:32:28 here and then we can say page go to and
- 00:32:33 then you enter your URL which should be
- 00:32:36 loaded and you also should have wait
- 00:32:38 this because all these browsers related
- 00:32:40 things are of our promises that simply
- 00:32:43 take some time to execute so you have to
- 00:32:45 await each step so now the should open a
- 00:32:48 browser and load this page let's try
- 00:32:51 this by running NPM test and it should
- 00:32:54 indeed open up a brand new window in
- 00:32:58 chromium which is basically like the
- 00:33:00 chrome word the core functionality of
- 00:33:04 chrome and you'll see that this is being
- 00:33:06 tested controlled by automated test
- 00:33:09 software so this was opened
- 00:33:11 automatically now let's go back and
- 00:33:14 let's add some logic here we don't just
- 00:33:17 want to go to that page let's say we
- 00:33:19 also want to enter something for that I
- 00:33:22 want to enter something into my input
- 00:33:25 with the ID name and age so in my test I
- 00:33:28 will await a step where I use that page
- 00:33:31 where I navigated to my app where I will
- 00:33:35 then click into the field with that
- 00:33:38 selector so click takes the selector off
- 00:33:40 the item it should click on once I click
- 00:33:44 there
- 00:33:45 we'll type and again you can find all
- 00:33:47 commands in the official puppeteer Docs
- 00:33:49 so you can really like instruct browser
- 00:33:52 the headless browser what to do so I
- 00:33:54 want to type and I want to type into the
- 00:33:56 same input and we wouldn't have to click
- 00:33:58 on at first but I want to simulate all
- 00:34:00 the steps a user would do I don't want
- 00:34:03 to insert let's say and I here to mix it
- 00:34:06 up
- 00:34:06 not always max so now I type in there I
- 00:34:09 will repeat these steps once I type the
- 00:34:12 name for the H so for the H field I will
- 00:34:16 enter 20 a let's say if you save that it
- 00:34:23 will open up a new window where you can
- 00:34:25 see that it enters these things now we
- 00:34:30 can now also add another step and click
- 00:34:33 on this button at the bottom of our page
- 00:34:37 so in fjs in the end it's this button
- 00:34:39 we're listening on for an event here
- 00:34:42 with ID button add user can grab that
- 00:34:45 selector and make sure we click on that
- 00:34:47 in our setup and now we get a full flow
- 00:34:50 setup
- 00:34:53 where you see that this gets entered and
- 00:34:55 then we click this button here at the
- 00:34:58 end you also saw that it didn't add an
- 00:35:02 item and this already shows us that
- 00:35:04 writing this text was not the worst idea
- 00:35:06 because it looks like something was
- 00:35:08 broken and indeed here in our automated
- 00:35:12 test if we open the developer tools we
- 00:35:15 see it that it didn't find the validate
- 00:35:17 input function here so since that was
- 00:35:20 missing or is missing
- 00:35:21 we have to check our util J's file and
- 00:35:24 see what's wrong with validate input in
- 00:35:27 here I'm using validate input here and
- 00:35:30 I'm defining it as a function here but
- 00:35:32 one thing I never did is I never
- 00:35:34 recompiled my code that's something we
- 00:35:37 have to do because the code that gets
- 00:35:39 imported in the browser is packed with
- 00:35:41 webpack and I never recompiled it after
- 00:35:44 changing my code so in a separate
- 00:35:46 terminal window I'll quickly run NPM
- 00:35:48 start to get web pack to run my code
- 00:35:51 it'll now also watch my code and
- 00:35:52 recompile if I change something and with
- 00:35:57 that it should have executed your test
- 00:35:59 automatically in case it didn't simply
- 00:36:01 add a blank and reopen your browser and
- 00:36:06 enter and it will reopen the browser and
- 00:36:09 execute this and now you see this works
- 00:36:11 and this is puppet here being used for
- 00:36:13 automated testing with a graphical user
- 00:36:15 interface now obviously we can automate
- 00:36:17 this a bit more and check the result
- 00:36:19 programmatically now to see if we got
- 00:36:22 the expected outcome because what I can
- 00:36:24 now do is I can also wait and now that
- 00:36:27 everything executed I can check if
- 00:36:29 something is the case for example I can
- 00:36:31 check for the existence of this list
- 00:36:33 item with a class of user item being
- 00:36:36 added to it so in my test I can await my
- 00:36:41 page and there I can use dollar email to
- 00:36:44 get access to an element and I will look
- 00:36:48 for the first element with a class of
- 00:36:52 user item and I pass a function as a
- 00:36:55 second argument to evil where I then
- 00:36:58 define what I want to do with the
- 00:37:00 element I select it there and here I
- 00:37:02 will get an element as an input and
- 00:37:06 for example return the text content and
- 00:37:08 this means that now the result of this
- 00:37:11 function will be returned by this
- 00:37:12 overall promise so I can store it here
- 00:37:15 final text for example will be the text
- 00:37:18 that I fetched from this element that
- 00:37:20 was created and now I can expect final
- 00:37:24 text QB Ana 28 years old now it's again
- 00:37:31 checking for that text but it's now
- 00:37:33 using the full flow in the browser it's
- 00:37:35 not just the unit or integration test as
- 00:37:37 we have it up there
- 00:37:38 it's really going through all the steps
- 00:37:40 we would execute manually as well and
- 00:37:42 then of course we should have that text
- 00:37:44 but we could check anything here we
- 00:37:45 could also check for the existence of
- 00:37:48 this class and we implicitly do so
- 00:37:50 because if that class would not be there
- 00:37:52 we couldn't select the element by it and
- 00:37:54 therefore final text would certainly not
- 00:37:56 be that text but now if I save this it
- 00:37:59 executes all our steps here and it
- 00:38:05 actually fails here because it basically
- 00:38:08 timed out that's just a limit setup by
- 00:38:11 just to ensure that our tests don't take
- 00:38:13 too long what we can for do for that is
- 00:38:16 the test function actually takes a third
- 00:38:20 argument and that is the maximum timeout
- 00:38:22 and we can set this to 10 seconds to
- 00:38:24 10,000 to increase the time we give our
- 00:38:27 browser to complete its operation so
- 00:38:29 that it doesn't timeout and now you see
- 00:38:31 it finishes successfully because should
- 00:38:34 click around to which we should assign a
- 00:38:36 better name does give us the result we
- 00:38:39 want and here I will now say should
- 00:38:42 create an element with text and correct
- 00:38:51 class something like this by the way we
- 00:38:55 can't of course our also set headless to
- 00:38:57 true disabled the slow motion and not
- 00:39:00 set these arguments and this will now
- 00:39:02 speed up the testing because now it
- 00:39:05 doesn't have to go through that step in
- 00:39:07 a real browser it does so behind the
- 00:39:09 scenes and that's one of the advantages
- 00:39:10 of having a headless browser that you
- 00:39:13 don't have to watch it execute the steps
- 00:39:14 but it can be nice to see the steps you
- 00:39:16 can do both and now we got a full
- 00:39:20 to a test or a user interface test in
- 00:39:22 place – I hope that this video gave you
- 00:39:24 a nice introduction to the different
- 00:39:26 types of tests we have and why we write
- 00:39:28 them and I will have more videos on
- 00:39:31 testing where we also write a little bit
- 00:39:32 more advanced tests but this video
- 00:39:35 hopefully shows you what tests are and
- 00:39:37 how will you create them and what their
- 00:39:39 advantages are hopefully see you in
- 00:39:41 future videos bye