feat(chromium): roll Chromium to r722269 (#5289)

This corresponds to Chromium 80.0.3987.0.

This roll includes:

- Implement support for the new ARIA `generic` role
  https://chromium-review.googlesource.com/c/chromium/src/+/1872305
- Expose button's children to accessibility tree
  https://chromium-review.googlesource.com/c/chromium/src/+/1845810
- Remove `Page.handleFileChooser` from CDP
  https://chromium-review.googlesource.com/c/chromium/src/+/1935410
This commit is contained in:
Mathias Bynens 2020-01-27 14:44:53 +01:00 committed by GitHub
parent 14b2369650
commit 013a86cf28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 43 additions and 51 deletions

View File

@ -182,6 +182,18 @@ class ExecutionContext {
return createJSHandle(this, response.objects); return createJSHandle(this, response.objects);
} }
/**
* @param {Protocol.DOM.BackendNodeId} backendNodeId
* @return {Promise<Puppeteer.ElementHandle>}
*/
async _adoptBackendNodeId(backendNodeId) {
const {object} = await this._client.send('DOM.resolveNode', {
backendNodeId: backendNodeId,
executionContextId: this._contextId,
});
return /** @type {Puppeteer.ElementHandle}*/(createJSHandle(this, object));
}
/** /**
* @param {Puppeteer.ElementHandle} elementHandle * @param {Puppeteer.ElementHandle} elementHandle
* @return {Promise<Puppeteer.ElementHandle>} * @return {Promise<Puppeteer.ElementHandle>}
@ -192,11 +204,7 @@ class ExecutionContext {
const nodeInfo = await this._client.send('DOM.describeNode', { const nodeInfo = await this._client.send('DOM.describeNode', {
objectId: elementHandle._remoteObject.objectId, objectId: elementHandle._remoteObject.objectId,
}); });
const {object} = await this._client.send('DOM.resolveNode', { return this._adoptBackendNodeId(nodeInfo.node.backendNodeId);
backendNodeId: nodeInfo.node.backendNodeId,
executionContextId: this._contextId,
});
return /** @type {Puppeteer.ElementHandle}*/(createJSHandle(this, object));
} }
} }

View File

@ -311,6 +311,8 @@ class ElementHandle extends JSHandle {
* @param {!Array<string>} filePaths * @param {!Array<string>} filePaths
*/ */
async uploadFile(...filePaths) { async uploadFile(...filePaths) {
const isMultiple = await this.evaluate(element => element.multiple);
assert(filePaths.length <= 1 || isMultiple, 'Multiple file uploads only work with <input type=file multiple>');
// These imports are only needed for `uploadFile`, so keep them // These imports are only needed for `uploadFile`, so keep them
// scoped here to avoid paying the cost unnecessarily. // scoped here to avoid paying the cost unnecessarily.
const path = require('path'); const path = require('path');

View File

@ -15,7 +15,6 @@
*/ */
const fs = require('fs'); const fs = require('fs');
const path = require('path');
const EventEmitter = require('events'); const EventEmitter = require('events');
const mime = require('mime'); const mime = require('mime');
const {Events} = require('./Events'); const {Events} = require('./Events');
@ -112,7 +111,6 @@ class Page extends EventEmitter {
networkManager.on(Events.NetworkManager.Response, event => this.emit(Events.Page.Response, event)); networkManager.on(Events.NetworkManager.Response, event => this.emit(Events.Page.Response, event));
networkManager.on(Events.NetworkManager.RequestFailed, event => this.emit(Events.Page.RequestFailed, event)); networkManager.on(Events.NetworkManager.RequestFailed, event => this.emit(Events.Page.RequestFailed, event));
networkManager.on(Events.NetworkManager.RequestFinished, event => this.emit(Events.Page.RequestFinished, event)); networkManager.on(Events.NetworkManager.RequestFinished, event => this.emit(Events.Page.RequestFinished, event));
this._fileChooserInterceptionIsDisabled = false;
this._fileChooserInterceptors = new Set(); this._fileChooserInterceptors = new Set();
client.on('Page.domContentEventFired', event => this.emit(Events.Page.DOMContentLoaded)); client.on('Page.domContentEventFired', event => this.emit(Events.Page.DOMContentLoaded));
@ -137,23 +135,22 @@ class Page extends EventEmitter {
this._client.send('Target.setAutoAttach', {autoAttach: true, waitForDebuggerOnStart: false, flatten: true}), this._client.send('Target.setAutoAttach', {autoAttach: true, waitForDebuggerOnStart: false, flatten: true}),
this._client.send('Performance.enable', {}), this._client.send('Performance.enable', {}),
this._client.send('Log.enable', {}), this._client.send('Log.enable', {}),
this._client.send('Page.setInterceptFileChooserDialog', {enabled: true}).catch(e => { this._client.send('Page.setInterceptFileChooserDialog', {enabled: true}),
this._fileChooserInterceptionIsDisabled = true;
}),
]); ]);
} }
/** /**
* @param {!Protocol.Page.fileChooserOpenedPayload} event * @param {!Protocol.Page.fileChooserOpenedPayload} event
*/ */
_onFileChooser(event) { async _onFileChooser(event) {
if (!this._fileChooserInterceptors.size) { if (!this._fileChooserInterceptors.size)
this._client.send('Page.handleFileChooser', { action: 'fallback' }).catch(debugError);
return; return;
} const frame = this._frameManager.frame(event.frameId);
const context = await frame.executionContext();
const element = await context._adoptBackendNodeId(event.backendNodeId);
const interceptors = Array.from(this._fileChooserInterceptors); const interceptors = Array.from(this._fileChooserInterceptors);
this._fileChooserInterceptors.clear(); this._fileChooserInterceptors.clear();
const fileChooser = new FileChooser(this._client, event); const fileChooser = new FileChooser(this._client, element, event);
for (const interceptor of interceptors) for (const interceptor of interceptors)
interceptor.call(null, fileChooser); interceptor.call(null, fileChooser);
} }
@ -163,8 +160,6 @@ class Page extends EventEmitter {
* @return !Promise<!FileChooser>} * @return !Promise<!FileChooser>}
*/ */
async waitForFileChooser(options = {}) { async waitForFileChooser(options = {}) {
if (this._fileChooserInterceptionIsDisabled)
throw new Error('File chooser handling does not work with multiple connections to the same page');
const { const {
timeout = this._timeoutSettings.timeout(), timeout = this._timeoutSettings.timeout(),
} = options; } = options;
@ -1351,10 +1346,12 @@ class ConsoleMessage {
class FileChooser { class FileChooser {
/** /**
* @param {Puppeteer.CDPSession} client * @param {Puppeteer.CDPSession} client
* @param {Puppeteer.ElementHandle} element
* @param {!Protocol.Page.fileChooserOpenedPayload} event * @param {!Protocol.Page.fileChooserOpenedPayload} event
*/ */
constructor(client, event) { constructor(client, element, event) {
this._client = client; this._client = client;
this._element = element;
this._multiple = event.mode !== 'selectSingle'; this._multiple = event.mode !== 'selectSingle';
this._handled = false; this._handled = false;
} }
@ -1373,11 +1370,7 @@ class FileChooser {
async accept(filePaths) { async accept(filePaths) {
assert(!this._handled, 'Cannot accept FileChooser which is already handled!'); assert(!this._handled, 'Cannot accept FileChooser which is already handled!');
this._handled = true; this._handled = true;
const files = filePaths.map(filePath => path.resolve(filePath)); await this._element.uploadFile(...filePaths);
await this._client.send('Page.handleFileChooser', {
action: 'accept',
files,
});
} }
/** /**
@ -1386,9 +1379,6 @@ class FileChooser {
async cancel() { async cancel() {
assert(!this._handled, 'Cannot cancel FileChooser which is already handled!'); assert(!this._handled, 'Cannot cancel FileChooser which is already handled!');
this._handled = true; this._handled = true;
await this._client.send('Page.handleFileChooser', {
action: 'cancel',
});
} }
} }

View File

@ -8,7 +8,7 @@
"node": ">=8.16.0" "node": ">=8.16.0"
}, },
"puppeteer": { "puppeteer": {
"chromium_revision": "706915" "chromium_revision": "722269"
}, },
"scripts": { "scripts": {
"unit": "node test/test.js", "unit": "node test/test.js",

View File

@ -81,7 +81,7 @@ module.exports.addTests = function({testRunner, expect, FFOX}) {
expect(await page.accessibility.snapshot()).toEqual(golden); expect(await page.accessibility.snapshot()).toEqual(golden);
}); });
it('should report uninteresting nodes', async function({page}) { it('should report uninteresting nodes', async function({page}) {
await page.setContent(`<textarea autofocus>hi</textarea>`); await page.setContent(`<textarea>hi</textarea>`);
await page.focus('textarea'); await page.focus('textarea');
const golden = FFOX ? { const golden = FFOX ? {
role: 'entry', role: 'entry',
@ -100,7 +100,7 @@ module.exports.addTests = function({testRunner, expect, FFOX}) {
focused: true, focused: true,
multiline: true, multiline: true,
children: [{ children: [{
role: 'GenericContainer', role: 'generic',
name: '', name: '',
children: [{ children: [{
role: 'text', name: 'hi' role: 'text', name: 'hi'
@ -182,7 +182,7 @@ module.exports.addTests = function({testRunner, expect, FFOX}) {
name: 'my fake image' name: 'my fake image'
}] }]
} : { } : {
role: 'GenericContainer', role: 'generic',
name: '', name: '',
value: 'Edit this image: ', value: 'Edit this image: ',
children: [{ children: [{
@ -241,7 +241,7 @@ module.exports.addTests = function({testRunner, expect, FFOX}) {
<div contenteditable="plaintext-only">Edit this image:<img src="fakeimage.png" alt="my fake image"></div>`); <div contenteditable="plaintext-only">Edit this image:<img src="fakeimage.png" alt="my fake image"></div>`);
const snapshot = await page.accessibility.snapshot(); const snapshot = await page.accessibility.snapshot();
expect(snapshot.children[0]).toEqual({ expect(snapshot.children[0]).toEqual({
role: 'GenericContainer', role: 'generic',
name: '' name: ''
}); });
}); });
@ -250,7 +250,7 @@ module.exports.addTests = function({testRunner, expect, FFOX}) {
<div contenteditable="plaintext-only" tabIndex=0>Edit this image:<img src="fakeimage.png" alt="my fake image"></div>`); <div contenteditable="plaintext-only" tabIndex=0>Edit this image:<img src="fakeimage.png" alt="my fake image"></div>`);
const snapshot = await page.accessibility.snapshot(); const snapshot = await page.accessibility.snapshot();
expect(snapshot.children[0]).toEqual({ expect(snapshot.children[0]).toEqual({
role: 'GenericContainer', role: 'generic',
name: '' name: ''
}); });
}); });
@ -360,10 +360,18 @@ module.exports.addTests = function({testRunner, expect, FFOX}) {
const div = await page.$('div'); const div = await page.$('div');
expect(await page.accessibility.snapshot({root: div})).toEqual(null); expect(await page.accessibility.snapshot({root: div})).toEqual(null);
expect(await page.accessibility.snapshot({root: div, interestingOnly: false})).toEqual({ expect(await page.accessibility.snapshot({root: div, interestingOnly: false})).toEqual({
role: 'GenericContainer', role: 'generic',
name: '', name: '',
children: [ { role: 'button', name: 'My Button' } ] } children: [
); {
role: 'button',
name: 'My Button',
children: [
{ role: 'text', name: 'My Button' },
],
},
],
});
}); });
}); });
}); });

View File

@ -94,22 +94,6 @@ module.exports.addLauncherTests = function({testRunner, expect, defaultBrowserOp
}); });
}); });
describe('Page.waitForFileChooser', () => {
it('should fail gracefully when trying to work with filechoosers within multiple connections', async() => {
// 1. Launch a browser and connect to all pages.
const originalBrowser = await puppeteer.launch(defaultBrowserOptions);
await originalBrowser.pages();
// 2. Connect a remote browser and connect to first page.
const remoteBrowser = await puppeteer.connect({browserWSEndpoint: originalBrowser.wsEndpoint()});
const [page] = await remoteBrowser.pages();
// 3. Make sure |page.waitForFileChooser()| does not work with multiclient.
let error = null;
await page.waitForFileChooser().catch(e => error = e);
expect(error.message).toBe('File chooser handling does not work with multiple connections to the same page');
originalBrowser.close();
});
});
}); });
}; };