Changes between Version 10 and Version 11 of Writing Layout Tests to test iOS UI features


Ignore:
Timestamp:
Oct 11, 2015 6:47:11 PM (8 years ago)
Author:
dbates@webkit.org
Comment:

Fix typos and make the content read well.

Legend:

Unmodified
Added
Removed
Modified
  • Writing Layout Tests to test iOS UI features

    v10 v11  
    33It's now possible to write layout tests that exercise code in the UI process in iOS WebKit2. This allows testing of things like tapping, zooming, keyboard interaction, selection, text input etc.
    44
    5 This is done by running JavaScript in an isolated JS context in the UI process form a test. That JavaScript has access to a UIScriptController, which has properties that expose information about the state of the UI process,. and functions to make things happen, including event synthesis.
     5This is done by running JavaScript in an isolated JS context in the UI process from a test. That JavaScript has access to a UIScriptController, which has properties that expose information about the state of the UI process and functions to make things happen, including event synthesis.
    66
    77The UI script itself runs asynchronously, and many of the UIScriptController functions are asynchronous. Callbacks are used to tell the test when something completes.
     
    4949}}}
    5050
    51 so we can use this in our test in some script that would run from the onload handler:
     51We can call this from our test inside some <script> that would run from the onload handler:
    5252{{{
    5353<script>
     
    5757    if (testRunner.runUIScript) {
    5858        testRunner.runUIScript("...", function(result) {
    59             document.getElementById('result').innerText = result;
     59            document.getElementById("result").innerText = result;
    6060            testRunner.notifyDone();
    6161        });
     
    6666}}}
    6767
    68 The script passed in to runUIScript() is just a string. You can pass a string literal here, or, for longer scripts make script tag and get its content as text:
     68The script passed into runUIScript() is just a string. You can pass a string literal here or, for longer scripts, make a script tag and get its content as text:
    6969{{{
    7070<script id="ui-script" type="text/plain">
     
    8282}}}
    8383
    84 So, what script can you run in the UI process? This UI-side script runs in a separate JS context that has no access to the DOM, no timers, no requestAnimationFrame, no XHR etc. What it can do is run vanilla JavaScript, and access properties and functions on [https://trac.webkit.org/browser/trunk/Tools/WebKitTestRunner/UIScriptContext/Bindings/UIScriptController.idl UIScriptController], which is exposed as uiController. Here's a simple example, using function-like syntax for the inline script, that returns zoom scale:
     84So, what script can you run in the UI process? This UI-side script runs in a separate JS context that has no access to the DOM, no timers, no requestAnimationFrame(), no XHR etc. What it can do is run vanilla JavaScript, and access properties and functions on [https://trac.webkit.org/browser/trunk/Tools/WebKitTestRunner/UIScriptContext/Bindings/UIScriptController.idl UIScriptController], which is exposed as uiController. Here's a simple example, using function-like syntax for the inline script, that returns zoom scale:
    8585
    8686{{{
     
    9696= UIScriptController functions =
    9797
    98 UIScriptController is the mechanism for driving behavior in the UI process, and to accessing UI state. Many of the functions will trigger UI behaviors that take time (e.g. a zoom animation, or bringing up the keyboard). Rather than blocking, these functions take a callback that is triggered in the UI script context when that operation is complete:
     98UIScriptController is the mechanism for driving behavior in the UI process and to accessing UI state. Many of the functions will trigger UI behaviors that take time (e.g. a zoom animation, or bringing up the keyboard). Rather than blocking, these functions take a callback that is triggered in the UI script context when that operation is complete:
    9999
    100100{{{
     
    108108Note that this console.log() won't show in layout test output, since it's being generated in the UI process (but it will be logged if you run WebkitTestRunner directly, which is useful for debugging).
    109109
    110 However, the web process needs to be told that the UI script is complete, so when your test has finished doing work in the UI process, it should call uiScriptComplete(), passing the result:
     110Also, the web process usually needs to be told that the UI script completed (see below for more details). So, when your test has finished doing work in the UI process, it should call uiScriptComplete(), passing the result:
    111111
    112112{{{
     
    130130}}}
    131131
    132 UIScriptController also supports sending key events. However, the keyboard must first be shown for the key events to be properly handled. First, your UI-side script must perform some action that will cause the keyboard to be shown. Your script must then bind uiController.didShowKeyboardCallback to a function which is invoked after the keyboard is shown and is ready to accept key inputs. This callback should call one of the typeCharacter methods (currently, there is only typeCharacterUsingHardwareKeyboard, but we intend on supporting software key events as well). In the below example, suppose that tapping at (50, 25) touches an input element.
     132UIScriptController also supports sending key events. However, the keyboard must first be shown for the key events to be properly handled. First, your UI-side script must perform some action that will cause the keyboard to be shown. Your script must then bind uiController.didShowKeyboardCallback to a function which is invoked after the keyboard is shown and is ready to accept key inputs. This callback should call one of the typeCharacter methods (currently, there is only typeCharacterUsingHardwareKeyboard, but we intend on supporting software key events as well). In the below example, suppose that tapping at (50, 25) touches a HTML input element.
    133133
    134134{{{
    135135(function() {
    136     uiController.singleTapAtPoint(50, 25, function() { });
     136    uiController.singleTapAtPoint(50, 25, function() { ... });
    137137    uiController.didShowKeyboardCallback = function() {
    138         uiController.typeCharacterUsingHardwareKeyboard("a", function() { });
     138        uiController.typeCharacterUsingHardwareKeyboard("a", function() { ... });
    139139    }
    140140})();
    141141}}}
    142142
    143 Observe that we didn't call uiController.uiScriptComplete. This is because when the key event is handled by the UI process, there is no guarantee that the web process has received the resulting editing event, so the value of the element may not be updated. Instead of waiting on the UI-side script to complete, we can instead invoke testRunner.notifyDone when the element itself has received an oninput event.
     143Observe that we didn't call uiController.uiScriptComplete(). This is because when the key event is handled by the UI process, there is no guarantee that the web process has received the resulting editing event, so the value of the element may not be updated. Instead of waiting on the UI-side script to complete, we can instead invoke testRunner.notifyDone() when the element itself has received a event to its oninput handler.
    144144
    145 If your UI-side script is very simple and only accesses uiController properties, then it doesn't need to call uiScriptComplete(). If you call any uiController functions that are asynchronous (i.e. take a callback), then you need to call uiScriptComplete() at some point unless you are waiting to invoke testRunner.notifyDone from the web process.
     145If your UI-side script is very simple and only accesses uiController properties, then it doesn't need to call uiScriptComplete(). If you call any uiController functions that are asynchronous (i.e. take a callback), then you need to call uiScriptComplete() at some point unless you are waiting to invoke testRunner.notifyDone() from the web process.
    146146
    147147You can chain as many asynchronous things as you like in the UI-side script, as long as you call uiScriptComplete() when the chain is complete. You can also call testRunner.runUIScript() as many times as you like from the test content, making it possible to test a long sequence of operations that bounce between the UI process and the web process.