Reusing Locators | Bondar Academy
Course: Cypress UI Testing with JavaScript
Module: Interaction with Web Elements
Instructor: Artem Bondar
Lesson Summary
In this lesson, we explore two fundamental concepts of the Cypress framework related to variable management and function results. Understanding these concepts is crucial for effectively using Cypress, as traditional approaches from other frameworks may lead to frustration. Key Concepts 1. Cypress Alias The first concept is the Cypress alias , a smart global variable that allows you to save locators for later use. Instead of using traditional constants, you can create an alias using the as method: cy.get('locator').as('inputEmail1'); To use the alias, reference it with an @ sign: cy.get('@inputEmail1').click(); This alias is globally accessible throughout the test run, simplifying the reuse of locators without the need for constant assignments. 2. Using Cypress Then Method The second concept involves the Cypress then method, which returns a jQuery object. To interact with the DOM using Cypress methods, you must convert this jQuery object back into a Cypress chainable object using: cy.wrap(jQueryObject); For example: cy.get('locator').then((inputEmail) => { cy.wrap(inputEmail).parents('selector').click(); }); Additionally, remember that you cannot return values directly from the then method. Instead, use aliases to store values for later use. Summary Use Cypress alias for saving locators globally. Utilize the then method with cy.wrap to convert jQuery objects back to Cypress chainables. Mastering these concepts will enhance your Cypress testing experience and reduce flaky tests.
Video Transcript
Hey guys, so this lesson will be a little bit mind-blowing, because we're going to touch one of the most important and core concepts and unusual concepts about Cypress framework, is how to create variables, and work with variables, and return result of the function, and reuse the existing values later in your script. Because Cypress, unlike other frameworks, has a little bit different mechanism of working in situations like that. And most of the engineers who never work with Cypress, try to use a traditional concepts in the Cypress, they don't work, and they frustrated that framework do not do what they expect it to do. And it is normal. So in this lecture, I will show you those concepts, and it is very important to understand. If you got it, then the rest of the framework and the rest of interaction of the framework will be actually very easy. Okay, so let's jump into it. So look, in the previous lecture, when we were talking about Cypress chains, we created two chains that start with the same element, getInputEmail1, and this example, and this example. And you could be wondering, what if we save this locator into the constant or variable, and then we'll reuse it in the script instead of copy pasting it two times. So, and what you would want to do, so let me copy this thing. I'll set the new test up for this demo. So that's the first beginning. This is the second. Second, like this, and like this. And from here, I grab the button like this. So what you probably want to do is do something like this, const inputEmail1 equals two, and then get this locator, assign it like this, and then you get here and replace this constant over here and over here. I would assume this is the first thing that you would try to do. But the truth is that this will never work. This will not work. Don't do like this. So Cypress works differently. If you try to execute this code, it may seem like it is working. So Cypress probably can find the second element, the first element, second element, maybe even interact with this. But if you try to follow this approach down the road, trust me, it's gonna backfire. Your test will be flaky and it's just not gonna work. And you will be surprised why my framework is not working as expected, why my tests are flaky. Because Cypress is not designed to use the constants like this. Instead, Cypress has a different approach managing the situations like this. And let me show you those examples. So I comment this code just for your reference. So you will never do things like this. And concept number one called, let me comment this up, called Cypress alias. So Cypress alias is a kind of smart global variable for the framework, and you can assign anything into this variable. So how does it work? I would call my CyGet, this guy, and then to save this locator for using it later somewhere in my test, I just call method s. This is a specific test. And then I provide the alias name, and for example, input email one. That's it. So the value saved into this alias. How to use it? Then you call CyGet, and then you call this alias inside CyGet, but you add this at sign. This is important. This is the part of the syntax. And after that, you call the methods that you wanted to call. Parents form button, and then I call this alias one more time like this, and then calling this stuff. And this is technically a variable that represents the locator for the input field. So let's try to run this code to see how it is working, what will be displayed in the runner. So running the test, and it worked perfectly. And look, when you create Cypress alias, you see in the runner, the name of the alias was created. Look, so the locator alias is at input email one. And then when this alias later used in the code, you also see it highlighted in the runner. We called it once, and we called it second time. So it is working. What is very nice about this feature is that this variable technically becomes global for your test run. For example, later, then we're gonna use different helper functions or page object and all that stuff. If you create like multiple layer architecture of your framework, and you call somewhere in some file, this alias creation, then you can call this alias globally in any other file or in the test within the framework. So you don't need to make like classical, return, then importing of the function, then assigning result of the function to the constant, and then using this constant inside of the test. All you need to do, create the alias once, and then within this test run, you can call this alias anytime, anywhere, and this value will be just there. Very cool feature. And later in the course, we will use it several times, so you will see how useful it is. Okay, so that's the concept number one. The concept number two. So using Cypress then method. Cypress then method. Okay, how this stuff works. Let me close this, so it will not run continuously. This one is a little bit trickier. So let me grab this locator. And then after the sci-get locator, I call method then, like this. And the result that returned by the get function, which is a snapshot or the instance of the DOM returning this web element, I assign to the variable input email, which is an argument for my callback function. So look, this is the fat arrow syntax. You know this fat arrow syntax. This is anonymous function, and this is the callback function inside of them. And so this input email is the argument that holds the value returned by the previous function. And then you can use it, but there is a catch as well. So if you try to use it something like this, like input email, and then try to call parents find button, right? So it seems fine. No red squigglies, nothing like this. So let me comment this, and I go back to Cypress, and I will show you what actually happening there. So running the test. And look, it stops right here. So it got input email one, but it didn't go any further. So this line was not executed. Why is that? So if I hover over this input email one, or yeah, over this parents, look, this parents element, look, it's jQuery type of the element. While if I hover over right here, so this parents, this parents is Cypress chainable type of the element. So what is jQuery? So jQuery is the selector engine that Cypress using under the hood to select web elements on the webpage. So technically Cypress kind of wrapping jQuery and using jQuery to find the web elements on the webpage. And when we call method then, then this argument inside of then becomes like a pure jQuery object. And parents element also exist in the jQuery library. I know, are you still with me? Yeah, I know this is confusing, but parents is existing jQuery library. And look, this is the link to the jQuery library right here. So I'm going back to the browser and opening here. And here we go. This is a jQuery. Parents and parents looking for the selector and so on. So it's a legitimate method that you can use. Going back, but it doesn't work because for us to continue interacting with the webpage, we need to use Cypress parents method. How would you do that? For that, you need to convert this jQuery object into the Cypress chainable object back again. How to do that? Cypress has a special method called Cywrap like this. And you are wrapping this object, Cywrap input email, and then Cywrap will return Cypress chainable type of the method. And look, parents right now is Cypress chainable and find method also Cypress chainable. So going back to Cypress runner, and now it works perfectly fine. Input email one, then we wrapped the object and then we're able to perform a form and button. And now we can reuse it. So I call Cywrap again. We can reuse the same object and call the second thing right here, going back. And look, it is executed as expected. So that's example number two. So methods Cywrap actually, it can be used not only for the jQuery objects to convert them to the Cypress. Cywrap can be used for any types of data. It can be, I don't know, JSON object, it can be text, it can be anything. Any kind of object or subject that you want to call Cypress command on, you can wrap this object using method Cywrap to be able to call Cypress chainable commands. And I can make a quick demo. For example, we can make Cywrap like this, and let me wrap just the text hello, hello into wrap. And then since Cywrap is wrapping the object, whatever, into the Cypress context, I can now call the should assertion of the Cypress. And I should validate that this text should equal hello. And that's it, going back. And look, assertion, wrap hello, assert expected hello to equal hello. Yeah, that's obviously, that is equal. But I'm just showing you the concept behind the wrap. That wrap, wraps whatever you have into Cypress context to be able to execute Cypress commands. What else? The nuance about the then function is that you cannot return anything from then, technically. You cannot make like a return statement and return something from this function, assigning it to the variable, something like this. I don't know, let me mess up a little bit. So let foo, and then let's say, I want to assign foo to input email, okay, like this. Not gonna work, this stuff will be undefined. And I think Cypress, no, Cypress does not return any errors, but this will be undefined. It will not be able to return. If you try to make some real return statement like this, so return input, all it does is you will have the error message that's saying that your callback function evoke one or more Cy commands, but then return synchronous value. Cypress commands are asynchronous and doesn't make sense to queue Cy commands and yet return synchronous value. So this is a weird stuff. So what you can do instead, call the second then if you want to return something, and let's say you want to return hello from here like this, and then you provide a return my hello like this. And then this hello text, which we know that this is a hello, will be available as the context if you continue chaining then command like here. So over, where's the then? It's right here. So going back and you see now it was working fine. So I think it's already confusing, right? So instead of doing all this weird stuff, if you need to return something from then, just use alias one more time. So let me remove this. Let me remove, I don't know, this as well, like this. And you call Cywrap my input email as, and then you call alias, for example, input email two. Let's call it like this. And then outside of then, you'll be able to access this. Cyget, then you call the alias input email two like this, and then you can do whatever. Click on this, for example. All right, going back and here we go. It works successfully. So I know that's quite a lot, right? Let's quickly summarize what we did in this lesson. So when you need to save any value into the constant or variable, never ever try to assign this value to the constant. It will never work. Instead, you have two options. Option number one, use Cypress alias. So you call method as after the Cypress command and give the name of the variable and then use method get using add sign calling your alias. The second example using then command. Then returns a jQuery object, but it's very important to not to forget convert this object back into the Cypress context using a wrap method. Once you wrap this object, you can call Cypress methods as well and interact with them. All right, that's it guys. And see you in the next lesson.