The HTML element canvas is a way to allow developers to typically do things like draw graphics and animations inside of the web.
In this particular example, we have a canvas that says, are you “Hungry?” And we definitely are. So, let’s click, “Let’s Eat” and we get a burger.
While this button might look like a button, if we actually inspect the code, we can see that we only have access to this canvaselement, which means it makes it a little bit trickier to test.
Typically, when using Cypress, we’re able to select the element as well as the button inside of that element, where we would actually be able to click it directly. But instead, we’re going to need to figure out where on this canvas we should click and then click it appropriately.
We’re going to see what this looks like, where I just set up a new test where we’re navigating to “/ingredients/canvas” and we’re creating a new test that simply says, it“should click a button on a canvas”.
Now, if I want to get this canvas, I want to get this canvas by its ID and in this instance, it’s “burger_canvas”. So, I’m going to start off by running cy.getand then passing its ID of “burger_canvas”.
The next thing I want to do is, I want to determine the dimensions of the canvas so that I can calculate where exactly I should be clicking on that canvas.
How Do I Click on a Canvas with Cypress?
The tricky thing with Cypress is it runs asynchronously, meaning, I can’t just simply run const cy.get, and maybe something like getting its width. I’m going to need to do something differently.
In this instance, I’m going to run .then, and I’m going to pass in an instance of canvasas the argument, where automatically Cypress will pass in that element where we have access to the jQuery API.
With that in mind, I can now get started by getting its width and height.
I can first define a constant called const canvasWidth, where I’m going to say “canvas.width” — const canvasWidth = $canvas.width().Again, because we have access to the jQuery AP,I we can do that pretty easily.
And I’m going to also define const canvasHeight,where we’re going to set that equal to “canvas.height” — const canvasHeight = $canvas.height().
Next, in order to help us navigate around this canvas, we’re going to find the center point so any calculations we do would be based off that center. We’re going to take this canvas width, and the canvas height, and we’re going to cut that in half, which would remain right in the center.
So, I’m going to define canvas Center X, which is going to be const canvasCenterX = canvasWidth / 2 and canvas Center Y, which is going to be const canvasCenterY = canvasHeight / 2.
Now, this isn’t quite where we want to be clicking on our canvas, but let’s set up a clickhandle real quick to see where we’re at. I’m going to run cy.wrapand I’m going to pass in the canvas, that way I again have access to that Cypress API.
I’m going to then run .scrollIntoView(), where that’s going to shift the page down, so that I can actually see that canvas in the Cypress test.
And then finally, I’m going to run the clickcommand. Typically, if we run this clickcommand, it’s going to click directly in the center of the element that we’re selecting. But we want to pass in an X and a Y coordinate so that we can click exactly where we want.
So, I’m going to pass in the “canvasCenterX”, and I’m also going to pass in the “canvasCenterY”
After our test runs, we can see that it first grabbed our element. It even scrolled it into view; and then it clicked directly in the center of that element. Which we can see by that dot on the right-hand side.
Next, because we’re in the center, we want to figure out how we can click this button in the corner. Because this canvas is responsive, we want to make sure that any size this canvas is showing at, that it’s always going to be in the right location.
To see what this visually would look like, I’m going to first draw this box that’s roughly showing the bottom right quadrant of our particular canvas. Now, we could probably make a rough estimate of what that would look like, but we have an easier way of how we can dissect this quadrant, so we can actually see where we can dynamically click in this box.
I first dissected the width of this by 3. I can see that after 2 segments I’m going to be already in that X axis of where the button is at.
If I’m looking at that inside of my code, I could first define “buttonX”, where I’m going to start off in the center of my canvas. But then I’m going to add the rest of that two thirds of the X, where I’m going to first say I want my canvas center X, I’m going to divide that by 3 (kind of similar to we saw in that drawing). Then, I’m going to say that I want to go 2 spaces inside of that box, so that we can get that X value that’s equal to that end of that second quadrant.
And to test that this is working so far, we can get this “buttonX”, and I’m going to swap it in for my “canvasCenterX”, and let’s see what this looks like.
We can see that when the test ran, we can go down to our click, and then we can’t see exactly overlaid on top of the button. But if we look at that right dot on the right side, and we hover back and forth over this, we can see that it’s in that two thirds quadrant.
If we were down in the right Y access, we would definitely be clicking on that button. If I do the same thing vertically, we can see that if we go down 2 spots, we’re going to hit that button. And we can see right at this axis here, this X and Y access, we’re going to hit that button.
I’m going to do the exact same thing as we did with “buttonX”. I’m going to copy this and I’m going to say, I want my “canvasY” and my “buttonY” to be exactly the same, where we divide it in 3 and then get 2 spaces in that quadrant.
And now, just like before, if I update that “buttonY”, we can already see that this time, Cypress found that button and I was able to click it. If we look at this dot, we can see that that’s right on top of that button, meaning we’re able to click it and it’s going to be able to dynamically do that.
To prove that this works dynamically, we can see that if we use the cy.viewportcommand and we pass in a String like “iphone-x”, we can see that inside of Cypress it loaded our canvas page in a size of an iPhone. It was still able to find that button and click it dynamically.
Visually Validating a Canvas with Applitools Cypress Eyes SDK
We still have one issue with this test, where we can’t actually validate that this clicking of the button worked inside of the canvas. Similar to actually clicking the button, we don’t have a way to grab this element and make sure that it is loaded properly.
To test that it works, we can use visual testing with Applitools, or particularly we can use the Cypress Eyes SDK. We can integrate that right into our application and easily run visual testing.
Because I already had that installed, I can run cy.eyesOpen, where I’m going to pass an object configuration as my argument. I’m going to pass in an appName, and let’s call this “The Kitchen”. I’m going to pass in my testName as “Canvas”.
So now that I have my eyesOpen, I can run cy.eyesCheckWindow, which is going to actually grab that snapshot for me.
Then I can run cy.eyesClose, which is going to finish up that test.
We can see it just like before. It went through and it ran that test, where it was able to click that button. We then ran Applitools to get a snapshot of that current state of the application. Now we have our new baseline, and any time we run that test, after that, we’re going to make sure that it’s working just like it should.
Summing It Up – How To Work with a Canvas in Cypress
In review, we wanted to be able to test clicking this canvas, particularly on this button, so that we could see this burger. But because we’re trying to use the canvas, we don’t actually have access to the elements inside of that canvas.
To get around that, we were first able to grab that canvas by its ID and then we accessed it using Cypress, where we can get its width and height, where we figured out the center of that canvas.
We figured out the “buttonX” and the “buttonY” by dissecting that area into different quadrants. And then we were able to scroll that element into view and click it exactly where we wanted.
To make sure it was working as expected, we were able to run visual testing with Applitools. Now every time we run that test, it’s going to make sure it checks that it’s working exactly as we expect it to.