Checking the image loading functionality with Cypress

I am interested in testing Cypress to verify that an image is successfully loaded onto a page.

Here is a snippet of my source code:

import React from "react";

export default class Product extends React.Component {
  render() {
    return (
      <div className="item">
        <div className="image">
          <img src="../images/Banana-Snowboard.png" alt="Snow Board" />
        </div>
        <div className="middel aligned content">
          <div className="description">
            <a>Snow Board</a>
            <p>Cool Snow Board</p>
          </div>
          <div className="extra">
            <span>Submitted by:</span>
            <img
              className="ui avatar image"
              src="./images/avatar.png"
              alt="Avatar"
            />
          </div>
        </div>
      </div>
    );
  }
}

Below are the test cases I have written:

it("should display an image in a div element with the class 'image'", () => {
  cy.get('div[class="image"]').find("img"); // include test code here to verify image loading and display on webpage
});

it("should display an image in a div element with the classes 'image' and 'extra'", () => {
  cy.get('div[class="extra"]').find('img[class="ui avatar image"]');
  // include test code here to ensure image is loaded and displayed on the webpage
});

How can I improve this code further?

Answer №1

We have made improvements to our static resource loading recipe. Visit this link for more details.

If you want to check if an image has completed loading, a convenient method is to inspect the image's properties like naturalWidth or naturalHeight.

// Ensure that the <img> element is visible
// before checking if the image has loaded.
cy.get('[alt="delayed image"]')
.should('be.visible')
.and(($img) => {
  // Check if "naturalWidth" and "naturalHeight" are greater than 0
  expect($img[0].naturalWidth).to.be.greaterThan(0)
})

Another approach is to use performance entries to verify the completion of any static resource loading process. For detailed instructions, refer to the pull request mentioned above.

Answer №2

When it comes to making sure elements are present on a webpage, the key is using assertions. In this scenario, using should('be.visible') appears to be the appropriate choice. Check out more information at https://docs.cypress.io/api/commands/should.html

it("Verifying that an image is displayed in a div element with the class 'image'", () => {
  cy.get('div[class="image"]').find("img").should('be.visible');
});

Answer №3

In my workflow, I utilize a chain of Cypress commands to ensure that all necessary images load for the user without loading any unnecessary or hidden images:

First, I gather all images on the page (including those within shadow DOM - https://docs.cypress.io/api/commands/get#Arguments)

cy.get('img', { includeShadowDom: true })

Next, I filter out only the images with a src attribute present (using the css selector - https://docs.cypress.io/api/commands/filter)

.filter('[src]')

Then, I narrow down the selection to only the visible images (utilizing the jquery selector - https://docs.cypress.io/guides/references/assertions#Chai-JQuery)

.filter(':visible')

Lastly, I confirm that all selected images have loaded successfully by checking if their "naturalWidth" property is greater than 0

.should(($imgs) => $imgs.map((i, img) => expect(img.naturalWidth).to.be.greaterThan(0)));

All these steps combined in one concise code block:

cy.get('img', { includeShadowDom: true })
        .filter('[src]')
        .filter(':visible')
        .should(($imgs) => $imgs.map((i, /** @type {HTMLImageElement} */ img) => expect(img.naturalWidth).to.be.greaterThan(0)));

I am grateful for the helpful insights shared by others in various forums and posts.

Answer №4

After reviewing jehon's perspective, I found that in our team's situation, we are unable to adhere to the recommended practice of maintaining a reliable, static image set. Therefore, I have modified the code to handle missing image urls without causing the test to fail:

cy.get('img', { timeout: 10000, includeShadowDom: true })
  .filter(selector)
  .filter(':visible')
  .each((el) => {
    const url = el[0]?.src || el[0]?.srcset
    if (url)
      cy.request({ url: url, failOnStatusCode: false }).then((resp) => {
        if (resp.status == 200)
          cy.get(el).should((el) => {
            expect(el[0].naturalWidth).to.be.greaterThan(0)
          })
      })
  })

Answer №5

One way to accomplish this is by following these steps:

    describe('Checking for Broken Images', function() {
        cy.get('img').each(($img) => {
            cy.wrap($img).scrollIntoView().should('be.visible');
            expect($img[0].naturalWidth).to.be.greaterThan(0);
            expect($img[0].naturalHeight).to.be.greaterThan(0);
        });
    })

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Securely store files by encrypting them with Node.js before saving to the disk

At the moment, I am making use of the multer library to store files on the File system. This particular application is built using Node and Express. I currently have a process in place where I save the file on the server first and then encrypt it. After e ...

Is it possible to move the res.send() outside of the function in node.js?

I currently have the following code: var server = http.createServer(function(req,res){ res.writeHead(200,{'Content-Type': 'text/html; charset=utf-8'}); var oo = require('/test.js'); oo(connection, function (e, res ...

Execute the getJSON calls in a loop for a count exceeding 100, and trigger another function once all

In order to process a large grid of data, I need to read it and then make a call to a $getJSON URL. This grid can contain over 100 lines of data. The $getJSON function returns a list of values separated by commas, which I add to an array. After the loop fi ...

specialized html elements within data-ng-options

I have a code snippet where I am populating select options from a controller using data-ng-options. However, I would also like to include an icon with each option. For example, I want to append <span class="fa fa-plus"></span> at the end of e ...

Managing data retrieval within React SSR frameworks for components outside of routes

As I delve into the world of React SSR frameworks like Next.js, Remix, and more, a burning question arises regarding data retrieval in components not linked to specific routes. Typically, these frameworks handle data loading at the route level, but what ab ...

Challenge with maintaining tab view data in Openui5

I am facing an issue with my application's tabs. Each tab renders data retrieved through ajax calls from the database. However, whenever I switch between tabs, the data gets refreshed each time. Is there a way to prevent this refreshing behavior and i ...

Real-time Data Stream and Navigation Bar Location

Utilizing the EventSource API, I am pulling data from a MySQL database and showcasing it on a website. Everything is running smoothly as planned, but my goal is to exhibit the data in a fixed height div, with the scrollbar constantly positioned at the bott ...

When attempting to add an object to an array in a collection, there was an issue with

In my application, I am accessing a collection in Mongodb using ReactJS and mongoose. One of the properties in this collection is set to an Array type. When I add elements to this Array, they are successfully added but for some reason, the _id field that ...

Why is it that even though I update the state using useState, when I try to access the state afterwards,

I have been working on a function that updates my states dynamically. Here is the code snippet: const refreshAfterCreate = async () => { try { const res = await fetch(process.env.NEXT_PUBLIC_MICROSERVICE_COMPANY_URL + '/companies&apo ...

Clicking on multiple instances of the same Vue.js component (popover) results in displaying identical data

Attempting to display an AJAX response in a popover shown by clicking an icon (a custom Vue component) brings about a challenge. The issue arises when there are multiple instances of this component, dynamically rendered through the v-for directive within a ...

There seems to be an issue with the product being undefined in the fake store API when using the console in Next Js within

When working with the fake store API in Next.js, I encountered an issue where the product was showing as undefined in the console. Even after trying to debug using various methods, such as console.log(product), the issue persisted and the product remained ...

React: automatically close other SubMenus when a new SubMenu is opened

Is there a way to automatically close all other open SubMenus when a user opens a new SubMenu? If anyone has a solution, I would greatly appreciate the help! This is my code: Menu.tsx -> const Menu: React.FC = ({ data }) => { return ( ...

Building a dropdown feature for rows in a table using ReactJS

I am utilizing a Material UI Table, and within one of the columns I have a SelectField component that displays a dropdown with a few selectable items. Here is a snippet of the code: <TableBody displayRowCheckbox={this.state.showCheckboxes} ...

Are MobX Observables interconnected with RxJS ones in any way?

Is the usage of RxJs observables in Angular comparable to that in React and MobX? I'm struggling to find information on this topic. ...

The leave animation for Angular's ngAnimate and ng-view feature appears to be malfunctioning

angular version: 1.6.1 I am attempting to create a fade in/out effect for my ng-view element, however, I am encountering an issue where only the enter animation is functioning properly. This is the relevant HTML code: <main class="main" ng-view>&l ...

Give your undivided attention to the customized TextField, no distractions allowed

Below is a component example using the TextField: const BarcodeField = ({disableEnter, ...rest})=>{ return <TextField {...(disableEnter && { onKeyDown: {(e)=>e.key === 'Enter' && e.preventDefault()} })} {...rest}> } ...

Tips for positioning divs on top of an image with Twitter Bootstrap

I'm having an issue with displaying an image and dividing it using bootstrap div columns. The problem is that the image is overlapping the divs, making it impossible to click or attach jQuery events to it. Here is the code I am currently using: #view ...

What is the best way to define the active <li> tab using JQuery?

Initially, my HTML code includes a set of <li> elements that I want to dynamically add to the existing <ul>. <ul class="tabs" id="modal_addquestion_ul"> <li class="tab-link current" data-tab="multipleChoice">Multiple Choice< ...

Having trouble submitting the form in ExpressJS - error encountered

Currently, I am in the process of learning ExpressJS and I have encountered an issue while trying to implement the login functionality. Whenever I attempt to submit the form using the POST method, I receive the following error message: "Cannot POST /login" ...

Add items to a separate array only if the material UI checkbox is selected

Exploring the world of React, I decided to create a simple todo app using React JS and Material UI. With separate components for user input (TodoInput.js) and rendering individual todos with checkboxes (TodoCards.js), I aim to display the total number of c ...