Lists and Dropdowns | Bondar Academy
Course: Cypress UI Testing with JavaScript
Module: Automation of User Interfaces
Instructor: Artem Bondar
Lesson Summary
In this lesson, we explore lists and drop-downs in web applications, focusing on the differences between native and custom drop-downs . Types of Drop-downs Native Drop-downs: These are built-in browser elements represented by a <select> tag in the DOM. Custom Drop-downs: These are designed specifically for the web application and often involve more complex HTML structures. Automation Techniques Automation for these drop-downs varies significantly: For native drop-downs , use the select method to choose values directly without clicking. For custom drop-downs , simulate user actions: click to expand, select a value, and then collapse. Example of Native Drop-down Automation cy.get('label:contains("toaster type")') .parent() .find('select') .select('info') .should('have.value', 'info'); Example of Custom Drop-down Automation cy.get('label:contains("position")') .click() .get('.option-list .nb-option') .contains('bottom right') .click() .should('have.text', 'bottom right'); Looping Through Drop-down Values To automate selecting all values from a drop-down: Expand the drop-down. Retrieve the list of options and loop through them using the each method. Ensure the drop-down is expanded before each selection to avoid DOM errors. In summary, understanding the structure of drop-downs is crucial for effective automation. Use the appropriate methods based on whether the drop-down is native or custom, and manage the DOM state carefully during automation.
Video Transcript
Hey guys, in this lesson, we will talk about lists and drop-downs. And there are two different type of drop-downs you may see on the webpages. So the native one for the browser and like custom drop-downs. And they are automated differently. And let me show you how. Let's jump into it. So we continue working on the model and overlays and toaster page. And we have two drop-downs right here. So this one, drop-down number one and drop-down number two. And if you look at those, their design even look different. If I click on this one, you see it's kind of a box with the values and a little bit kind of pop up from the user interface. And the second drop-down, it's like a box behind this input field or this is a button with the values. And the difference, they have the different design because this is a native browser built-in type of the drop-down. And this one is a custom one for this web application. And how do I know the difference? So if I make a right-click and inspect and look for the native drop-down, you would have this type of the DOM. It would have a select tag. And if you expand it, it will have options. Option one, option two, option three, and all those options have values. Also, it has value and the text display in it, and this is how it is designed. While this element, if I expand it, look, it's actually like a button. Inside of the button, we have some other tags, like icon and span. And inside of the span, we have the text. And we don't have in this example, where is the actual drop-down? And the actual drop-down is in a completely different section of the page. So look, it's in the bottom of the page, separated from the main drop-down, like ul, option list, and there is nb option. Anyway, completely custom setup. And automation for both of those examples is also different. So let's start with the native drop-down, and then with a custom one. Going back to Visual Studio Code, I set up a new test list and drop-downs on the toaster page. So site contains, and let me target this drop-down by its label. So toaster type, inspect, it has a label. I select this label, going back, this is a visible text. And to target the native drop-down, we need to target precisely this select tag. But look, we don't have any unique attributes or unique ID or something. How we can target is just class with some ng-pristine, ng-valid. So no unique locators for that. So the label is a unique locator, so we can find the label. Then find the div, which is a parent element, and then within this div, find this select. So this is what I'm doing. So toaster type, the parent will be div, like this. Then from this toaster type, I can find child element, which is a select tag. And then to select any value from this native drop-down, I use a method select. So to select the values from this type of drop-downs, I don't need to click on this. I can use just select method. And it is smart enough to select the value from the drop-down that I need. So I have primary success info and so on. And look, those values, they have text. This is a text info, and they have value info. Sometimes in the applications, the value and the visible text can be different. And method select can select by any of those. So whatever value you provide, it either will select by value property or by visible text. So let's say we will select the info, and I will provide the info. And it should just work. Let's try it out. UI components, running the test, and here we go. The select was selected, and it was selected successfully. Now let's add just a validation at the end. And I can use exactly the same select allocator, and I just add should. And since this behaves similarly like the input field, I can use have value, and it should have value info. Going back, Cypress, yep, it was working. The info was selected and validation passed successfully. All right, so that was example number one. Now going back to the example number two, how we automate the second guy. So the second guy is not a typical select. In this case, in situations like this, you need to automate it like you would normally do using your mouse and performing operations. So you need to click on that, then it expands. You select the value, and then it collapse. So let's do the same way. Inspect, I will select it by label, but the label will be a position. So I copy this guy. Instead of toaster type, it will be a position, a position. All right, so then I will need to find what I'm looking for. First, click on this NB Select to expand it. So I find the NB Select and just click, click, okay. After this guy is expanded, it shows this kind of drop down or drop up in this example because I have a higher resolution. And then we need to find where this guy is located. So this is an option list that have NB options. So we can use this class OptionList with a bunch of NB options to get this list. So let's do this. I take this OptionList. So I get, this is a class, so I use dot. And then within this OptionList by text, I can select the item that I'm looking for. Let's say it will be, I don't know, bottom right. Let's do it, bottom right. And then I make just a click, right? And at the end of this validation, so bottom right. To make the validation that this value is displayed. Again, this is not the input field. This is not the native select drop down. So I cannot use half value. The actual value is this bottom right now is selected is the text because it's visible inside of the DOM. So we have to use just a half text validation. So let's do this. I use this NB Select one more time. And then shoot half text. And the text we are expecting is bottom right like this. And let's try to run it. Running the test, so that's the first one. And the second one, bottom right, you see it is selected. So this is the main difference between the native drop downs and their custom drop downs. And now, let's have some fun a little bit. So how about if we automate this scenario if you want to select all values from the drop down one by one validating that your selection works successfully. So how about that? So let's build some small loop and I will show you how we can loop through the list of the elements. So I start with my initial element that returns me actual button or the input field that we're going to click. And then I save it, then name it drop down like this. And then the first step is a side wrap. I need to, what? To expand it. What did I do? Okay, drop down, copying this. I need to expand it, dot click, step number one. After we did this, we need to get the list of all the options right here. But this option list will give me the parent elements. Look at this, inspect. So this will give me the option list locator. But what we need instead, we need a collection of web elements that will give me the actual list of the elements. So I'm targeting the child nb-option that will give me a collection of the elements, so option list, space nb-option. And after that, we will loop through this list using method each, like this. And for every cycle through this list, this option property will give me a single element on every loop cycle. What's next? Then I need to click on this option, side wrap. Side wrap, then I wrap this option and make the click. And then let's try to run it, and let's see what's gonna happen. I want to show you something interesting. So run in this thing, and look. So it selected the first item from the list, but then test failed. And look at the error. Failed because the page updated as a result of this command, but you tried to continue the command chain. This subject is no longer attached to the DOM. Remember earlier in the course, I mentioned to you that if, as a result of the any action command, the DOM structure was changed, but Cypress remembered this DOM snapshot. And if that web page does not match what Cypress remembered, you will see this kind of error. The subject is no longer attached to this DOM. Why does this happen? Because when we selecting the value from the drop-down, when we make a selection, the drop-down collapsing, right? But in order for us to continue the loop and select the next item in the drop-down, the drop-down have to be expanded. And in our code over here, so once we selected the click, the loop trying to continue to select the next item from the drop-down, but it can't because drop-down is collapsed. And Cypress over here, it remembered that, hey, we have the list of the web element. I remember that we have it, and I'm trying to click it, but I see that the actual DOM of the web page right now looks different, and I'm not able to do that. So that's why you see this error that DOM is no longer, how does it say? Subject is no longer attached to the DOM. To fix this problem, we need to expand the drop-down again after we selected it. So when the loop cycle repeats, we'll be able to select the next item again. So at the end of this list, after we selected the item, I click on the expanding drop-down one more time, and we're going back. And here we go, look at this, isn't it fun? So it's executing all the values inside of drop-down one by one, one by one, looping one by one. And let's do one little trick here. At the end of this execution, I don't want this drop-down to stay expanded. I want it to be collapsed at the very final cycle of this loop. How would we do this? Let me show you. So this each option, let me close it temporarily. So this each option, it has three other arguments. So the second argument will be index, which will return the index of each element during the loop cycle. So it start with zero and go zero, one, two, three, four, and so on. Totally, we have eight elements, so it start with zero and end with seven. And the third argument is list. So list will give us just the entire list of the elements, all those options that we are iterating through. And now based on these two arguments, we can create a condition. For example, if the index is less than the length of the list, then we want to continue the expanding the list. Other than that, we don't want to do this. So before the final step, I will do like this. If index is less than list.length, and length minus one, like this, I want to expand this loop. Why do I use minus one? Because index start with zero, but the list return me the actual number of the values, which is eight. So what we need to do, when the index is seven, and the list length is seven as well, it means that seven is not less than seven. It means this will not be clicked at the very final loop of the cycle. Got it? I know this kind of a little bit advanced, right? So we're doing some coding and logic over here we are implementing. But I think it's good time to begin adding some complexity to our scripting. So this is how this logic work. And let's try to run it, right? So UI components and running this test, yes, it works. So look, at the final step of this loop, we selected the final bottom start. Bottom start is selected, but we did not expand at the very end the dropdown. So this is what we try to achieve. All right guys, so let's quickly summarize what we did in this lesson. So when you want to select the native dropdown that has a tag select, you can use method select of the Cypress and select the value from the dropdown directly without expanding the dropdown. And you can use assertion should have value to validate the value displayed inside of this input field for the dropdown. If it is a custom dropdown, you need to use just a regular logic and flow like clicking on the dropdown, expanding it, selecting the value. And then it collapses automatically. And for those types of dropdowns, most likely you will have to use a regular assertion like have text because those values are not really values. They are HTML text displayed on the page. And to make a loop through this dropdown, you can use this each method that let you loop through the list of the elements. Each method has a three arguments option, index on every loop cycle and the list of the total elements. And to avoid the situation that element is no longer attached to the DOM, make sure that you control the flow and your list is expanded before continuing the nest loop cycle. All right, that's it guys, and I'll see you in the next lesson.