Transcripts
1. Course Introduction: Hello, and welcome to the course Advanced testing
for react with V test, react testing library,
and playwright. This is a very
comprehensive course. I will teach you all of the concept about
testing in the react. We will first start with
unit testing with V test. I will talk about
the test factories. We will implement FACRes with
the help of ACG library. And then we are going to go to the next step which
is integration testing. We are going to use
react testing Library. I'm going to teach
you everything about react testing library
and we are going to use user events for simulating the actions that users,
for example, clicking, submitting for
entering information, and then we will go
and we will test our whole application with the tend testing framework,
which is playwright. I already created two
repositories for this project. I will show you
how you can set up a simple block
with react and all of our tests and all of
the lectures will be done for this blog and here
you can see that we have an admin dashboard and
I will walk through you about the setting up the
project in every step, you will do the coding with me. You can sit and watch the videos and also
implement them yourself. And at the end of the course, we will have a complete
tested application with all different kind of
testing like unit testing, integration, and end to testing. I'm really excited to see you in the course and please
join me in the course, we will have so much fun
in this course together.
2. Course Pre Requirements: And what will be the
course pre requirements? I have designed this course to not require a lot of things. A basic knowledge of
typescript and Javascript and also a basic knowledge of react would be enough
for this course. And everything that you need
to learn about the testing, I'm going to cover
in the course so you don't need to know
anything about testing. You can learn everything
in this course, just a basic knowledge
about how JavaScript works and how typescripts
work and what is react, how react components work would be enough for this course. There is a section good to know. I have used TNSAquery or Rea
Query for the communication between the rea client
and our No J server. But if you don't know it, it is not mandatory to have it. I will inside the videos, I will tell you how it works
and how you can use it. But if you already worked it, it would be easier for
you to follow the course. But if you have not
worked, I already I'm already going to teach you everything that you
need for this course. As I said previously,
it doesn't need, you don't need to know a lot
before starting this course. Just start this
course with me and I will teach you everything in
the duration of the course. Let's start together.
3. Why Testing Matters: Let's talk about why
testing matters. Testing will help us to make sure that the code is
working as expected. Also, testing will help
us to prevent regression. And what does this
mean regression? Any changes to the software can break the existing
functionality. And if we do some kind
of coding and this coding changes some
part of the code, but it breaks another
part of the code, we will call these kind
of errors as regression. Testing will help us to
prevent regressions, and testing will also help us to ensure
better code design. When the code has been when
we are adding more tests, it helps us it helps
developer and us to better understand the code and it helps us to have a better code design. And also it increases
the product reliability. It increases the
product quality, and it will bring confidence for the whole team because the team knows about the quality
of the product, and this gives the
team confidence. And it saves a lot of
time in the long term because when you want
to add new features, there are a lot of
tests that will make sure that the old
functionalities won't break. And also, if something happens, you can detect it immediately
at the first step. So it will also help you
to save time in long term. And what is the difference between manual testing
and automated testing? So in manual testing, it requires a team. Manual testing usually
will be done by humans. So a software tester usually
be higher and then he he or she starts testing
every possible flow that in software can happen, and this is the process
of the manual testing. But manual testing requires team and it requires
a lot of time every time that the
software development team changes something
into the software, the A team needs to
do a lot of tests, and this requires a lot of time. As it is not error prone as we all human can make mistakes. So maybe in the first time, there is a bug and
somebody finds it, but maybe the next
time somebody forgot that he or she
should check a flow and then he misses this flow and then the
bug is not detected. So the whole process
is not error prone. And also it can be a boring job. Usually, when a team works over six months or one year and they are every day
testing the same flows. Sometimes it's getting
boring for them, and also when it gets boring, it means that they don't put 100 person attention
on this job, and it makes it that some of
the bugs cannot be found, and we are returning back to the item that it
is not error pro. And let us talk about the
4. Different Types of Testing: In automated testing, we have three different
types of testing. First is unit testing, second is integration testing, and the third is E to
E or N to N testing. What is unit testing? In unit testing, we are
focusing only on one unit. For example, a
function or a class, and our purpose is to test
this unit separated from all of the other
functionalities and all of the other components of our
in integration testing, we are going a level higher, and then we are testing the integrity been different
components and modules. First, with unit testing, we are sure that every unit
is working as expected. In integration
testing, our focus is to see how these
units work together. So for example, if the
API adds a new field and the front end is not
aware of this new field, then we can have an
integration test to make sure the integrity between
our front end and our BC. And the last one is
end twin testing. Into end twin testing, we will see the
suffer as a whole. We will test the whole suffer from the perspective regardless
of how many components, how many modules, and how these components
and these modules interact with each other. We are testing it as a
whole and as a system.
5. Testing Pyramid: Let's talk about
the testing prompt. As I mentioned previously, we have three different
kinds of testing. The first one is unit testing, integration testing,
and end two testing. And if we look at these three kinds of
tests as a pyramid, on the top, we
have unit testing, which is we have a lot of tests. They are fast when we want to run them
and they are cheap, so they don't require a lot of time and we can easily
write unit testing. They are easy to maintain, and they are easy to change. And as a result, we have
many of the unit testing. On the bottom of pyramid, we have end ten testing, which means they are usually
in production environment, there are few TN tests, and running this kind of tests, it is slow, and it
is also expensive. So it requires a lot of time for writing this
kind of tests and also maintenance of these tests are really difficult
and time consuming. And as a result, we
don't have so many end TN testing relative
to the unit testing. Not saying that you
should not have it in your project and
your production, the more that you
have TN testing, it is better so you can provide more quality
for your software. But relative to
the unit testing, which is easy to write and they are so much
faster for running, we have in practice in
production environment, in staging environment,
usually a lot less NTN testing relative
to unit testing. And between them, there
are integration tests. So there are more than
two t, fewer than units. And from the cost, they are also in between, so they are not as
cheap as unit test, but they are also
not as expensive as the end two testing.
6. Introduction to Testing Tools for This Course: All right, let's get
our hands dirty. In this module, I'm going to talk about the testing tools
that we are going to use for this project and also
I will show you how to set up them and how to install
them and how to run them. Let's get started. The testing tools that we
are using for react for this project is V test react testing library
and playwright. And we are using V
test for unit testing, and for integration testing, we are using react
testing library or RTL, and for TN testing, we are using playwright. In this course, I'm going
to show you step by step, and we will first start
by writing unit test with VTS and then we are going to write integration
testing with RTL, and then at the end,
we are going to write TN test with playwright. So let's get started. I already created two
repositories for the project. These are the links to the front end repository and
server repository. And then the next video, I'm going to show you
about the project setup. So we want to add test for a project which
is already running. I will show you the
features of this project, and then I will talk
you what components we want to test and how will
be our testing process, and I will also show you how you can run these projects
locally on your machine, so you can also follow with me step by step
during this course.
7. Simple Blog Repositories and How to Run Them (Part 1): So I have created two
repositories for this project. One is called Simple blog, which is a reactor application, and the other one it is
called simple Blog server, which is a packing
service for this block. In order to run this
project on your local, you need no JS, and first you have to
clone these repositories. So here, when you
press on this button, you will get a URL, and you can copy this and
then inside your terminal, you can write Git clone and
then you can write this. I already did that, and
here I have two folders. One of them is simple blog, one of them is simple
block packing, let me open a new tab. And when you've done that, you can easily go to there and to run the projects,
you need NodeJS. I'm using NodeJS version 22. So I also suggest you to use the exact same
version so you will make sure that everything
that I am doing, you can also do it on
your local machine. So if you run node version, I have version 22.14. I also suggest that to use
the exact same version. And here I will going to the first thing
that you need to do is run NPM install to install the
dependence of the project. I will pause the video and
I will continue after that.
8. Simple Blog Repositories and How to Run Them (Part 2): So I did the NPM install, and then after that, you
can easily run NPM Stop. Just one note that
you should notice, I'm going to change this
project and I'm going to add codes as we go in
this project together. I'm going to add some test. In order to check out the
start of the project, I have created a tag, which is called start for both the front end and
both the back end serve. And when you want to
check out the repository, you can run Git tags, and here you will see
that sorry, Gits tag. And here you will see
that I have a tag, and then you can check out this specific tag so
you can return back to the start of the
project and you can continue your work
with me step by step. And when I do the changes, you can also do the changes. After adding all of the tests, I will leave the repository
at the final estate, so you can also use
it in the future. Okay. Let's start. We already have the dependencies and also let us go
to the back end. And here I will go
to the simple blog. I and here as also I also
need to run in PAM install. I already did it, so my
packages are up to date. And here you have a file which
is called server dot JS. The only thing that I need to
run is node server dot JS. And you will see that the server is running and local host 3,001 now that our
backend service running, let us go to the front
end and let us run NPM start and now you will see that the client
is running in this pot. I'm going to copy this link
and I'm going to open it in my browser, wonderful. Now you will see the project.
9. Simple Blog Project Tour: So let's talk about
what is this project. I have created a simple blog that when you come
in your homepage, you will see a simple blog. Every block has a
photo, has a picture, a title, avatar of the
creator of the post. And then when you click on that, you can see the
details of the post, and then when you go back, you will see you can
back to the home page. As you can see, we
already have a box, so I already have my icon here and but when in the home page, this is a default icon. So this is one of the things that the testing can help us. This is an intended
that we will fix it in this course together and also we will provide the test for. We have the About page, which is tell that this is a log that I have created
for this course and also, these are the details for me
if you'd like to contact me. And this is the blog site, and we also have an admin tunnel which I
can write slash admin. And here, I will see the number of the posts
that have been published. And to be accurate, you should write
slash admin slash. And we can also
see the post here. We can create a new post, we can edit posts and
we can remove posts. So for example, if I go
and if I edit this post, and then I just had a two
at the end of the post, I can see that this
has been changed. If I go to the simple blog, I can see also this
has been changed. If I return back to the
admin home section, I'm going to the
post and I'm going to return this back
to what was before. And we don't have
authentication. Here it is not important
right now for us. Usually in the
production environment, you should hide the admin
and user should login. You should have a usernPassword, and this area should
be protected. But for this course, it
is not required for us. We got this project and now
we want to add tests for it. We are starting with unit
test and then we are going to integration
testing and then at the end we are going to
write some test with plat.
10. Introduction to Vitest & It's Features: In this course, we are going to use V test for unit testing. But what is VTS? V test is a fast unit
testing framework and it by default,
supports typescript. The react project that
I have created with TypeScript and most of the modern projects are
also with typescript. This is a really good
feature of the test that we can use V test
with TypeScript. And also it is just
compatible API. If you have previously
worked with react, a lot of react
developer previously were using Jest
for unit testing, and VTS and T are nowadays more modern tool and a faster
tool that we are using. And VTS is also compatible API. VTS has the compatible
API with J. So it is really helpful for the developers who have
already experience with the JS learning VTS
is so much easier because we have the same
API like describe it, expect, and all of these
APIs are the same. The learning care for VTS
for the developers who have previously worked with Jess
is so much easy and so much, it doesn't require so much time. One of the features
of VTS is that it supports code coverage
out of the box. I will discuss about the quote coverage in
the future lectures. But for now, just know that test by default provides us with the Code coverage report and it also provides the
parallel test execution. Our test doesn't need to run a sequential in
one by one test, run them in parallel, which makes them faster and
we can run our test faster. Let us go and set up
our test environment. In the next video,
I'm going to show you how to add the test to our project and we are going to write
our first unit test.
11. Vitest Installation: I have opened the
project inside my ID. I'm using webstorm. You can use whatever ID that you are more
comfortable with it. Webstorm is a
commercial product. You can get a 30 day trial if you want to use it and if you like it, you
can purchase it. I am enjoying a lot
with working with it, so I already purchase it, but you don't have
to purchase it. You can use Atom
sublime or any other text editor or ID that you
are more comfortable with it. And so let us see the
project structure. We have an SRC folder here. We have an admin folder which is related to the admin
section of the web log, which is post addition
post removal adding post. We have a folder called API
for the API communication. We have a constant
folder for the constant and the site
is the block part that every user can see the
post the shared is some components that
are shared between the website and admin. Let us open the constant
folder and here we have one index file and here three variables
have been defined. Let us set up test and let us first write our first
test for this file. To install test, I'm going to my terminal
and I'm going to write in pristall dash DSD means that this is for only
dev dependencies, and this dependency is not part of our
production dependencies. It is only for the development. When I run this command, you will see that package
package that Jason has been changed and if I see
what file has been changed, now inside our dev dependencies, we have V test. What is the difference
between depth dependency and the normal dependency
depth dependencies will be only used for the local development
because the tests we write tests to only
run them when we are developing and they are not part of the production
environment, so we install VTS as
a depth dependence. Now we have VTSt and let us go and here I want to
create a first test. By default, by convention, I will name it as a test, I would say index the test, the ts let us write
our first test.
12. Writing First Unit Test: To write our first test, we first define a
describe block and a describe block will tell
what we are going to test. Because I'm going to
test a constant file, I'm going to call this
constant and inside, second parameter will be a
function that I am passing. And here I will write it and here I can define what
condition I want to be tested. The first parameter is an
string that, for example, let us write the test and
let us make sure that the course name is stay always and the correct value
of which is this value. Let me then write my first, then I would say should return the correct value
for the host name. The second parameter is
also a function that I can pass and I will
define my test here. Here, we have what
we are going to expect from the test and
what we are going to expect. We have a expect function from B test that we can
give a condition and then it will check
if this condition is true or false or
what should it be? Here, I'm going to use course name and I'm going
to import course name. I'm expecting the
course name to be this advanced testing
with react and Test. I think here also, I have a problem because this
course is not about est, but I should write
it with playwright, but we will fix it together now. With this, this will be our first test. What
does that mean? That means I'm going to first
define a describe lock and describe is a collection
of the test and every test will be
inside it block, the first parameter will be a message that if
the test is failing, it should it will tell
us this message so we can identify which one
of the tests is failing. And here I'm going to write exactly what I am
going to expect. As you can see in my
vastorm ID already detected and I have
two bottoms here, and this is a cool
thing about gastrom that also provides
with support for TS. But if you are using another
ID or something else, you can just inside your
terminal write NPX V test. As you can see,
it's automatically detected and it is
running my test, but I have an error
and it says that describe is not defined. The reason is that we have
not configured V test yet. In the next video, I'm
going to configure V test.
13. Configuring Vitest and Completing Our Unit Test: So let's configure our test. Inside this project, there
is a file called it dot JS. This is a configuration for the T. In order to add the
configuration for test, I will also add a
parameter here. Here, you will see
that we are saying that our project is a a project. And also for our imports, everything which is sorted up, please replace it with SRC. Here I'm going to add a
section and for the test, and I will set the
globals to true and environment to
the J Describe, these are the global keywords, and here I'm telling VTS that to understand
describe and it. As you can see, the error is that describe is not defined. With this configuration,
we are saying that we want to
have the globals. For our testing,
which is describe it and also our testing
environment will be Jz. Let us go to the terminal. As you can see, it
automatically re run my test. I didn't have to start
and stop it again. This is also another
cool feature from VTS, which is automatically re running the test when
you are changed. Now, you will see
that my test is failing and it says that
our expected value is advanced testing
with reacts test and the received value
is something else. Let us go and see what
was actually the value. The actual value is here. Now, I didn't add the
playwright section, so I only said that I'm expecting this
value to be this p, which is definitely wrong. I'm going to replace this value. Now when I say we will see
that it automatically run it again and this time I'm
expecting my test to pass. As you can see now, my test is passing. I can also let me press Control C and
also run and pick test. Now I have one failed
test and one past test. This is the default
test by react. Let me also go and remove
this at the Ts five. I have created this
project with create react up and this
test has been created by react let me also
remove that and let us go. Now our test should be clean. We have one test and
this test is passing. Amazing. And know what is the benefit of
having this test? Where do we see this string
inside our web blog. You see here I have a simple block created for the course advanced
testing we react. If we do only manual testing, this text is in the footer
and when the blocks gets more complicated and a lot of people working with different
elements and the tester, can easily ignore this part. As a result, a
developer may come and start writing and maybe he
wants to write something, but he doesn't notice that
he's actually typing, so he will do this and
when he will do this, you will see that our
web log is broken. But with this test, immediately, we will see that one of
the tests is failing. So I can see exactly in which file and which
line test is fake. Let me first remove just because this test for the course
line will be atlas testing for react with test,
RTL and Plavt. I changed the test, but I didn't change
the actual value, so let us go and also
change the actual value. From these moments that I
have this test, I know, I am sure that this part of the text will
always be correct. Nobody by mistake if anybody by mistake
comes and for example, at the G, immediately, we have a test which is fail. Wonderful. Let's continue our
work by adding more tests.
14. Code Coverage Definition and Metrics: As previously I mentioned, one of the benefits
of VTS is that it provides the code coverage
report by default. And what does code
coverage means? Code coverage is a measure
for the quality of our test. I said that we are
going to improve the quality of our software
with automated testing. And now, how we can make sure what is the
quality of the test? Actually, what is the quality
of our automated test. And here there is a new concept which is called code coverage. And the code coverage is the percentage is a number
based on the percentage, and it is the percentage
of the lines and the code that will be executed when you are
running the tests. So if I have a function, if I have a class and this
class has ten lines of code, and if I write a test for this class and during the
execution of this test, eight lines of these ten
lines will be executed, then my code coverage
will be 80%. And this is the definition
of the code coverage. And but code coverage also
have different metrics. In the next videos,
I will show you on its and we can actually
see these numbers. Here I want you to give you the definition of this matrix. We have five numbers from its when we add code coverage report to
it, first is the lines. The second one is a statement. The third one is branch, functions and uncovered lines. The lines actually shows us how much percentage of the
lines has been covered. So like I said before, if I have a function
and this function has ten lines of code and
during the execution, eight lines will be executed, then the code coverage for the metric of the
lines will be 80%. Statement is similar
to the lines. The only difference
is that I can write multiple statement
in the single lines. In the lines calculation, this will be calculated as a one if I have three statement. But in the statement number, this will be
calculated as a state. And branch means whenever I have an IL condition or a switch case that based
on different condition, my program goes in
different direction. This is called branch
and actually its also provide many percentage of our branch has been covered during the
execution of the test. And the function,
also the number of the functions that have
been called during the running of the test relative to the whole number of the functions that we
have in our code bias. And at the end of the report, also VTS provides
us uncovered lines, so we can actually see which
lines of the codes have been covered by execution
of our tests and which lines have
not been covered. And by seeing these lines, we can improve and
we can also add more tests for those
lines that have not been covered to increase
good coverage and increase the
quality of our tests.
15. Code Coverage vs Test Coverage: There is also another concept which is called test coverage, and usually it will be discussed when we are talking
about the code coverage, code coverage and
the test coverage. These are two
important concepts. Sometimes they have been
used interchangeably, but if we want to be accurate, code coverage is actually
the percentage of the code base that is executed when we are
running our test. And the test coverage is a more general term and more
broad term referring to actually how much our
application behavior has been covered by the test. So maybe there are
some cases that our application we didn't even implement in
our application, and because we didn't even
implement it in our code base, even if there is
no test for them, it doesn't affect the
code coverage because this part of the
application logic has not been even seen. This can be this can
happen that, for example, a product manager hasn't
seen some functionality that existed and we didn't even implement those
part of the code. This coverage is a more general
term which also tries to address and those condition
and those scenarios. Here I wrote a simple example. I have defined a
divide function as a arrow function in
just one single line. I said that the first parameter is number and the
second parameter is number and please
return A divided by B. And if I add a test, and if I say, for example, I am expecting that when I
am dividing a four by two, the results will be two. Then my code coverage will
be 100% because I only have one line and this line will be executed during the test. So the code coverage
will be 100%. But here, I didn't
check if B is not zero. So if I call this function with A and for the
value of the B, I will pass zero, then I will get an exception, and this first, I should check
that B should not be zero. And this is a definition. This is the concept
of the test coverage. And actually, I haven't seen the behavior that B
should not be zero, and my code actually doesn't
even consider this option, and this condition
has not been checked. But my code coverage is 100%. So having a good code coverage
is a really good thing. It's something that you
should try to have it, but it doesn't mean that our application doesn't have any issue or any
bug or any error.
16. Adding Coverage Report to Vite: Now that we have learned the concept of the
code coverage, let us add our code
coverage report and let us see the code
coverage report for our test. To run the code coverage, I will run test, I would say NP
test run coverage. As you can see, it says this is missing dependence
cannot find VD coverage, V, do you want to install
it? I would say, yes. And let us wait until
this dependency gets installed and now we have it. Let us go and re run the cover. Here you will see that
no I will get a table. And these numbers are
the numbers that I have explained in the
slide assessment, branches, function, lines,
and uncovered lines. Now for our index that is file, we actually see the
code coverage report. This is inside SRC constant. If I go and if I
find this folder, you will see that SRC constant, I have the 100% because this statement and these
branches have been covered. You will see that this
actually is green, and the others are red. After that, after
running this command, I also have a coverage folder. I can also open this coverage
folder and I can also see the code coverage report by running this
index that GML file. Let me click on this. Let me right click on this file, and then I would run it and u. It has opened column and let me just copy this link
to my brave browse. Let's see it in our breve. You will see that here I have none of these
files have been tested, so I don't see any
value here and here I will see my
index at Ts five. Because this is an import, the moment that this
file has been imported, the lines all of these
variables have been initialized and all of
them have been executed. The coverage is 100%. Uh,
17. Digging Deeper in Code Coverage Report: Let us dig a little bit about the code coverage concept and
let me change this file and add a function as I
defined it in the slides that I'm expecting and function which A and B will
be number and it returns and it returns a value, which is number and
this is A divided by B. Now I added the function
and I don't change my test, and let us run and see
the coverage again. Because I am using webstore, webstore has a good integration with test that's actually here, if I write click on the
test file, I can run it. I can devugate and also I have this option run
index with coverage. And I will press this. However, if you
don't use webstom, you can always run the coverage
report with the terminal. But for easier explanation in this course, I'm
just running this. When I do this, actually,
it will ask me, do you want me to replace
the suit or do you want to not apply any
changes or replace it? I'm going to press replace
and then I'm going to refresh the page page that
I have here you will see that actually now
the states when we have 100%, the branches, 100%, the function where we have a function which has
not been covered. This is I will get a zero, if you go to here and
you can also see here, that now we have a function
that has not been covered. Let us go and let us
also implement the if condition let me expand
this and I would say, I want to return a divoid baby, but if be equal zero, then I want to, for example, true exception. New error that division
by zero is not possible. On de, I will go
and I will return. I have a typo here, so let me write division. I have an link tissue, express. I also have an link tissue here. Now, I added a new
condition here and I'm checking if B is zero, then I'm going to
through an exception. Let us go and let
us rerun our test. I'm going to replace. Sometimes there is an issue with coverage that in the first
time it doesn't work, so I'm going to
read on it twice to make sure that I will
get the correct number. Now you will see that change, the coverage report has been changed and let us
see it in our HT. Now, we will see that
actually the statement, we have nine statement, only four of them
have been tested. Branches is 100% function zero and lines is only four
nines have been. All right. Let us go and let us add a test. I don't need this test, I don't need this function, but I'm just using
it as an example. In the next video,
I'm going to add some tests for this function. Let me add a test. I can add a test by
writing and it's here, but since this is a
different function, and it is one of the best
practices to actually separate the things that are
connected to each other. I'm going to define another describe block and I would call it divide and here I will pass a function,
an arrow function, and then I would say, I should return the divide value of A by B. Then in my test, I'm going to add, I'm going to expect that if I call this function divide
with four and two, then it should be two. This will be my
test. By intention, I didn't test the zero parts, so let us see what will happen. I'm going again, I'm going
and run the test with coverage and I'm going to replace and you will see that this number has been
changed to 77%. Let us also see it here. So actually, now
you will see that previously it was red,
which was not good. Now it is yellow, so we
are not a sil green. We are not on a good
statement on a good status, but it is a little bit better. So seven of nine statement
have been covered branches. Now now we have a function. If you remember in
the previous video, the function was zero because we didn't call the function at all, but the branches was 100% because the function
has not been called, the branches has not been calculated because
except the function, we don't have any branches. We just define three variables. But now that the
function is executed and we have the 100%
coverage for the function, only one of our Is is being
executed and because of that, the coverage for the
branches is 50%. Our lines and statement
are the same. The coverage report for
these two are the same. Let us go and let us also add another test and let
us a test that we are expecting when this
time I'm going to pass zero and I
am expecting that this time I should receive
an error as an exception. In order to test that we can use a provider from test
which is called to throw. I can pass with this, I can actually say
that when I want to this function
should throw an error. I will also wrap it
into an arrow function because now that this
function throws an error, if I don't wrap it, then the execution of the whole
file will be interrupted. I'm wrapping it into
an arrow function, but I am saying I am expecting
that in is arrow function. Be executed, I am exciting
that an error to be true and that error the message relative to that error
should be this strength. Let me paste this value and let us now run the test again. And let us replace
the suit and amazing. Now we'll get 100% coverage. Let us go to the
coverage report. Let us refresh the page.
Now we have a green. Fantastic. All of the nine
lines have been covered, all of the statement
have been covered. We had an if and s, both of the branches
have been covered. We had one function
that has been covered and all of the
lines have been covered. Amazing. We did a
really good job. Let's continue our work.
18. Adding Unit Tests for QueryKeys: Let us continue our work
by adding more test. I already wrote a test for the constant
folder and we will see that the code coverage
is 100%, which is really. In this video, I'm going
to add tests for the API. Inside the API, I
have one folder for the models and one
folder for the post. And the models is the actual
data definition of the post. So if we take a look at this, we have a post type
and this post type has a ID title description
and has an image, author and the published date. And this is a simple type. So I don't need to write tests for the
interface because this is just a type definition. And if I go to the post, I have some
tanstaquery the hooks, and I have the query
line and query que. So if you are not familiar with Tanstaquery or re aquari,
it is no problem. I already have another course which you can take a
look at if you are interested introduction
to Tanstaquery or aquari. But for this course, it is not mandatory
to understand and know all of the features
of the Tansta query. And just to give you a small overview about
what is actually doing. So if I go here, I'm reading this blog
posts from the API. To do that, I can show
you, for example, if we go to the site, we have a page and here if
we go to the blog page, here we are using a hook which this is the
syntax of the rea cor, and I defined use pose which
has been defined here. And this function actually uses rea query to
call a function, which is called query
function, which is fetch post. And what does this
fetch posters? It actually uses Axios to
get a network request to the API for the API that
has the list of the post, and it will do a get request and then at
the end, returns the data. And because this is an async
action and I have here a weight and here a
sync with rea query, we can use an external hook with this four that I am saying, I need a query key, which will be an string, which here is posts, and then a query function, which is this function. I will define this
as a custom hook and here inside my component, I can easily just call this custom hood and
this will handle the Async operation of the calling the API
fetching the data. I can map this data to
a variable which is called pause and it also
return me a bullion, which is loading and also error. Is loading shows if this
hook has been resolved, this API call has been resolved and if there
is an error in the API, then the error will be set. And here inside the component, I'm checking if this is loading, I'm returning just a
loading component, simple in a simple paragraph. If this is error, I
will return error. And these two and
if this is loading, it's false and error
is also false, it means that I have
the list of the posts. So here, I'm going to map. The post and I show
them inside this page. For this course, the only thing that we need to know
is that actually a query uses a query client and we have these kind of
hooks and I use posts, I created this custom book
to return all of the posts. This one returns one
post with the ID. And this one is
for the addition, deletion of the pose and
creation of the post. However, if you are interested in learning more
about rea query, you can see my other
course introduction to Tana Sta query or Ra query. But for this course, we don't need to know a lot
about rea query. The only thing that
we need to know is actually just how
this function works. And for this video, I'm going to add write
test for this query. And here you will see this
is a really simple file. I just define query
key as an object. It has a key pose and
the value is post. Let us go and let us
create a test file for this and let us
call it query keys, the test, the ts and I'm going
to write a describe block. And I will have one
as written, correct, query key, and I don't
need async, I just need. I'm going to add expect
and expecting that query that posts to be posts. And let me run this test. This is a easy test also
let me run it with coverage and the coverage should be
100%, which we can see. If we return to
our brave browser, if I return to old files, now you will see
that inside SLC API. For this file, I
didn't add any test, but for this file, we
have 100% code coverage.
19. What is Mocking?: But the more challenging
part would be actually to write test
for these custom hooks. Let us see the first hook. So we have use post. And for simplicity, first, this is a function fetch post, and then we have use post, and then we are using
this function as a query function and we are exporting this
cons as a default. This function is private, and there is no export. For simplicity, I'm going
to export this function for now and we are going to first write a test
for this function. What does this function do is called the axis that get and then passes the URL for the
post and returns the data. But remember that
in unit testing, actually we are not interested
in the interaction with our back end and our APR and if I want to
write a test for this function and I don't want to run an instance of the
back end for my testing. And this test should be because I'm testing
only this unit. And inside unit testing, we have the assumption
that all of the other units are
working as expected, we are focusing on
just this unit. So how we can do that, and here it comes a really important concept in unit testing,
which is mocking. So what is the concept
of the mocking? Mking means replacing a
unit with a fake unit. And this fake unit
actually mocks the behavior of
the original unit. And this is the reason that
we are calling it mocking. When we are talking
about mocking, it means that we are
not interested in the actual behavior of
a unit or a component, and we just want to have a fake unit instead
of the original unit. And remember that
in unit testing, we are focusing on one unit. So we are not interested about
how the other units works. And because of that, because
we want to add a test for one unit and we will use mocking for the other
units and we will make them as a fake in
order to just act as we expect instead of
running the real code behind them and we only focus on the unit that we are actually
writing test for it. How can we do marking in its? It is so much simple
which can just write dot Mk then we will pass the name of the module
that we want to mark. In this example,
I have used axis. V is also the short form for VTS and the mark is
actually the function, so I can easily
mark an axis module with dot Mg. Let's
see it in practice.
20. Writing Unit Test for FetchPosts with the help of Mocking: So in order to write test, I'm going here, I'm
creating a file. I will call it use
post test dots. I will add a describe block, and call it use post and
the function inside it. Inside because I
have two function, I will create a describe
block for every function. The first one will
be fetch post. I just for the part for the E, let us just make
it empty for now. I will explain it later
what we want to write here. But what we actually expect
for this function to happen. When we are calling
this function, we are expecting what can go wrong if a developer
changes this URL, and we expect this
function to call the correct URL and then returns the correct
data. Let's do it. I'm going and let us add expect lock and we want to import
fetch Bs instead of this, I want expect fetch to be to to a strict equal. When I say equal, usually it will be used for primitive types like
integer numbers. But when I have an object
and because in Java script, the objects will be
compared by the references, I'm interested in actually the
properties of the objects. I want to just
have strict equal. Let me just run it to
see what will have. So as you can see, this shows an arrow, expected promise because
this function is an ASN function and I
am just calling it. Let us first fix this. Let's call it the response and
let us wait for the result and let us say that
we are expecting that response to be
something response. Because I'm using a weight, so here I should also add an ASN keyboard here
and let us ignore it. Because this is an array, actually I should pass
an array of object. Let us fall now,
pass an empty array. Let us run the test. Now, you will see that actually It is called
the actual IPI, but this is not what
I am expecting. If I stop the server, let us go and stop the server. Let us stop the server and
let us know run the test. And now you will see that
actually us cannot run. This is not actually
we are looking. We don't want to have
a server running. We don't want to have an
interaction with the API. In the end twin testing, yes, but in the concept in the
scope of unit testing, we just want to have to
just work with one unit. And for that, I'm going to use marking and I
would say dot Mk xS. With this line, I'm
telling that actually, I I don't need axis itself. I need only a marked
version of axis. Now that I wrote this line, you will see that
this part is red. Let's see what you're saying. It says cannot find name
at file globals Ts config. Let me do it and
now I can do it. Let's see what has been changed inside our Ts config file. It added the types
for the VTest. Also TypeScript understands
that we are using VTS because these are
the keywords from VTS. Know that I added this, actually the exxus has been replaced with the
marked version. After that, I can pass and I can say that whenever you are
calling the exxus with the G, I want to get a
response instead of having a having a real response. Let's just define a response. What we want? For example, we
want a marked pose to be an array of the post type. For example, ID would be no this variable would
be an array of post type the post tip has
so many parameters. Let's see what it says. Let us ask our ID to place where it should provide us with some automatically fill
in data more action. No and I'm passing an empty object using the properties IT
title description. Unfortunately, it
doesn't appear in it, so let me just type
ID would be one, title would be a string of title and description would be
a string of description, what else I am missing created
image author published. Created t will be
an empty string, Auor will be an object. Over you will be an empty string and the name will be a string. Let me just use my name. Now we are missing image and published dates
and the image also lets us go with an empty object and the published date
also empty string. Now let us fix the whole
file with the preta m. And current file. Now I want to use this as a
response for the API call. I can do that by
saying that's marked. I am saying every time that axis that gets has been called, I'm expecting to
get a result value, which is an object and the
data will be marked post. Let me also import axis source. So here we added dot Mg
which we are telling actually we don't need
axio and here we are telling that whenever
axiusG has been called, this is exactly
what this function does is calling this function. We need to get this data. And now when fetch
post has been called, what does fetch post cause? If we replace this
line with that value, it returns the data property, it returns this object. I'm expecting and my
condition should be that this response should be this marked post
that I have defined. Let us run the test
and it should fail now because now I
added this object, so let me replace it and
marked post and after that, this test should pass. Wonderful. What is happening, let me summarize it again. I am defining an array of some objects and I am telling whenever Axios
has been called, please resolve because
this is an ASN function, I am using marked result value. We have also a
mark return value, which is for synchronous
operation for ASN, I'm using mark result value. Please return an
object which has a key which is data and the
response should be. Whenever we call the fetch post, we are expecting
that to get this. Here, if I start the server, now you will see that
still the test is passing because it doesn't have any interaction with
our node JS server. It is just a completely replace axis with
the marked version. There is also another thing
that I want to test here, which is actually when
we call this function, we want to make
sure that actually XS get has been
called and has been called with this
correct parameter. To do that, I will also add
another line for the expect. I would say I'm expecting that axus dot called and T provides
us with the function, which is called have been
called WT here I'm expecting that it should have
called with this UR. I'm going and I'm going
to pass this value. Let us run the test again
and the test is passing. If a developer by mistakes come and change this to, for example, APURA let me also
import this No, we have a test that
actually tests that fetch post should be called
with the correct URL. Now, this test is
failing because it says that you have been expected to be called
with a slash post, but this value is not correct. Now we are sure that any changes to that
function will be tested. Now let us write the description of the
I what I am testing, I would say returns the
correct data from API. Let us also see the coverage
code coverage report, let us run it with coverage. Let us see our let
us go one level up. We have the API fold there and let me go to SRC API posts. We didn't add any
tests for these files, but I have used posts and this
function has been tested. These red lines means
this *** has been tested, which is not the function
that we wanted to test. But now it is amazing. All of this function
has been tested.
21. Writing Unit Test for usePosts: So let's continue our work by writing unit tests
for this function, which is use posts. And what do we expect? We expect actually use query
comes from react query, so it is an external library. I don't need to write units
for external library. What I am doing is actually
I should make sure that I am passing the correct query
key and query function. And when this hook
will be resolved, I'm expecting to get the data that I am
expecting from that. And in order to do that, first, we need to let me go to the describe block and let me add another
describe block. Here we are going to add another described block and
this will be for use post, and I'm going to
pass a function, and here I'm going
to add new it. For the message, I would
say it is good returns the correct data from the APA. Let us because this
is a custom hook and I need to render
this hook and I need to wrap this hook
inside the provider. How we can do it. I will
define to using a rea query, as you can see here, we have a query line first, we should first
initialize a queric line. Let us come here. This is also an interesting
part that I want to show also some of
the definition. Like it, we have
another block which is called before each and this before each
will be run before every test will be executed. If we have some variable initialization and
stuff like that, we can also put it here
and but for this test, I don't need it, I will define my variable exactly
above of this test. Let me put this inside the other describe block
because here I don't need this. But let me put this here. Let me also create a
wrapper function that's actually a strapper and it expects an intro turns as a JSX element, aquatic client provider Aquatic clin provided. And our clients will be. Let's also close this. Now because I am using TSIX, I should also rename
the file to TSX. Let's import this query
client provider then you also need to import
this from the a que our client will be
the quer client and everything else will be
going inside this I'm just ping everything
that I am passing to this I will pass
children properties here and I will say that hilern
is a type of react nut and the ton will be react elements then I
have a type here. This will be the wrapper. Now I am expecting that returns
the posts from the APA. Let us start writing this. What we expect if we're
going to render this hook, we if you get the results here, I'm expecting this result. I'm going to use
react render Hook which will explain it in a
second and I will go use post, and then I will also
pass the rapper here. I will import use post and also I will import from
testing library react. Testing library is the
react testing library, and we are going to discuss it in the next module which
is integration testing. For this video, I'm
just importing it. For now, the only thing that you need to know is actually, I have a custom booking
react and in this way, I can render this book
inside this wrapper. Let me also fix this pretty. When this is happening, the result will be set up. But this hook is Async hook and how can I make sure that
this has been resolved? Because this is also
an ASN function. We have a function which
is wait for again in the react testing
library that it will block our execution until one condition
has been met. What is the condition? What is the condition we are
expecting that the result that current is
success to be true? What does this line means? We are saying that
because this is an AC and this is when the current
success is true, please wait until that moment. What does that mean? That
means that react renders this hook and then rea
query calls the API, which we don't want the API, we are replacing it
with the mark version. But when the successful that
promise has been resolved, we can add an extra condition
here and after that, we will make sure that fetch
post has been completed, we can get the data from
that with current data, and we are going to expect this data to be equal
by the marked posts. And I should do exactly what
I did with the marking of the posts that I did here there. Because this variable
is the same, so I will bring this up into this level so I
can use it in both and I'm going to
also use this line. Exactly like the
previous example, I'm making I'm marking the
axis that gets and here I'm expecting that after that the results should
be this value. Let us run the test amazing. Now the test is running, to make sure that we
are doing it properly, I can just change
it to something like an empty array and
now this test should fail, of course, because we are expecting to get this
array of object. And also the other
condition that I like to check here is that fetch posts to have been called actually with the
proper message. And But for now, we can just ignore that. I do it in the next video. Now we added the test. For this video, it is
maybe it is too much. If you like, please return if it was difficult
for you to follow, please rewash this video. Now let us run the coverage
and see the whole coverage. Now we have two describe blog, one for fetch boost, one for the boost and
both of them are running and now you will see that all
of the red lines are gone. So amazing. We have 100% coverage for this. By writing this test, we learned a lot of concepts. First of all, we learned
about the mocking. Second of all, we learned
about how we can actually render a custom hook
inside the wrapper. Then we also learned another
function which is wait for, which is for Async operation, we can block our execution
of the test until we make sure that the
reacquery response is ready. And we know that it has been
successful and it is true, and then we can check our
condition that actually if we mark exusgs if you are saying that whenever exxous that get has been called, then when this hook
has been resolved, then the value should
be marked process. Let us do a little bit cleanup. As you remember, I added this export to
this function just for the explanation
purpose because it was easier to test this function. If I wanted from the
beginning to test the hook, then you should know
everything about the marking, everything, but it was
easier to first explain it. Just for this, which is easier
and then for this hook. But you will see that function, most of the tests that
we wrote is similar. Actually, we don't
need to export this function and
this function should be kept private inside this. The only thing that
we need to use is actually to test the actual
hook. I remove that. I will let me also
remove fetch post here. And let us run the
test to make sure that actually we didn't break anything and now I have one described lock in
the post in the top level, so I don't need this
described lock. I can remove it and also I can do a fread here
for the whole file. Now it is easier to understand marked we have a marked object, we have a querc alliance and we have a wrapper and
then we marked it and then we expect that I can also bring this
inside the test, it lock this is related
to the to this test. In this test, we mark
the axis that get and then when we render the hook, we expect the results
to be this value.
22. Writing Unit Test for fetchPostById: Congratulations. We added
a really complicated test, and I'm happy that
you are with me here. So now that we have this test, adding a test for other files
will be so much easier. Let us do it. Let us
also see the use post. This is also similar. We have the axis that gets the difference is that here
we are getting a post by ID, and then here we also returning this function as a query function for this Hoch, and we also have it
as a as a query key, we have two parameters post D. Let us go and
create a test file. I'm going to I can also just
copy and paste this file, use post, and I can call
it, this one, this one. Use post that test 65 and
I will inside my descri, I will go with post and
these parts will be similar. I would say returns the
post by ID from the APA. This time I'm expecting
if I have this time I expecting that as that gate will return
me a single object, not an array of the mark pose. We can also change
this instead of an array to be only
one object and I will return this remote these lines and let us fix the pret
here for this file. Here we are going to expecting that we will return one object and then we are going to
instead of use posts, you are going to render use postcode and then we are
expecting the data to be marked post and you can
also replace this because this is not an array so let us also use a single
form for this variable. And we don't need to use post, let us run these
tests, wonderful. Let us also run
with the coverage. Let us also see the
coverage report. And here, amazing, we also
have 100% code coverage. This is a really important thing that I want to tell you that this is happening
with testing. Maybe at first, it will
require a lot of time. But when you have a little
bit of test when you already your project structure is good and you
have other tests, you can easily easily
add more tests. Sorry, I just forgot here
that I can also should as a number as a parameter to
this. This is really easy. Now, I added another test and I also let us go and run the
coverage for the whole files. I can run it with rung coverage. Now that we have both of
our tests now we will see that we have
100% test coverage for most of these files.
23. How CreatePost Mutation works?: In this video, I want to
write test for create post. This is a real query custom book that allows us to create
post inside our weblog. But first, let us see it in our dashboard and let us
see what is happening. So here inside the
admin dashboard, I have C post, which is meno which
I can see all of the posts that have been
published on the weblog. And I can create a new post
here by writing, for example. Title, test description and I can also upload the picture. I will use a docure if I
submit the post now you will see that immediately I have four posts and if I
go to my dashboard, as the number of the posts, I will see four here. If I remove this admin section and if I go to the web log, we also have a new post here. So how did I implement this? I implemented this with
a mutation in a query. Let us see the source code. One of the really
good benefits of rea query is that all of these actions can be done
without having a store. This is a different a
component. This is a table. I have a new form
inside this page, which is a different
rea component and how these components
interact with each other. Because now as you saw, when I created an element here, this table has been updated immediately and also this number has been updated immediately, and this is happening, for
example, with deletion, if I delete this post, now, if I go to the phone, you will see that this number has been updated immediately. Rea query provides function
in validate queries, which inside that when
I am using mutation, mutation is being used when we want to change data
on the server, for example, addition, creation, deletion, and all of
these three are mutation. And when we want
to read the data, we will use query and when we want to change
the data on our API, we will use mutation. And here you will see the code. The code is simple. I'm just calling a post on the post endpoint and I am passing a form
data which is all of the title description
on the image with the header and success, I also forgot what
call it here common. On success, when
this API has been resolved and this
API has been fixed, I'm asking rea query to
invalidate the query, and what are the
queries that I want to invalidate the queries which
is related to the posts. And with this, I'm telling
rea query that you need to refetch and recall all of
the hooks which is related, which have these query keys, which is, for example, use posts because this is also you will say that the
query key is the same. So when we do that and when we know that we added a new post, the list for the post
should be updated. Then Ra query does this for us. The only thing that
I need to do is to say invalidate query, and after that rea Query understands that this
list has been updated. We can also see together. If I come here, if I go here, if I go to the Netfox section, I create ATPost
when I press here, when I add a new entry, you will see inside my NetforxtpF
I have a post request, which is for the creation
of this No blog, and the payload is
the parameters, the thing that I have entered. The interesting thing that I have get request for the post, and this is happening
by invalidate queries. So rea query understand that now this query this query
key has been invalidated, so it will recall the API and this time the API
returns four object. So this table will
also be updated. And this is happening.
We can also see, for example, for deletion, we will see two requests. One first for the deletion
and this is now, again, the request for the G and
now we have three objects. And this is happening
by this line. So to write this mutation, I need to add two tests
first to make sure that I am calling the
correct API endpoint, and the second one is
actually when we are happening when we finish
success is happening, I want to make sure that I am invalidating the
queries and I'm also invalidating the
correct query key. The
24. Writing Test for useCreatePost (Part 1): So let's start writing
test for us create post. I can do the testing
like we did for us post by marking the axios, but in this video,
I want to show you another way of the
testing that we can do. To do that, I want to move this upload post
to another file. Let me create a file
and call it api. Let me move this const to that, let me import export
default upload posts. Why am I doing this?
Because I want to show you another
way of the testing. Now that I did this, now we are importing upload
posts from these APIs. We also need the comma here. Now I want to write units
for this and I want to treat this upload post as an external dependency that
it outside of this module. There are two ways
that we can do marking on test versus with dot mark that I showed you in the previous videos and another way is with
the method of spy. And for this video, I want to use this new method. Let us go and I will copy this use post
test and I will call it use create pose and I will also change my
describe to use Create Pos. Here I want to add a new
test that that actually, I want to make sure
that when my mutation, when I use create pose, it calls the API with
the correct parameter. So I will call it
calls upload pose when mutate is called. Instead of marking axios, I will remove this line and
let us see use create post. I want to completely mark
this function because now it is an external dependency to this unit and in unit testing
as we discussed previously, I'm not interested in
what other units do. I want to completely replace this upload post
with the marked version. To do that, I will go and I will call I will remove this line
and instead of this line, I will call Spire. As the first parameter
I will call it, I can let's also go and change. Let us import stars AVs from up a slash post slash aps Ts. The first parameter
will be the module that I want to mark. The second one will be actually the default exports
which I want to mock, which in this case, is this upload post. With this, I am
saying that whenever the default module
of this APIs module, which is upload post
has been called, I don't want to run the
actual code inside it. I just want to return
a mark value for me. What does this function
do when the API calls, it will be successful, it will return the post. I will just pass the mark
post that I have created. And in this way, I can say that whenever this
API has been called, please don't go to Axios, don't execute the code, return me this object. And with the spy on, we can actually see if this
method has been called, how many times has been cut with which parameters
have been called. So it returns in spy version, a very well, which
I stored and I will call it upload post Spy. And now I want to actually call and actually
call my mutation. Instead of use force, I will change this to use
create force and I will import this and the wrapper with the same so I'm
rendering this hook. In order to call the mutation, I will call results that current that mutate and
I will pass it mark Post. And I will need the
weight for block, but there will be a difference. I am going to test is that
I'm going to expect that my SPI to have been called and also its provides us to have
been called times. I'm expecting that it has
been called one time. I have an error here because
I'm passing the mark time. Let us see the create post. So when we are calling when
the mutation has been called, the parameter is four data, so I should pass the four data. So let us fix that. Let me create mark post data, which will be type of form data. And let me attached
to this a title, an ID, which will be
one and a description, which will be description. And when I'm calling the mutate, I need to pass
this Mk post data. Let us see together
what is happening. I'm creating a form data object. I am replacing the default
import of the APS, which is Upload
force upload post with the Spy version and I am saying please return
me the Mk post that I have created previously,
and this is the Spy. Now I want to
render my mutation. Whenever the mutate will be
called with this form data, I'm expecting that the
API should be called. Let's run the test.
And wonderful. The test is passing. So if I change this, for
example, to two, this is definitely should fail because there should
be, as you can see, it says that you have expecting it to be
called two times, but it has been called alta. And my condition for
this test should not only be also that this
function has been called, but I'm expecting also to have been called with
the proper parameters. So there is another function, and to have been called VD. In this way, I can also test that actually which parameters, function spy version of this
function has been called. I will run the test and
now the test is passing
25. Writing Test for useCreatePost (Part 2): So the first, the first part
of the test has been done, we wrote the first test
regarding the use create pause, which was related to
the mutation function, which is upload pause. Now we want to test this
success. What does this do? This actually reads
the query client from this file and then calls the invalidate queries
with this query key. We want to make sure
that first of all, whenever this mutation has been called on success
of this mutation, invalidate queries
will be called and also it will pass the
correct parameters. Let us do it. I will just copy this test
and then I will start changing what I need
to change for this. Let me also change
the description. I will write invalidate
queries and success. The form data stays, the render hook stays,
the mutation stays. Here, instead of testing, I also want to create an spi for this quercline
because we are also importing from a API quercine. Let us go at the top
file and let us import ts query client I am importing this query client and here I will also
create another spy here. For this spy I'm going
to I'm going to use this module and the method that I want to create an Pi
is the invalidate queries. Here I can also write return
value, mark result value, but for this test,
I'm not interested to what is returning
with this function. I just want to have an SPI as the name suggests Spy
means spying on something. I just want to make sure
that after this mutation, this invalidate query has been caught and has been called
with the correct parameters. I will define it as
invalidate queries spy. Inside my expectation,
I'm expecting that invalidate query spy to
have been called one time. Let's run the test. And now we will see that
the test is failing, so let us debug it together
what is happening. Here I have success, here we have the invalid query. My bad, this was a mistake. When I see the reference
of this query line, this is actually it is going to this variable that
I have defined here. It is also always good to sometimes show errors
that we are facing. It is not like that whenever I start coding, everything
works perfectly. You will see that this line has been covered because by mistake, I have used the same. Let us go and let us call this queric client
module, for example, inside our Spi we expecting to to actually expire on this module and then
let us run the test. Now wonderful it is passing. Now I also have a typo here. Now I am sure that
this is getting cut and we also
want to make sure that a it has been called
with the correct parameters. I will just let the test fail because we are sure
that this is not one. Let us see the error message. So now you see that the
test is failing because it expects actually to receive an object from
query key to posts. So as you can see, the passing
object is query key posts. So I will change this, let us fix this by query
client and not query client, query key, and the
value should be posts. And let us run the test
again and let us see query and also it should
be an array because we are also passing an array
and not just string. Let us see amazing. Now our test is passing
by writing this test, now I am make sure that if any developers come by mistake, for example, adds
something to this. Now I have a test that will fail and will prevent
this to happening. And this is the benefit of having unit test and
automated testing. If for example, another
developer comes and by mistake removes these lines
of code or changes that, this test will also fail. We are always sure that
everything will work as expected. Now that we have the test also let us go and run the whole block with the coverage to see our
code coverage report. And let apply and let
us go fresh this. Wonderful. Now, you will
see that actually use Create Post has a 100% coverage, this test all of this file has
been covered by our tests. I will come in and push my
changes and I will continue my work by writing tests for
use edit and use delete.
26. Unit Tests for useEditPost & useDeletePost: I added two other tests
for the other hooks, use edit post and use delete post and most of
the codes were similar. So I strongly recommend
you to pause the video, try to write the test. You can use the other
tests that I wrote, use Epos and then learn it
from it and write the test. For example, there are
some small changes, but it is also a
really good practice that you do it for yourself. For example, here
in edit post in our sucton we are
invalidating two queries. First is the relative
to the list of the pose and the second
is the relative to the ID of that specific post that has been edited the
way that we can test this is that I can call I can ask that I want this
to be called twice, and I want it to be
called one time with the posts as an array and also one time with
the post and ID one, which is ID one is
the ID of this post. And now we have a really good test for
all of these folders. So let us go and let us run
all of our tests and let us and to see the whole
coverage of the project. I can also do it
on the terminal. So if you are not
using Web store, we can run NPEgs with
Rundah coverage. And here if I return
back to my browser, I can also see on my terminal. But if I return here, now you will see that actually
our API is 100% covered, our constants and hostile, all of these these hooks
that I have created, all of them have
been 100% covered. So all of the statement, all of the branches, all of the lines and everything
has been covered. And for this module, I didn't create external
tests for these files, and that's the reason that
they have not been covered. And for now, we can ignore it and this is not
important for us right now. But there is an
issue with the test, and we can improve our
test a little bit more. Now it is really good that
we have 100% coverage for almost everything and
we can also run this here so you can also
see it inside our ID. Here you will see that
all of these files have been 100% covered
with the tests. But there is another
improvement that we can do to make our tests better. In the next module, I'm
going to talk about that.
27. Test Factories and Their Benefits: There are some
improvements that we can do to have better testing. Imagine here, we have
added so many tests, for example, for use created. Use create post, I
have a marked post, which is type post type and I have a hard coded object here. Inside use edit post, this is also the same
inside, use post. Again, we have a marked post, which is a hard
coded object inside, use posts have an
array which contains only one object
and this object is also a hard coded object. This is a type definition. Imagine that you are working on the production product and after sometimes there is a new
requirement for customer, from business development
team or from support team that every post should
have another field. For example, number of
the likes or number of the comments for this post
or an array of the comments. And in order to support that, we should and the API first will provide that data and imagine if we want
to implement that. Then for example,
number of comments. The way that we will implement
it is that we will change our type and we will add
this parameter to that. But now, all of our tests we have this problem
that because these values, this has this field didn't exist in the time
that we wrote the tests, now we should update
all of the tests again, the property does not exist and we can also see
in use create pose. This is a problem that we can solve it by using
test factories. With test factories, instead
of hard coding an object, I'm going to define
a function that returns to me one object, and this is the test object, and then we can change
our implementation in a way that these tests only use that factory and they
are not dependent. They are not hard coding
on the fit. Let us do it. I will create a folder, I will inside SRC, I will call it test factories. Inside test factory,
I'm going to create a new file and I'm going to call it post factory dot ps. Inside this file, I
will define a function. I call it I will call it, for example, get test post, which is a function
which returns a post type and the return value for this
function will be the post type. The definition would be, I can simply return this
object, for example. I will also need to
import post type. I can even make it really
simple one line with this because I only
return one object. Let us go and for now, let us first remove this type
to get rid of this error. And now I have a function which actually returns a test object. I will go and inside all of the tests that I have
created for the API. I'm going and instead of this, I will just call this function. Test post. Inside my factory, I also need to export
default test post. Here I will just
call this function. H. And inside my edit post, I will do also the same thing. Inside use post, I will also replace this
hard coded object with KD test post
and also import it. Here I think I
forgot to import it. Let us also import this
one inside my use post, I will also replace this with get test boost and
also need to import it. They can also simplify
this to this let's us run all of the
tests to make sure that we didn't direct
anything and wonderful. Now all of the tests are passing now if the API is
changing and for example, if we need to add a neopl, the only place that I need
to add this will be here. For example, I will go. Now again, none of my
tests need to be updated. None of these changes. Need to be done. I will
just put the value here. Let us keep it as it is. Perfect. This is the concept of the factory and factory
is a design pattern in software engineering
and the test factor is called when we
are using factories, some functions that generates
us an object and we will use this object inside
our tests in this way, we are separating the domain
definition from our test. If anything inside our domains need to change in the future, we don't need to update
all of our tests. We just need to
update our factory.
28. Introduction to FakerJs: Another improvement
that we can do for our test is that as
you can see here, I hard coded some values
as the test object. But in real life and in
production environments, users will use our software
with different dataset. This dataset can have
some special characters. So H cases might happen
with the string with numbers and a lot of
these cases can happen, but if we only have one object
with hard coded values, and this cannot test all
the possible solution, all of these possible
situations that can happen. In order to address that issue, we are going to use
fakare library, and FakreGS is a
library that generates data that mimics real world
values like names, addresses, date, anything about email, anything about, for example, a name of the person, a name of a company and
stuff like that. And are going to change test, factory to use faker in
order to generate and get a test object which actually is a real world object
instead of coding value. There are benefits. The first thing is we can have dynamic
and realistic data. And also there are benefits with face that we can
easily create arrays and have multiple entries that these entries
are not oplicated. In my case when we have use post when we create
a test for use post, I just created an array
with one element. But with Faker Js, I can easily create multiple
objects and multiple arrays, which is more realistic to the
thing that I want to test. And also it provides us with better test coverage
because the data is random. It may contain a
special character, it may contain Hcases. If you are working with numbers, it provides us negative numbers, positive and all of these
things can be put into our test and actually our test is testing
the real world data. Also it provides us with a way to avoid
hard coding values. In the next video, I'm
going to install faker Js and I'm going to change
our test to use Faker.
29. Using FakerJS with Post Factory: So let's start with
working with Facare. You can see the official
website of facare in fakjs dot v. Here, you will see they have
different modules for person, location, date, finance,
commerce and localization. I will go to get a start
and here for installation, I'm just going and copy this
and this is what we need. I'm going to our terminal. Again, because the whole testing
is for development only, this will be installed as
only a dev dependency. Now that Facure has
been installed, I'm going and I'm
going to import fac so I can import it
from the package. I'm going to write
FacimportFakre, from Fakre Js. Instead of hard coding
number one for ID, I'm going to use fare, that data type, fare data type, umber or fare number. That's it. This line actually returns
me a random number. I have a weather storm issue
which is not important. I didn't understand that. I already install it,
but we can ignore it. For Titan, I'm going
to use random string. I'm going to use Fac Lorem
that sentence for description, I'm going to use to generate a random paragraph
and this time, I will go with paragraph. For created that faker provides a lot of helper
for working with dates. I'm going with faker, that dates and because I
want to use a recent time, there is a helper
function recent which returns a recent and I'm going to convert it to Iosring because our type
definition is a swing. And for our tR URL, we need a random image URL, so I'm going to use the image of the image or module
of the faker, and for the name, the name
should be name of the person. I'm going to name and I
will just use first name. I think this has
been deprecated let us see I think it
says use person instead instead of
let us go and pick the first name and you can also use the full name for this. For the image, again, the only thing for us
is important is URL, so I'm going to just create
an URL for published date. I will go and I will date. This time I will use a past. A past means that
it has been passed in some date in the past. Because it is String, I will convert it to ring
and for number, I'm going again to
use an integer. Also we have some options. For example, I can provide mean and max because
for example, I know that the number
of the comments is always a positive number, so I will use a minimum
value of four Z. And now you will see that every time this function when this
function is getting called, we are getting a new object
and this object does not have hard coded values and it is with some real data and it has
been filled with real data. Now that we have the fake, I can also go inside my use post and here instead of hard
coding only one value, I can use an array of the faker. Faker also provides
an easy way to actually generate multiple data. In this case, I'm
just going and I'm using array dot From. I'm going to pass an object which the length
would be, for example, ten and inside and I will pass arrow function and inside that I will use this. In this way, I can
also actually, when I have an array, I can also replace this
with a more realistic data. Let's run this test and make sure that this
test is also working. I can also make
it better instead of having a fixed length, I can also go and I
can use with faker and then can go to number
and ink with something, for example, minimum one and
let me also import fake. And maximum would
be, for example, 20. I just need to fix it. In this way, I am actually testing my code
with real data and every time I'm getting
a random array which contains all of
the random objects. Let us go to the terminal
and let us run all of the tests to make sure that
everything is still running. Perfect. Okay.
30. Unit Testing Module Summary: All right.
Congratulations. You have finished this module, which was relative
to unit testing. We have covered a lot of topics. First, we start
talking about VTSt, we installed and configured VTS, and then we talked about
the code coverage, different metrics that exist in code coverage like lines,
branches, statement, function, and also
we discussed about the differences between the code coverage
and test coverage. And then we dig into the coding, and then we added
some unit test. First, we wrote some
simple unit test, and then we talked about the advanced concept
in unit testing like marking and also using Spy with the method
of spy on invites, and we added some unit tests. Also for each unit test, we calculated the
quote coverage to make sure that we will test
all of the possible options. And then after that, we started to improving our test with using of
the test factories. We talked about the factory. What is the definition
of a test factory? And we have created a post
factory for our project. And at the last module, we also talked about faker Jes, and we used faker to generate realistic data for
our test cases. This module was a really, really good module that
you have finished, and now you have a really good understanding of
the unit testing. I also encourage you if some of the parts
were not clear for you, you can always return back to these videos and
watch them again. Or you can also
finish the course. And when you have seen all of the videos for the
future references, you can always return back. Maybe some of the
parts will be more clear for you if you
finish the course first. But congratulations to you. You did a great job. So maybe you can take a
coffee and get a break, and then I will be happy to
see you in the next lecture.
31. Introduction to Integration Testing: Congratulations
for the finishing of the last section
about unit testing. In this module, we are going to talk and work about
integration testing. Let us do a summary about
what is integration testing. As we said previously, unit testing focuses
on one unit like a function or a class as we
did in the previous module. For example, we started writing
tests for a single unit, and for the other units, we used marking and spying to replace them with
the marked and spied version. So our focus was
only one motion. And in the integration testing, we are going to
test the integrity between different components
and different motions. And if we return back and if we look at
the testing pyramid, integration testing
is in the middle. So they are not as
many as the unit test. They are still
faster than testing, but slower than unit testing, and writing them is a little
bit more challenging. So they are not as easy
as cheap as unit testing, but they are still easier
for writing two testing. In this module, we
are going to use react testing library for
writing integration tests. And first, we will
set up this tool and then we will work with this tool to write
integration test.
32. Seting Up Environment for Integration Testing: So let's start writing
our first test. First, we need to install the dependencies required for
the react testing library. I'm going to show
the package that Jason filed and here I'm going to test I'm going to search
for testing library. From the previous video, we added the testing
library dump. Just don't react
and user events. So we already have the
dependencies inside our project, and we can start
writing our test. But for the configuration, we also need to change
our IT configuration. Let us see our with conf. Here we added a test section, we set global suturu and we set the environment
to the JS. Here I will also add
another line and I will add a key which is
setup files and I'm going to pass it to
SRC slash Setup Ts. Inside my setup, I'm
going to create a file, creates a typescript
file with setup. Inside the setup file, I'm going to import
testing library JSA. I'm going to put this line. This is the this actually helps that when we are using some matches like to
be in the document, it makes it globally available, so we can ID our ID understand
and we can also use them. And for our first component, for our first test, let us go and let us write
inside our share folder. We have a components folder. We have an index file, and I want to write my first integration
test for this component. And what does this component do? Actually, when we are
visiting our website, when we are on the home
page of our website, we have a post component, and when I click on that, you will see the
picture of this post, the description of the pose and the person who wrote this post. As you can see, we
already have a bug here. Here, the image is wrong and this is if I am
the writer of this post, then the image
should be corrected. For this one, I'm going I want to add a
test for this component. Let us see at the source code, it's going to we have a cospose which
is a type of pose type and here we are reading
image and title from the post and then we
have a style card, which is a and design element. Then here we are setting Avatar, avatar is a hard coded value
and the title of the post. What am I going to test, I'm going to test that actually
when I visit this test, I want to see an image
with the t. I want to see I want to make sure
that this post URL, the image URL is
the correct value and I also want to make
sure that I will see the correct avatar and I want
to also make sure that I will see the correct
title for this test. So let us do this in
the next video until now I describe how we are
going for which component, we are going to add a test
and in the next video, I'm going to write test
for this component.
33. Writing the First Integration Test: In order to write the test, I'm going and I'm going
to create a file, which I call it index
that tests that Tsix. I will use the exact
describe block and we are going to test our
post component. Then I will add
describe, I would say, renders the post
image or post title. Probably here I'm
going to add this. What we are going to
do is we are going to first get this
component and render it inside the page and then we will see what is going
on with this rendering. For that, we are going to use a render function which is provided by the react
testing library. I'm going to import render
from testing library react. Inside the render,
I can actually as a a complete react component, and I will also need
to import this. My condition for
the test would be I also can have another function from react testing library
which is a screen. Here I can ask from screen
that I'm expecting get by text to be in the document. I'm going to put this
into an expect and then I'm expecting to be
in the document. What I am expecting to see, I'm expecting when I am
rendering a post component, I'm expecting when I see
the source I'm expecting that I should have the title
of this text to be shown. I will also see an
error here because our post component actually expects a post object
to be received. Let us go and first create
a post object and we can use our factories to get a random post
here I'm going to pass this to this component, and now I am expecting that post the title to be
inside this document. React testing library
renders this component with this variable and
then my condition for test would be that I am expecting that the
title of this text to be sin Let us run the test. Now we will see an
arrow that actually says windows that match
media is not a function. Let us first fix this arrow.
34. JSDom vs Browser Environment: So what is this error and
why does this happen? For rendering the component,
we need a browser. Actually, when we
deploy a react project, browser executes our
Javascript source code and then it renders
the component. But when we are doing testing
with react testing library, we don't have the browser
and because of that, we are using JSTO. And JSDOM is implementation is a JavaScript implementation
of Dom and HTM, and it simulates a
browser like environment. But there are some cases that not all of the functions
that exist inside Browser also exist inside
the JST here is the case that when I am
running from browser, we are expecting to see a match media and why this
is happening because I am using t design as a UI
library and Aunt design uses this function internally and when it works inside the
browser, it is fine. But when I am running this test against JS Done in a
simulated environment, this variable doesn't exist. How we can solve this problem. We already learned this
from the previous videos. We can mark this function, which means that we don't
actually need this function, we just need to pass something that mimics the
behavior of this function. And in order to do
that, as you remember, I have created a
set of the Ts file, which we are
importing just done. Here I can also define a mock
version of the function. Here I added this code
and I'm saying if windows that match media
is not equal function, which means if this
doesn't exist, I'm going to define
this function. This function returns
an object and most of these objects are
null, the functions, I have replaced them with empty functions that
does do nothing, but it just gives this when
As design wants to use, it just makes it available
inside the JStO. Let us add this and let us return back and let
us run our test. And wonderful. Now our test is passing.
35. Finishing the Integration Tests for PostComponent: So until now, I just tested that I can see the post
title properly. So let us see the component, what do actually
this component does. It has a cover which is this
image as a featured image. And this image has a title as alt attribute that if I Sorry, if I move my mouse over it
and if I inspect on this, I can see that here I have the title of the
post as a alt attribute. It also has the
SRC of the image. I also want to test that my post component also
renders the image properly. Let us add also a
test for it and let us right renders the
featured image of the posts, and I will also add. For the start, I
will also again use the I will get a
factory for my post. I'm going to render my component with
react testing library. Here now we can use another helper function
from react testing library, which is G by Alt text. I'm going to say
get by Alt text, which means get by
alternative text. I'm going to expect I'm going
to call this as an image. First of all, I'm expecting this image to be
inside the document. To be in the doc. I'm expecting that my component renders an image
and second of all, I'm expecting that this image to have attribute for the SRC. For that, I can also use this helper function
to I am expecting the SRC to be post image dot R. First, I want to make sure that the image has been rendered
properly and also I want to make sure that the
post has the correct image. Let us run this test. And wonderful now
our test is failing. If I come here and if, for example, remove these lines. Now, I am sure that there is a test that will fail because now when we render
these components, testing library says unable to find an element with
the alternative text. And here you will
see a random value and this is exactly what we discussed about features
and about the values. Let us also test the metal that actually we are expecting to
see an overture. We already tested this one, so I'm going to copy this block. And I'm going to render the
utter avatar ter avatar and I choose slash Te and let us make it
with prettier, better. Let us use double codes here and that's what
you're saying your code. Here now I am expecting again, what I am going to search. Here I can use another
helfare function I can use to fetch a post by its role name. There is another
another function, get all by role. Here I can pass an image. I would say I want to
see all of the images. When I am using get all by role, it means that I am I'm getting all of the images
and as you can see first, I have this image and also
there is another door. This will be an array. I am expecting so let's
us call these images, and I am expecting that the
images to have length of two. I'm expecting first to see
two images and for the 01, I already add a test
for the first one, I am expecting that
this one to have the post right what was it? The at that avatorR. For the SRC, for
the second image, which is the index of one, I'm expecting to
see the avatar uR. Let us run the test. And now you will see that
the test is failing. So let us see unable
to find an element. Here are the accessible. Sorry, I had a mistake. The role name should be
IMG. I will replace it. Let us run the test again. And now we will see that
actually our test is failing, so the element that SRC, this condition is not met. This is because we know that
we already have this bug because the URL is
something else. This is the hard coded URL. First, let us fix our code. Let us replace this with post, AatorRN and let us see that
actually our website has been updated the
aur ing is correct. Let us fix this with prettier. Let us bring this to online. Now this time the test
should pass. Wonderful.
36. Code Coverage Report for PostComponent: And exactly like unit testing, we can also calculate the
coverage for this test. So I'm going to expect it. And here, I'm going to
run post with coverage. And first, it will run
all of these three tests, and all of them are passing. And I will run it again. Sometimes there is
an issue that in the first time it doesn't
calculate the coverage. So let us just make sure that I will get the
correct value for the coverage, and we are in the
SRC shared postfolo. Let us go to the
coverage report, let us back to the old file. We are in the SRC shade
and here you will say that fonder we have 100%
coverage for this file.
37. Writing Integration Test for Footer Component: Let us continue our work by writing a test for
the foot component. What is a footer component? It is just a style foot
is a foot that has been wrapped with the text Ali center and it shows a simple message. If we want to see it
inside our web page, we will see this is
the footer component. I'm going to create
a new file for this. I will call it index test. T six and I'm going
to describe block and the describe block would be for the full component and I
need an arrow function here, and I also need a block here, so I will say renders
full properly, and I also need a
arrow function here. And I have a type here. It is always good that when you are learning a new technology, a new library or new framework to practice the
same concept twice. For testing this component, this is a simple component, so we only need
to make sure that this line and this will
be showed properly. For that, I'm going to use render footere and I'm going
to import footer component. I'm going to import it from
my own folder not from there. Design and I'm also
going to import a screen render from react testing library
and also the screen. My condition for this
test would be simple. I am expecting to see this text inside my document
to be in the document. I'm going to copy this text and I'm just going to pass it here. Let us run the test. Now you will see that
actually the test is failing because this has been rendered as we
have inside our component, we have a bolt and in order to make sure that it
is writing properties, so I will use these
two sections. I'm expecting to see this text and I was expecting
to see this text. Let me just duplicate this line and for the first condition, I'm expecting to see this
text and for this one, I'm expecting also
to see this line. Let's fix it pretty here
and let us red on the test. And wonderful. Now,
the test is passing. As always, if a developer by mistake comes and
puts here something, we are make sure that we will find the error related
to this test and also let us run the
coverage and I'm expecting a 100% coverage because this
is just one line of code. If we see it here, let us return back and let us
go let's refresh this page. We have the footer component
and here we will see a 100% code coverage. And
38. Writing Integration Test for Contact Page: So until now, I added a test for this component for
this post component and also for the Foote, but I didn't test
the whole page. The integration test that we wrote for the
post components make sure that the component
will be rendered correctly. But this page, if we
want to test this page, we want to make sure
that when we are on the root of our website, we will see all of the posts that are
coming from the API, and then we will also see the footer components and also we want to make sure
that this also works. It is a little bit
more complicated, let us go and first write for the test for the
about page and for the contact page
because they are simpler static page and it
is easier to write test. Let us first, for example, let us go and start writing
a test for contact page. Inside contact page,
you will see that I added a text that if
you have any suggestion, please add me a text. I think I have a I have some ES link and
typos and stuff like that. I added an email address to me and my Github report
and also my link. Let us go and create
a test for this. Let us call it contact
page that tests that six, let's describe and describe
will be about contact page? I don't know I heard. I will add shows the peop linked in links correctly. For this, I'm going to render
my contact page component. I'm going to import
this component. I also import render function
from the testing library, and I'm also import
a screen and here my condition would be that I am expecting to get my
email address inside the text and what will be
to be inside the documents. What I'm going to
say, for example, I want to see my
LinkedIn URL here. I want to make sure that
inside my contact page, I have the linked in URN
and the URL is correct. Let us run this test and let us also see that
actually we have the Github link so let me also add this one for the GTub Also I have an text for
the email address. Let us also make sure that the text will be
rendered. Correct. Apart from that, I also
have one paragraph. I also have a contact
which is an H two, I also can add a test for that. I can say spring screen get by roll heading when I'm
expecting a heading to have this and I'm expecting
this to be in document and I'm going to
expect this to be in documents. Here get by roll except heading role and the first
parameter is the name, but I think it will fail, so that's assist Because actually this tech
doesn't have the title, it doesn't have the name, but what I am searching actually would be actually
if I search heading, and I want to have this
text, which is contact. C. I can test it with this
function to have text cont. Now the test is passing. I am sure that I can also use it by screen that text and
expected to be in the document. But here I am adding
another condition. I'm also checking that actually this text exists and
also this is a heading. I can test the whole
paragraph for this. I would say it is not necessary, so we can and we
can ignore that. Until now, I just tested
that these tes exist, but actually all of them
are buttons and they have links and they
have some icons, so I can also add
some tests for that. I can come and say, I can again use screen get by roll and this have
the butthead roll. I am expecting to see
actually the three buttons. Let me separate this, let us run the
test, it is fading. Let us see us unable to find an accessible
element with the role. Let us see what actually react testing library is rendering. As you can see, they have
been replaced with anchors. They are links, they are links. When we have the anchor, the role will be link. Let me just slip link. And found multiple, I
should say get by row. Now the role name is correct, but because there are
multiple elements, so I should say get word. Now I am sure that
there are actually three anchors to be set. There are three anchors
inside this page and also now I can
start testing them. I can define this as a variable. And I can say, first, I need to see three links, and then I can actually test the links to make sure
that they are correct. Then I can expect links
and for the first link, to have instead of, I would say to have
attribute and I am expecting the attribute of
H ref for the first one would be mail to that
contact at one programmer D. Let us run this test first to make sure that
I wrote it correctly. Perfect. It is passing. Let us also add tests for
the second and third link. The second link should be my Github link and the third
link should be linked. I also Let us run the test. I'm wonderful the
test is passing. Let us run the
test with coverage to also see the code
coverage report. Let us see the coverage
inside our folder. We are in the SRC side pages
folder and here we have the contact page and all the force lines
have been covered. The code coverage is also good. With this test, I am
actually making sure that always my contact page is
valid and correct page.
39. Writing Integration Test for About Page: I also added a test
for the A page. In this video, I don't
go and I will not write it because it is also similar to the
previous video. I encouraging you to
write the test yourself. Please pause the video, write the test yourself and you can compare it with my solution. It is an aesthetic page. The only thing that
matters for us is this text to be shown properly, and as you can see, I have two header here
relative to the contact page that it has only one header
and for some of the test, it wasn't so much
important, so I add, but I just wanted to make
sure that, for example, this paragraph is this
paragraph is also exits. If you see the test
like previous, I will render the page. I will get all of the headings because now we have two
headings for the first one. It should be about
this project as we can see inside our A project
for the second heading, it should be the course ta
then I am expecting to see the text and the goal and the code base and
also all of this stuff. Actually, I already did
the test for this one, so I can remove this because
I already had this test for the heading so I can
also remove this test. Let us run the test. It is an easy test, so all of them should be passing and let us also
run into coverage. And let us see the
cost coverage report. Now we also see that we have the 100% coverage
for the about sage.
40. Writing Integration Test for Blog Page (Part 1): Until now, the integration tests that we wrote didn't
have any interaction. We were just
rendering a component or rendering a page
and then we were expecting to see the
correct test text inside the page or
inside the components. Let us now go and
write a test for a component which
is a little bit more complicated
with the block page. As you can see inside
our block page, we have a list of posts
and when I click on this, when user clicks, you can see
the details of this post. And now I want to add a test that actually also
tests this behavior. So we want to write a
test for a block page. That makes sure
that the components will be rendered
correctly and also involves a user interaction and that user interaction
is clicking on one post and making sure that actually this
page will be rendered. When we click, we are expecting
to go to a page which is slash post slash two and this involves the
user interaction. Let us go and let
us write this test. Let us create a file. I will call it. Log page, the test six let
us describe log. For the first one, I would
share renders posts correctly. Let us see the component. Here again, we are
using react query. So in order to do that, we should do the
marking again and we should also provide
some post and here we can actually test to see if we see the
post element and we also see the link and also
we will see it properly. Let us go and let us remove the unit test that we
added for the API. Here we had a post and
we had a use post. The way that we did this, it was what we marking, we created from Faker, we got a number of 1-20
and for each of them, it was this test factory that
was generating a test post, and then we wrapped the whole component inside the reacquery and then
we were testing that. Let me just copy this as post values and let us
go to the blog post page. Let us do it step so you will see everything
that is happening. First, let us run
there our blog page. Let us run for now this test
and see what will happen. Let's turn back here,
let's close this. As you can see,
the first will be no query client use
query client provider. We already know this error, so I'm going to return and
I'm going to use actually to use a wrapper and I'm going to copy this whole line and
inside my post component, I need to first render a
query client provider. Because this page uses this
component and for the client, I'm going to use clients and what have we
done previously? It was like we were using
this as a query client. Let us create a query client
and let us pass it to this. Let us now run the test again. Let us also fix it pretty, let us run the test. And now you will see
the test is passing because we don't
have any expect. So now, let us go
and add a condition. What do we want
to expect because the first time component will be inside the
loading estate, so I'm going to expect
to see this text. So let me add expect here
screen that gets by text, and I'm expecting
it to be inside the document in the document. So let us run the test. And the test is passing, but this is not my purpose. This is not my goal. I want to actually make wait until this API
call will be resolved, and then I want to make sure that I will see
all of the posts. And of course, I'm
not interested in the actual API call and the API call with the
interaction with the server. I want to mark this
use post in a way that it returns an array
of this marked post, and then I want to test that actually if this function
returns the collect value, do I see the proper page or not? So let's do it and let us
actually mark this us post. I'm going to import this. I'm I'm going to use D as
much as we previously used, and I'm going to mark this
whole file and post USPost. Inside my test, I'm
going to say that actually after I have
defined this variable, I'm saying that I'm
expecting use posts. As a mark to always
return a fixed value. I also import mark from its what would be the return value for the return value as
we expected the data, which we need a data, which will be marked
for we are reading is loading an error and is loading should be false and
error should be no. So I'm replacing the
whole use voice, replacing the whole line
with something fixed. And here, I'm going to mark the whole
module with this value. Another thing that it is
important because at page actually is a page that
has been post sorry, block page is a link and we have links
inside this component. I also need to wrap the whole component
in the memory router. I will also add a memory. Router here and I'm going to use the component inside
because when you want to use a link component, you should always have
a router as out of scope and I'm going to
put a memory router here. Now, I'm expecting that
actually this time, I'm expecting this line to be not in the document
because I'm expecting that this condition wouldn't be run and I'm actually
rendering this for component. Let us first test this part. And the test is failing, let us it is saying that
unable to find a text, and this is exactly
what we expected. But here now, I should replace
this with query by text. I'm just expecting this
or to have length zero. Because when I'm saying expect, then get my text, it searches for this text. Now I am saying that actually if you query for this whole text, and query or if
you are searching for for this test and inside
the render component, you should not see anything and this should have length z. Now the test is passing. My purpose was to
actually test to see all of these components and first, I want to make sure that
actually the post will be rendered and also I want to make sure that the links are correct. And how many links
should I see inside? It will be the number of
the posts that I have. I'm going to set
and I'm saying get all my role and for the
role I'm going to use Link, and I'm expecting this to have the number of
these marked posts. I would say marked
posts, that's it. Because what is happening, I'm telling the react query. I'm telling this line to return the fixed value
which is this fake, the number of the
fake posts 1-20 and this iterates over
all of these tests. I'm expecting to
see this number of these links inside my component. Let us see this and this
should also be passed. Now that I have this, let us make sure
that, for example, the first post actually
has a correct link. Let us copy this line and here I'm going to
get the first element. I'm going to test that
this test actually have the SRC and HR attribute and the HR attribute should be a
post and the ID of the post. Let me also use
templates screen. I should be post and
the first post that ID, I'm sure this link should
have this extra attribute. Let's run the test again
and this should also pass. Now I am making sure that
actually there is a link. If somebody comes and changes this source code to
something like this, still users see the posts. But this is not calculable, and this test that we added is actually making sure
that there should be links and the links should also have a
correct Hf attribute. Let us return we
have removed now, the test should be passed Also, I want to make
sure that actually this post component
will be also rendered. If we saw it in the previous
video that we had some test, I can also bring all of that, or I can easily
say because I have another test for the post. I already tested that,
so I only need that, for example, to see
actually the title. The title of the text
should be in the document. Let us just test the tight. I would say get by text and I'm expecting
the market posts. The first one that's title
to be in the document. With this, I'm making sure that actually post components
has been rendered. Wonderful. Now this is passing and this
works as expected. If you want, you can
also go and also add more conditions for the oatory
URL and also the image. This makes the test even
better to test that.
41. Writing Integration Test for Blog Page (Part 2): Until now, I have
tested that actually, I can see the contents
of this page, but I did a test that actually user can
interact with the page. In order to do that,
we are going to use user event from
react testing library, which is a library
which allows me to simulate and mimic the
behavior of a user, for example, clicking, inputting a form and
stuff like that. So first, let us go to
our package, Jason. It's already existed, so we're testing
library user event, but it is an old version. Let us install the latest
version of this library and let us go to the terminal
and let us run NPM install. First, I'm going to update this library and then I'm
going to add a test that actually tests the the click of the user on the test. Most of the test
will be the same. I'm going to create a set of function here and
I'm going to let us create a set of function and we want to mark the whole post and we want to have the
same random method. Let me put everything
here and let me just call the setup here. Let me just return this
multi post because I need this from this function, I'm going to render and then
I'm going to turn kips. For the second test, I'm going to write a
test like navigates to the ID page after clicking on the items. What I am going to test, I'm going to actually
test that when user clicks on one button
and when user navigates, then he will see this page. For that, I'm going to
use again the setup, I'm going to get
the marked post. Now, I will get an user object
from user events library, from react testing Library. I will call the setup method. I will give us a user that I
can do something like click. Something that click. This actually simulates
an interaction of a user with an
element until the page. What I'm going to click on,
I'm going to, for example, click on the first link which is related
to the blog post. Let us make sure that first
we have all of the links. Let us define a variable. I would say all post
links which will be and I'm getting all of the links inside the page
after rendering my components. And I'm expecting first the length to be the length of Mc post because for each post, I have a link, so I'm expecting the
first link to be done. Then I'm going to click
on the first link. First, let us make sure that until here,
everything is correct. Let us run this. Now we will see missing
setup index specifier. Let us go and see if I
did the import wrong. Let us fix this. We need just to
import user event. Let me just remove this and
then let us import it again. I don't need the index
but I just need to branch this from user events. Let us run the test again. Good. Now it is
passing and let us make sure that actually
this clique works. To test that, actually, I need to create the
links correctly. For the first because we
didn't need the test, we didn't need the links. I just added a memory router and I just flapped it because the only thing that we wanted to check was to make sure
that the link is correct. But now that we have actually the interaction
between the links, let us see how also
our app works. We are using memory
router and this is a browser router and whenever
we are in the slash, we are going to have
the block page and then whenever we are going
to slash post ID, we are going to see this page. I will also need to bring
these routes inside my test. I would say that I want to have these two routes and also I want to wrap it inside
the route element. And we also need to import routes from react
router Dom and I will also remove this blood page and then I will
put this to here. Now, actually, I have a router which has
an slash which shows the render page and
post show this page. Inside our memory router, I can actually say
initial interest, which means what I am currently, what the user is there we can say we are already slash
to render the block page. Now that actually user
click this thing, it means that we started
from the block page. The memory router render
these components. Now, you are expecting the post details page to be
rendered after clicking. This is the content
that I want to test. For now, because this
page again, uses a query, which is a different
query that we marked, I'm going to just test that actually we are
seeing the loading. I'm going to add expect here and when this happened when
we are clicking on the post, we are going from the blog page, we are going to develop
details page and first, we will see a loading, but then this will be resolved to a response and then we will see
the whole thing. But for now, I
will just add this because I'm expecting it to
be inside the documents. Let us run the test. Now the test is fasting because the click the click
is Acnc action, so I will also add an here and I will also make this
function acing. Let us give it time until
the link and the click and everything works to make
sure that this is working. Perfect. Now, the
test is passing and now I am sure that
actually this navigation, this click on this
page is working. If you want to make
sure 100% because this loading is also exists
inside the block page. We have also here a loading. Now, I can show you something, for example, change this
to load posting details. And then inside my test, I can say that
actually I need to see this to be sure that actually I am testing the
correct thing because maybe maybe this is
coming from the thing or the other way which
will be better would be actually to say
that before clicking, I'm expecting to not
see the loading test. If I change this with
query alba text, I'm expecting it to
be have length zero. And it means that here I am sure that the mock value for
the use post has worked. I'm seeing the block page, all of the block
has been loaded, so there is no loading page. But when the user clicks on it, then I will see
the loading test. Let us run this test, and this is also passive. The correct way actually
would be actually to also have a mark
value for this one, this book and to make
sure that, for example, the difference between
this page is like that, we will show the
writer name here. If I want to test that
actually after clicking, we are on the right page, I should search for the writer of this author of this post. Let us do that. Let us also go and let us exactly
like what we have. Let us mark the use post here. I just use post which
brings all of the list. Let us now march the single one. In order to do that, I'm just copying this line, I'm going to also
map this the post. I'm also going to copy
all of this mark. I'm going to say that
actually for this time, let us always return
the first post. The parameter is
not important here I'm going that now I don't
want to see the loading, but I want to see actually
the author of the first post. This is the first and now I'm
expecting that to see this. So let's run this test and now we will see that posts that map
is not a function. I have a typo here, I should get use post and also I
should import use post. I also really
always love to show these errors to my students because this is not like that I am writing code and it
works for the first time. It always happens that
we don't see something. Now I have an actual realistic
test that I am testing, that I have created
a memory router, I have created these pages, I have linked them and I
am starting with slash and now I am involving
in user interaction. And when I click on that, I'm making sure that the page has been changed
and because I know in this new page that
this element exists. This is also one of
the best practices to not check the URL. I can check that, for example, the URN should be a slash Postm, but this is something internal and in integration testing, we are interested in
actually what is happening. So what is happening
when the user clicks, he should see the name of the person and he
should, for example, also see the description
of the test and you can also add a condition, and I would say gets
that description. But because description
has multiple lines, I will also need to add
one condition I would say, if only the first ten lines first ten character
is there, it is fine. Let's run the test. Probably it's going to fail because description
has a lot of enters. Okay, no perfect. No,
it has been working. And now I am sure that actually this works
because if I come before clicking on this page
and I say query all by text, I'm expecting to not see the not see the description because when I am
in the Blog page, I only see the title, the photo. If I add this, then
I am sure that actually if this test passes that I am testing
the correct scenario. You can also remove
this loading. First, we are in the Blog page, we don't have any description. Now, user clicks on it. I'm expecting to see
the author name and this time I'm also expecting
to see description. And congratulations. This was a really
complicated test. We had to do a lot of stuff, we have to work
with memory router, we had to mark some of the
queries that we had but we did it and this is a real good test that we can
use it inside our project.
42. Introduction to Writing Test for the Admin Section: We already added tests for the blog pages and all of the blog pages have tests and we also run the
tests with the coverage, we will see that all of them are completely covered,
which is wonderful. In this section, I
want to go and I want to start testing
the admin section. For the block side, we wanted to see that the
blog page is working, so we will see the post and when the user clicks on that the navigation changes and we can also see the description
of the post. And now I want to write
test for the admin section. If we go to the admin and home, here we have a number
of the post as a card. Inside the post, you can
see the list of the post. Here user admin has an
option to add a post. I can write something and I can at the post or I
can come here and I can press Edit and I can change the description and
the content of this post. These scenarios are more involved with the
user interaction. Actually, if you
want to test this, first user Admin should
visit this page, then he should come
and click on this it and then he should change
something in the title, change something
in description and then probably change a photo, submit the post, and
then we can make sure that actually something
it is working correctly. These tests are a little
bit more complicated than the tests that we had
in the previous section. But the interesting
part will be that we will use more react testing
library and we are going to use more functions and more methods from
react testing library. And so in the next video, I'm going to show
you a little bit about the methods and functions that react testing library for
user interactions provide, and then we are going to add
tests for our admin section.
43. Different User Event Methods and Actions: So let's talk about user events. User event is a component
from testing library from react testing library that we can import it like this, import user event at testing
library, slash user event. The purpose of this component is to provide interaction
of the user. For example, we can
have different actions. The first one, I
can go and I can type inside an input
element, hello. And with these helpers, we can actually test the user interactions
with our four element. In the second
example, I can clear what I already wrote
in the test element. And with click and DBL
click, it's double click. I can click on a button or I can double click
on a cell element. Imagine you have a table, and the table if you use a double click goes
to the edit more, so you can change the
content of itself. And for testing that we have DBL click, which
is double click. We can test hovering of the mouse over an element to see if a tool
tip is happening. If we have a select that
have multiple option, we can use method select option to select a value
from this option. If you have a checkbox to
make it check, we can also call again, click with the checkbox elements
and for the upload, we can call user events
upload and then we will pass the file that we
want to upload and also the inputs that it is
allocated with this action. These are the different
actions and I find it really interesting that with the help of react
testing library, we can test all of
these kind of actions and we can see what
will happen in our app when we
simulate the actions that users are taking when
working with our application.
44. Writing Test for the Admin Table (part 1): So let's start by going
to our admin folder. Inside our admin folder, we have two folders, components pages, and I'm going to first write test for
the components folder. And you will see that we have a sidebar and the sidebar
is a menu element that this is the menu that is showing in the left
side of our page. And we have a post which here we have
create or edit post. This is the component that
when we create a post or edit a post shows this form
and we have the list post, which is this table component that renders list of the post, and we have the
delete button which when user presses on it, I can it shows a first, it shows a confirmation
and if user presses yes, then it deletes the post. So let's start writing test with the first
for the list post, and let us see the component, what does the component do. It uses, again, we are using here reac query
to fetch the posts, and if it is in the loading, it returns, and then
if there is an error, it returns, and then we are
going to have a columns, which is an array of of objects. And this is actually
the table that will be rendered and every column is the first column is a number, so we are just rendering
an index in it. The first column the second
column is the feature image, and we are reading from the post the property of
the image and URL, and the rendering
will be an image with the alternative text of the
post title and image URL, and then this is
the second column. The third column
will be the title. Which we are just reading
the title of the post, and the first column
will be the actions. And inside the actions, we have first a link to an edit which goes to this
link admin post edit, and we have a dite
button that we are rendering and we are
passing the post ID to that. And actually, we are rendering a table with these columns
that I showed you, and our data source
will be actually the objects that will be
rendered inside this table, which are the posts that
we have read them from reacquire so let's
start writing test. I'm going to create a file. I will collect List posts. The test test and I will
add a describe block and it will be for the list post component and inside that I
will add a block. As a first test, I
just want to make sure that if the page is loading, we are going to
show this loading. I'm just write randoms loading if the posts
have not been loaded. Yet. I'm going to
pass a function here and my expectation
will be actually, let us also import. Let us render the list
component and let us Let us import post, let us import render, let us also import Screen from react testing library
and our condition would be screen that gets by text
loading to be inaccurate. I am sure that you know that the first time this test is not going to pass because we need
to actually mark use posts. We already did that, so
I'm going to the pages, I'm going to site and I'm going to pages and I'm going
to the blog page. We did it like this. Use post. I'm going to copy
this that we had previously. I can put it before here. We also need to first
mark the whole module. I need also to bring
this line for this one, I want a data to
be nothing to be an NTR and I want here to
ease loading to be true. I want to make sure that this component shows the loading. Let's run these tests. And one point that I
want to mention here is it is the most important
thing about the testing. You see now how easy
I added the test because I had previously
the same solution, and I just use the
same solution here. And a lot of developer at first, when they start
learning about testing, they think it is complicated.
It requires time. At first, yes, but when you
set up your project and you are setting when you are
writing the first test cases, after sometimes you can always use the helpers,
use the marks, use the spice that you
have previously created, and it will make it a lot easier for the future
to write tests. So now you will see that I just copied something from
my previous test, and now I have my
first scenario, which is to make sure that actually this
testing is loyal. And now let us go and let us change and add another
test that actually we are expecting renders a
table with a list of posts. And now, I'm going to test
that actually if if I change this mark to returns to loading would be false and returns a list of marked posts, I'm expecting to see a table. And this table should
have an index. This table should have and all of the columns
that we have seen. And for this marked post, again, I'm going to use the thing that I have
created previously. I'm going to just
copy this line. We already have the faker. We are generating a number with a faker and for each of them, we are going to use
the helper function, the test factory that we
have created for this test. I'm going to render this time, I'm going to expect
not to see anything. I'm going to query
all by text and I'm expecting this to
have length of zero. I'm expecting this
to not be shown. Let us run this test. We already saw this
error previously. This is happening because if
I go to the list post here, we also have a link element. In order to fix this issue, I should wrap my component
inside the memory route. I'm going to wrap it in a memory route and I'm going
to fix it with prettier. Let us read on the test again. And now we will get another error that we
also saw previously, we have not provided
query client provider, let us go and also let
us bring this from our other test and
let us wrap it. We also need the query line, let us also bring this
line from the other test. I will put it inside my
decried block so all of the tests can use
it. Remove these. Let us rerun the test. No and this error actually
is not related to our test. This is coming
from our component that react expects that
when we have a list, which is like, for example, a table, every row
should have a unique ID. And design provides us with a property row
key that we can say, every pose has a ID and please use that ID as the key for this. And because we know that the IDs are unique, this will be unique. So let us add that and let
us run the test again. And now we will see that the previous warning
has been gone, and now we have a new error, not implemented window
that computes style. And this is the same
situation with the JSTOm and browser that inside JSTOM we don't have all of the functions, so letter to solve
that let us go to our setup set of file. And like that we did previously
with the match media, I'm also going to
add a new mark here. So I'm going to just write this as a windows that
get computes style, and and I'm just going to mark this with something that
always returns and a string. That was come and return
and run the test. Now the test is
passing and we don't have any warning and error, so it is clean.
45. Writing Test for the Admin Table (part 2): But actually, to make
the test realistic, I need to make sure that the
table will be rendered and I will see all of these rows
and all of these columns. So in order to do that, I will define a
variable for rows, and I would say screen
that gets all roll row. And I'm using Ant Design for the UI library and ntsign
a row row for every row. So here we have one header row
and three is for the post. So I'm expecting to C, the number of the rows
should be the number of the marked posts that's
length and one also for head. If I have three rows, then I should see a table
with a row with four rows. Let us run its test. And now it is passing. But let us run the
test again and let us run the test again and now you will see
that the test is failed. I wanted to show you
because this is also a really interesting
subject in the testing and now we will see
the benefit of having the faker and benefit of
generating random numbers. If here I had an array of fixed
length of three elements, this test would
always be passed. And I couldn't see this case. Why this case is happening. Let us see I ran the test for the first two times it was passing for the third
time, it is failing. It says that we
are expecting 21, but the actual is 11. What is happening
here is nsdsign. This table from ntsign by default provides a pagination
with the size of ten. Oh, I I have more
than ten posts, it will show a page ination. We can test it by
setting a pagination to be an object to be an object. I think I should pass
the page size of one. Let us imagine that if I have the page size of two or two, you will see that now, it shows me a pagination, for the if I change
this page size to one, now I will see three pages. By default, this options exist and it is for the ten rows. When it's happening when the number of the marked
s are more than ten, and design only shows
the first ten row and we have one header
row so it should be 11. In order to make this test work, I have to test this
that if marked length greater than ten, then I am expecting to
get an 11 to see an 11. Otherwise, I am expecting
to see the length. So if the number of the
poster I have more than ten, I am sure that the page
ination will happen, so I am expecting
to see 11 records. But if it is less than, it should be actually the
number of the post plus one. Now let us run the test
again. Now it's passing. Let us run it again and
let us run it again, and now we will see
that it is always. In order to make sure I can
change also this number to 12 to make sure that actually my test is covering
with the pagination. Or we can change it to the. It is even better if I separate this test to two categories. Let me just copy the whole test. Let us first also
create a setup file because I don't want to
copy and paste everything. Let us create a setup
and this setup will be a function that I will
put all this thing inside setup and I'm going
to return Mark post like we did previously
here I'm going to call setup I'm going to say that and I will define
also marked posts here for the first test case, I'm expecting that
it shows them. I will copy the whole
test and I will also make it sure that I will call it renders a table B Hagenation if the number of the
posts are more than ten. And for this test case, I'm expecting to always get 11 if I know the number of the
posts are more than 11. And to simulate this, I'm going to pass a
parameter to setup, which will be number of posts, which will be a number. And here I'm going to let us let's just
call it min and max. I want to also min
max number of posts. Let's call it number of posts. Instead of always one and 20, I'm going to pass
these parameters here. For the first test case, I'm going to always
pass a test and I can also make it the default
value for one and on 20. For the first test case, I want to make sure that
it is less than ten, so I will go with one and nine. I want to get a
number of the posts 1-9 and I have expecting to see. For the second test case, I'm going to fix
something 11-12. For this one, I want to
make sure that the test is actually the table
shows a pagenh. Amazing. Now, I have
two tests specifically. For two condition
which is happening. With this, I can also
make sure that my table shows the pagination and how we can make sure
that it is running. I I just come here and
change the pagination. For example, to false, that means that the page table doesn't show the
pagination here, then this test should fail. And you will see that this is
failing because it actually renders all of the rows
and not only the first. Now I am sure that I
am rendering a table, and this table has enough the correct number of the rolls. But I want to also show that I am rendering
the correct table. And what does this table has? This has a header,
so I want to make sure that I will get all of this these headers correctly. I want my first condition
to be get by text, and I'm going to use a hash
tag to be in document. Let us run this test. And it is passing, so I'm going to test and I'm going to add a comment here testing
the table headers. And the second will be a featured image or
you're expecting to see this text inside my table, I also expect to see a
title and an action. Now, I am sure that actually the table also has
the correct headers. Let us also test that. For example, the first post
will be shown properly. Let us go and copy this line and let us
testing the table content. For the first one, for example, I will get the first post. And I'm expecting the title of this text to be
inside the document. I also want to see the
edit and delete button. For now, let us
remove this because I have always multiple buttons, let us get them by all by role. The first one is
actually a link, so I can use the link row. Let us get all by rod and
get all by roll and let us then get the first link and
what do we want to check? We want to check that actually the link has a correct value. You have attributes Hf it should be Admin post
edit and the post ID, admin post Edit also get
the ID from the first post. Let me just remove these two. Let us fix this with prettier
and let us run the test. And now the test is failing, actually expect the element
to attribute admin post. I have one S here extra. I can also replace this
with the template testing. Instead of having a plus, I can also replace
it to be like that. If I do that, I think it will be possible in
well I know it is. Let's return it to what
it was previously. But I had a typo and now
I am expecting this time to pass so now I see, I am sure that the
title is here, the edit is here and
also for the delete, we have a buttoF this one, I can also make sure
that the buttons exists, so I can also get expect screen that gets all roll and here I'm
going to say button, I am expecting to see exactly as the number of
the posts for the button. If I have three posts, I also want to see that my
table renders three and three. Now we have two an error because I think the
pagination is also here. Let us make it more clear that to make the test more
specific for the button, I can pass a second
parameter when I am using get role and I can say I want to get only
the buttons that the name of the
button is delete. Because if we look
at the component, if we see I have, this is a confirmation and
two options are yes and no, and the text is delete. I'm telling them, please give
me only the buttons that are the name is deleted so I don't want to be confused
with these buttons. Let us read on the test. And now it is passing. Let us read on it multiple times to be tested with
different datasets, so we are actually make sure that our test is correct and we are
testing the correcting. Wonderful. Now I have
the test for the table. I have the test for
the pagination, and in the next video, I'm going to actually interact
with the Edit button. I want to actually click on
this Edit button and I want to click on this Eit button and I want to add scenarios
for these two cases.
46. Testing Edit Action Item: Now that we have added tests for the rendering
on this table, and we are making sure that
the title is rendered, the number of the
rows are correct and the table renders properly. I want to add a test for edit
and delete Actions button. And in this video, I'm going
to add a test for edit. And what I am going to test, I want to make sure that when
user clicks on this edit, then users will see this page and this
page have an input, have a text area, has an upload button
and submit button. But the interaction of
users for this page, it is not important
for me for this page. I just want to make sure that when I am pressing
the Edit button, this will go to the correct
page and user will be redirected to the
correct page to do that, I will call and I will create
a new describe block and I would say shows the edit post page when user clicks on the Edits Edit action. I'm going to pass
a function to it and let us remove this. Like previous, I'm
going to set up my post and I'm going to just
limit the number to 1-5. I will say cons marked posts equal this post. What I am expecting, I am expecting to see the links, so I'm going to the
first condition would be actually that this
link has a correct attribute, it should be a slash admin, if you see on the left
bottom corner of the page, the link should be admin, slash post, edit one. Let us get links and I would get them by a screen
that gets all by roll. For the first link, I'm
going to expect that links zero to have
attributes Hf links. The href should be
admins ID, post Edit. Let me replace this with the
templates string and let me add also exactly
a marked post. I'm expecting to get the ID of the first post will be
inside the f of this link. Let us run this test
and it is passing. After that, I want to
click on this link and we can do that with the help of user event from
React testing library. I will define a user and I
would call user events that setup and I'm going to
click on the first link. Because I added evite, now I should also change
this function to be async. And after this edit, I'm going to expect and I'm
going to see the edit post. I will add the condition, but I know that the
test will fail. Let us do it together and I will tell you why this is
fail. Let us go here. Let us click on the edit. I'm going and I'm telling
you that I expect this to be seen
inside this page, and I'm going to expect this text to be
inside the document. And let us run the test. As I said, it will fail. We already faced
this problem before. I want you to pause the
video, think about it, and guess what is going
wrong here. All right. If you remember, we had the same issue inside
the blog page, and the reason is that because if I come
back to our setup, here, I just added a memory router and I just render the list
post components. And why did I do that? Because inside our
list post component, we had a link, and in react, every link should be wrapped inside a router and
I just added this. But I didn't define the routes. I didn't define the links. I didn't define the
navigation between them. Where does this
has been defined? If we go to our after tier 65, the routes have
been defined here. I also need to define
them for the test. I don't need all of them. I only need for example, here I thought when we are
in the admin slash post, please load the post page. When we are in the edit page, please load the Edit page. So I'm going to bring this and I'm going to have a
routes block here, routes block, and
I'm going to bring this and I also need
the post space. I only need these two routes. And I will also add
an admin prefix. I would say if you are in
the admin posts because this page is slash
admin slash posts. Please load the post page. If you are in the
admin post delete, please render the
edit post page. Where do we start? We are starting from this page. I'm also going to pass this
parameter as initial entry. So now, I have actually
a memory router. I have a router that has two routes and we
are starting here. Now then I press the edit, there is an element and there
is an index for this route. Let us go down and let
us re run the test. And the tests are still failing, let us see what is happening. You will see that inside, no, I haven't loading component
and what is happening? Actually, the navigation
has been done, but because we went
to the edit post, let us go and let
us see this page. When we are going to this route, this page will be loaded and this page, we
have this line. So because it tries to fetch the post from the server and then it goes first to
the loading state. So we are still
seeing the edit post, we are not seeing this title. So let us go and let us mark this use post
inside our test. And to mark post, we already did this
also previously. I'm going to just remove just going to copy the test that
we had from the block page. We did it like this. I'm going to just
copy the whole block. And inside my admin page, I'm also going to add this and we are
saying that actually the first post
should be returning always in the perura use posts, return all of the posts in the short form, return the zero. I also need first to also mark the whole module
that's so with this, I am marking this
module and here I am defining that if this
mark has been called, this fixed object
should be returned. Let us return and let us run
the test. And wonderful. Now the test is passing. I always like to have a clean
warning and arrow section. Let us also fix the error
that we are seeing here. You will see that I
have one warning here. The test has been passed, so the user sees this page, but we also have a warning. What is happening when user
presses on this and clicks. In this area, I have
used CK Editor, and the error that we are
seeing is related to that. And in this test, I am not actually
interested in CK Editor. I am not interested in
interacting with that. And this is, again, one of the usefulness
of features of mocking that I can completely ignore CK
Editor and I can mock it. And let us do this to not see
a dirty console like this. Let us go and let us see our edit postage and let us see inside
our edit post page. We have the header, we have a component and
this component has a CCA Eeditor which is
probably here, exactly. Let us see where this
has been imported. This has been imported from
Editor five and Editor five. I'm going to mark
the whole module. Let us go and let us duplicate this line and this
time I'm going that I want to mock Ckditor
and let us return back and let us read on
the test and wonderful. Now the test is working and also don't see any
warning and any message
47. Testing Delete Button (case 1): So wonderful. We have a really good progress, and I am really happy that
you are with me here. We are testing every piece
of our software and we are making it a really high quality software
with this effort. Right now, we test at the table, we tested the edit fcton. And in this video, I want
to test the delete button. And what will happen when
users press the delete button? First, they will see a pop up and then they can decide
to see yes or no. If they say no, then
the post stays. But if they say yes, then this test, this
post will be removed. If you did this by mistake and you want to return
back the post, you just need to
restart the server. So if you just stop the node
J server and restart it, and if you refresh the page, you will get again
back the same post. So let us go and let us write
the test for this scenario. I will create two
tests because first, I want to make sure
that I will see this confirmation box and then I will start writing
tests for the scenario. Let us add a block here, I would say shows a
confirmation box, let users click on users
click on deletes action item. And again, because
I need the user, I can pick most of the
lines from this test and 1-5 posts will be enough. This time, I'm
interested in buttons. I'm going to get all of the buttons and because I'm only interested in
the delete button, I will add a second
condition here. I will say I only want to
see the delete button. I'm going after that, I'm going to click on this button on the first
button that I'm seeing, and then I am expecting
to see this text. Let us add a condition
to expect a screen that gets by text to be
in the document. If this is happening,
then my test should pass. Wonderful. Order to make sure I can also add
another condition, I can add also this line before and I can say
query all by text. First I want to check that actually this one
have length of zero. I want to make sure that this doesn't exist inside
the document. When I press on this click button, then
this is happening. Let me also bring this
a little bit down and I also don't need the return
value for the setup function. First, I am checking that I
should not see this text, then if I press one of
the delete buttons, then this text
should be displayed. And wonderful the
test is passive.
48. Testing Delete Button (case 2): Now let's go and let's
test the second scenario, which will be that if I
press the yes button, and what will happen if
I press the yes button? Let's read the source
code together. We have a list post and inside we have two
action buttons. This is the link,
this is the button. What is this delete
button code button? This is first this
conformation and then it has two text, yes or no. And when we are confirming, actually the delete
post will be cut. And what is this delete? This delete is a
mutation from rea query, which will call an API call and then actually deletes the
post from the server. But for this test, we are not interested in the
interaction with the server. We are the only thing that
condition that I want to test to make sure that this
function has been cut. So if the user
clicks on the yes, I want to make sure that this function has been called and this function has been called
with the correct parameter, which is the test le. Let us write that test. I will copy the whole
this block and I will call I will change this. I will say delete the post or let us be
more calls delete post. If user confirms
the the deletion. What do we expect? Again, I'm creating pi pos. This one I already tested
so I don't need it. I will get the delete
button, I will click on it, and I'm I'm expecting
to see this text. This time, I'm going
to get the yes button. Instead of this condition, I will define a yes
button and I'm going to say a screen get all by roll. And with the button and
this time I'm targeting the yes button and I will
get the first button. I'm going to click on
this but this time I'm going instead of
I will change this. Here it should go
my expectation and my expectation would be that
actually that function, this delete posts to be cut. But this delete
post first in order to make sure that it
is getting called, we should first mark it. This is coming from this module and in order to be
able to check it, I also need to mark it. Let us go to the
top of the page. Let us duplicate
this line and let us replace the passes up API
posts, use delete posts. Let us go up API post,
use delete post. What does it do? It returns an object
which is the mutate is delete post and
it has an E pending. We already did this, so I'm
just going to copy this and I'm going to bring this Inside. I can put it also inside
the setup section, I will put it all together here. I will use DiltPst and
I would say a mutate. The key will be mutate. And pending, I will pass
the E pending fogs. For this one, I will define
spire call it delete post. I'm going to also delete
the delete post here. I would say const
post equals t fn. As you remember, dot
fn is a spy function. It doesn't do anything, but I can just make sure that
this function has been cut. If I come down, my
expectation would be that this function to have been called one time to
have been called times one. I am saying that
whenever this happens, this yes button clicked, I'm expecting that this
delete function to be cut. Let us run this test. And it is passing and
to make sure that I am actually testing
the correcting, I can bring this
also here and I can say this function should
have not been called. And whenever we are
getting this yes button and when we are clicking
on this yes button, we are expecting to be called. And now I am make
sure that actually the action of this button has caused this
button to be cut. I will also add
another condition. I'm saying that I
am expecting to have been called and
with which parameter, if I check the code, we are passing the ID of
the post because here I'm also getting the first post with these links and
with these buttons, we are expecting
this to be called with the marked post and we
also need the marked post. Let us first get the
mark posts here. And I have a type
of marked post. I'm expecting this has been called with the ID of
the first marked post. Wonderful. Now we also have a test for the
delete scenario.
49. Getting Coverage Report for Admin's ListPosts Component: As the last step, let us run the whole describe
block and let us see the whole code coverage
code coverage. We have an error here, sorry, I forgot to remove
the lists posts here. And now two of all
tests were failing so we run the tests and now
all of them should pass. Let me run the tests
with coverage and let us see the code coverage
report for this component. So let us go here and let us refresh the
page and let us go to we were in the SRC
admin slash posts. Wonderful now we will see that the post page has
been tested with the coverage of 100% and we have also
covered all of these. This is a really
also good tests. We can also see the coverage
for the actual components. If we go to the admin
components post, the list pus components
has been also completely covered
and as a side effect, delete button has
been also covered, but our purpose was not to cover this from the edit component, we will see that these red lines means that they have
not been covered and these are actually relative to the actions
which is happening, for example, submitting form
and uploading something. But because we just have the navigation and because
of the navigation, we rendered this form and
these lines have been covered, but the action because
we didn't have any interaction with that form, those parts has
not been covered, and of course, it
was not our purpose. We will create a separate
test for that component. But for the list
post now we have a really good
coverage and all of the thing that is happening
inside that has been covered, which is really good. And
50. Introduction to CreatePost Section: We added test for the list posts component
inside the admin page, and in the previous
videos we already tested that we could
see the title, we could edit and go
to the edit page and also we could delete the post
by pressing this button. Now we are going to actually
test creating a post. And here when I want to
create a post as a user, I can enter, for example, post title, and I
have an editor here. I can write my content inside
this and then I can select the photo and then when
I press submit post, then this post will be
shown in this page. And let us refresh the page and make sure
that post is there. In this video, I'm going to write test for this component. As you see, it requires a lot of user interaction
which we are going to use react testing
library for that first, I need to enter the title inside this input
first and then second, I need to enter the content
of the post that I want, and then I should be able to
simulate a click and then selecting a file and then
uploading it with this button. Then I should be able to send
all of these parameters to the API with this pose and then my test should check that actually it is
happening and it is work. Let us get a start with coding and let us implement this test. It will be so much fun. Let's start it together.
51. Looking at CreateOrEditPost Component: As the first step, let us see this component, create or edit post. So this is a This
is a react element, and here we have a form. We have an state variable
for the description. We have an state variable for
the image oil and we have two mutation from RaqueryO for create post and
one for edit post. And here, handle API
call is responsible to to do the API code. And this component, the same
component has been used for adding a post and
also for the edition. So if you see the URL, if we go to the edit, this is the same form
and same element. The difference is
that it will show you the content and the title of the post which is already load. And if you are going
to add new post, then we will see
the same component, just everything is empty. The way that it's handle is here we are in the
admin post create. But when we are editing a post, we are in admin post edit form. We have the post ID
here inside the URL. The way that it works, we are using navigation and here we are reading in
the post object. If the post exists, it means that we
already have a post, then we are going
to edit this post with the ID and
also the form data. Otherwise, we are
going to create post, and for this we need
only the form data. The handle submit also for it as a validation
message to make sure that we already
selected the files and then he uses the form data, we are appending
title description, and then we are
adding the image and then we are calling
the previous method, which was handle API card
and if we are successful, then we are going to
add in slash post. Here for the JSX, you will see that
we have a item. The first one is the title. If the posts exists, we are using an initial value. Of the post title, this feed should
be required and if the user does not
enter the title, we will show a message. Please enter the title. Then we have a content. Here we are using a Ck Editor and we have an unchanged which when user enters something
inside this form, then it will be called. And then we have
an upload button, which user can select
a file for the image, and then we have
the subject button. In this video, in
the next video, I'm going to write test
for this component.
52. Testing Rendering of Correct Form Elements: So let's get started. The first thing that I will do, I will create a new file. I will call it creates or edit post the test that T
six Let us a describe block, we are going to test, create or credit post component, and here we will have it. Then I would say, first, we can just make sure that the form is rendering properly. We can just say
renders an empty form. For this, I'm going to render create or edit most
component. I will import it. I also need to import render
from react testing library. I will add a screen. I will also import a screen. Then what do I expect? I expect to see an input. I'm going to or I can also make sure that I
will see only one input. I can use get all by
roll and then I can say that I'm expecting
to see one row. I'm going to expect a screen
and I will change this get all by row input to
have length what. Let us first run this test and let us
see what will happen. As you can see, encounter
or use navigates maybe you use inside a
router component. Like previous tests,
we also need to wrap our testing component inside a router and
inside a memory router. I'm going to bring all of these since a since we don't actually
need navigation for now, I'm going to just wrap it
inside a memory router. I will define a set of function. Inside this set of function, I'm going to return render here I'm going
to use a memory route. I will pass this parameter
here and instead of this, I will just the I will just call the set function. We need to cover here
semicla com here. Let us run the test again. We will see the query client. We also need the rea query. Let me also bring this
and we need to close it. And we also need the
query client parameter. Let us also copy from here. I like to show it to you that first we start with nothing, then the error will come and
then we will fix the error. I could completely copy
and paste from this test, but I like to see you
how I am approaching, I am writing a test and whenever
something doesn't work, how I debug it. Now actually we see that the previous errors
have been solved, but now we have a new error. The CK editor component
requires you say editor, we can ignore it for now, unable to find a row. We will first see testing library unable to find an x seven element
with the role of. But we have our input and I need to the title input is here. I think the role
is just textbox. Let us change this to textbox and let us see
what has happened. And wonderful. Now
the test is passing. Now I am sure that I am actually seeing an input
inside the textbooks. For the testing
of the CK editor, actually, I don't need to
load the whole CK editor. For the purpose of this test, the only thing that
I am interested that this component
should be rendered. And when user types something on it and
press submit voice, this data would be
transferred to the APA. CK editor for us is an
external dependency, so we don't need to actually test an
external dependencies. We can just mark it. To do that, I'm going and I will just add this at
the top of my file, I'm going to replace
I'm going to mark CK Editor with a in this object, which I am just replacing
it with the text area. This text area has a test ID that whenever I
want to get this editor, I will use this ID. It has some different value if you pass it and it has
an unchanged value. Here I'm going to but now that I am marking this and
I have a text area, now I have two text boxes. So this condition
will be failed. For checking the existence of the CC editor because I have replaced it with
the marked version. The only thing that
I need to do is to just check that this element
with this test ID exists. I'm going to expect screen
that gets by test ID. This is also another
helper function from the testing limate that we
can assign the elements, a test ID, which we can use it in the future
to getting help. I'm expecting it to
be in the document. And now I'm expecting
this condition to run, but this condition will
fail because now I have two inputs and
I also expect not to see the warning message
because I am replacing it with the I am replacing CK and
this one with the mark sure. Let us replace this with two
and let us ran on the test. And now the test is passing and I don't also see the
error message and how do I make sure that I am testing
the correcting if I come to the component and if I
remove this section, now this test should
fail because I have not rendered the CK ditor. If I return this back to one and if I re run
the test again, because I have not loaded the
CK editor inside my phone, so this mark has not been executed and this
condition is failing. So I am actually making sure that an element of the CK
editor has been rendered and because I am replacing
a CK editor with a marked text area
which just has test ID and I am testing
that this element exists. I am sure that this
test is actually functional and it
works as expected. And to make it better now
that we have two text box, I can return back to here and to make sure I can
also specify and I can get this first one with
the label or with the title. For that, I can also add
another condition here, I would say explain that gets by texts and the text is title. I'm expecting this one to
also be in the document. Now I am actually making
sure that I am rendering the correct textbox inside
my create for postage. Now let us test the buttons,
we already test this. First item, we tested the Ckeditor and now I
have two buttons here. I want to make sure
that this form also has a upload button
and also has a subit pose. I can also do that with expect screen that
gets all by roll and this time I will
use roll button and I am expecting to see two
buttons inside my phone. Let us run the test. The test is passing
so wonderful. Now I would define
this as a buttons. I will define as a
variable buttons and I will assign it to this. Now I am expecting the first button to have text
content of click to upload. For the second button, I'm expecting it to
show submit posts. Let us lay on the test. Wonderful. Now the
test is passing. You can do it like this, with defining a
variable or I can also use it by something
like this that, for example, I'm expecting submit posts and elements with the idea with the text of sub cost
to be in the document. This is also another
way of testing this. But for now, I will just
keep it as this is. Now I am I have a
test that makes sure that the form is rendering properly and
rendering correctly. I need to run at another test for the interaction of the user with this form. For that test, I'm
expecting to enter a title. Enter a description
for the post and also select a file and upload it and then it should actually calls to create post
mutation from reacquiri.
53. Writing Test for Post Creation: So let us write test for that. Users can create a post form. Or I can just make it simple. My test would be to make sure that users
can create a post. But I will make it better
when I write the test. For now, let us ignore it. Again, I will call the setup
to render the components, render everything from
the previous test, I know that I have
two textbooks, so I'm going to get this and
I will call them inputs, and for the first one, I also need ear user events. I will also call Hs user
call user events setup. Because for this test, we need the interaction from the user, so I'm going to call
the type method on the first input and then I'm
going to use post title. For the second one, I'm going to type content of the post. Now I need a file and I because here I have
an upload button. In order to that, I'm
going to use and this has a label so I can get this
form element with this label, but I only interested in
the input of this image. Let us get it together. I will say a screen that gets by label text and my label
text will be feature image. And then I'm going to for now, let us just test this
to be in the document. I want to do it step by step. Let us run the test. And it is failing. Let us see what is unable to find an element
with feature image. Let us see we have the content, we have the feature image here, the title is feature
image so that we make sure that I can also make it and then I'm interested in this
actually input. Or I can just directly
input it because this is the type is a file. I can also get it from that. Let me just change this
and get it by that. I would say cons file because that's my role and I would
say I want an input, but I don't want
all of the inputs. I want an input which the type
is it's the type is five. And testing library
does not provide this, so again, I need to get
it from the container. I will get this I will get the container back from my
setup file and here I'm going to call containers
queries selector, and then I'm going to expect
file to be in the Natural. Let us run the test um, and wonderful not is
passing, so I have it, and now I want to upload a
file inside this file input. Let me call this file input. I'm expecting this file
input to be in the document, then I'm going to
define an actual file. As a constructor as the
content of the file, I will say just
sample file content is not important
for the file name, I would say feature image
that's PNG and for the options, we can also pass option process, for example, type
this image, pH. Testing library provides us with a function which
we can actually upload. Inside an element, a file
and the first argument will be the HTML input elements
which will here is file input, and the second
part will be file. Actually, the file that
we want to upload, because I have used a weight, so I should change ACN. I can also add a weight
for these two because these two user types also AC to make sure that my
test works as expected, I will also add a
weight to this. I can also bring this top, let's make it a
little bit cleaner. And now here I have because
now I have an error, the argument of type
of null is not let us also tell type script that we know that
this value exists. Now what will happen, I already input
something in the post, I already input
something in the file. Now I'm going to press
the submit button and I will user click and I
would get all of the buttons. I know there are two buttons, so I would I can also get it
by roll and passing a name. Let us pass it in the name and the name will be something post. This is also a sync, so I will also add an
Avight here at the end, I need to check that actually
the upload has been called. But I added so many lines, so let us for now just run the test to make sure that
I didn't break anything. For now, it looks good. What will happen when actually when we are
submitting the post this form has a handle submit and inside this handle submit, first, I want to make sure
that this has been called and it will create
a format object, it will put all
of the values and then it will call the API. We are expecting and because we don't have the post object
because this is a creation, I'm expecting this create
pose to be called. And we already did this
in our previous test. I need to mark this mutation
from reacquery and I want to make sure that this has
been called and this has been called with the
correct parameters. Let us go to what
we already did. We did this for the
same with the deletion. Let us go and let us bring this. But for this test, I need to I need to import, not use delete post
but use Create post. For this line to
be executed first, we should mark the whole module and then we can actually test. We can tell what we
want to be executed. I'm going to mark up API
post, use create post. For the use creat pos, we are going to
create a spy here. I'm going to call it
create spy equals FM. I'm just creating an empty
function that I can test if this has been called and
which parameters aspect. Our condition would be that after clicking of the submits, we are expecting
that this create a spy to have been
called one time. So let us run the test. Actually, I have a mistake here. If you look at the
code of the component, when we are use create force, here we are reading the property
of the mutate async and here I am marking
the mutate function. I should replace this
to be mutate sync. Now that I am using
an async option, so I should also need to wrap this inside
the wait for block. I will also wrap it inside
the wait for block. Let me also import wait for. We can also add eight
here and weight. Let us read on the test again. Wonderful. Now the
test is passing.
54. Testing createPost Parameters: But for this test, I also want to make sure that this function has been called
with the correct parameter. This is really interesting
here and I want to use this opportunity to also
teach you something else. I cannot simply use it the previous methods
that I have been using. For example, I would
say to have been called W. Because if I pass, for example, a new form data, what is this form
data, it is an object. And if I do it
something like this, but this comparison doesn't
exist in form data. How we can test actually that, we can ask our react
testing library. We can ask this Spy all of the calls that
has been called, and then we can make our own
comparison for the title, description, and
also for the image. Let us do that. For that, I can get all of these parameters
that this function has been called I will call it
for data arguments with this. Now this is an SPY. I can every SPI has a function mock and then I have
an array of calls, which is a two
dimensional array. The first argument is the
first time that it has been called because it has
been only called once, I will use zero and the
zero will be actually the first parameter that this
function has been called. If we had, for example, create a spy with
something else, then that would
be the index one. The number of the calls will
be actually the first index. These are all the parameters
that has been called and this object I can iterate over this
and I can create a dictionary for myself for all of the parameters that
this has been called. For example, I will call
it for data entries. And then I would say, I
will define a dictionary, which is a record of the
ring to an unknown object. And then I'm going to iterate on this form data argument for the arguments that this
function has been called, and I'm going to expand this with value which should
be no and the key, which will be
string I'm going to fill my dictionary
with this value. What I am doing here
is just a simple flo that I am reading all of these parameters that this
SI has been called and I am creating a dictionary with
a key and value for this. Now, I can make
sure that actually here it starts my assertion. For that, I can
expect that now that I have four data entries, now I can actually test
the tight, for example. And here, because this
is now the string, I can just say I'm
expecting to be host tight. So let us first run this
test to make sure that this is actually
working and wonderful. Now I am actually make sure that the value that user enter inside the first input has been passed inside my
create spy function, which is an spy version of the create mutation of the reacquery which
actually calls the API. I am making sure with this
test that the whole form, the submission part of
the form works correctly. I will also do this
for the description. Let us make sure that it
is failing because now it should fail because then it should be the
content of the post. Exactly. Now we are
expecting post title. This should be content
of the post and Now, I am sure that the
description is also there for the image foil, I'm going to use and I can read this with the image and let us also make
sure that this is image. Yes, because we are
appending an image. I want this just to be
an instance of a fil. We expect it to be a file. Also we want to make
sure that, for example, the file name and also has
been passed correctly. Import, when I am
creating this file, I am also calling a feature age. Let us also test that as well. Let us also expect this
image to have name of feature image dot page. Let us run this test
this is passing, I have an issue with
the type script because doesn't know and I can just use it like
this as an object. I know that this
is an object which has the name is string so I can just to make it type
script doesn't complain, I can also change this. Now I am making sure
that actually test, this form has been
submitted with all of the values that the
user has been entered. Now, let us make
our test better. I added some hard coded values, but we already have
the fake care. Let us create these values here. I will define the
post title here. I would say fake Let me
first import fake care from our faked library and I'm going to use a sentence for the post title and
for the post description. I'm going to use a paragraph. For the image name here, I added a hard coded image name. I would just also define as a image name I would get fake
from system module of the fake and I will get the
file and here I can also pass an extension which
will be, for example, pH. Extension cons I
don't need this, let us make it simple. Here, instead of a
hard coded value, I'm going to use an
image name and here I'm replacing this value
with post title and here I'm replacing this
with post description. Inside my test now I am expecting that the post title
would be the post title. And the description would
be the post description and also the name of the
file should be file. What did I name it? I name it image name and
this should be image name. Let us read on the test. I know that every time that
I am running this test, some random values
will be generated for the post title
description and file name and it looks exactly like how users interact with our system because everybody
uses different things, different characters
and different values. Now I am sure that
actually my API call, my mutation has been called
with the correct parameters.
55. Analysing Code Coverage for createOrEditPost Component: Now, let us see the
code coverage report. We added one test for
rendering the empty four and we added one test
for creating the post. Let us come in here and run
the code coverage report. The first test is failing and this is because
we added a mock. We mock this create pose and
now for the second test, I added this Spy but for the first test this
doesn't exist. Let us move this to a
before each block and let us define this as inside before each block and
let us also define this outside Aslett and let's us override it before each
with the spy version. Now I don't know I cant the
first and let's call it, or we can also call it with e's just completely
bring this out. The first test doesn't
have any interaction with it should be fine. Now the first test
is also passing, let us run the coverage report. Let us go onto our browser. Let us go to all files. We were on the components post. Now we are under 90%
coverage, let us see it. As you can see, the edit
section has not been covered. Also the catch
section has not been covered and these three lines of code has not been covered. For this, in the next video, I also go and I will also
create a test for this case.
56. Adding Test for the API Failure Case: Just before starting
writing tests for these, there is one point
that I should mention. You don't have to, for example, write tests for everything. Right now, we have
a coverage of 90%. In a lot of resources and books, one of the best practices is to have a coverage more than 80%. Oh. And actually, we
are already there, so I can ignore this. But because this is
an educational video and I want to show you all the power and all of the things that we can do
with react testing library, I'm going to add this line
I'm going to add test. But technically,
after this test, I will test only one
single line of code. And it is sometimes you should think you can think
maybe it is too much. If you don't want to do it, feel free to not do it. I'm just want to
show you that if you wanted to do it,
how you can do it. So let us write the test, and this test is similar
to the previous test. The only thing that here
we want to do is like that if this function fails and
if the API calls fail, we want to make sure that users will get one error message. For that purpose,
I'm going to copy the whole block and I'm going to replace it users message if creates post mutation phase. We want to add a test for
the case that it is failing. And now that I have a before each block that marks this and this
is all successful. For this case, I want
to make this to fail. And because this test
has a lot of duplicates, we can also refactor this kind of duplicate, but I
will do it and then. Let us first come here. Instead of returning a mark
result value instead of saying that this
is working fine, let us reject this with an error that for example,
create mutation failed. Now for this case, I'm going to tell vitas that I want this
mark to be failed. I want to simulate an API error
and a failure in the APA. What I am expecting to
see when this happens, I'm expecting that this will this message that
error to be called, and this message should
be shown to the user. Also, in order to do that, let us create an SPI for it. I will say error. I call it error spot. I would say that FN, we spy on message and error. I'm creating a mark for the message
that's error because I want to test that
this has been called. Now, at the end of
the test here when we are clicking on
the submit button. Again, we are expecting
that this has been called. I already tested all of these conditions so I
don't need to test it. But this time, I know
that this will fail. I'm expecting that
I'm going to add an expect B to my errorspiT
time to have been called one and I am expecting it to have
been called to have been called with this error message that error and
creation of the posts. I don't need this line anymore, so my weight for
command will be that this error message should
have been called and should have been called
with the correct paramet. Wonderful. Now the
test is passing, let us re run all of the tests together again
and let us see that I didn't break anything any previous test by
adding this new one, all of them are testing, all of them are passing, wonderful now let us
run it with coverage. And this time, I'm expecting when I come here and
when I refresh the page, this line should not be read. Let us see together
and wonderful. Now this line also
has been covered. Now our coverage has
been increased 90-93%. I still have two conditions. I use I will test this in
the edition and I will also write we can ignore this or we can also
write a test for this one. Just another thing
that I want to do this video because
I have a lot of parts or are shared
between these two tests, I can also create a
helper function for that. For example, call it, I can copy all of this
function and I can call it I can call it interact
or fill create post for. After my setup, I
can define this as a feel can define this function and we put
all of this block here. And because all of these
actions are the same, so I have a typo, let me fix this typo and
here I can also remove all of these lock parts and I just simply replace
it with this. Now it is easier to understand what is
happening inside the tests. Let us re run the whole tests again to make sure I
didn't break anything. And now the function should also be a sync
because I added. I'm using a weights here, that was on the test. Inside my tests also, I should also add an evade here, I should also add evade here. Now I also need these tests
needs actually these values. We can also extract
these from this. Instead of returning nothing, I can return an
object of post title, post description, image name
and I can get them here. I would say cos post title, post description and image name. I am writing them here. I also have a typo here. Let us read on the test again. I also have semicol on here. Let us read on the
whole describe. Wonderful. Now my tests are
passing and also it is easier to understand if another
developer wants to read the test and see
what is happening here, it is so much clearer that we are spying on
message that error, we are rejecting the promise, and then we are
filling the form and then we are expecting to
be called a spy here, we are expecting
here we are filling the form and we
are expecting that the creative spy
have been called and also we are expecting this form data to be passed
with correct parameters.
57. Adding Test for Edition of the Post: Now I want to add a
test for the addition. So if we have, for example, because we didn't test
this part of the code, this part of the
code is the same, but this component can
accept the post object. If we pass it a post object, then we are expecting it to we are expecting this
edit function to be called. Let us go and let us bring all
of our rendering function. This time I want to
pass a parameter, so I would say calls
what did we use, we use users can create a post. Let us also make
this message better. Let us say calls calls, create post mutation when
users fill the form. Here I would say calls
the other mutation, which is it calls,
edit post mutation. If a post is cast. Again, this will be an acing, so I'm going to render this
time and for the post, I'm going to use our test factory that we
have created, get test post. And here I'm going to pass
the post object here. I would say post equals to post. I also need a query client. Let us also bring a query
client for this one. This will be our
render function. I have a need also on this for Now I am rendering the same
thing with the host. I can use the same helper
function that I have created. I can then do all of the
interactions that I had with the four but now I need a new spi also I will bring
all of this block here. But then I just don't
need create spy, I will also create a
function phon Edit posts, spy I also here spy the whole spy the
second mutation which is use Edit posts. I'm going to copy this block. I'm going to this time I'm
going to use Edit post, call it a mark and this time
for the task for the spy, we are going to use Edit post. Of course, if I am
doing this first, I should mark the whole module, so I'm going to the
top of this file, I'm going to also
mark use Edit post. And then after that, these
lines will be executed. I have the edit post. Now I am expecting
that this time, I am expecting my
edit postpe to be cut and the parameters that I am reading from it will
be from this time. Let us run the test and let
us see what will happen. We have an error, let
us debug it together, found multiple roll element with the name button of
the submit posts. Now we have a before
each block and inside before each block, I think I already had
the setup submit post, submit post then we
have the content. We have the feature image
inside our contents and but I didn't call the
setup in this function. I think we have the setup here. Usually we set up
container equals. Because I have the container here which is calling
the setup now, I am rendering the four
twice and this field form actually also does this. For now, let us just let us For now, let me just simply
copy the whole block. Here inside instead
of this line, I'm going to use this. It has so much duplication, but for now, we can ignore it. Let us see if this will
solve our problem. Because now I am rendering
my component here. The test again is failing, and I should also
remove this line, the whole purpose was to remove this line and bring the
function call here. We also the container. Let me also bring
the container here. Again failing form
data arguments that for each is not a function. Let us see here we are
getting an edit ppi. The form has been called once, so this function
has been aligned. Let us from now remove these codes and let
us re run the test. Now, I am sure that actually my edit spy has been called
because if it was failing, it should have failed on
this log let us debug it, so let us see what is happening. And Okay, wonderful. Now, let us debug it together. When the edit post is
calling, actually, it will receive an object
which has an ID and has a property of the
form data and the ID is the ID of the post and
the form data is for theta. Previously, we were just passing the first argument as
the whole form data. Now that I am doing this, actually this this is the ID because I'm
using the first posts, and then let us
duplicate this line. I need and sorry, this is the whole object. This is the whole object
that has been called, which is this one, ID. So let us go and let us instead
call this as like this. Instead of say, I
would say an object, and I'm reading a form data. The first call will be this
object for the form data, then I'm going to
iterate over this. This time, it should
not be a problem. Actually, no, it is failing because it is also another interesting thing that I can discuss it and
I can teach you. Now that we are passing
a post object here, so this input, the
inputs that we already have has a value. And when I am going and when I am typing something inside this, it will be appended to that. For that, I'm going to
first clear the input, and I would the user
input that clear to make it a to make it empty and
then adding something to it. Or I can simply remove
all of these object, and then I will
say, for this test, I just want to add a two. How do we test it manually
if I come here and if, for example, press edit here, if I want to test manually, sometimes I will just
add a number and then here I will see it has been changed,
so this is good. For this test, I'm going
to just inside the title, I'm going to add this
and then I am expecting it instead of this random value, I'm going to expect it to have my title of the post plus this new value
that I have added. For now, let us
remove these lines. Let us make sure that just
to test if this is work. And wonderful. Now my
test is actually passing. For this test, I can also do the same thing
for the image name. I can also do this
for the same thing. Let us go and instead of
passing actually a value just append description to the value that is already there and it is also it says us that it
prefers to use a temple item. Let us change this to be
like this and let us also change to be post the previous description
that the post had, and then we are
adding a description. We are appending a
description for this one, for the image because
this is an upload button, the image will be replaced so I can leave the image
as it was before, so I can just go and I can
bring the same fake line here. And now I'm expecting
this test to be passing. Let us see it together. Wonderful. I didn't check ID, so let us also
test that actually the edit post will be
called with the correct ID. I was adding an expect and I'm expecting
it to be post ID. Let us run the test. I'm also expecting
this to be passed. Now let us run all of the
tests together to make sure that I didn't break anything
during these changes. So wonderful it is passing. Let us rerun the test
with the coverage to also see the coverage report. This time, I'm expecting that these two lines also
have been covered. And wonderful. This
has been covered. Also I can exactly like what I did with
the message that error. I can also test that. When the edition is successful, we are seeing inside
our source code that we are showing
message that success. Let us also test that. Here before rendering, I'm
going to call message. Instead of spying on
message and error, we are going to spy on success. So and I'm going to
call it success spot. When this has been finished, when all of this has been done, we are also expecting that success spy to have been
called once and also we are expecting to have
been called with this message which is post has
been updated successfully. Let us rerun all of the tests. And wonderful. Now
my test is passing. Also the coverage
has been increased. I also added this test
for these two lines. The coverage has been
increased from 93% to 96%. And in the next video, I will put this as
an exercise for you. You can also add test for this. Here, we had a condition that
if the post doesn't exist, it means it is an
create post file. And we are not editing it
because we are creating. If users doesn't select a file, we will show an error
message and if you want to see it inside our blog, if I write title here
and if I write content, but if I don't select a feature
image and I try submit, then we will see
this error message. You can also add
a test for this. This will be fun. Please stop the video and add
a test yourself.
58. Adding Validation Test for Image Selection: So let us come to
the solution part. Let us add the last test and
let us finish this lecture. For the last test,
I would say shows an error message if users
have not selected a file. After sometimes writing tests will be so much easier
because I already created everything that I need from the previous examples. The only thing that
I need is just to copy and paste all of the
things that I already have. Let us go and let
us bring Actually, this one is easier to
copy this time because we need to spy on the
message that error, so I'm going to replace
all of these things. I will bring all of these
values from my setup file, I don't need the return value, I will just bring them for this last test here instead of I won't
enter the image name. I will remove this line, I remove the creation
of the file. I remove the file input, getting the file input, I remove the uploading file
and I am just submitting the form with this empty value because I don't
need upload file, I also don't need this
container, let us make it. Simple here I'm just generating a post title post description. We have a before each plot which always marks the create
with a successful message. For this test, we want it to be successful we don't want to enter we don't want to
enter the file output. After that, we expect it to be error message to be called
with this error message. Let us go and first time, let us try to let it fail to make sure that actually we are testing the
correct thing. Let us run this test. And you see that
exactly it is calling, it expects it to be
called with this message. So I'm going to add this and
I'm going to run the test. This was easy 2 minutes to write this test because I added
already all of the other cases. And this is really interesting
with testing that when you have some at first,
it looks complicated. It looks like time consuming. But after sometimes it's
just getting so much easier because you
have everything that you need for your test. I'm running the test
with the coverage, I'm refreshing the
page and wonderful. Now these lines have been
also covered and now I have 100% for this component. All the lines, all
of the branches, all of the function,
and everything has been covered for this test.
59. Integration Testing Module Summary: All right. Congratulations. You have finished this module. This was a tough module. I know we have covered a lot of topics with writing test for
create and editing post. Actually, we learned a lot. We learned how we can
actually input something into the text area with
user that type. We have learned how we can
write tests and simulate the uploading of the
file for a form. We also learned about marking complex editors like CCA Editor and just replacing
them with a normal a text area. Also we
have learned about the success and failure
API because we wrote tests for different situation if the API works and how we
can simulate an error in the API that we are showing
the error message to the users and also
we implemented tests for validation
logic like that. If the user has not selected a file and he wants to
create a post, then the app shows a morning message, and we also wrote test. This was a really
advanced module, so I'm really happy that
you finished it. It's time. Let's get your time
and do a quick break. I'm really proud of you, and I'm hoping that you will
use all of these things that you have learned in this module
in your future projects.
60. Introduction to End 2 End Testing: So let's get a start
with end ten testing. Congratulations for finishing
the previous sections. I'm really proud of you that
you came this long way. And in this module, we are going to talk about end ten testing. And what is end twin testing, let us go and let
us do a review. We talked about
the unit testing. We said that unit testing
focuses on one unit, which is a function or class. And in integration testing, we are testing the integrity between different
components and modules. But in end twin testing, we are seeing the
software as a whole. So it doesn't matter for us in which technology it
has been written. It can be react, angular, view or anything else. We don't know what back
end technology is using. It can be CSO, Java, JS or anything else. And in in term testing, we are seeing the
software as a whole, and we are testing the expected behavior
of this software. And let us again return and think about the
testing per bit. So first, we started
with unit testing, which they were many
fast and cheap to write. And now we want to
write end Twin tests. And doin tests from the
number, there are fewer, a lot fewer than the unit test, and they are fewer also
than integration testing. And running this kind
of test is slower relative to the unit test and relative to
integration testing. And usually for developers and for the companies,
they are expensive. So from the time the
developers need to put from the resources that they require and from the
time for execution. And now we want to start with this module with the end twin testing and
with playwright. So let's get it started, and let's start with
installing playwright.
61. Installing Playwright: For writing unit tests, we are using playwright. Playwright is a tool
for ten testing, writing, and what does it do? It actually open a browser, a Corum He Firefox or Safari and then it renders it visits the website
that you want to test, and then it is acting like
what a normal tester does. It opens the page and then you can have different
condition that, for example, this text should be visited or this link when I click on
it, something should happen. If I submit this form, I should see this
message and then the page should be
redirected to this page. All of these conditions, we can test it with playwright. So let's start by
installing prey right. I'm inside my terminal, and here, if I do an LS, you will see that I
have two folders. One is for the simple blog
and one is for the back end. I'm going to create a folder
and I will call it TN test, and then I'm going to go to this folder and to
install playwright, I will run this comer NPM
ElenPlaywt at latest. I will pray. And it will ask me, do I need type script
or Javascript? The default option
is type script. I will pick the type script and where to want to
put your twin test, the default is a test folder, so I will accept
also the default. And the next question is at
the Git of action workflow. And what does this mean? Usually in the companies and in the production
environment, we are using heat of
action that whenever merge is happening
into our main branch, a pipeline should be run and that pipeline it's running
all of our Twin test. For now, we don't need that, so I will go with the no option. And the next question will
be what playwright browsers, do I need to install? I will pick the default
option that will by default install all of the
three main browsers. I will just change it as true, I set it and then now it is actually installing and it
is downloading the browser. As you can see here,
for example, first, it starts by
installing Colombio. This is also interesting
for you to see that it actually download the browser, it is actually testing
the whole software in the exact same way
that a browser and a user and a tester
works with the software. And and now in the next section, it is trying to download
Chromium headless, Chromium headless is
the Chromium version that doesn't have
the user interface that a normal user works. So as a normal user, when we are working with a with the room, we have these windows. We have all of these things, and Corobu headless
only has the APIs for Corom that renders
and for the testing, we only need the headless
part of the browser. And here you are seeing them, it starts to download the firefox and then it
starts to download the web. And these are the
three major browsers that playwright does. This is also again, interesting that when we
write tests with playwright, actually, we are testing our software with
different browsers. And this is also
really important that we are sure
that our website works and our web application works properly in
different browsers.
62. Running Playwright Example Tests: So it has been installed, and you will also see this is the icon of the playwright
and we can also see it here. Playwright comes with
some default tests in order to run them, we can run this PX
playwright test. And these are some
predefined test just to make sure that we have installed the
playwright correctly, and you will see that all of
this test has been passed, and now I can confirm that actually my installation
has been successful. It generates an HML report, and we can see that by
running this command and pigs playwright show report. Here, when you run that, you will have a page page and I will open
it on local host. You will see that I
have one test which has been run against Combo. The second, this is the same
test has been run against Firefox and this is the same case has
been run against bk. Then I have another test
which is get a started leak and the same has been run
against different browser. Here you will also
see the time that each of these tests took to run. If I click on it, you will also see
the steps that, for example, it has a before, which is a setup and
installation and then it visits this web, which is the official
page of playwright and then it expects
to see the text of the playwright
and then it will do some kind of afterhoks
Let us see the other test. The other test is, again, it visits the
playwright website and then it is searching for a link which is get started
and then it clicks on it. Let us also see it. Here we have this link which
is get started. This test is actually
for this button, then it clicks on it, and then it expects that to see a page with the
heading of the installation. Let us see together.
If I click on here, you will see that I have
a page with the header of a installation and this is exactly what
does this test do. And for running
tests in playwright, there is also another option, which is running them
inside a UI mode. And I can also show you here. So if I run the same
covered and NPxPat test, and if I add UI, it opens the test mode in the
UI form of the playwright. And here you will see that I have a window and
I have two tests. I can see my test, and here I can run them. And here you will see that
actually what is happening. So it first visits a
playwright website and then it expects to see this
playwright text and then it will do
some kind of cleanup. For the second test, you
can also run it here, and you will see that
it first came to this page and then it
clicked on this button, and then it expects to
be going to this page and see this installation text.
63. Playwright Methods and Helpers for Testing: And let us see the
playwright methods that we have used in the
previous example tests. We have some basic methods, page dot GT, for example, this is the first thing
that actually with this, we can tell the browser that playwright is using
to visit a URL. And then like react
testing library, we have G by role and we can query from the HTML of the
page based on the link button, inputs, text o and we
can get this element. And for conditions
exactly like we test that we had in
the previous videos, we have an expect. We have some matchers
like to have title, we can test that an element, a title exists ins the page. We have to be visible, which is which is similar to be in the document
of react testing library. And now that you
have learned test, now that you have learned
react testing library, learning playwright
will be so much easier because you
know the terminology, you know what is the purpose of the testing and what
we are going to test, and it will be so much easier
to also implement T test. And I also opened the
project in my ID, so I have created this T test. Let us go and let us
see the test examples. And here you will see you can
also go to the test folder. So let us first see this one. This is actually the example
test that we have run. And as you can see here, I have two tests, but we will see six because every test will be run
regarding three browser, Chromium, Firefox, and web kit. And here you can see that I have the test keyboard
and this comes from playwright and the test exactly like what we saw in the test and reactesm library, we have a description for the test and we
have the function, which is most of the
playwright tests are AC because when we go to when
we are visiting a page, this is an AC Gas action. So we have this AXI from playd we will receive
a page object, which we can do methods on it. For example, we can call
the go to to visit a page, and we can expect
also this page. So here we are
first awaiting for this to make sure that this
action has been finished. So browser open this page because this requires
a network request. It can be async and so
we added an await here. And then here, I'm expecting this page
to have this title. When we write it like this, it is look it's a rejix so it is not exact strength
but it is a rejix. And for the second test, I'm again seeing this URL. Again, I will receive a page as the parameter and
then I am visiting and you already know you
already have seen syntax. First, it will get a link. But if you are getting link, there are many links, so it will also add
another condition for get started and then it
clicks on this link. Again, we have the await
here and then we are expecting to see to visit a page that has a heading and that heading should
be installation. This is the two
example test cases that we saw in the area.
64. Writing Our First E2E Test: All right. Let's start and let's write our first
test with Playt. And I'm going to test my page, and I'm going to implement the exact same test that I
want to visit this website, and then I want to see
some elements in it. So I opened the browse I
opened the project in my ID, and I'm going to copy
the whole test here. I'm going to name
it blog section. Here I'm going to define
a variable for the URL. I'm going to use. I'm going to store this as a variable here exactly
like the example test, I'm going to visit this page. I'm expecting what title I will see the title is the thing that we will see here,
simple block page. I'm expecting when
I visit that to see the simple block
page and language. This is an easy test, so let's run it and let's see. As you can see, now I have this window and I will see
the chromium web cube, firefx tested against
different browser and all of these tests
have been passed. Congratulations. We did our
first test in playwright.
65. Testing the Blog's Header: And let us also see and
make sure that we will see a correct header
for our website. I'm going to add another test. I'm going to copy all of
these sections and I'm going to call it has correct heading. Like the previous page, we are going to visit the page. Here now I want to
get this element, which is an H one element. I will get it by
page dot locator. Here I can pass H one, I can get a selector and this will give me
the H one for this page. Then I can say that I'm expecting this H
one to have text. The text will be something that I am expecting to see here. I'm going and I'm saying
that for this test, I'm expecting it to see
simple blood created by. Let us run this test, wonderful. Now it is also passing.
66. Testing Click Event and Navigation between Page: For the next test, I also want to visit this page and then get the first element
and then click on it and make sure that I
am actually seeing the title of that post
article inside my page. It is a little bit
more complicated. It requires multiple steps, so let us do it together. Let us change this test
and let us call it users can see a post
by clicking on it. As the first step, again, I'm going to visit the URL. I'm going to get a I'm going
to get all of the leaves, and for that, I'm
going but I don't want to limit based on the title
or based on any condition. So I will remove this condition, and I will also remove the action button and I
will change this to call it gets links and I will store the results
into the variable. For the first condition, I actually expect to have three links and let us see
if this is working or not. Let us just add an
expect condition. Let us say that we and let us define we are expecting the
count links to be three. Let us also define
these count links, which will be the
links dot card. I want to store I want to
store the number of the links, and I want to test if
I see three links. Let us run this test. Actually, it is failing, and you will see that
I am getting three but I am expecting three, but I am receiving six. Because I also have
other elements here, I also have, for example,
these meno elements. They are also links. Let
us make it more specific. Let us inspect and see
the H t of the page. Here I have one A and inside, and this is inside a DV and
I have the main section. I can actually narrow my selection to be only
searching inside the main area. Oh, let's do this. Instead of searching
inside the whole page, I just want to get the links that are
inside this main tag. So let me first get
the main section. Let's be come here and
let's get main section. And I can do that by
page dot locator. And here I will pass selector, and this will give me a subset, all of the H table
inside this main tag. So instead of getting all of the links and instead of query
Get by role in the page, I'm going to change this
get in main section. And I will change this to main. So I'm running the
same requirement, same query, get by roll, but I'm not running it
inside the whole page. I'm going to run it only
for the main section. Let us run the test, and this time I'm expecting the test to be passed
and wonderful. Now my test is passing, I am here inside this
area and and now my next step would be actually
to click on the first one and make sure that I am
seeing the correct title. And so I will add
two conditions. The first condition
would be actually to see this text five mounts
wearing receipt. And then my second condition
would be when I click on it, I'm expecting to see a
page that has this title. Let us do that. I'm
going to expect that my first link turns
links to have text. Let me just change this. I'm expecting links. I'm going to get
the first link by this method NTH and
I'm passing an index. I'm saying that I'm
expecting this to have the text that I am expecting five bound
watering receipts, you need to try this way. I also need to add ant
because every time when I am actually calling a method and counting or
getting a method, this is also an azing operation. Let us rerun the test and
the test is passing so good, I will see this text
and now I'm going to click on this on the first link. And what will happen
when I click on is, I will go to a page and
let us see what is this. I also think this is an H two. So I'm expecting also
to be on a page that these t exists
there as an H two. And we already did that here. So I'm going to copy
the same thing. I'm going to use it here. This time, I will just use an H two locator and my condition would be
exactly like this. So I'm going to expect
H two to have text, this will be the text that I am this one this is the text
that I am expecting to see. This is also a. Let us also add an
Image and let us also add an ps and
let us run the test. And wonderful. Congratulations. We need a test. We did a really good test first what we are
going in this sense, first, we are visiting
our homepage. Then we are getting
all of the links that are inside this main area. Then we are testing
to see three posts, and then we are testing that the first link should
have this text. And then we are going and we are actually clicking on this text, and we are expecting
to have an H two tag, and this H two tag should
also have this text. So now we are making
sure that all of our users can click
on this element, and when they click, they
will go to a page that has an H two tag and the title
of the post is there.