playwright/src/injected/utilityScript.ts
Dmitry Gozman 064a0a1154
fix(webkit): do not swallow errors when returning by value (#2723)
We currently return undefined whenever we had an error trying
return the evaluation result by error. The most common error
is "execution context destroyed".

This produces very unexpected undefined from methods that do not
ever expect undefined. Instead, we should throw because we were
not able to return the result.
2020-06-26 09:50:57 -07:00

55 lines
2 KiB
TypeScript

/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { serializeAsCallArgument, parseEvaluationResultValue } from '../common/utilityScriptSerializers';
export default class UtilityScript {
evaluate(returnByValue: boolean, expression: string) {
const result = global.eval(expression);
return returnByValue ? this._promiseAwareJsonValueNoThrow(result) : result;
}
callFunction(returnByValue: boolean, functionText: string, ...args: any[]) {
const argCount = args[0] as number;
const handles = args.slice(argCount + 1);
const parameters = args.slice(1, argCount + 1).map(a => parseEvaluationResultValue(a, handles));
const func = global.eval('(' + functionText + ')');
const result = func(...parameters);
return returnByValue ? this._promiseAwareJsonValueNoThrow(result) : result;
}
jsonValue(returnByValue: true, value: any) {
// Special handling of undefined to work-around multi-step returnByValue handling in WebKit.
if (Object.is(value, undefined))
return undefined;
return serializeAsCallArgument(value, (value: any) => ({ fallThrough: value }));
}
private _promiseAwareJsonValueNoThrow(value: any) {
const safeJson = (value: any) => {
try {
return this.jsonValue(true, value);
} catch (e) {
return undefined;
}
};
if (value && typeof value === 'object' && typeof value.then === 'function')
return value.then(safeJson);
return safeJson(value);
}
}