dequelabs / axe-webdriverjs

Provides a chainable axe API for Selenium's WebDriverJS and automatically injects into all frames.
Mozilla Public License 2.0
130 stars 46 forks source link

AxeInjector hangs when provided invalid "include" elements #158

Open juliannalangston opened 4 years ago

juliannalangston commented 4 years ago

If I have axe-core running on a website, and I try to run it with a context like window.axe.run("#elementThatDoesntExist"), an error is printed to the console. However, if I am using axe-webdriverjs, and I try to call this, then my code just hangs:

await axeBuilder(myDriver)
 .include("#elementThatDoesntExist")
 .analyze("My title");

The error message never gets surfaced.

I found that, on axe-webdriverjs/lib/index.js:159, there's this code:

 window.axe
 .run(context || document, options || {})
 .then(arguments[arguments.length - 1]);

Since this is invoked inside a driver.executeAsyncScript function, the only way to exit that script is to call arguments[arguments.length - 1]. However, if an error is thrown while running window.axe.run, there is nothing to catch that error, so driver.executeAsyncScript doesn't actually exit, unless some kind of timeout forces it to exit.

juliannalangston commented 4 years ago

For a functioning example:

const AxeBuilder = require("axe-webdriverjs");
const webdriver = require("selenium-webdriver");
require("chromedriver"); // if you don't have it installed separately

(async function(){
    const driver = new webdriver.Builder().forBrowser("chrome").build();
    await driver.get("http://www.google.com");

    await AxeBuilder(driver)
     .include("#viewport")
     .analyze((error, results) => {
         console.log(`There were ${results.violations.length} violations`);
     });

     await AxeBuilder(driver)
      .include("#doesNotExist")
      .analyze((error, results) => {
          console.log(error);
          console.log("This prints after the script timeout error.");
      });
})();