How to create your own Swiper / Carousel / Slider in React and TypeScript with tests

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi everyone my name is dominic arjado i'm a web developer and these are guides tips and tricks to web development so in this video i'm going to show you how to build your own swiper or also known as carousel or slider in react and typescript and you also learn how to write tests for it using jess and testing library so in my early days of web development i actually didn't know how to build one and have to use a third-party library to add it in my web projects but now as i gain more experience and knowledge in web development i've learned how to build one of my own and that's why i'm sharing this knowledge with you guys and there's some advantage to that in learning how to build your own component first is that you don't sacrifice the bundle size because when you use a third-party library there are some features that you don't actually need and if you don't use it then it just adds unnecessary size to your bundle and second so for example you have to follow the expected design from your designer for example um the third-party library may not have all the customizations that you require to achieve that expected design and you have to override those styles and again it brings back to point number one which again adds size to the bundle and third and i think this is the most important part is you become less dependent on third-party libraries and you'll give you knowledge and confidence to build one of your own or even extend this swiper component and maybe eventually you also need this knowledge that you gain and build another component which might be related to swiper so yeah if you're interested follow me along and i highly suggest that you write code with me i think that's the most effective way of learning at least for me and yeah let's get started so yeah let me just quickly show you what we'll be achieving by the end of this video [Applause] so this is a very simple uh swiper component so basically there's current image being displayed the first image and there's some indicators over here so basically show you how many images we have on this swiper and i can do a mouse drag so i click first and you see that the images will follow my mouse cursor so once i let go you move to the next image and so forth to the until the last image and i can't do any swipe anymore but i can go back i can go back and swipe back and i can also use these indicators to basically do the same thing but with less effort and yeah and this also works in mobile so let me just show you in chrome's device toolbar this is the chrome's device toolbar to toggle it and you can see this is actually a swipe i mean a touch touchscreen finish it's recreating that touch action and yeah it works fine as well all right so i also add the link to the description below for the for this five images that we'll be using and yeah to quickly get started with react and typescript uh you go on we're gonna use uh create react app and there's this typescript template and let's just copy this and i already run this in my terminal because it will take some time to install all the packages basically just replace my app with the name of our project so i'm going to use react type quick swiper and just type press enter and it will install all the packages for you so i already done that so i'm just going to open it in my ide so i'm using visual studio code as my id so you can also use that because i'm using some of the extensions such as prettier es7 snippets oops sorry about that and yeah important part is the ptr because it automatically format the code for us and i have this vs code settings over here under that vs code folder and settings citation so you can copy this as well if you like and this is the prettier conflict and once you download all the images this file will just put them under the public folder over here all right let me just make this bigger and you can open your terminal on this studio code by pressing command tick and then let's run our react app yarn start so a couple of assumptions right here i assume you have some basic knowledge in web development and react and yarn npm install all that but if you're new to typescript and yes and that's fine i'm going to guide you along the way and yeah you open my browser and open the app which is running on port 3000 right so everything is working fine as expected and let's make some code changes so this one we don't need it for the apps that's css we also don't need it we don't need the logo oops sorry delete this for the indexes we don't need this code style but we need to add star for every element to make it border box so basically if we define a width or height it will follow that exact pixels it will even if there's padding borders margin all that and then for app that's css let's make the changes to the component so let's name this as container we don't need the logo for the container i want the wheel to be become 100 with a max rate of 800px and basically just some padding all right oh you also need it to be centralized and i think that's about it and usually when i create components i put it under a components folder so i create a folder here and let's create swiper.tsx so you may have noticed this is how we write a typescript file in react so instead of just jxx we're going to use dsx so it's a typescript template in react and i'm going to use the snippets to automatically write the code for me swiper and let's add a class name over here let's have it striker container and uh unordered list with a class of cycles and we also need a style for it so i'm creating a swipe for that pcs and import it over here okay so for the swiper container i want it to have a width of 100 and max rate at also 100 flow so basically you have a scroll bar if it exceeds more than the wind for the swiper list this will become lex flex basically if you see here these are all ordered in displayed as flex so all of these items will be displayed as specs and if the images is too small for the container at least we have the swipe release as minimum 100 so the image will occupy 100 of the container and for this we also have the direction of the flex to be instead of vertically arranged it's horizontally arranged and what else can is here this style none oops yeah adding should be zero because unordered list has a default padding as well as margin so we don't need that okay look at our app there's nothing to see yet because we haven't had anything just the div and the ul so later you'll get to see something in a bit so let's just code for now now i'm going to create swiper item.tsx then using the snippet this should be li so this item is swiper item and this is image so basically the image individual image of our swiper let's have the source and our alternative text as empty for now and this will use five image again we'll create a style for it as well and import it for iphone css as again 300 and it should not shrink complex strength is zero so for example here image already uh occupies 100 if there's another image it will not be reduced to 100 it will still be 100 so that's why we have the flex shrink over here and then for the image itself we just want it to be 100 percent with a higher bottom so that it doesn't look uh disproportionate you will scale accordingly to the base on the width and you also don't want the select so if you for example do this like kind of selection you will not turn the image into highlighted image so that's why we have user select none all right so apparently this swiper item is not reusable yet but how to make it usable basically accepts props so image source and image alternative text so as you can see there's a squiggly error over here that's actually from typescript so this if you're new to typescript is your first lesson so you can just implicitly import a props which is not defined in the type so to define a type for a component so just semicolon and since it's an object we're also going to use object and the name of the key along with its type so source is a string which alternative text all right and we're going to use this here so in typescript you can actually create a what they call a type less so basically an object having a name so i'll name this as it's like declaring a variable in javascript same way in typescript you can define a type that you can reuse so i'll just copy this and replace that like this all right and i can even create a file over here name it types and copy that copy this and this cipher icon box i mean cipher item type and export it and i can use it over here starter item type so the reason why i put it in the type folder so that i can reuse it and even in our swiper item which what i'm going to do right now so also this one props sorry i want to to export this as well reason why i'm exporting the props is that we'll be using it in our test later on so yeah so same thing over here but for our swiper it actually accepts an array of images so we'll have this at items so find the type again you have our error because it's not defined in our type yet so let's define it so in typescript you can wrap array in an every interface basically this would be an array of remember we created this we can reuse it over here so swiper icon type basically items are an array of cyber type so basically area of this object right here which is an image source and other things both both are text all right so i hope that was that wasn't confusing so here i'm just going to loop the items and this is an item and i'll be using the index as the key and let's use our slider item let's just pass the item which is the swiper item type as the props for swiper item and index sdk all right so i think that's about it now we're ready to use this in our app component so i'll just import swiper over here as you can see if i didn't pass anything typescript would complain so you can already see the benefits of using typescript because i didn't pass items so that would show an error so let's create the items remember the images right here we're going to use them right now so i'm just going to copy my code so that is faster so right here just is the picture number one two five and i added another alternative text and i'm just going to pass that as a props to our swiper item so now we should see something in our app so here you go and there's a scroll bar because we exceeded the 100 of the swiper container so as you can see if i use a scroll bar i can swipe to the end of the images so what do we do now next so before we write in write the code for that let me just explain you what we're going to do so basically we'll be having a listener so a mouse event listener so by the time i click the mouse down i will record that x position so you know in a partition plane sorry i'm using a mathematics term there's a y-axis and an x-axis so x-axis is the horizontal position while the y-axis is the vertical part of the cartesian plane so we'll just focus on the x-axis that's how you actually move the items from left to right or vice versa so you see that the x position would change from 0 to something negative because when moving from right to left it's actually decreasing in the x-axis so that's why that's how we're going to move the images basically so in our swiper component we're going to define the state that basically change the position of the the images so the style for that would be transform 3d so we didn't use transform x you could actually use that but popular third-party libraries that that has a swiper they use uh transform 3d but i think because of performance so we're going to use that as well okay and yeah before we go into editing swiper component let's create a folder called library or live and i'm going to add books over here so i'm going to create some books helper for us so that it is much cleaner in our code and also it will be easier for us to write a test for it so i'm going to import user over here sorry left object in react we have different kinds of books so one is use wrap so basically you can store the dom elements to it or you can also store variables so in order for that to access those use ref you have to call you have to execute ref.current so get rest value so how do you get the value of the ref basically you can wrap that current so now i have this error right here from typescript so in order to solve this i'm going to use one of typescript features which is called a generics so generics is like the way for you to define a variable that you can use so this this graph will have a type of wrap object from react is a custom type defined by react the way we custom define this wiper item type and this accepts a t so this is again another generic so i'm just going to use c this letter right here can be anything actually it doesn't have to be c can be like uh current or something but in shorter you can just use a single letter capitalize and the type of c will then be return as the current so why am i doing this it's because for example i define a ref let's say number ref and then i use us right zero so when i get the number i'm passing left from the get ref function that i created so inside this get ref this uh is the current which is the value zero so actually it will be easier for me to just use over here as you can see right here i passed the number f and now that when i hover on to the number the type is a number so same thing if i pass a string then it will be a string so that's the benefit of using generics so basically whatever the type you're passing on the usref we can still get the same type as the return value so that's why i have this helper component right here so another upper that i'm going to create is basically use state with a wrap right so this accepts a default value again we we use generic so that you don't you don't have you let the users define your type since default value can be anything it can be number string again that's why we use are generic over here so default value can be anything so i'm using s and then same way you define a state first and again you have state so instead of just set state i'm going to add an underscore right here you get to know why what you state from react again the default value is the default value passed by the [Music] function i'm going to create a set state function over here called the set state with the value the value is again same type as our default value so that's why you can already see the benefits of using generics you get to reuse whatever the type is being passed over here right and then this would overwrite the let's just return it the same way uh use state is being returned so you see state set state and then we'll just add the ref as the third argument i mean the third item in the array to state state set state then do that all right so you can also add a type to the return so semicolon plus an array of s with a function that accepts the value as s which is just void and the ref this object is the type of s all right so i hope that wasn't too difficult to understand anyway this is not the main topic of our video so you can take your time to understand this part so the reason why i created youtube is basically i don't have to create this usref again and again it just basically i can immediately use the ref which has the same value as the state and why do i use ref for example you have a function that you need the value of the state if you want to access the latest value of the state you can use ref so why not use state because you will recreate that function which is not efficient uh and so when you access ref it's more uh efficient yeah okay so going into the swiper item let's use the usted all right and this will be zero so remember how do how do we move the images using the x offset [Music] all right so this object x basically we can use in a style so transform which is we're going to use translate 3d so it accepts x y and z so we're just going to override x over here using the offset x so let's try to run this and we should remove overflow and [Music] let's make this draggable pause reason why is because when you try to see i can drag the image and open a new tab and we want to prevent that dragging effect so you make the image draggable false now you cannot drag it anymore all right and yep okay it's it is displaying the first image as expected and this offset x is going to be our ui state to basically move this container of images so for example i try to write downward it should translate i forgot to add a pixel over here okay so you see i passed a 500 and it moved the container of the images so if i put 800 because that's the container size it would display the second image or slightly because the images are not 100 percent yes here container should be oh our container has to 20 padding so that's why it's 770. so if we put 717 we will display the second image right here all right so now we can you can basically get the idea of how we're going to move the images so using offset x now let's try to add the style i mean sorry the mouse events so first i'm going to add an on mask down so since this is a i'm going to use it over here since i'm going to access the event data i also have to define the type so this is since i'm attaching it in a reactive way we're going to use react mouse event and it accepts an argument this is basically the type of the html so this is a html give element all right and then let me explain what we need to do so basically on mouse down i'm going to record the x so in the event data there's a thing what we call client x so the x position of your mouse cursor and as i move my mouse that's also recording another x which i will deduct from the starting x so the starting x would come from the mouse down and the current x would come from the mouse move so i deduct that and that would be the difference or like the distance that i did so that distance i'm going to deduct it even further with the offset x so currently where where is my image position or like offset two and then that's how we eventually get the new offset x so on mouse down on mouse up then we just basically stop listening to the mouse move and that's where the image will be last positioned so i hope that explains it if not let's start coding and maybe you eventually understand it so again i'm going to add current x first so current x offset x ref let's make this zero again so we need to record where what was the position of our uh container the last the previous position of our container so in order to get that you can use the get ref value from the offset extra all right and that's how basically pass in and update the current observations so this is the last position of our swiper container and then what we're going to do is basically listen in we're also sorry i also need to write the start x position so start xlr so default value is zero get it from the event data line x all right so that's about it for it and we need to add two new events so on mouse so event data don't need the event data right here we need to define this so i'll just use some regular mouse event because i'm going to attach the events these two events in the window smooth mouse up reason why i attach it in the window it's because if we started listening over here this is the swiper container the same width as the the swiper container if our mouse cursor goes out it cannot listen to the mouse move anymore because that's outside the swiper container and we don't want that to happen because even if we go outside this mouse as you can see right here it stills continue to move even if i'm outside the container that's why we need it to attach in the window itself so because we're not using this event listener in a reactive way you can just use the generic mouse event which is available by default you don't need to import it from anywhere and yep we can move on and do the mouse move logic on mouse up we just have to remove this event listeners right here oops and on the mouse move what we need to do so we get the current x current x yeah which is in available in the event data client x okay now we need to deduct current x is start x which is i save it in a ref so that's why i can access this over here so the startx can get it using the helper function that we created get ref value and pass in start next rep and the difference for that [Music] b start x minus x all right so now we have the difference or the distance between this the point that i click and when i move so that is the difference so we can immediately use difference because you see as i try you see that it's moving the opposite way and it's not updating the thing so we need to deduct this diff with the current offset x so we can get that turn offset x let's use it now and you can just use this like this all right and basically the current offset x new opposite x okay obviously yes we lit up with the d all right and that would be the new opposite x so let's try out refresh and you can see that it follows my mouse cursor and yeah that's how we know it's working fine as expected and you may have noticed when we removing outside the image we cannot see any image anymore we will be preventing that later on but yeah i think we're getting there so now what we need to do is basically let's support uh on touch before we add more logics so that we cover the the mobile version of this as well so i'm going to rename one mouse move sorry not rename but yes do you name this move because normally i approach my development in a mobile first approach so that's why i like to rename it as mobile and we'll just reuse these same functionalities in the mouse here so here one touch start the timeless move is the same as well so here i'm going to add and all right and let's ignore the errors for now and just basically we need event listeners and okay so now we have mossy band but we don't have the touch either so let's just add touch event over here and also same thing for event over here it should be so in touch type script if you're new to typescript you can have a or condition so that will be using the pipe character so you just do it like this so event data could be touch event or mouse event so that's how you do conditionals in typescript so this should be attached to that and now how do we solve this e client x so normally i create a function for that so basically i call it [Music] get touch data so this accepts event data we're using these four types over here so touch event and once again there's an or condition for react all right so i use four of them basically check uh because in touch events they don't hide actually the client x directly they store it in an array called change change watches this an array of objects which contains the client x so if change touches exist in the event data so what i do is basically return uh the first uh object of the change touch that's how i can get the client x from the touch if not then just return the normal event data so this is how i'm going to use it get data passing the e and now you see that there's no more error for the client x as you can see typescript is saying that clientx doesn't exist in a touch event all right so same thing i'm going to use this over here so now if we try it again it still works just fine for the mouse event and we can try on the device toolbar when we refresh and yeah you can see that it also works fine you see that the container is moving you can actually prevent that by adding a touch action and y so basically only y axis actions will have the browser effect so now you see that it's not moving the container anymore because in a mobile browser they have these special actions when they do touch so we want to prevent the x the x-axis from doing those special effects we only need the y-axis because for x-axis we handle that all right so now mouse down and touch down touch starts are settled we can move on to add additional conditions to our swiper components so remember we don't want user to keep swiping to the left or to the right when there's already no image so how do we prevent that so for the first image we know that the first image is uh displayed at zero let me just show you real quick you see that the translate 0 is displaced the first image but if you go to the right it increases to a positive value so basically we just need to prevent if the new offset x is more than zero then we should just return 0 as the new offset so here call it snap x 0 because it's a positive value that's why this is the max so if new offset x is more than the max then we should make offset axis zero let's try that as you can see i cannot swipe to the right anymore but i can still swipe to the going to the left i mean don't get confused by that uh i'm going to move to the right and it still works so now we just need to set settle this right part you see there's no image already and basically how you compute that is basically multiply the number of items you have on the number of images and multiply that with the container so container is like 770 times five so if you see we calculate [Applause] um [Music] 770 times five that's a 380 50 3850 if you try to show that here that's actually displaying none so basically we have to minus that with the container size 770. so if we try 380 382 that is displaying the last image so basically multiply by the number of items and reduce by one so how do we get we can actually get the container size from untouched so let me define the container element ref so when you declare a ref that contains the dom element you have to pass now as the default value first and then you have to pass in the type like this yeah and the opposite x this should actually be a list so container ref so basically this i'm going to pass the ref over here and that's how you you can basically call this get ref value with this and you can get the container element so i'm going to get the container element right here now this will return the html element and how to get the win the width will be offset width um let me define another which is the mean of x so we have a max offset x we already know it's zero but for mean offset x we have to compute it on touch starts so i don't compute it on the much most mode because mass mode fires a lot of times and you don't have to always calculate it there you can just calculate it one touch start so that's why i do the calculations over here so that is not affecting the performance so how do we calculate mean offset x then we basically get the offset width deducted with the forward so scroll width is basically the contain the the size of this swiper list containing all the images remember we had the scroll over here before we remove the overflow figure now the size of the scroll to scroll until the end this will be this program so we did we minus offset width first because we want it to be a negative value you see that it's a negative value so that's why the larger number will be on the right side and now we can use this right here in offset x ref and if our new offset x is less than our mean option x just replace that with the option x so let's give this a shot i refresh it and i try to reach at the end i can't swipe anymore as you can see so that logic is covered so next what can we do so you can see when i try to swipe it doesn't automatically swipe it to the next like how it does it over here you see there's a smooth transition to the next image and i just have to do like a lazy uh swipe see i just have to do like something like this of course if it's too small it still remains the with the current image but it is large enough then it's auto swipes for me and that's better for user experience as well so how do we do that so we're going to use a formula let me just show you real quick this is the formula that we'll be using so let me just write it over here so let's say i want it to swipe to the next image just show you this first you already know that the first image is displayed at zero offset the next image is the container size in negative value so we know the container size is 770 and the third image is basically twice of this of the swiper container width by negative value and same for this is twice it's basically just a multiples of our container with so how do we get the nearest position of the container we can just basically for example it is in multiples of five we just basically calculate the nearest number of uh [Music] for example five so for example i'm number four nearest number will be five if i'm one two then it's nearest to zero then five and for example is nine then it will be ten so something like this how do we come up with that basically this is the formula map that round so the offset x would be basically this offset you divide it with the container with which is for example 5 or 770 then multiply with the container width so that's how you get the multiple nearest to the multiples of this number right here so using this formula let's get the container with first i should save this container with as a ref don't have to keep getting it from the dome element all right that should be it let's just pull this now i have a container with over here basically i need to get offset x so we can access this from this right here so next strap i'm using this formula just now around the new x divided by container with then we just basically set the offset x with this new offset x right here and oops let me just charge my laptop all right let's test it out as you can see if i swipe over here and move to the next image currently we don't have transition styles yet but you can already see that it's working fine if i just do a little bit it doesn't move as much it doesn't move from the current image but if i move just enough for it to round off to the next and yeah it works fine so how do we add styles so we need to write a state [Music] [Applause] and can we add swiping on the touch start when it ends on touch end so touch start swiping issue on touch end it's not swiping so when it is not swiping then we can add some overrides so i'll be using a class to define this swiping class over here so on my class let's add a star over here and just wait for this transition transform duration is less 300 milliseconds transition style is is out and if it's swiping we don't want this position as you can see when i'm swiping i don't like the transition but if it's not then it transitions slowly maybe i can show you when we just have the transition all the time you can see oh there's an error we need to import it from as you can see let's try it out you see that the swiping is delayed that's why we need to prevent that if we are swiping then there should be no transition at all all right and that should solve it now you can see it swipes smoothly for us and when i let go then there you go it's much more smoother all right so now that's settled we still can make improvements to this type of component as you can see if i do like this it still doesn't move to the next image i have to like more than half of the container then it will move to the next image so we need to make this easier for our users how do we do that basically we can implement like a lazy kind of swiping so basically we don't need more than half we just need like uh what i'll be using is 40 pixels and then it will move to the next image so something like this you can see i didn't do much swipe and it already moves to the next image so let's do that here how can we do that basically instead of just ma math that round we'll be using math ceiling and not that so we just need to determine if it goes to the right we'll be using uh [Music] to the right and to the left is the master ceiling so it doesn't need to be round off it's basically whichever direction you want it to go so how do we determine the direction basically if the difference is a positive number means it's going to the right going to the right like this and i reach the right end and it's going to the left you know that is is negative so that's why if the difference is negative it's going to the left and if it's going if it's positive then it's going to the right so that's how we do it so in code basically we get the current offset x from the current opposite x get the difference between current offset x and the new offset x so now i'm going to define max what required that's the 40 pixels that i mentioned so it doesn't have to be more than half it's just whether you're more than 40 then you will do the swipe so if this difference will be either positive or negative value so we have to use absolute so that we always get a positive value of the diff it's more than the swipe required so basically swipe to go right as possible swipe to the left if this is negative this is where we can use the mat the ceiling or math that floor if it's not then you will just you can just use neuron which is basically if it's less than 40 then it will just stay in its current position because the value is not enough to move to either directions so who you can check if diff is more than zero and it's going to the right remember we're just going to replace the round two ceiling plus here it's basically going to the left so you use flaw so i think that's about it we can try this out remember it's this logic happens on the touchpad all right so let me refresh and did we miss anything currency of that new offset x more than zero not sure why step oops sorry i missed it should be floor and ceiling sorry about that and yeah as you can see i just have to do like this and you will swipe to the right or left if i do less than 40 then it stays it stays here in the current image if it's more than 40 then yep you can see that it's so easy to use that's great so we're almost done here so we just have to create this indicator and then after that we can start writing tests so let's create an indicator so swiper indicator so the number of indicators is the same number as the images so we can just leave the indicators right here again you don't need the item actually just move it here this will be a list item as well then you should have a key of the index should be swiper indicator all right so how do we determine if it's the current image so basically from the index because arrays works on index so if it's displaying the first image then index is zero so we already can get the index of each indicators when we look into it so basically we can have an acting class so oh before that we should create a state um call this current index um so press image index is zero so zero is the default value and we can compare this if index is equal to the current index and we should add an active class if not then there's no active class at all and we should also add a listener so let's add it that we know on data context we'll just pass the index as the number so basically when we click this we should move to the next image so we need the index value for that [Music] this one let me pass it on here first one click anonymous function to pass in the index so like this indicator and click then we pass the index so anything else we forgot all right so when we're doing a swipe we need to update the current index to the to the whatever image is currently displayed so currently second image is displayed so the second the index number one should be active so how do we compute for this so basically we can compute it on the untouched end and set the current index so we already know that each offset is a multiples of the container with so we can just divide [Music] new offset x and since this is a negative value this offset x could be a negative value most of the time we need to make it a positive number because our index works in a positive sign so we need we need the positive value for that we just map that absolute and then for the indicator click same thing so instead of dividing it you basically multiply the index with the container with so i'm just going to copy this set the current index to the index being passed and set the offset x by basically multiplying container with the index since in order to move to the left it should be a negative value so we just wrap it in a negative sign so this should work so let me see oh we forgot to add some styles for the indicator let me add it over here indicator this play plex still quite content to the center since this is a style we don't want this i don't want these bullets we want to create our own and margin should be 50 on top and just basically set the zero to the other margins and padding as well swiper indicator item we need to have a width of 12 tile 12 this circle margin should be px to the side so left and right background should be default it's like a slightly grayish you shouldn't have a cursor pointer when you hover onto it alright so if this is active and we should set the background to uh slightly darker 777 [Music] uh gray all right as you can see it's basically working the same way in our production uh swiper and if i click it goes to the last image if i click on the first it goes to the first image so yep we're done but we still have to write tests for it so we'll get into that and i hope you learn a lot for this building this wiper component and let's start to write some tests so normally when i write test i put it in a test folder so that it doesn't mess up our main main fast so when we're developing we don't see the test files we see it in the test folder so first i'm going to write tests for swiper item dot tsx so the convention for writing the test file for me at least i use that test and then the type of that file so tsx as well so now what we're going to do is basically write a describe so subscribe is a function in jest basically just describe where you're testing so i'm testing swiper items so i'm just going to write swipe item right here and i'm going to import it as well all right and i also have a props so let me put it here as well and normally i create a reusable render component functions which accept the props that's why i'm going i imported it here so that i can pass it here we can call one of the functions from react uh testing library so from this you have a render function which basically render your component in a test environment here i can just pass swiper icon and pass in the props so you can see that in test files you also still get typescript errors so i think that's good also so that we don't we can get some errors even when we're writing tests and we can catch bugs early on all right so that's about it and to write a test case in a describe block you can use it or you can also use s function so i like to use it so first it should render our image props so we should accept image source and image of ops so how do we check for this so first we need to generate a random image source and image alternative text so for that i'm going to use a library called faker so generate random data for us this makes our test case uh more robust because the data is always in random we don't hard code anything so we're going to use faker and paper also has the types i'm using a specific version right here because the developer for faker messed up the latest version and yeah you can check it out it's quite a funny incident so but this is the working latest working version so we'll use this i'm sorry i forgot to add yarn add all right so let's wait for this to install so once once that's installed let me just start writing the code we can generate a random image source using thicker dot image dot image url and then the image alternative can be just a sentence [Music] sentence all right so okay now let's render the component using our render component function and pass in the pipes the image source image authority so now in this test case our component gets rendered so what check can we do so in the same testing library by react there's actually what we call the screen screen which we can query the dom element so there's a lot of query right here so there's query by alt text which you're going to use there's other things like display value label text placeholder role s id text title so you can we can use a lot of queries but for now we're just going to create by alt text we already know what the alt text is this is going to be the image element and for this after we query we basically check whether this image element that we query exists and has a image source same as what we pass in the box so there's another function by jess which is expect this is basically like a verification whether what we expect is there so we expect image element then there's a matchup function returned by the expect so dot to have an attribute so there's a lot of mature functions like to be in the document to have a class we have a style for this we're just going to have the attribute check source compare it with our current source that we pass basically when we render the component we query whether that alternative text is there and we check whether that image element returned by the query as a source of image force basically that that's our verification that this props uh this component is working fine as expected so to check i'm going to run in our terminal yarn test and i like to pass coverage so that we can see how much it covers the file component so it also helps us to see what are the uncovered lines as you can see our first test case already achieved 100 coverage that's great but i cannot promise you the same thing for swiper item i mean the swiper component because there's a lot of logic into that so basically we're done with this wiper item we can move on to more complicated one which is swiper dot tsx so again i'm going to do the same thing in part swiper and do a describe block and same thing i like to create a reusable function reason being if i have this render in each test case again and again when i change the file name then it will become harder to replace so having it here at the top it makes it easier to make changes and same same [Music] same thing for props and if this props changes i mean you don't have to keep changing it on all the test case we can just changes here on the top all right so crops import from swiper and then the render by testing library by react and this pass the props over here so for this we basically check whether the images are displayed so we can do the same check that we did in the swipe item and it should display this then we're going to use faker to generate fake images for us so our swiper i swiper component accepts a number of items so a number of images not just one so i'm also going to pass an array of items so what i like to do is basically create a [Music] more than this is necessary but you you can change this if you want basically i want to compose an array of images so let's just basically same thing as we did over here we generated the image source and image alternative over here as well so now that it goes through loop loops through and returns you the items so now i can just basically call this you can render our components all right so how can we check whether the images are displayed so we can actually look through this and this will determine the item on image and remember how we check this image element we can actually reuse it here as well so screen by let's import it here and this item has an image alternative text and once we query that we should check whether the source is the same all right so once i save this this should still pass great so now you can see how many uncovered lines are there oops sorry so 26 to 41 44 to 70. so when we look at our swiper tsx we go to line 26 this is the touch move to 41. and this is the touch and so basically this is the swiper logic because we haven't done anything to test that and that's what we're going to do now so it should [Applause] swipe on mouse move so i'm going to do mouse first and we can do the touch later where they're basically the same the same test case but just different uh events fired in the test environment and also before we start writing tests i just want to create another helper for our test so i'm going to create a file called testhelpers.ts let me explain to you why so you know in a normal browser we have things such as whatsappgrid let's go with so this actually just these two things we already use it to compute the container with and scroll with to compute the mean minimum offset x so these are parts of our swiping logic right but in a test environment these values are actually zero because these are actually computed with your css styles in the browser but in test environment it's always zero and that could be a problem for us because how do we then verify that our swiping logic is working if it's always zero all all of your results will just be zero and that's not really reliable so what we can do is basically overwrite this offset wind and scroll wind with a with the number that we desire or want to use so it would have been easy if we just use element that offset with then let's define our own number but these properties are read only properties and you cannot easily do it so we have to we have to create a helper function in order to override these values i'm going to create a function set with only property and let's just add the arguments first so it accepts an object and then a property of that object and the new value that i want to override let's ignore the typescript for now and then i'm going to call object define property passing the object from the argument in the property and then this accepts the value and it is configurable true all right so this basically just overwrites a read only property and again i can use a generic because these objects and properties can be any any of value so again i'm going to have o as the object p as the property v as the value and we can actually do an extension so you know similarly in javascript we have class and we can extend the class in typescript it works the same we can extend a generic and we expect this object to be uh an object so this thing what we call record it's basically like an object which then accepts two arguments so object has a property so the property naming we want it to be a string and the value of that property can be anything again this property this should be as key up and again this is a feature in typescript so basically p is a key of o so basically if we try to pass anything that doesn't exist in o you would get a typescript error later i'm going to show you an example so in this value v we just extend it as any so yeah this is done [Music] you just have to pass in the generics to this each of the arguments and now we can reuse this so again we can use the same thing over here and this values we need to override the offset with and so container element right so how do we get our container element or actually it should be this you element use again the screen and query by this time we can create by role so role is basically our browse you know and web web development so there's different kinds of row so there's a list row oops here so basically ordered list automatically has this row so that's why we can query for it and we can just share we use query by row you can see i try to do this i'll get a js error right here because there's two unordered lists in our swiper item so the list for the images and the list for the indicators so instead of using query by wall you can query all by rule and we just need the first item and that's how we get our this container and let's generate a container with this we'll use the faker data type and number so this will generate a random number and we can pass a minimum value for it so we don't want zero so we'll add one minimum of one and how do we compute for the score [Applause] it's basically container width multiplied by the number of items all right so now that we have the container width and container scroll width we'll just override it using our property set read only property passing the object which is the list element in this case property and trainer width let's duplicate that for the screen this is actually offset absolutely as you can see just now i try to pass in a property that doesn't exist in last element and i get a typescript error because i'm using the key of so that's why it's very useful for this case all right now that we already override it we can now do some checks so first thing we need to check whether our list element we expect our release image to be positioned to to display the first image so how do we check that we can use to have style and basically he accepts our object like a style or you can react and we want what you need xyz i think that's just it so if it's zero you should be displaying the first image so let's check whether that's correct oh sorry it should be translate 3d all right and that should pass our so basically starting position is zero all right now let's execute some mouse events how do we do that so again there's a another function from react testing library which is fire events this is the function to co to trigger uh different kinds of dom elements so not just mouse events you can trigger touch events you can do to your scroll and different kinds of dom events and yeah i'm going to show you how to fire a mouse event so first we have three different kinds of mos events so first we do a mouse down and then we mouse move and then we mouse up that so let's pass in it accepts the first argument as the element that you want the event to get triggered all right so in this mouse down in most move we actually use the client x or the x position so we can pass it here as an option so basically it can you can add values to the event data so i'm going to define x over here zero so we start at zero so that's easier to digest and then in order to move the images it should be more than 40. remember the swiper the minimum swipe should be 40. so our n x should be negative 41 because we want to move to the left it should be a negative value so we just pass it over here as a client x and same thing for mass move that will be our mx so now that we triggered this events to the list element we can do a verification again so now it should not be zero it should move to the next image or the second image so what is the position of the second image is a negative value of the container width so times one of the container win all right and it should be a negative since we're moving to the left and this should pass so [Music] all right let's check whether our test pass and yes indeed it passed and you see that the uncovered lines change and our coverage increased that's great and since we if we check the uncovered lines again 934 it's basically it shouldn't move to the edges we move to the 38 same thing 57 to 60. so this is the one that i wanted to see so you you were able to move from left to the right but we haven't covered the opposite side so we can do the same thing again so normally i like to create a separate test case for this but i think this is a special case that makes sense because we already moved to the left by right we should move to the right we don't have to repeat this code in order to just cover a separate test case so that's why i think we can just continue from here and do the checks although it's advisable to have separate test cases in a different scenario not this because it makes it easier to maintain and also when you have a lot of expectation then you get the test case becomes more complicated and hard to understand now imagine you have a lot of code and you have to read that bunch of code so if it's like this then is you see that one test case has a small test one expect only and that's easier to understand yeah but for this case is a special case which i think makes more sense all right so now instead of negative value we just make it a positive value and we expect it to go back to zero again so we should move to the right once we save this it should still pass again and it did and you see that that's the line 57 is now over there and how about line number 60. so again we can do the same thing so basically for line number 60 it should stay if it's less than our minimum swipe required so less than 40. so we can do that just copy again describe this code right here so it should verify should stay in position or yeah all right so what we can do here is we can use faker to generate a number for us that's minimum of zero and maximum of 40. so since our minimum required should be more than 40 so any number within this range would fit we just stay on the same position as the previous one let's try that all right and you see that we are getting lesser uncovered lines and line number 60 is not here anymore that's great so what else can we cover so line number 38 is basically if it's already the first image then it shouldn't go to the to the left side so let's try to cover that basically um hold on actually this should be a negative value we're trying to move to the left [Music] all right now let's try to move the items see the 34 here which i was trying to test so for this we just need one try to move to the right event further but it should still stay and it should pass verify [Music] shouldn't move to the right if already at the start so what about the other side so what if we we want to test this part so we can calculate for the main object best case so how do we compute for that speed just container with minus containers volume all right that is the minimum offset this is the minimum offset displaying the last image so again copy this and we want to be able to this is a negative value to move to the left this is moving to the right it's moving to the left with a negative value we just add a plus one and again it should stay to the minimum offset x so we added a plus one here but the image shouldn't move beyond that so we're shooting one player to the left we've already at the end all right oops why did that fail let me rerun again this element contains called oops sorry it should be container scrolling minus yeah because this is a positive value then we convert it to negative over here and now we check what is this line 94 to 98 is actually the indicator on click we didn't do any test case to trigger the indicator on click and if we check one two three is the same line one two three is the on clip but before we move to that i just want to show you that we haven't covered the touch event so i'm just going to copy our mouse test case and it should swipe items sorry swipe items it should swipe items on touch move so how do we convert this test case oops sorry this is our lines into mobile so basically just replace this three right here so touch start remember our events touch move and touch n and there's actually no client x in touch devices so same thing for this and then just copy everything from here all right [Music] all right so that should pass and yep everything's still past and still looking green for us just uh we're just left with the uncovered lines so let's cover that so for our next test case it should swipe icons on indicator clip for this i'm just going to copy the same thing we did to override okay this part right here copy it here okay so again we can still do the same check that the position is at this part zero starting position and how do we check whether indicators are working fine so we know that the first image is displayed so the first item in the indicator should be or should have a class of active so how do we do that basically let's get the first indicator element and we cannot simply just use query by rule so i'm going to show you how to use a data test id here i added an attribute so that we can query the indicators more easily in jess i mean in our test case so here we can query because this all of them have the same test id by test id and indicator all right so the first item this has an index of zero so we expect the first indicator to let's try and save this and check our test case we failed how come because this is not this id oh i forgot to save the changes over here that should work fine now and it did and now let's query for the second indicator element which is in index one so this one we expected to not have so there's if you can use expect but not so basically the opposite of to have class so the second indicator should not have an active class all right now we can fire an event so here we're doing a click event and passing the element that we want the event to get triggered now when this is clicked we basically do the swap of checking so now the second should have the indicator second item while the first should not have an active class all right and that should still pass and just an as an additional check we should verify that the position move will move to the left so just a extra precaution that when you do the indicator click it should move to the left so times one of the container with a negative value and this should pass all right and we achieve 100 coverage for swiper and swiper item component and yeah that's actually all for now for this video and i actually want to challenge you to extend this component because i actually didn't add the arrow functions over here you can try that and yeah i think i hope you learned a lot from this video and don't forget to subscribe and like and share this video so i'll see you again and thank you for your time so bye
Info
Channel: Dominic Arrojado
Views: 7,949
Rating: undefined out of 5
Keywords: web development, react, typescript, email template development, email development, mjml, web development guides, web development tips, web development tricks, node, nodejs, expressjs, mongodb, front end development, front end, frontend, back end development, backend, back end, development, programming, web app, web application development, technology, web, html, css, javascript, web technology, web application, html email template, mjml framework, jest, redux, test, unit test, docker, reactjs
Id: V0dfhBc2lj8
Channel Id: undefined
Length: 105min 1sec (6301 seconds)
Published: Fri Feb 11 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.