Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock an image with a fixture in cypress

I'm using cypress to test my VueJS application. The one thing I'm having trouble with is mocking an image to be displayed on the page. For my use case, I'm simply loading a user profile with the following code:

describe('Test Login', () => {
  it('Can Login', () => {
    cy.server();
    cy.route({
      method: 'GET',
      url: '/api/account/',
      response: 'fx:profile.json',
    });
    cy.route('**/media/demo1.png', 'fx:demo1.png');
  });
});

fixtures/profile.json

{
    "avatar": "http://localhost:8080/media/demo1.png",
    "username": "cypress",
    "email": "[email protected]",
    "pk": 1,
    "is_staff": true,
    "is_superuser": true,
    "is_active": true
}

The profile fixture data is loading correctly in the test. In my fixtures folder, I also have a demo1.png file. I am expecting this image to be loaded and displayed on the page during my test, but it is being displayed as a broken image.

In the network tab, it shows demo1.png as a broken image with a 200 response code and type of text/html.

The cypress documentation mostly discusses images in the context of uploading images, but I haven't been able to find an example of how I can mock an image that is loaded through a <img> tag. Is there an easier way of doing this?

like image 210
briancaffey Avatar asked Oct 16 '22 07:10

briancaffey


1 Answers

I am not sure if this answer can help you. But at least it is a workaround for this problem ;-)

Say we have a HTML like this:

<html>
    <body>
        <button id="button">load</button>
        <div id="profile">

        </div>

        <script>
            function httpGetAsync(theUrl, callback)
            {
                var xmlHttp = new XMLHttpRequest();
                xmlHttp.onreadystatechange = function() { 
                    if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
                        callback(JSON.parse(xmlHttp.responseText));
                }
                xmlHttp.open("GET", theUrl, true); // true for asynchronous 
                xmlHttp.send(null);
            }

            document.getElementById("button").addEventListener("click", () => {

                httpGetAsync("/api/account/", (result) => {
                    var div = document.querySelector("#profile");
                    var img = document.createElement("img");
                    img.src = result.avatar;
                    div.appendChild(img)
                })
            })

        </script>
    </body>
</html>

source: HTTP GET request in JavaScript?

And you want to load the profile after the click was done. Then you can use MutationObserver to replace the img.src.

First, write the MutationObserver:

var observeDOM = (function(){
    var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;

    return function( obj, callback ){
      if( !obj || !obj.nodeType === 1 ) return; // validation

      if( MutationObserver ){
        // define a new observer
        var obs = new MutationObserver(function(mutations, observer){
            callback(mutations);
        })
        // have the observer observe foo for changes in children
        obs.observe( obj, { childList:true, subtree:true });
      }

      else if( window.addEventListener ){
        obj.addEventListener('DOMNodeInserted', callback, false);
        obj.addEventListener('DOMNodeRemoved', callback, false);
      }
    }
  })();

(heavily copy & pasted from Detect changes in the DOM)

Now you are able to do this:

describe('Test Login', () => {
    it('Can Login', () => {
        var win = null;
      cy.server();
      cy.route({
        method: 'GET',
        url: '/api/account/',
        response: 'fx:profile.json'
      });
      cy.visit("index.html").then(w => { 
          cy.get("#profile").then(pro => {
              var e = pro[0];
              observeDOM(e, (m) => {
                // add a red dot image
                m[0].addedNodes[0].src = "data:image/png;base64,"+
                "iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGdBTUEAALGP"+
                "C/xhBQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9YGARc5KB0XV+IA"+
                "AAAddEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIFRoZSBHSU1Q72QlbgAAAF1J"+
                "REFUGNO9zL0NglAAxPEfdLTs4BZM4DIO4C7OwQg2JoQ9LE1exdlYvBBeZ7jq"+
                "ch9//q1uH4TLzw4d6+ErXMMcXuHWxId3KOETnnXXV6MJpcq2MLaI97CER3N0"+
                "vr4MkhoXe0rZigAAAABJRU5ErkJggg=="
            })
          })
          cy.get("button").click()
      })
    });
  });

(yeah at least some lines of code are written on my own ;-P)

You can read the image from the img.src attribute from the fixtures folder. For the sake of simplicity I have used a static base64 string here.

And the result: enter image description here

We are not using this kind of stuff in our aurelia app but I tried similar things in a private project some time ago.

like image 100
Josef Biehler Avatar answered Oct 21 '22 03:10

Josef Biehler