Changeset 254329 in webkit
- Timestamp:
- Jan 10, 2020 12:44:37 AM (4 years ago)
- Location:
- trunk
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebDriver/ChangeLog
r254118 r254329 1 2020-01-10 Carlos Garcia Campos <cgarcia@igalia.com> 2 3 Automation: evaluateJavaScriptFunction should use Promises 4 https://bugs.webkit.org/show_bug.cgi?id=204151 5 6 Reviewed by Brian Burg. 7 8 * CommandResult.cpp: 9 (WebDriver::CommandResult::httpStatusCode const): Timeout errors should return 500 not 408. 10 * Session.cpp: 11 (WebDriver::Session::executeScript): Ensure the script body goes between new lines to avoid problems with 12 trailing comments like in function() { return foo; // Comment }. 13 1 14 2020-01-07 Carlos Garcia Campos <cgarcia@igalia.com> 2 15 -
trunk/Source/WebDriver/CommandResult.cpp
r254118 r254329 149 149 case ErrorCode::UnknownCommand: 150 150 return 404; 151 case ErrorCode::ScriptTimeout:152 case ErrorCode::Timeout:153 return 408;154 151 case ErrorCode::JavascriptError: 155 152 case ErrorCode::MoveTargetOutOfBounds: 153 case ErrorCode::ScriptTimeout: 156 154 case ErrorCode::SessionNotCreated: 155 case ErrorCode::Timeout: 157 156 case ErrorCode::UnableToCaptureScreen: 158 157 case ErrorCode::UnexpectedAlertOpen: -
trunk/Source/WebDriver/Session.cpp
r253883 r254329 2134 2134 if (m_currentBrowsingContext) 2135 2135 parameters->setString("frameHandle"_s, m_currentBrowsingContext.value()); 2136 parameters->setString("function"_s, "function(){ " + script + '}');2136 parameters->setString("function"_s, "function(){\n" + script + "\n}"); 2137 2137 parameters->setArray("arguments"_s, WTFMove(arguments)); 2138 if (mode == ExecuteScriptMode::Async) {2138 if (mode == ExecuteScriptMode::Async) 2139 2139 parameters->setBoolean("expectsImplicitCallbackArgument"_s, true); 2140 if (m_scriptTimeout != std::numeric_limits<double>::infinity()) 2141 parameters->setDouble("callbackTimeout"_s, m_scriptTimeout); 2142 } 2140 if (m_scriptTimeout != std::numeric_limits<double>::infinity()) 2141 parameters->setDouble("callbackTimeout"_s, m_scriptTimeout); 2143 2142 m_host->sendCommandToBackend("evaluateJavaScriptFunction"_s, WTFMove(parameters), [this, protectedThis = protectedThis.copyRef(), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) mutable { 2144 2143 if (response.isError || !response.responseObject) { -
trunk/Source/WebKit/ChangeLog
r254328 r254329 1 2020-01-10 Carlos Garcia Campos <cgarcia@igalia.com> 2 3 Automation: evaluateJavaScriptFunction should use Promises 4 https://bugs.webkit.org/show_bug.cgi?id=204151 5 6 Reviewed by Brian Burg. 7 8 Make the function to run scripts async and handle the result as a promise. To implement the script timeout we 9 use another promise that starts the timer and then we run a Promise.race() with both promises. To simplify the 10 results reporting, all exceptions (including timeout errors that are now handled as exceptions) are now handled 11 as errors passed to the resultCallback. The boolean parameter has been removed, we can simply check the type of 12 the value received because results are always strings and errors are always exception objects. 13 14 * WebProcess/Automation/WebAutomationSessionProxy.cpp: 15 (WebKit::evaluateJavaScriptCallback): Handle the script result, including all possible errors now (not only timeouts). 16 (WebKit::WebAutomationSessionProxy::evaluateJavaScriptFunction): Any exception running the script should be an 17 internal error now. The code to handle error has been moved to evaluateJavaScriptCallback(). 18 * WebProcess/Automation/WebAutomationSessionProxy.js: 19 (WebKitAutomation.AutomationSessionProxy.prototype.evaluateJavaScriptFunction): Call _execute and handle the 20 promise result to call resultCallback wityh either the result or the error. 21 (WebKitAutomation.AutomationSessionProxy.prototype._execute): Make the function to run the script async and 22 handle the result as a promise. 23 1 24 2020-01-10 Carlos Garcia Campos <cgarcia@igalia.com> 2 25 -
trunk/Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.cpp
r254328 r254329 182 182 static JSValueRef evaluateJavaScriptCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 183 183 { 184 ASSERT_ARG(argumentCount, argumentCount == 4);184 ASSERT_ARG(argumentCount, argumentCount == 3); 185 185 ASSERT_ARG(arguments, JSValueIsNumber(context, arguments[0])); 186 186 ASSERT_ARG(arguments, JSValueIsNumber(context, arguments[1])); 187 ASSERT_ARG(arguments, JSValueIsString(context, arguments[2])); 188 ASSERT_ARG(arguments, JSValueIsBoolean(context, arguments[3])); 187 ASSERT_ARG(arguments, JSValueIsObject(context, arguments[2]) || JSValueIsString(context, arguments[2])); 189 188 190 189 auto automationSessionProxy = WebProcess::singleton().automationSessionProxy(); … … 194 193 WebCore::FrameIdentifier frameID = WebCore::frameIdentifierFromID(JSValueToNumber(context, arguments[0], exception)); 195 194 uint64_t callbackID = JSValueToNumber(context, arguments[1], exception); 196 auto result = adoptRef(JSValueToStringCopy(context, arguments[2], exception)); 197 198 bool resultIsErrorName = JSValueToBoolean(context, arguments[3]); 199 200 if (resultIsErrorName) { 201 if (result->string() == "JavaScriptTimeout") { 202 String errorType = Inspector::Protocol::AutomationHelpers::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::JavaScriptTimeout); 203 automationSessionProxy->didEvaluateJavaScriptFunction(frameID, callbackID, String(), errorType); 204 } else { 205 ASSERT_NOT_REACHED(); 206 String errorType = Inspector::Protocol::AutomationHelpers::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::InternalError); 207 automationSessionProxy->didEvaluateJavaScriptFunction(frameID, callbackID, String(), errorType); 208 } 209 } else 210 automationSessionProxy->didEvaluateJavaScriptFunction(frameID, callbackID, result->string(), String()); 211 212 return JSValueMakeUndefined(context); 213 } 214 215 JSObjectRef WebAutomationSessionProxy::scriptObject(JSGlobalContextRef context) 216 { 217 JSC::JSGlobalObject* globalObject = toJS(context); 218 JSC::VM& vm = globalObject->vm(); 219 JSC::JSLockHolder locker(vm); 220 auto scriptObjectID = JSC::Identifier::fromUid(m_scriptObjectIdentifier); 221 if (!globalObject->hasProperty(globalObject, scriptObjectID)) 222 return nullptr; 223 224 return const_cast<JSObjectRef>(toRef(globalObject, globalObject->get(globalObject, scriptObjectID))); 225 } 226 227 void WebAutomationSessionProxy::setScriptObject(JSGlobalContextRef context, JSObjectRef object) 228 { 229 JSC::JSGlobalObject* globalObject = toJS(context); 230 JSC::VM& vm = globalObject->vm(); 231 JSC::JSLockHolder locker(vm); 232 auto scriptObjectID = JSC::Identifier::fromUid(m_scriptObjectIdentifier); 233 PutPropertySlot slot(globalObject); 234 globalObject->methodTable(vm)->put(globalObject, globalObject, scriptObjectID, toJS(globalObject, object), slot); 235 } 236 237 JSObjectRef WebAutomationSessionProxy::scriptObjectForFrame(WebFrame& frame) 238 { 239 JSGlobalContextRef context = frame.jsContext(); 240 if (auto* scriptObject = this->scriptObject(context)) 241 return scriptObject; 242 243 JSValueRef exception = nullptr; 244 String script = StringImpl::createWithoutCopying(WebAutomationSessionProxyScriptSource, sizeof(WebAutomationSessionProxyScriptSource)); 245 JSObjectRef scriptObjectFunction = const_cast<JSObjectRef>(JSEvaluateScript(context, OpaqueJSString::tryCreate(script).get(), nullptr, nullptr, 0, &exception)); 246 ASSERT(JSValueIsObject(context, scriptObjectFunction)); 247 248 JSValueRef sessionIdentifier = toJSValue(context, m_sessionIdentifier); 249 JSObjectRef evaluateFunction = JSObjectMakeFunctionWithCallback(context, nullptr, evaluate); 250 JSObjectRef createUUIDFunction = JSObjectMakeFunctionWithCallback(context, nullptr, createUUID); 251 JSObjectRef isValidNodeIdentifierFunction = JSObjectMakeFunctionWithCallback(context, nullptr, isValidNodeIdentifier); 252 JSValueRef arguments[] = { sessionIdentifier, evaluateFunction, createUUIDFunction, isValidNodeIdentifierFunction }; 253 JSObjectRef scriptObject = const_cast<JSObjectRef>(JSObjectCallAsFunction(context, scriptObjectFunction, nullptr, WTF_ARRAY_LENGTH(arguments), arguments, &exception)); 254 ASSERT(JSValueIsObject(context, scriptObject)); 255 256 setScriptObject(context, scriptObject); 257 return scriptObject; 258 } 259 260 WebCore::Element* WebAutomationSessionProxy::elementForNodeHandle(WebFrame& frame, const String& nodeHandle) 261 { 262 // Don't use scriptObjectForFrame() since we can assume if the script object 263 // does not exist, there are no nodes mapped to handles. Using scriptObjectForFrame() 264 // will make a new script object if it can't find one, preventing us from returning fast. 265 JSGlobalContextRef context = frame.jsContext(); 266 auto* scriptObject = this->scriptObject(context); 267 if (!scriptObject) 268 return nullptr; 269 270 JSValueRef functionArguments[] = { 271 toJSValue(context, nodeHandle) 272 }; 273 274 JSValueRef result = callPropertyFunction(context, scriptObject, "nodeForIdentifier"_s, WTF_ARRAY_LENGTH(functionArguments), functionArguments, nullptr); 275 JSObjectRef element = JSValueToObject(context, result, nullptr); 276 if (!element) 277 return nullptr; 278 279 auto elementWrapper = JSC::jsDynamicCast<WebCore::JSElement*>(toJS(context)->vm(), toJS(element)); 280 if (!elementWrapper) 281 return nullptr; 282 283 return &elementWrapper->wrapped(); 284 } 285 286 void WebAutomationSessionProxy::didClearWindowObjectForFrame(WebFrame& frame) 287 { 288 String errorMessage = "Callback was not called before the unload event."_s; 289 String errorType = Inspector::Protocol::AutomationHelpers::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::JavaScriptError); 290 291 auto pendingFrameCallbacks = m_webFramePendingEvaluateJavaScriptCallbacksMap.take(frame.frameID()); 292 for (uint64_t callbackID : pendingFrameCallbacks) 293 WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidEvaluateJavaScriptFunction(callbackID, errorMessage, errorType), 0); 294 } 295 296 void WebAutomationSessionProxy::evaluateJavaScriptFunction(WebCore::PageIdentifier pageID, Optional<WebCore::FrameIdentifier> optionalFrameID, const String& function, Vector<String> arguments, bool expectsImplicitCallbackArgument, Optional<double> callbackTimeout, uint64_t callbackID) 297 { 298 WebPage* page = WebProcess::singleton().webPage(pageID); 299 if (!page) { 300 WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidEvaluateJavaScriptFunction(callbackID, { }, 301 Inspector::Protocol::AutomationHelpers::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::WindowNotFound)), 0); 302 return; 303 } 304 WebFrame* frame = optionalFrameID ? WebProcess::singleton().webFrame(*optionalFrameID) : page->mainWebFrame(); 305 if (!frame) { 306 WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidEvaluateJavaScriptFunction(callbackID, { }, 307 Inspector::Protocol::AutomationHelpers::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::FrameNotFound)), 0); 308 return; 309 } 310 311 JSObjectRef scriptObject = scriptObjectForFrame(*frame); 312 ASSERT(scriptObject); 313 314 auto frameID = frame->frameID(); 315 JSValueRef exception = nullptr; 316 JSGlobalContextRef context = frame->jsContext(); 317 318 if (expectsImplicitCallbackArgument) { 319 auto result = m_webFramePendingEvaluateJavaScriptCallbacksMap.add(frameID, Vector<uint64_t>()); 320 result.iterator->value.append(callbackID); 321 } 322 323 JSValueRef functionArguments[] = { 324 toJSValue(context, function), 325 toJSArray(context, arguments, toJSValue, &exception), 326 JSValueMakeBoolean(context, expectsImplicitCallbackArgument), 327 JSValueMakeNumber(context, frameID.toUInt64()), 328 JSValueMakeNumber(context, callbackID), 329 JSObjectMakeFunctionWithCallback(context, nullptr, evaluateJavaScriptCallback), 330 JSValueMakeNumber(context, callbackTimeout.valueOr(-1)) 331 }; 332 333 { 334 WebCore::UserGestureIndicator gestureIndicator(WebCore::ProcessingUserGesture, frame->coreFrame()->document()); 335 callPropertyFunction(context, scriptObject, "evaluateJavaScriptFunction"_s, WTF_ARRAY_LENGTH(functionArguments), functionArguments, &exception); 336 } 337 338 if (!exception) 339 return; 340 341 String errorType = Inspector::Protocol::AutomationHelpers::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::JavaScriptError); 342 343 String exceptionMessage; 344 if (JSValueIsObject(context, exception)) { 345 JSValueRef nameValue = JSObjectGetProperty(context, const_cast<JSObjectRef>(exception), OpaqueJSString::tryCreate("name"_s).get(), nullptr); 346 auto exceptionName = adoptRef(JSValueToStringCopy(context, nameValue, nullptr))->string(); 347 if (exceptionName == "NodeNotFound") 195 if (JSValueIsString(context, arguments[2])) { 196 auto result = adoptRef(JSValueToStringCopy(context, arguments[2], exception)); 197 automationSessionProxy->didEvaluateJavaScriptFunction(frameID, callbackID, result->string(), { }); 198 } else if (JSValueIsObject(context, arguments[2])) { 199 JSObjectRef error = JSValueToObject(context, arguments[2], exception); 200 JSValueRef nameValue = JSObjectGetProperty(context, error, OpaqueJSString::tryCreate("name"_s).get(), exception); 201 String exceptionName = adoptRef(JSValueToStringCopy(context, nameValue, nullptr))->string(); 202 String errorType = Inspector::Protocol::AutomationHelpers::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::JavaScriptError); 203 if (exceptionName == "JavaScriptTimeout") 204 errorType = Inspector::Protocol::AutomationHelpers::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::JavaScriptTimeout); 205 else if (exceptionName == "NodeNotFound") 348 206 errorType = Inspector::Protocol::AutomationHelpers::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::NodeNotFound); 349 207 else if (exceptionName == "InvalidNodeIdentifier") … … 358 216 errorType = Inspector::Protocol::AutomationHelpers::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::ElementNotInteractable); 359 217 218 JSValueRef messageValue = JSObjectGetProperty(context, error, OpaqueJSString::tryCreate("message"_s).get(), exception); 219 auto exceptionMessage = adoptRef(JSValueToStringCopy(context, messageValue, exception))->string(); 220 automationSessionProxy->didEvaluateJavaScriptFunction(frameID, callbackID, exceptionMessage, errorType); 221 } else { 222 String errorType = Inspector::Protocol::AutomationHelpers::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::InternalError); 223 automationSessionProxy->didEvaluateJavaScriptFunction(frameID, callbackID, { }, errorType); 224 } 225 226 return JSValueMakeUndefined(context); 227 } 228 229 JSObjectRef WebAutomationSessionProxy::scriptObject(JSGlobalContextRef context) 230 { 231 JSC::JSGlobalObject* globalObject = toJS(context); 232 JSC::VM& vm = globalObject->vm(); 233 JSC::JSLockHolder locker(vm); 234 auto scriptObjectID = JSC::Identifier::fromUid(m_scriptObjectIdentifier); 235 if (!globalObject->hasProperty(globalObject, scriptObjectID)) 236 return nullptr; 237 238 return const_cast<JSObjectRef>(toRef(globalObject, globalObject->get(globalObject, scriptObjectID))); 239 } 240 241 void WebAutomationSessionProxy::setScriptObject(JSGlobalContextRef context, JSObjectRef object) 242 { 243 JSC::JSGlobalObject* globalObject = toJS(context); 244 JSC::VM& vm = globalObject->vm(); 245 JSC::JSLockHolder locker(vm); 246 auto scriptObjectID = JSC::Identifier::fromUid(m_scriptObjectIdentifier); 247 PutPropertySlot slot(globalObject); 248 globalObject->methodTable(vm)->put(globalObject, globalObject, scriptObjectID, toJS(globalObject, object), slot); 249 } 250 251 JSObjectRef WebAutomationSessionProxy::scriptObjectForFrame(WebFrame& frame) 252 { 253 JSGlobalContextRef context = frame.jsContext(); 254 if (auto* scriptObject = this->scriptObject(context)) 255 return scriptObject; 256 257 JSValueRef exception = nullptr; 258 String script = StringImpl::createWithoutCopying(WebAutomationSessionProxyScriptSource, sizeof(WebAutomationSessionProxyScriptSource)); 259 JSObjectRef scriptObjectFunction = const_cast<JSObjectRef>(JSEvaluateScript(context, OpaqueJSString::tryCreate(script).get(), nullptr, nullptr, 0, &exception)); 260 ASSERT(JSValueIsObject(context, scriptObjectFunction)); 261 262 JSValueRef sessionIdentifier = toJSValue(context, m_sessionIdentifier); 263 JSObjectRef evaluateFunction = JSObjectMakeFunctionWithCallback(context, nullptr, evaluate); 264 JSObjectRef createUUIDFunction = JSObjectMakeFunctionWithCallback(context, nullptr, createUUID); 265 JSObjectRef isValidNodeIdentifierFunction = JSObjectMakeFunctionWithCallback(context, nullptr, isValidNodeIdentifier); 266 JSValueRef arguments[] = { sessionIdentifier, evaluateFunction, createUUIDFunction, isValidNodeIdentifierFunction }; 267 JSObjectRef scriptObject = const_cast<JSObjectRef>(JSObjectCallAsFunction(context, scriptObjectFunction, nullptr, WTF_ARRAY_LENGTH(arguments), arguments, &exception)); 268 ASSERT(JSValueIsObject(context, scriptObject)); 269 270 setScriptObject(context, scriptObject); 271 return scriptObject; 272 } 273 274 WebCore::Element* WebAutomationSessionProxy::elementForNodeHandle(WebFrame& frame, const String& nodeHandle) 275 { 276 // Don't use scriptObjectForFrame() since we can assume if the script object 277 // does not exist, there are no nodes mapped to handles. Using scriptObjectForFrame() 278 // will make a new script object if it can't find one, preventing us from returning fast. 279 JSGlobalContextRef context = frame.jsContext(); 280 auto* scriptObject = this->scriptObject(context); 281 if (!scriptObject) 282 return nullptr; 283 284 JSValueRef functionArguments[] = { 285 toJSValue(context, nodeHandle) 286 }; 287 288 JSValueRef result = callPropertyFunction(context, scriptObject, "nodeForIdentifier"_s, WTF_ARRAY_LENGTH(functionArguments), functionArguments, nullptr); 289 JSObjectRef element = JSValueToObject(context, result, nullptr); 290 if (!element) 291 return nullptr; 292 293 auto elementWrapper = JSC::jsDynamicCast<WebCore::JSElement*>(toJS(context)->vm(), toJS(element)); 294 if (!elementWrapper) 295 return nullptr; 296 297 return &elementWrapper->wrapped(); 298 } 299 300 void WebAutomationSessionProxy::didClearWindowObjectForFrame(WebFrame& frame) 301 { 302 String errorMessage = "Callback was not called before the unload event."_s; 303 String errorType = Inspector::Protocol::AutomationHelpers::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::JavaScriptError); 304 305 auto pendingFrameCallbacks = m_webFramePendingEvaluateJavaScriptCallbacksMap.take(frame.frameID()); 306 for (uint64_t callbackID : pendingFrameCallbacks) 307 WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidEvaluateJavaScriptFunction(callbackID, errorMessage, errorType), 0); 308 } 309 310 void WebAutomationSessionProxy::evaluateJavaScriptFunction(WebCore::PageIdentifier pageID, Optional<WebCore::FrameIdentifier> optionalFrameID, const String& function, Vector<String> arguments, bool expectsImplicitCallbackArgument, Optional<double> callbackTimeout, uint64_t callbackID) 311 { 312 WebPage* page = WebProcess::singleton().webPage(pageID); 313 if (!page) { 314 WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidEvaluateJavaScriptFunction(callbackID, { }, 315 Inspector::Protocol::AutomationHelpers::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::WindowNotFound)), 0); 316 return; 317 } 318 WebFrame* frame = optionalFrameID ? WebProcess::singleton().webFrame(*optionalFrameID) : page->mainWebFrame(); 319 if (!frame) { 320 WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidEvaluateJavaScriptFunction(callbackID, { }, 321 Inspector::Protocol::AutomationHelpers::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::FrameNotFound)), 0); 322 return; 323 } 324 325 JSObjectRef scriptObject = scriptObjectForFrame(*frame); 326 ASSERT(scriptObject); 327 328 auto frameID = frame->frameID(); 329 JSValueRef exception = nullptr; 330 JSGlobalContextRef context = frame->jsContext(); 331 332 if (expectsImplicitCallbackArgument) { 333 auto result = m_webFramePendingEvaluateJavaScriptCallbacksMap.add(frameID, Vector<uint64_t>()); 334 result.iterator->value.append(callbackID); 335 } 336 337 JSValueRef functionArguments[] = { 338 toJSValue(context, function), 339 toJSArray(context, arguments, toJSValue, &exception), 340 JSValueMakeBoolean(context, expectsImplicitCallbackArgument), 341 JSValueMakeNumber(context, frameID.toUInt64()), 342 JSValueMakeNumber(context, callbackID), 343 JSObjectMakeFunctionWithCallback(context, nullptr, evaluateJavaScriptCallback), 344 JSValueMakeNumber(context, callbackTimeout.valueOr(-1)) 345 }; 346 347 { 348 WebCore::UserGestureIndicator gestureIndicator(WebCore::ProcessingUserGesture, frame->coreFrame()->document()); 349 callPropertyFunction(context, scriptObject, "evaluateJavaScriptFunction"_s, WTF_ARRAY_LENGTH(functionArguments), functionArguments, &exception); 350 } 351 352 if (!exception) 353 return; 354 355 String errorType = Inspector::Protocol::AutomationHelpers::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::InternalError); 356 357 String exceptionMessage; 358 if (JSValueIsObject(context, exception)) { 360 359 JSValueRef messageValue = JSObjectGetProperty(context, const_cast<JSObjectRef>(exception), OpaqueJSString::tryCreate("message"_s).get(), nullptr); 361 360 exceptionMessage = adoptRef(JSValueToStringCopy(context, messageValue, nullptr))->string(); -
trunk/Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.js
r254120 r254329 42 42 evaluateJavaScriptFunction(functionString, argumentStrings, expectsImplicitCallbackArgument, frameID, callbackID, resultCallback, callbackTimeout) 43 43 { 44 // The script is expected to be a function declaration. Evaluate it inside parenthesis to get the function value. 45 let functionValue = evaluate("(" + functionString + ")"); 46 if (typeof functionValue !== "function") 47 throw new TypeError("Script did not evaluate to a function."); 48 49 this._clearStaleNodes(); 50 51 let argumentValues = argumentStrings.map(this._jsonParse, this); 52 53 let timeoutIdentifier = 0; 54 let resultReported = false; 55 56 let reportResult = (result) => { 57 if (timeoutIdentifier) 58 clearTimeout(timeoutIdentifier); 59 resultCallback(frameID, callbackID, this._jsonStringify(result), false); 60 resultReported = true; 61 }; 62 let reportTimeoutError = () => { resultCallback(frameID, callbackID, "JavaScriptTimeout", true); }; 63 64 if (expectsImplicitCallbackArgument) { 65 argumentValues.push(reportResult); 66 functionValue.apply(null, argumentValues); 67 if (!resultReported && callbackTimeout >= 0) 68 timeoutIdentifier = setTimeout(reportTimeoutError, callbackTimeout); 69 } else 70 reportResult(functionValue.apply(null, argumentValues)); 44 this._execute(functionString, argumentStrings, expectsImplicitCallbackArgument, callbackTimeout) 45 .then(result => { resultCallback(frameID, callbackID, this._jsonStringify(result)); }) 46 .catch(error => { resultCallback(frameID, callbackID, error); }); 71 47 } 72 48 … … 82 58 83 59 // Private 60 61 _execute(functionString, argumentStrings, expectsImplicitCallbackArgument, callbackTimeout) 62 { 63 let timeoutPromise; 64 let timeoutIdentifier = 0; 65 if (callbackTimeout >= 0) { 66 timeoutPromise = new Promise((resolve, reject) => { 67 timeoutIdentifier = setTimeout(() => { 68 reject({ name: "JavaScriptTimeout", message: "script timed out after " + callbackTimeout + "ms" }); 69 }, callbackTimeout); 70 }); 71 } 72 73 let promise = new Promise((resolve, reject) => { 74 // The script is expected to be a function declaration. Evaluate it inside parenthesis to get the function value. 75 let functionValue = evaluate("(async " + functionString + ")"); 76 if (typeof functionValue !== "function") 77 reject(new TypeError("Script did not evaluate to a function.")); 78 79 this._clearStaleNodes(); 80 81 let argumentValues = argumentStrings.map(this._jsonParse, this); 82 if (expectsImplicitCallbackArgument) 83 argumentValues.push(resolve); 84 let resultPromise = functionValue.apply(null, argumentValues); 85 86 let promises = [resultPromise]; 87 if (timeoutPromise) 88 promises.push(timeoutPromise); 89 Promise.race(promises) 90 .then(result => { 91 if (!expectsImplicitCallbackArgument) { 92 resolve(result); 93 } 94 }) 95 .catch(error => { 96 reject(error); 97 }); 98 }); 99 100 // Async scripts can call Promise.resolve() in the function script, generating a new promise that is resolved in a 101 // timer (see w3c test execute_async_script/promise.py::test_promise_resolve_timeout). In that case, the internal race 102 // finishes resolved, so we need to start a new one here to wait for the second promise to be resolved or the timeout. 103 let promises = [promise]; 104 if (timeoutPromise) 105 promises.push(timeoutPromise); 106 return Promise.race(promises) 107 .finally(() => { 108 if (timeoutIdentifier) { 109 clearTimeout(timeoutIdentifier); 110 } 111 }); 112 } 84 113 85 114 _jsonParse(string) -
trunk/WebDriverTests/ChangeLog
r254255 r254329 1 2020-01-10 Carlos Garcia Campos <cgarcia@igalia.com> 2 3 Automation: evaluateJavaScriptFunction should use Promises 4 https://bugs.webkit.org/show_bug.cgi?id=204151 5 6 Reviewed by Brian Burg. 7 8 Remove expectations for tests that are now passing. 9 10 * TestExpectations.json: 11 1 12 2020-01-09 Carlos Garcia Campos <cgarcia@igalia.com> 2 13 -
trunk/WebDriverTests/TestExpectations.json
r254255 r254329 536 536 } 537 537 }, 538 "imported/w3c/webdriver/tests/execute_async_script/promise.py": {539 "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/204151"}},540 "subtests": {541 "test_await_promise_reject": {542 "expected": {"all": {"status": ["PASS"]}}543 }544 }545 },546 "imported/w3c/webdriver/tests/execute_script/promise.py": {547 "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/204151"}},548 "subtests": {549 "test_await_promise_reject": {550 "expected": {"all": {"status": ["PASS"]}}551 }552 }553 },554 538 "imported/w3c/webdriver/tests/element_send_keys/content_editable.py": { 555 539 "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/180403"}}
Note: See TracChangeset
for help on using the changeset viewer.