Skip to content

Commit

Permalink
fix: get correct new window handle with Selenium 3 workaround (#1031)
Browse files Browse the repository at this point in the history
This is the workaround fix that supports Selenium 3 and 4. We would
likely switch to #1027 should we drop Selenium 3 support.
Rather than always using the last handle after opening a new window, we
filter for the unique new handle and use it. This is analogous to the
[axe-core-maven-html
approach](https://github.com/dequelabs/axe-core-maven-html/blob/ad58b26a8d0e2f1afed33b2c5cbca22b54644b99/selenium/src/main/java/com/deque/html/axecore/extensions/WebDriverExtensions.java#L126).

Closes: #936

---------

Co-authored-by: Zidious <[email protected]>
Co-authored-by: michael-siek <[email protected]>
  • Loading branch information
3 people authored Apr 1, 2024
1 parent 7e152b6 commit b72c735
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 4 deletions.
18 changes: 15 additions & 3 deletions packages/webdriverjs/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,9 +274,21 @@ export default class AxeBuilder {
await driver.switchTo().window(win);

try {
await driver.executeScript(`window.open('about:blank')`);
const handlers = await driver.getAllWindowHandles();
await driver.switchTo().window(handlers[handlers.length - 1]);
// This is a workaround to maintain support for Selenium 3, which does not have the `newWindow` API in Selenium 4.
// TODO: Remove this workaround should we drop support for Selenium 3
// https://github.com/dequelabs/axe-core-npm/issues/1032
const beforeHandles = await driver.getAllWindowHandles();
await driver.executeScript(`window.open('about:blank', '_blank')`);
const afterHandles = await driver.getAllWindowHandles();
const newHandles = afterHandles.filter(
afterHandle => beforeHandles.indexOf(afterHandle) === -1
);

if (newHandles.length !== 1) {
throw new Error('Unable to determine window handle');
}
const newHandle = newHandles[0];
await driver.switchTo().window(newHandle);
await driver.get('about:blank');
} catch (error) {
throw new Error(
Expand Down
72 changes: 71 additions & 1 deletion packages/webdriverjs/test/axe-webdriverjs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ import { assert } from 'chai';
import path from 'path';
import fs from 'fs';
import { Server, createServer } from 'http';
import { Webdriver } from './test-utils';
import { FirefoxDriver, SafariDriver, Webdriver } from './test-utils';
import { AxeBuilder } from '../src';
import { axeRunPartial } from '../src/browser';
import { fixturesPath } from 'axe-test-fixtures';
import { Command, Name } from 'selenium-webdriver/lib/command';

const dylangConfig = JSON.parse(
fs.readFileSync(path.join(fixturesPath, 'dylang-config.json'), 'utf8')
Expand Down Expand Up @@ -837,6 +838,48 @@ describe('@axe-core/webdriverjs', () => {
);
}
});
it('throws an error if switchTo fails', async () => {
driver.switchTo = () => {
throw new Error('switchTo failed.');
};
const title = await driver.getTitle();

assert.notEqual(title, 'Error');
try {
await new AxeBuilder(driver, axeSource).analyze();
assert.fail('Should have thrown');
} catch (err) {
assert.match((err as Error).message, /switchTo failed./);
}
});
it('throws an error if unable to determine window handle', async () => {
// note: overriding executeScript to run twice and thus force finishRun to throw
driver.executeScript = async (script, ...args) => {
driver.execute(
new Command(Name.EXECUTE_SCRIPT)
.setParameter('script', script)
.setParameter('args', args)
);
return driver.execute(
new Command(Name.EXECUTE_SCRIPT)
.setParameter('script', script)
.setParameter('args', args)
);
};
const title = await driver.getTitle();

assert.notEqual(title, 'Error');
try {
await new AxeBuilder(driver, axeSource).analyze();
assert.fail('Should have thrown');
} catch (err) {
assert.match((err as Error).message, /Unable to determine window/);
assert.include(
(err as Error).message,
'Please check out https://github.com/dequelabs/axe-core-npm/blob/develop/packages/webdriverjs/error-handling.md'
);
}
});
});

describe('setLegacyMode', () => {
Expand Down Expand Up @@ -1026,4 +1069,31 @@ describe('@axe-core/webdriverjs', () => {
assert.lengthOf(allowedOrigins, 1);
});
});

describe('driver', () => {
it(`should not throw when it's Chrome`, async () => {
assert.doesNotThrow(async () => {
await driver.get(`${addr}/index.html`);
await driver.get('about:blank');
}, Error);
});
it(`should not throw when it's Firefox`, async () => {
driver = FirefoxDriver();
assert.doesNotThrow(async () => {
await driver.get(`${addr}/index.html`);
await driver.get('about:blank');
}, Error);
});
// skip this if we're not on Mac
(process.platform === 'darwin' ? it : it.skip)(
`should not throw when it's Safari`,
async () => {
driver = SafariDriver();
assert.doesNotThrow(async () => {
await driver.get(`${addr}/index.html`);
await driver.get('about:blank');
}, Error);
}
);
});
});
12 changes: 12 additions & 0 deletions packages/webdriverjs/test/test-utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { WebDriver, Builder } from 'selenium-webdriver';
import chromedriver from 'chromedriver';
import chrome from 'selenium-webdriver/chrome';
import firefox from 'selenium-webdriver/firefox';

export const Webdriver = (): WebDriver => {
const builder = new Builder()
Expand All @@ -18,3 +19,14 @@ export const Webdriver = (): WebDriver => {

return builder.build();
};

export const FirefoxDriver = (): WebDriver => {
return new Builder()
.forBrowser('firefox')
.setFirefoxOptions(new firefox.Options().addArguments('--headless'))
.build();
};

export const SafariDriver = (): WebDriver => {
return new Builder().forBrowser('safari').build();
};

0 comments on commit b72c735

Please sign in to comment.