Fix racy condition in case of multiple parallel screenshots

Page.screenshot operates the global state of the page. In case of
multiple Page.screenshot() commands running in parallel with different
clipping rects, they interfere with each other.

This patch makes Page.screenshot() commands run sequencially
even though they were called in parallel.

Fixes #15.
This commit is contained in:
Andrey Lushnikov 2017-06-16 20:20:36 -07:00
parent 3b0bc0802d
commit dbb374d4af
2 changed files with 29 additions and 0 deletions

View File

@ -56,6 +56,8 @@ class Page extends EventEmitter {
/** @type {?function(!Request)} */
this._requestInterceptor = null;
this._screenshotTaskChain = Promise.resolve();
client.on('Debugger.paused', event => this._onDebuggerPaused(event));
client.on('Debugger.scriptParsed', event => this._onScriptParsed(event));
client.on('Network.responseReceived', event => this.emit(Page.Events.ResponseReceived, event.response));
@ -391,6 +393,7 @@ class Page extends EventEmitter {
* @return {!Promise<!Buffer>}
*/
async screenshot(options) {
options = options || {};
var screenshotType = null;
if (options.path) {
var mimeType = mime.lookup(options.path);
@ -423,7 +426,16 @@ class Page extends EventEmitter {
console.assert(typeof options.clip.width === 'number', 'Expected options.clip.width to be a number but found ' + (typeof options.clip.width));
console.assert(typeof options.clip.height === 'number', 'Expected options.clip.height to be a number but found ' + (typeof options.clip.height));
}
this._screenshotTaskChain = this._screenshotTaskChain.then(this._screenshotTask.bind(this, screenshotType, options));
return this._screenshotTaskChain;
}
/**
* @param {string} screenshotType
* @param {!Object=} options
* @return {!Promise<!Buffer>}
*/
async _screenshotTask(screenshotType, options) {
if (options.clip) {
await Promise.all([
this._client.send('Emulation.setVisibleSize', {

View File

@ -70,6 +70,23 @@ describe('GoldenTests', function() {
}
});
});
imageTest('screenshot-parallel-calls.png', async function() {
await page.setViewportSize({width: 500, height: 500});
await page.navigate(STATIC_PREFIX + '/grid.html');
var promises = [];
for (var i = 0; i < 3; ++i) {
promises.push(page.screenshot({
clip: {
x: 50 * i,
y: 0,
width: 50,
height: 50
}
}));
}
return await promises[1];
});
});
/**