Skip to content

Commit

Permalink
Correct handling of Promise values
Browse files Browse the repository at this point in the history
Previously, Execute Script and Execute Async Script were updated to
invoke the "execute a function body" algorithm by "promise calling" it.
[1] This did not have the intended effect because "execute a function
body" continued to return WebDriver "success" and "error" values,
Additionally, fulfillment of the promise returned by the user-provided
script did not influence completion of the operation.

Refactor "execute a function body" to return an ECMAScript completion
value so that it may be invoked via "promise call." Update both Execute
Script and Execute Async Script to recognize a synchronously-returned
Promise value in accordance with the discussion which motivated the
original change [2].

[1] 7307dd6
[2] #381
  • Loading branch information
jugglinmike authored and AutomatedTester committed Oct 19, 2018
1 parent af2e76a commit 6166c07
Showing 1 changed file with 60 additions and 37 deletions.
97 changes: 60 additions & 37 deletions index.html
Expand Up @@ -216,17 +216,22 @@ <h3>Dependencies</h3>
<dt>ECMAScript
<dd><p>The following terms are defined in the ECMAScript Language Specification: [[!ECMA-262]]
<ul>
<!-- Abrupt Completion --> <li><dfn><a href="https://tc39.github.io/ecma262/#sec-completion-record-specification-type">Abrupt Completion</a></dfn>
<!-- Completion --> <li><dfn><a href="https://tc39.github.io/ecma262/#sec-completion-record-specification-type">Completion</a></dfn>
<!-- CreateResolvingFunctions --> <li><dfn><a href=https://tc39.github.io/ecma262/#sec-createresolvingfunctions>CreateResolvingFunctions</a></dfn>
<!-- Directive prologue --> <li><dfn><a href=http://www.ecma-international.org/ecma-262/5.1/#sec-14.1>Directive prologue</a></dfn>
<!-- Early error --> <li><dfn><a href=http://www.ecma-international.org/ecma-262/5.1/#sec-16>Early error</a></dfn>
<!-- Function --> <li><dfn><a href=http://www.ecma-international.org/ecma-262/5.1/#sec-4.3.24>Function</a></dfn>
<!-- FunctionCreate --> <li><dfn><a href=https://tc39.github.io/ecma262/#sec-functioncreate>FunctionCreate</a></dfn>
<!-- FunctionBody --> <li><dfn><a href=http://www.ecma-international.org/ecma-262/5.1/#sec-13>FunctionBody</a></dfn>
<!-- Get --> <li><dfn><a href=https://tc39.github.io/ecma262/#sec-get-o-p>Get</a></dfn>
<!-- Global environment --> <li><dfn><a href=http://www.ecma-international.org/ecma-262/5.1/#sec-10.2.3>Global environment</a></dfn>
<!-- IsCallable --> <li><dfn><a href=https://tc39.github.io/ecma262/#sec-iscallable>IsCallable</a></dfn>
<!-- Own property --> <li><dfn data-lt="own properties"><a href=http://www.ecma-international.org/ecma-262/5.1/#sec-4.3.30>Own property</a></dfn>
<!-- parseFloat --> <li><dfn><a href=http://www.ecma-international.org/ecma-262/5.1/#sec-15.1.2.3>parseFloat</a></dfn>
<!-- Promise --> <li><dfn><a href=https://tc39.github.io/ecma262/#sec-promise-constructor>Promise</a></dfn>
<!-- PromiseResolve --> <li><dfn><a href=https://tc39.github.io/ecma262/#sec-promise-resolve>PromiseResolve</a></dfn>
<!-- realm --> <li><dfn><a href="https://tc39.github.io/ecma262/#sec-code-realms">realm</a></dfn>
<!-- Type --> <li><dfn data-lt="ecmascript type"><a href=https://tc39.github.io/ecma262/#sec-ecmascript-data-types-and-values>Type</a></dfn>
<!-- Use strict directive --> <li><dfn><a href=http://www.ecma-international.org/ecma-262/5.1/#sec-14.1>Use strict directive</a></dfn>
</ul>

Expand Down Expand Up @@ -6449,15 +6454,11 @@ <h3>Executing Script</h3>
</ol>

<p>The rules to <dfn>execute a function body</dfn> are as follows.
The algorithm will return <a>success</a>
with the <a data-lt="clone an object">JSON representation</a>
of the function’s return value,
or an <a>error</a> if the evaluation of the function
results in a JavaScript exception being thrown.
The algorithm returns <a data-lt="completion">an ECMASCript completion record</a>.

<p>If at any point during the algorithm a <a>user prompt</a> appears,
abort all subsequent substeps of this algorithm, and return
<a>success</a> with data <var>null</var>.
<a>Completion</a> { [[\Type]]: <code>normal</code>, [[\Value]]: <var>null</var>, [[\Target]]: <code>empty</code> }.

<ol>
<li><p>Let <var>window</var> be the <a>associated window</a>
Expand All @@ -6472,7 +6473,8 @@ <h3>Executing Script</h3>

<li><p>If <var>body</var> is not parsable as a <a>FunctionBody</a>
or if parsing detects an <a>early error</a>,
return <a>error</a> with <a>error code</a> <a>javascript error</a>.
return
<a>Completion</a> { [[\Type]]: <code>normal</code>, [[\Value]]: <var>null</var>, [[\Target]]: <code>empty</code> }.

<li><p>If <var>body</var> begins with a <a>directive prologue</a>
that contains a <a>use strict directive</a>
Expand Down Expand Up @@ -6514,13 +6516,7 @@ <h3>Executing Script</h3>
<li><p><a>Clean up after running a script</a>
with <var>environment settings</var>.

<li><p>If <var>completion</var> is an <a>abrupt completion</a>,
return an <a>error</a> with <a>error code</a> <a>javascript error</a>.

<li><p>Let <var>json data</var> be a <a>JSON clone</a>
of <var>completion</var><code>.[[\Value]]</code>.

<li><p>Return <a>success</a> with data <var>json data</var>.
<li><p>Return <var>completion</var>.
</ol>

<p class="note">The above algorithm is not associated
Expand Down Expand Up @@ -6557,26 +6553,29 @@ <h3><dfn>Execute Script</dfn></h3>

<li><p>Run the following substeps <a>in parallel</a>:
<ol>
<li><p>Let <var>result</var> be the result of <a>promise-calling</a>
<li><p>Let <var>scriptPromise</var> be the result of <a>promise-calling</a>
<a>execute a function body</a>, with arguments
<var>body</var> and <var>arguments</var>.

<li><p>If <var>result</var> is an error,
<a>reject</a> <var>promise</var> with <var>result</var>.
<li><p>Upon fulfillment of <var>scriptPromise</var> with value <var>v</var>,
<a>resolve</a> <var>promise</var> with value <var>v</var>.

<li><p>Upon rejection of <var>scriptPromise</var> with value <var>r</var>,
<a>reject</a> <var>promise</var> with value <var>r</var>.
</ol>

<li><p>If <var>promise</var> is still pending and
<a>session script timeout</a> milliseconds is reached,
<a>reject</a> <var>promise</var> with <a>error</a> with
<a>error code</a> <a>script timeout</a>.
return <a>error</a> with <a>error code</a> <a>script timeout</a>.

<li><p>Upon fulfillment of <var>promise</var> with value <var>v</var>,
return <a>success</a> with data <var>v</var>.
let <var>result</var> be a <a>JSON clone</a> of <var>v</var>, and
return <a>success</a> with data <var>result</var>.

<li><p>Upon rejection of <var>promise</var> with reason <var>r</var>,
if <var>r</var> is an <a>error</a>, return <var>r</var>.
Otherwise, return <a>error</a> with <a>error code</a> <a>javascript error</a>
and data <var>r</var>.
let <var>result</var> be a <a>JSON clone</a> of <var>r</var>, and
return <a>error</a> with <a>error code</a> <a>javascript error</a>
and data <var>result</var>.
</ol>
</section> <!-- /Execute Script -->

Expand All @@ -6597,10 +6596,9 @@ <h3><dfn>Execute Async Script</dfn></h3>
<p class=note>
The <a>Execute Async Script</a> <a>command</a>
causes JavaScript to execute as an anonymous function.
Unlike the <a>Execute Script</a> <a>command</a>,
the result of the function is ignored.
instead an additional argument is provided as the final argument to the function.
This is a function that, when called, returns its first argument as the response.
An additional value is provided as the final argument to the function.
This is a function that may be invoked to signal the completion of the asynchronous operation.
The first argument provided to the function will be serialized to JSON and returned by <a>Execute Async Script</a>.

<p>The <a>remote end steps</a> are:

Expand All @@ -6623,26 +6621,51 @@ <h3><dfn>Execute Async Script</dfn></h3>
<li><p>Append <var>resolvingFunctions</var><code>.[[\Resolve]]</code></var> to
<var>arguments</var>.

<li><p>Let <var>result</var> be the result of <a>promise-calling</a>
<li><p>Let <var>result</var> be the result of calling
<a>execute a function body</a>, with arguments
<var>body</var> and <var>arguments</var>.

<li><p>If <var>result</var> is an error,
<a>reject</a> <var>promise</var> with <var>result</var>.
<li><p>If <var>scriptResult</var>.[[\Type]] is not <code>normal</code>, then <a>reject</a>
<var>promise</var> with value <var>scriptResult</var>.[[\Value]], and abort these steps.

<p class=note>Prior revisions of this specification did not recognize the
return value of the provided script. In order to preserve legacy behavior,
the return value only influences the command if it is a "thenable" object or
if determining this produces an exception.

<li><p>If <a data-lt="ecmascript type">Type</a>(<var>scriptResult</var>.[[\Value]])
is not <a>Object</a>, then abort these steps.

<li><p>Let <var>then</var> be <a>Get</a>(<var>scriptResult</var>.[[\Value]], "then").

<li><p>If <var>then</var>.[[\Type]] is not <code>normal</code>, then <a>reject</a>
<var>promise</var> with value <var>then</var>.[[\Value]], and abort these steps.

<li><p>If <a>IsCallable</a>(<var>then</var>.[[\Type]]) is <code>false</code>,
then abort these steps.

<li><p>Let <var>scriptPromise</var> be <a>PromiseResolve</a>(<a>Promise</a>,
<var>scriptResult</var>.[[\Value]]).

<li><p>Upon fulfillment of <var>scriptPromise</var> with value <var>v</var>,
<a>resolve</a> <var>promise</var> with value <var>v</var>.

<li><p>Upon rejection of <var>scriptPromise</var> with value <var>r</var>,
<a>reject</a> <var>promise</var> with value <var>r</var>.
</ol>

<li><p>If <var>promise</var> is still pending and
<a>session script timeout</a> milliseconds is reached,
<a>reject</a> <var>promise</var> with <a>error</a> with
<a>error code</a> <a>script timeout</a>.
return <a>error</a> with <a>error code</a> <a>script timeout</a>.

<li><p>Upon fulfillment of <var>promise</var> with value <var>v</var>,
return <a>success</a> with data <var>v</var>.
let <var>result</var> be a <a>JSON clone</a> of <var>v</var>, and
return <a>success</a> with data <var>result</var>.

<li><p>Upon rejection of <var>promise</var> with reason <var>r</var>,
if <var>r</var> is an <a>error</a>, return <var>r</var>.
Otherwise, return <a>error</a> with <a>error code</a> <a>javascript error</a>
and data <var>r</var>.
let <var>result</var> be a <a>JSON clone</a> of <var>r</var>, and
return <a>error</a> with <a>error code</a> <a>javascript error</a>
and data <var>result</var>.
</ol>
</section> <!-- /Execute Async Script -->
</section> <!-- /Executing Script -->
Expand Down

0 comments on commit 6166c07

Please sign in to comment.