jsdom icon indicating copy to clipboard operation
jsdom copied to clipboard

jsdom doesn't fire iframe.onload after iframe.contentDocument.close()

Open andyearnshaw opened this issue 7 years ago • 1 comments

Basic info:

  • Node.js version: 8.9.4
  • jsdom version: 11.6.0

Minimal reproduction case

Apologies for the lack of jsdom setup in the repro case, I'm using Jest, which sets up the jsdom environment for me and I'm unfamiliar with setting up jsdom directly myself. I don't believe different setups would make any difference on this issue.

const JSDOM = require('jsdom').JSDOM;
const text = `<html><body></body></html>`;
const document = new JSDOM(text).window.document;

const ifr = document.createElement('iframe');
ifr.onload = () => console.log('loaded');
document.body.appendChild(ifr);

ifr.contentDocument.open();
ifr.contentDocument.write('hello');
ifr.contentDocument.close();

How does similar code behave in browsers?

In this JSBin, you will see two console logs that say "loaded". One for the initial append of the iframe, the second for the subsequent open(), write() and close(). With jsdom, only 1 string is logged—the one that is triggered by appending the iframe.

andyearnshaw avatar Jan 29 '18 12:01 andyearnshaw

Hi, I'm trying to migrate to JSDOM to test epub.js library. I encountered a similar problem: iframe.onload event refuses to work. It's hard for me to assess what exactly is causing this behavior. However, this problem is not observed in the browser. For testing, I use only mocha framework. Here is my setup.js file for setting up global parameters.

The load function initiates the process of writing the source text via the iframe.write function:

load(contents) {

    const loading = new Defer();

    if (!this.iframe) {
        loading.reject(new Error("No Iframe Available"));
        return loading.promise;
    }

    this.container.appendChild(this.iframe);
    this.document = this.iframe.contentDocument;
    this.iframe.onload = (e) => this.onLoad(e, loading);

    if (!this.document) {
        loading.reject(new Error("No Document Available"));
        return loading.promise;
    } else if (this.method === "blobUrl") {
        this.blobUrl = createBlobUrl(contents, "application/xhtml+xml");
        this.iframe.src = this.blobUrl;
    } else if (this.method === "srcdoc") {
        this.iframe.srcdoc = contents;
    } else {
        this.document.open();
        this.document.write("<!DOCTYPE html>");
        this.document.write(contents);
        this.document.close();
    }

    return loading.promise;
}

As you can see, the iframe.onload event is added after the this.iframe node is added to the container.

At the same time, I see that the innerHTML property contains data. That is, the write is successful.

How to reproduce the issue:

I created a new jsdom branch for testing. To reproduce the problem, you need to copy the test/rendition.js file to the tests/ directory, then start the server with the npm run start command, and then run the test with the npm run test command.

Basic info:

  • Node.js version: 20.18.0
  • jsdom version: 25.0.1

intity avatar Oct 06 '24 16:10 intity