Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: get correct new window handle with Selenium 3 workaround #1031

Merged
merged 19 commits into from
Apr 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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();
};
Loading