Using the event recorder
========================

Event recorder is a component of Siesta, that records the user actions, and then generates a corresponding Siesta {@link Siesta.Test#chain chain} call.

For example, when user click some DOM element, a corresponding `{ click : '.selector' }` action will be recorded, containing
a selector, for the element clicked.  

Siesta always tries to find the shortest and most stable selector, uniquely identifying the target element of the action.
Be aware however, that if you change the markup of your application, the selectors inside the test should be updated too.  


Setup
------

In this guide, we'll be using the sample React application [Google Fonts Space](https://github.com/pankajladhar/GFontsSpace) 
It is bundled in the Siesta examples in the directory `examples-browser/react-google-fonts-space`.

To complete the setup of the example, run in the console, inside the example folder:

    > npm install
    
And then to launch the server-side part of the example:

    > npm start-siesta

This should open a Chrome window, pointing to application - `http://localhost:3000/`. Siesta web interface will be available at `http://localhost:3000/siesta.html`


The event recorder interface
---------

To activate the recorder in the Siesta web interface, click the video camera button in the top-right toolbar.

{@img images/recorder1.png}

In the top left, the buttons are quite self explanatory: `Record`, `Stop`, `Play`, `Clear actions` and `Add action`. 
In the top right section, there are `Show source` and `Close` buttons.

The grid has 3 columns:

* The 'Action' column is the type of action.
* The 'Target/Value' column contains the either the target of a UI action, the value
(when typing text) or source code for the special function step.
* The 'Offset' column allows you to set an offset for your action allowing you to click at a precise point inside your target.


Recording user actions
----------------

Recorder operates in two modes - recording of the web page, and recording of the Siesta test.

### Recording actions from the web page

To record actions on the web page, you need to place Siesta web interface on the same host (and port) as the page itself. 
This is because Siesta is limited by the same-origin policy enforced by all web browsers.

Alternatively, you can disable web-security and same-origin policy, by launching Chrome with special options, 
as described in <a href="#!/guide/cross_page_testing">this guide</a> 

In our case, both the Siesta web interface and the page are available on `http://localhost:3000`, so everything is fine.

So, we open the Siesta web interface at `http://localhost:3000/siesta.html`, hit the recorder button and type the URL of the target page into the `Page URL` field:
`http://localhost:3000`

{@img images/pageUrlField.png autogen}

Hit ENTER in that field, and the web page will (re)loads in the DOM view. You should see something like this:  

{@img images/siesta-web-interface.jpg}

Now hit the `Record` button and start interacting with the web page normally,
using mouse and keyboard. You will see the action entries show up in the recorder grid. Once you are done, hit `Record` again, to stop recording. 

After recording, ensure that the test case does what you expect by replaying it with the `Play` button. The web page will be reloaded
and the recorded user actions will be replayed on it. 

To avoid having one huge flat list of actions, you can also group actions together in "sub-tests" sections, by marking them and right clicking 
to enter the name of the group. We recommend to create logical groups in the recorded tests, to make the whole test easier to maintain.
 
Once you are happy with the result you can click the "Show source" to get the test source. Then you can create a new test file and paste the content into it. 

For example we've recorded a sample scenario, of typing two different strings "Something" and "Something else" in different colors.

```javascript
describe("New recording...", function(t) {
    t.it("First text box", function(t) {
        t.chain(
            { click : "#root textarea" },

            { type : "S", target : "#root textarea", options : { shiftKey : true, readableKey : "S", key : "S" } },

            { type : "omething", target : "#root textarea" },

            { click : "#root .ColorOption__ForeGround .ColorPicker__Color" },

            { click : "#root [title='\#D0021B']" },
            
            { click : "#root :textEquals(Compare)" }
        );
    });

    t.it("Second text box", function(t) {
        t.chain(
            { click : "#root .TextBoxContainer > div:nth-of-type(2) textarea" },

            { type : "S", target : "#root .isActive textarea", options : { shiftKey : true, readableKey : "S", key : "S" } },

            { type : "omething ese[BACKSPACE][BACKSPACE]lse", target : "#root .isActive textarea" },

            { click : "#root .ColorOption__ForeGround .ColorPicker__Color" },

            { click : "#root [title='\#BD10E0']" }
        );
    });
});
```

We can place it as a new test `compare.t.js` test in the `/src/tests/blackbox-app` folder. We'll also need to add a test descriptor 
to the Siesta project plan:

```javascript
{
    group       : 'Black box tests',

    pageUrl     : 'index.html',

    items       : [
        ...
        './TRANSPILED/src/tests/blackbox-app/compare.t.js'
    ]
}
```

### Recording actions from the Siesta test

This is very similar to testing a web page, but instead of loading a page - the test code will create a page to interact with.
 
So, first write some code in the test, which will produce the web page you want to interact with:

```javascript
    describe('Test case name', t => {
        document.body.innerHTML = '<input type="text">'
    });
```

Then, run that test in the web interface, to execute the code and receive the desired state of the test page. Now you can record actions on 
the created page as described in the previous section, just don't enter anything in the `Page URL` field and click `Record` right away.


Recorder configuration
----------------

Recorder has various configuration options, listed in {@link Siesta.Recorder.Recorder} class. To specify these options, use the
{@link Siesta.Project.Browser#recorderConfig recorderConfig} option of the Siesta browser project, there's also {@link Siesta.Project.Browser#recorderClass recorderClass}:

```javascript
project.configure({
    ...
    
    recorderConfig : {
        recordInitialWindowSize        : true
    }
});

```


Editing the target locator
---------

All fields in the recorder grid are editable, so it's easy to adjust the values inline. Clicking a `Target` cell allows you to either choose one of
the alternatives gathered by the recorder, or you can type any value you like. As you type, Siesta will try to highlight the target. 

{@img images/editing_target.png autogen}


Race conditions. Waiting for asynchronous operations
---------

As you will see, just recording some clicks on the screen and playing them back, sometimes won't work. 
This is because user interface usually contains asynchronous behavior, which takes undetermined amount of time. 

Let's say the test scenario is to click a button to load a client list into some `<div>`. After the data is fetched, we want to assert 
that the list is updated correctly and contains some text. The recorded script will look just

    // Start loading data
    { click : "input[value=Load data]" },
    
    { click : "..." },


We insert a function step, to verify that text `Client A` has appeared inside the `#client_list` element: 

```javascript
StartTest(t => {
    document.body.innerHTML = '<div id="client_list"></div>'
        + '<input id="button" type="button" value="Load data" />'


    document.getElementById('button').addEventListener('click', () => {
        // fetch new data - this takes undetermined time
        fetch('http://server/customers/get').then(() => {
            // update the UI with new data
        });
    });

    t.chain(
        // Start loading data
        { click : 'input[value="Load data"]' },
        
        next => {
            t.contentLike(document.getElementById('client_list'), 'Client A')
        },
        
        ...
    )        
});
```

But this test will be failing, because, most probably the data fetch will be taking some time, but the next step in chain will be executed immediately,
without taking in-progress actions into account.

Better and more robust solution would be to use the {@link Siesta.Test.Browser#waitForContentLike waitForContentLike} assertion method.
It waits for condition we exactly need - until the content of the given DOM element matches some string. In fact, we don't even need
a function step for this:

```javascript
// Start loading data
{ click : "input[value=Load data]" },

{ waitFor : 'ContentLike', args : [ '#client_list', 'Client A' ] }
```

You can wait for arbitrary condition, with the {@link Siesta.Test#waitFor waitFor} test class method. 
Using "waitFor" in the chain described here: {@link Siesta.Test.Action.Wait}.

Now the test will be robust, as it will be waiting for the asynchronous action to complete. It does not matter whether the data fetching 
will take 10ms or 10000ms to complete. However, all waiting actions are supposed to complete
within {@link Siesta.Project#waitForTimeout waitForTimeout} time, to avoid stucking.

Waiting actions can be added in the Recorder UI too. Click the '+' button to add the new action, then use a drop-down in the `Action` cell.


The function step
---------

As you interact with your application UI you most likely want to verify some assertions along the way or execute some arbitrary code. 
While this is easier to do add in your own IDE, we've added a simple code editor to the recorder too, which allows you to create
a function step in the scenario - which will just execute that function. 

To add such step, click the cell in the `Action` column, select the `fn` action in the list and hit `TAB`. Now we can execute any JS code, 
and use {@link Siesta.Test} assertion methods.


Recording a move-cursor-to step
---------

Sometimes you want to just move the cursor to certain place on the screen without doing any further action. Since the recorder doesn't record every
mouse movement, there is a special way to signal to Siesta that you want to move the cursor somewhere. 

Move the mouse to where it should be and leave it for 3 seconds, you'll then see a **moveCursorTo** action added to the list. 

This is useful in lots of scenarios, for example when triggering a menu item to show. You cannot click the menu item right away, 
since it's hidden until you move the cursor over the menu header.


Getting the generated source code
---------

When you are done with your recording actions, hit the `Show source` button and copy-paste the contents into your test file. That is all it takes
to generate a test.

{@img images/recorder_generated_code.png autogen}


Buy this product
---------

Visit our store: <https://bryntum.com/store/siesta>


Support
---------

Ask question in our community forum: <https://www.bryntum.com/forum/viewforum.php?f=20>

Subscribers can post expedited questions in Premium Forum: <https://www.bryntum.com/forum/viewforum.php?f=21>

Please report any bugs through the web interface at <https://www.assembla.com/spaces/bryntum/support/tickets>


See also
---------

Siesta web-page: <https://bryntum.com/products/siesta>

Other Bryntum products: <https://bryntum.com/products>


COPYRIGHT AND LICENSE
---------

Copyright (c) 2009-2018, Bryntum & Nickolay Platonov

All rights reserved.