Scenarios reference
===================

A Scenario is a JavaScript file containing a hash whose enclosing curly braces will be automatically added and containing two keys: `description` and `scenario`.


File naming
-----------

Scenario files have to start with a numerical (positive integer) index, and end with `Scenario.js`.

Prefix indices are needed for Watai to determine dependencies. Currently, there is no support for complex dependencies, so your test suite has to be a linear scenario. To make that scenario explicit, scenario filenames have to be prefixed with their index.

Indices don't have to be continuous, i.e. you may have scenarios 1, 2, 3 and 5.

### Best practice ###

Separate the names of your scenarios from their prefixes with a dash, such as `1 - LoginScenario.js`, `2 - LogoutScenario.js`.

You can quickly exclude a scenario from being evaluated by renaming it to something like `(pending) 4 - FixTheWorldScenario.js`.

> If you just want to ignore some scenarios for a run, see the [[`ignore` option|Configuration#wiki-ignore]].


Description
-----------

The description of a scenario is a String. It is a human-readable description of the expected behavior the scenario is testing.


Steps
-----

A scenario is made of an array of **steps**, stored in the `steps` key. You can define as many steps in a scenario as you want.


### Action step ###

Any Component action (functions defined in components) may be referenced as a step.

These functions have to be called, just like you would any JavaScript code.


#### Example ####

```javascript
// SearchBarComponent.js
field:        'input[name=q]',
submitButton: '#search_button_homepage',
searchFor: function searchFor(term) {
    return this.setField(term)()
               .then(this.submit());
}
```
```javascript
// in `1 - SearchScenario.js`
description: 'Search for something',
steps: [
    SearchBarComponent.searchFor('something')
]
```

This is strictly equivalent to:

```javascript
// SearchBarComponent.js
field:        'input[name=q]',
submitButton: '#search_button_homepage'
```
```javascript
// in `1 - SearchScenario.js`
description: 'Search for something',
steps: [
    SearchBarComponent.setField('something'),
    SearchBarComponent.submit()
]
```

The difference is that in the first case, the component offers an **action** and hides its implementation details, making the scenario higher level.

The choice of granularity and repartition between component actions and scenario steps is up to you, but it should follow the same rules as any object model: semantics win. In our example, a search bar component's main use is to allow searching, not to enter some text in a field, so searching is probably the action your users will want to be doing with it, and thus that's what you'll be testing.

> Even though it looks like you're calling the action directly, it is just syntactic sugar through a [partial application](http://en.wikipedia.org/wiki/Partial_application). The actions are actually wrapped, and their return value is a promise-returning function of arity 0, ready to be chained with other steps.
> The reason for this trick is that the WebDriver context is not yet available when scenarios are parsed. Components prepare your actions so that you may call them in scenarios, but calling them here only binds the actual action to the given arguments.


### State description step ###

A **state description** is a JavaScript object listing component elements and their corresponding expected value.

```javascript
steps: [
    {   // this hash is a state description step
        'ZeroClickComponent.header': 'Meanings of ' + lookupTerm,
        'ZeroClickComponent.header': true
    }
]
```

Any hash in a scenario will be interpreted as a state description. Each key/value pair is called a **state descriptor**.


#### Keys ####

State descriptors have **element selectors** as keys. That is, a String that selects an element inside an existing component.

```javascript
// in MyComponent.js
myField: '#field',
// …
```

The corresponding state descriptor key is `'MyComponent.myField'`.

Remember that keys have to be strings and, as they contain dots, will need to be quoted for the JavaScript parser to allow them.


#### Values ####

Values of state descriptors may be one of the following:

- A String against which the textual content (or the `value` attribute for inputs) will be matched (exact match).
```javascript
    {
        'ZeroClickComponent.header': 'Meanings of ' + lookupTerm
    }
```

- A RegExp against which the textual content (or the `value` attribute for inputs) will be matched.
```javascript
    {
        'ZeroClickComponent.header': /Meanings of/,  // match the textual content with a static regexp…
        'ZeroClickComponent.header': new RegExp(lookupTerm + '$')  // …or with a dynamic one
    }
```

- A Boolean defining mandatory presence (`true`) or mandatory absence (`false`) from the user-visible DOM.
```javascript
    {
        'ZeroClickComponent.header': true  // prove that the element exists
    }
```

- A Function that may implement any logic and throw to reject the match. The function will be called with a reference to the element referenced by its key, as a `wd` object, on which all of [`wd`'s API](https://github.com/admc/wd#supported-methods) is made available. Node's [assert](http://nodejs.org/api/assert.html) default library is also injected, so you can use it instead of `throw`ing yourself.
> A custom function may also return a promise, whose fulfilment state will be honored.
```javascript
    {
        // providing a good name (i.e. prefixed with `is`, `has`…) for the function will allow for better reports
        'ZeroClickComponent.header': function isAlwaysValid(header) {
            assert.ok(true, 'This is always valid');
        },
        'SearchBarComponent.field': function hasNoAutocompletion(searchField) {
            return searchField.getAttribute('autocomplete')  // note that if you're using a promise, you should **always** `return` from it
                    .then(function(attribute) {  // a promise-returning matcher will be evaluated based on whether it was resolved or rejected
                        assert.equal(attribute, 'off', 'Expected autocompletion to be off');
                    });
        }
    }
```

_You can see all of these descriptors in their full executable context in the [DuckDuckGo advanced matchers example](https://github.com/MattiSG/Watai/tree/master/example/DuckDuckGo%20-%20advanced%20matchers)._

#### Options ####

State descriptions may define the `timeout` option to specify how long to wait at most for a match in a specific state assertion, overriding the [[config|Configuration]]-given timeout for the suite.

```javascript
// in `1 - CorrectionScenario.js`
description: 'Text typed in a field should be corrected asynchronously',
steps: [
    TextInputComponent.type('somethign'),
    TextInputComponent.correct(),
    {
        timeout: 20000, // correction could be very long
        'TextInputComponent.textarea': 'something'
    }
]
```


### Custom function ###

You can also reference any custom function, either defined inline or referenced from a Fixture file, as a scenario step.

Such a function can either be synchronous, or return a promise for async execution.

```javascript
// ClockScenario.js
// ...
    ClockComponent.lookup(clockLookupTown),
    function hasExpectedTimeDiff() {
        return ClockComponent.getCurrentHour()()
                          .then(function(hour) {
                            assert.equal(hour, previousHour - 1);
                          });
    }
// ...
```

By contrast with action steps, custom functions must not be called directly.
