mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
feat: nicer protocol error messages (#2742)
This patch: - stops appending `undefined` to our protocol messages unnecessarily. - rewrites `Cannot find execution context id` to `Execution context was destroyed, most likely because of a navigation.` when it occurs from a Puppeteer ExecutionContext. The error message is left alone if it occurs via a CDPSession.
This commit is contained in:
parent
9a650c818d
commit
73f9c48081
@ -108,7 +108,7 @@ class Connection extends EventEmitter {
|
|||||||
if (callback) {
|
if (callback) {
|
||||||
this._callbacks.delete(object.id);
|
this._callbacks.delete(object.id);
|
||||||
if (object.error)
|
if (object.error)
|
||||||
callback.reject(rewriteError(callback.error, `Protocol error (${callback.method}): ${object.error.message} ${object.error.data}`));
|
callback.reject(createProtocolError(callback.error, callback.method, object));
|
||||||
else
|
else
|
||||||
callback.resolve(object.result);
|
callback.resolve(object.result);
|
||||||
}
|
}
|
||||||
@ -213,7 +213,7 @@ class CDPSession extends EventEmitter {
|
|||||||
const callback = this._callbacks.get(object.id);
|
const callback = this._callbacks.get(object.id);
|
||||||
this._callbacks.delete(object.id);
|
this._callbacks.delete(object.id);
|
||||||
if (object.error)
|
if (object.error)
|
||||||
callback.reject(rewriteError(callback.error, `Protocol error (${callback.method}): ${object.error.message} ${object.error.data}`));
|
callback.reject(createProtocolError(callback.error, callback.method, object));
|
||||||
else
|
else
|
||||||
callback.resolve(object.result);
|
callback.resolve(object.result);
|
||||||
} else {
|
} else {
|
||||||
@ -256,6 +256,20 @@ class CDPSession extends EventEmitter {
|
|||||||
}
|
}
|
||||||
helper.tracePublicAPI(CDPSession);
|
helper.tracePublicAPI(CDPSession);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!Error} error
|
||||||
|
* @param {string} method
|
||||||
|
* @param {{error: {message: string, data: any}}} object
|
||||||
|
* @return {!Error}
|
||||||
|
*/
|
||||||
|
function createProtocolError(error, method, object) {
|
||||||
|
let message = `Protocol error (${method}): ${object.error.message}`;
|
||||||
|
if ('data' in object.error)
|
||||||
|
message += ` ${object.error.data}`;
|
||||||
|
if (object.error.message)
|
||||||
|
return rewriteError(error, message);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {!Error} error
|
* @param {!Error} error
|
||||||
* @param {string} message
|
* @param {string} message
|
||||||
|
@ -64,13 +64,13 @@ class ExecutionContext {
|
|||||||
if (helper.isString(pageFunction)) {
|
if (helper.isString(pageFunction)) {
|
||||||
const contextId = this._contextId;
|
const contextId = this._contextId;
|
||||||
const expression = /** @type {string} */ (pageFunction);
|
const expression = /** @type {string} */ (pageFunction);
|
||||||
const { exceptionDetails, result: remoteObject } = await this._client.send('Runtime.evaluate', {
|
const {exceptionDetails, result: remoteObject} = await this._client.send('Runtime.evaluate', {
|
||||||
expression,
|
expression,
|
||||||
contextId,
|
contextId,
|
||||||
returnByValue: false,
|
returnByValue: false,
|
||||||
awaitPromise: true,
|
awaitPromise: true,
|
||||||
userGesture: true
|
userGesture: true
|
||||||
});
|
}).catch(rewriteError);
|
||||||
if (exceptionDetails)
|
if (exceptionDetails)
|
||||||
throw new Error('Evaluation failed: ' + helper.getExceptionMessage(exceptionDetails));
|
throw new Error('Evaluation failed: ' + helper.getExceptionMessage(exceptionDetails));
|
||||||
return this._objectHandleFactory(remoteObject);
|
return this._objectHandleFactory(remoteObject);
|
||||||
@ -83,7 +83,7 @@ class ExecutionContext {
|
|||||||
returnByValue: false,
|
returnByValue: false,
|
||||||
awaitPromise: true,
|
awaitPromise: true,
|
||||||
userGesture: true
|
userGesture: true
|
||||||
});
|
}).catch(rewriteError);
|
||||||
if (exceptionDetails)
|
if (exceptionDetails)
|
||||||
throw new Error('Evaluation failed: ' + helper.getExceptionMessage(exceptionDetails));
|
throw new Error('Evaluation failed: ' + helper.getExceptionMessage(exceptionDetails));
|
||||||
return this._objectHandleFactory(remoteObject);
|
return this._objectHandleFactory(remoteObject);
|
||||||
@ -116,6 +116,16 @@ class ExecutionContext {
|
|||||||
}
|
}
|
||||||
return { value: arg };
|
return { value: arg };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!Error} error
|
||||||
|
* @return {!Protocol.Runtime.evaluateReturnValue}
|
||||||
|
*/
|
||||||
|
function rewriteError(error) {
|
||||||
|
if (error.message.endsWith('Cannot find context with specified id'))
|
||||||
|
throw new Error('Execution context was destroyed, most likely because of a navigation.');
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -124,7 +124,7 @@ module.exports.addTests = function({testRunner, expect}) {
|
|||||||
error = e;
|
error = e;
|
||||||
}
|
}
|
||||||
expect(error).toBeTruthy();
|
expect(error).toBeTruthy();
|
||||||
expect(error.message).toEqual('Protocol error (Network.deleteCookies): At least one of the url and domain needs to be specified undefined');
|
expect(error.message).toEqual('Protocol error (Network.deleteCookies): At least one of the url and domain needs to be specified');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not set a cookie with blank page URL', async function({page, server}) {
|
it('should not set a cookie with blank page URL', async function({page, server}) {
|
||||||
@ -154,7 +154,7 @@ module.exports.addTests = function({testRunner, expect}) {
|
|||||||
}
|
}
|
||||||
expect(error).toBeTruthy();
|
expect(error).toBeTruthy();
|
||||||
expect(error.message).toEqual(
|
expect(error.message).toEqual(
|
||||||
'Protocol error (Network.deleteCookies): At least one of the url and domain needs to be specified undefined'
|
'Protocol error (Network.deleteCookies): At least one of the url and domain needs to be specified'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -226,6 +226,16 @@ module.exports.addTests = function({testRunner, expect, puppeteer, DeviceDescrip
|
|||||||
return audio.play();
|
return audio.play();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
it('should throw a nice error after a navigation', async({page, server}) => {
|
||||||
|
const executionContext = await page.mainFrame().executionContext();
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
page.waitForNavigation(),
|
||||||
|
executionContext.evaluate(() => window.location.reload())
|
||||||
|
]);
|
||||||
|
const error = await executionContext.evaluate(() => null).catch(e => e);
|
||||||
|
expect(error.message).toContain('navigation');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Page.setOfflineMode', function() {
|
describe('Page.setOfflineMode', function() {
|
||||||
|
Loading…
Reference in New Issue
Block a user