2019-12-19 16:53:24 -08:00
/ * *
* Copyright 2017 Google Inc . All rights reserved .
* Modifications 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 { CRSession } from './crConnection' ;
2020-05-27 17:19:05 -07:00
import { getExceptionMessage , releaseObject } from './crProtocolHelper' ;
2019-12-19 16:53:24 -08:00
import { Protocol } from './protocol' ;
2020-08-22 15:46:42 -07:00
import * as js from '../../javascript' ;
import * as sourceMap from '../../utils/sourceMap' ;
import { rewriteErrorMessage } from '../../utils/stackTrace' ;
import { parseEvaluationResultValue } from '../../common/utilityScriptSerializers' ;
2019-12-19 16:53:24 -08:00
export class CRExecutionContext implements js . ExecutionContextDelegate {
_client : CRSession ;
_contextId : number ;
constructor ( client : CRSession , contextPayload : Protocol.Runtime.ExecutionContextDescription ) {
this . _client = client ;
this . _contextId = contextPayload . id ;
}
2020-05-27 22:19:05 -07:00
async rawEvaluate ( expression : string ) : Promise < string > {
2020-05-20 15:55:33 -07:00
const { exceptionDetails , result : remoteObject } = await this . _client . send ( 'Runtime.evaluate' , {
2020-06-11 18:18:33 -07:00
expression : sourceMap.ensureSourceUrl ( expression ) ,
2020-05-20 15:55:33 -07:00
contextId : this._contextId ,
} ) . catch ( rewriteError ) ;
if ( exceptionDetails )
throw new Error ( 'Evaluation failed: ' + getExceptionMessage ( exceptionDetails ) ) ;
2020-05-27 22:19:05 -07:00
return remoteObject . objectId ! ;
2020-05-20 15:55:33 -07:00
}
2020-06-03 17:50:16 -07:00
async evaluateWithArguments ( expression : string , returnByValue : boolean , utilityScript : js.JSHandle < any > , values : any [ ] , objectIds : string [ ] ) : Promise < any > {
const { exceptionDetails , result : remoteObject } = await this . _client . send ( 'Runtime.callFunctionOn' , {
functionDeclaration : expression ,
objectId : utilityScript._objectId ,
arguments : [
{ objectId : utilityScript._objectId } ,
. . . values . map ( value = > ( { value } ) ) ,
. . . objectIds . map ( objectId = > ( { objectId } ) ) ,
] ,
returnByValue ,
awaitPromise : true ,
userGesture : true
} ) . catch ( rewriteError ) ;
if ( exceptionDetails )
throw new Error ( 'Evaluation failed: ' + getExceptionMessage ( exceptionDetails ) ) ;
return returnByValue ? parseEvaluationResultValue ( remoteObject . value ) : utilityScript . _context . createHandle ( remoteObject ) ;
2019-12-19 16:53:24 -08:00
}
async getProperties ( handle : js.JSHandle ) : Promise < Map < string , js.JSHandle > > {
2020-05-27 17:19:05 -07:00
const objectId = handle . _objectId ;
2020-01-13 13:33:25 -08:00
if ( ! objectId )
return new Map ( ) ;
2019-12-19 16:53:24 -08:00
const response = await this . _client . send ( 'Runtime.getProperties' , {
2020-01-13 13:33:25 -08:00
objectId ,
2019-12-19 16:53:24 -08:00
ownProperties : true
} ) ;
const result = new Map ( ) ;
for ( const property of response . result ) {
2020-05-27 17:19:05 -07:00
if ( ! property . enumerable || ! property . value )
2019-12-19 16:53:24 -08:00
continue ;
2020-05-15 15:21:49 -07:00
result . set ( property . name , handle . _context . createHandle ( property . value ) ) ;
2019-12-19 16:53:24 -08:00
}
return result ;
}
2020-05-27 22:19:05 -07:00
createHandle ( context : js.ExecutionContext , remoteObject : Protocol.Runtime.RemoteObject ) : js . JSHandle {
return new js . JSHandle ( context , remoteObject . subtype || remoteObject . type , remoteObject . objectId , potentiallyUnserializableValue ( remoteObject ) ) ;
}
2019-12-19 16:53:24 -08:00
async releaseHandle ( handle : js.JSHandle ) : Promise < void > {
2020-05-27 17:19:05 -07:00
if ( ! handle . _objectId )
return ;
await releaseObject ( this . _client , handle . _objectId ) ;
2019-12-19 16:53:24 -08:00
}
}
2020-05-20 15:55:33 -07:00
function rewriteError ( error : Error ) : Protocol . Runtime . evaluateReturnValue {
if ( error . message . includes ( 'Object reference chain is too long' ) )
return { result : { type : 'undefined' } } ;
if ( error . message . includes ( 'Object couldn\'t be returned by value' ) )
return { result : { type : 'undefined' } } ;
if ( error . message . endsWith ( 'Cannot find context with specified id' ) || error . message . endsWith ( 'Inspected target navigated or closed' ) || error . message . endsWith ( 'Execution context was destroyed.' ) )
throw new Error ( 'Execution context was destroyed, most likely because of a navigation.' ) ;
if ( error instanceof TypeError && error . message . startsWith ( 'Converting circular structure to JSON' ) )
2020-05-28 16:33:31 -07:00
rewriteErrorMessage ( error , error . message + ' Are you passing a nested JSHandle?' ) ;
2020-05-20 15:55:33 -07:00
throw error ;
}
2020-05-27 22:19:05 -07:00
function potentiallyUnserializableValue ( remoteObject : Protocol.Runtime.RemoteObject ) : any {
const value = remoteObject . value ;
const unserializableValue = remoteObject . unserializableValue ;
return unserializableValue ? js . parseUnserializableValue ( unserializableValue ) : value ;
}