jsdom icon indicating copy to clipboard operation
jsdom copied to clipboard

Default type to XPathResult.ANY_TYPE in XPathExpression.evaluate

Open deej-io opened this issue 1 year ago • 3 comments

I got a DOMException when using the HTMX library inside JSDOM, as it does not provide an argument for the type parameter in XPathExpression.evaluate. This PR allows the type parameter to be optional and defaults the value to XPathResult.ANY_TYPE (0).

The whatwg living DOM spec states that the type argument should default to 0 (any): https://dom.spec.whatwg.org/#interface-xpathexpression.

Whilst the IDL in the level 3 XPath spec doesn't state explicitly that the type parameter is optional, it does use the phrase "If a specific type is specified" in the parameter description, which implies optionality: (https://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathExpression). Therefore, I believe this patch is spec-compliant on both counts.

Fixes #3422

deej-io avatar May 20 '24 14:05 deej-io

Can you add a test for this, or find an existing one, per the instructions in CONTRIBUTING.md?

domenic avatar May 26 '24 08:05 domenic

@deej-io @domenic any chance this can be merged? Facing this issue. Is there a workaround?

stekyne avatar Aug 12 '24 23:08 stekyne

Sorry, I've not had a chance to take another look at this yet. Will see if I can find some time today to get a test case sorted.

deej-io avatar Aug 13 '24 06:08 deej-io

Just ran into this issue, using JSDOM to test an HTMX application.

Until merged, I have the following workaround:

const fixXPathEvaluator = (browser) => {
  const { XPathExpression, XPathResult } = browser.window;
  const evaluate = XPathExpression.prototype.evaluate;
  XPathExpression.prototype.evaluate = function (context, type, res) {
    return evaluate.call(this, context, type || XPathResult.ANY_TYPE, res);
  };
  // YOU PROBABLY NEED TO ADD THIS TOO
  // browser.window.Document.prototype.evaluate = XPathExpression.prototype.evaluate
};

From browsing the jsdom code, it appears that each jsdom instance has it's own XPathEvaluator class, so you can't fix it in a global setup, but need to call this for every instance of JSDOM you create. In my case (where I use it as a headless browser for a running web server)

    const browser = await JSDOM.fromURL(url, { runScripts: "dangerously", resources: "usable" });
    fixXPathEvaluator(browser);

I didn't replace Document.prototype.evaluate as I don't have any issues with that, but I guess it could be necessary.

stroiman avatar Oct 25 '24 09:10 stroiman