simulate.mustache revision 5d3dc0444c51f18e44c016a89b16a8951529518c
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai<div class="intro">
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai <p>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai When creating automated tests for your application or modules, you need
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai to be able to mock user events. The DOM supports creating native events
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai that behave essentially the same as user generated events, though
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai without the associated browser default behaviors (e.g. following a link
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai on click).
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai </p>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai <p>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai The `event-simulate` module adds the `Y.Event.simulate` method for
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai working with raw DOM nodes, but for most cases, the
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai `node-event-simulate` module is the right choice, since it allows you
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai to call the `simulate` method directly from the `Node`.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai </p>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai</div>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai<h2>Simulating Mouse Events</h2>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai<p>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai There are seven mouse events that can be simulated:
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai</p>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
d62bc4badc1c1f1549c961cfb8b420e650e1272byz<ul>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai <li>`click`</li>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai <li>`dblclick`</li>
bb25c06cca41ca78e5fb87fbb8e81d55beb18c95jg <li>`mousedown`</li>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai <li>`mouseup`</li>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai <li>`mouseover`</li>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai <li>`mouseout`</li>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai <li>`mousemove`</li>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai</ul>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai<p>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai Each event is fired by calling <code>simulate()</code> and passing in two
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai arguments: the type of event to fire and an optional object specifying
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai additional information for the event. To simulate a click on the document's
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai body element, for example, the following code can be used:
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai</p>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai```
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaiYUI().use('node-event-simulate', function(Y) {
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai Y.one("body").simulate("click");
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai});
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai```
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai<p>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai This code simulates a click with all of the default properties on the
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai <code>event</code> object. To specify additional information, such as the
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai Shift key being down, the second argument must be used and the exact DOM
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai name for the event property specified (there is browser-normalizing logic
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai that translates these into browser-specific properties when necessary):
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai</p>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai```
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaiY.one("body").simulate("click", { shiftKey: true });
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai```
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai<p>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai In this updated example, a click event is fired on the document's body
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai while simulating that the Shift key is down.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai</p>
bb25c06cca41ca78e5fb87fbb8e81d55beb18c95jg
d62bc4badc1c1f1549c961cfb8b420e650e1272byz<p>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai The extra properties to specify vary depending on the event being simulated
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai and are limited to this list:
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai</p>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai<dl>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai <dt>`detail`</dt>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai <dd>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai Indicates the number of times a button was clicked (DOM-compliant
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai browsers only).
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai </dd>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai <dt>`screenX`, `screenY`</dt>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai <dd>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai Coordinates of the mouse event in relation to the entire screen
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai (DOM-compliant browsers only).
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai </dd>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai <dt>`clientX`, `clientY`</dt>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai <dd>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai Coordinates of the mouse event in relation to the browser client
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai area.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai </dd>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai <dt>`ctrlKey`, `altKey`, `shiftKey`, `metaKey`</dt>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai <dd>
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai The state of the Ctrl, Alt, Shift, and Meta keys, respectively
(true for down, false for up).
</dd>
<dt>`button`</dt>
<dd>
The button being used for the event, 0 for left (default), 1 for
right, 2 for center.
</dd>
<dt>`relatedTarget`</dt>
<dd>
the element the mouse moved from (during a `mouseover` event) or to
(during a `mouseout` event).
</dd>
</dl>
```
YUI().use('node-event-simulate', function(Y) {
var node = Y.one("#myDiv");
//simulate a click Alt key down
node.simulate("click", { altKey: true});
//simulate a double click with Ctrl key down
node.simulate("dblclick", { ctrlKey: true });
//simulate a mouse over
node.simulate("mouseover", { relatedTarget: document.body });
//simulate a mouse out
node.simulate("mouseout", { relatedTarget: document.body });
//simulate a mouse down at point (100,100) in the client area
node.simulate("mousedown", { clientX: 100, clientY: 100 });
//simulate a mouse up at point (100,100) in the client area
node.simulate("mouseup", { clientX: 100, clientY: 100 });
//simulate a mouse move at point (200, 200) in the client area
node.simulate("mousemove", { clientX: 200, clientY: 200 });
});
```
<h2>Simulating Key Events</h2>
<p>There are three key event simulations available:</p>
<ul>
<li>`keyup`</li>
<li>`keydown`</li>
<li>`keypress`</li>
</ul>
<p>
As with the mouse events, key events are simulated using
<code>simulate()</code>. For <code>keyup</code> and <code>keydown</code>,
the <code>keyCode</code> property must be specified; for
<code>keypress</code>, the <code>charCode</code> property must be included.
In many cases, <code>keyCode</code> and <code>charCode</code> may be the
same value to represent the same key (97, for instance, represents the
&quot;A&quot; key as well as being the ASCII code for the letter
&quot;a&quot;). For example:
</p>
```
YUI().use('node-event-simulate', function(Y) {
var node = Y.one("#myDiv");
//simulate a keydown on the A key
node.simulate("keydown", { keyCode: 97 });
//simulate a keyup on the A key
node.simulate("keyup", { keyCode: 97 });
//simulate typing "a"
node.simulate("keypress", { charCode: 97 });
});
```
<p>
Key events also support the <code>ctrlKey</code>, <code>altKey</code>,
<code>shiftKey</code>, and <code>metaKey</code> event properties.
</p>
<p>
<strong>Note:</strong> Due to differences in browser implementations, key
events may not be simulated in the same manner across all browsers. For
instance, when simulating a keypress event on a textbox, only Firefox will
update the textbox with the new character of the key that was simulated to
be pressed. For other browsers, the events are still registered and all
event handlers are called, however, the textbox display and
<code>value</code> property are not updated. These differences should go
away as browser support for simulated events improves in the future.
</p>
<h2>Simulating UI Events</h2>
<p>There are several UI event simulations available:</p>
<ul>
<li>`blur`</li>
<li>`change`</li>
<li>`focus`</li>
<li>`resize`</li>
<li>`scroll`</li>
<li>`select`</li>
</ul>
<p>
As with the other events, UI events are simulated using
<code>simulate()</code>. There are no properties that are required to
simulate UI events as these events don't carry extra information. Some
examples:
</p>
```
YUI().use('node-event-simulate', function(Y) {
var node = Y.one("#myInput");
//simulate a change event
node.simulate("change");
//simulate a select event
node.simulate("select");
});
```
<h2>Caveats and Coming Soons</h2>
<h3 id="faking">Don't use simulation in user facing code</h3>
<p>
Event simulation is for automated testing. Your application should respond
to real user events. For reasons
<a href="#only-what-you-ask-for">mentioned below</a>, it can be easy to get
your application into a confused runtime state when some callbacks have
been executed but not others.
</p>
<p>
Typically, event simulation is sought to trigger certain callbacks. If a
function needs to respond to user action or be called programmatically, it
should be written accordingly and called directly in the latter case.
Often a better solution is to extract the core logic from the event handler
into a separate function and call that method from the event handler and
from the other part of the application that was going to use simulation.
</p>
<p>
In some cases, simulation is wanted because there may be any number of
subscriptions on a node, and all applicable callbacks should be triggered.
If this is the case, investigate using <a
href="../event-custom/index.html">custom events</a>, instead.
</p>
<p>
The bottom line is, reliance on event simulation in production code is a
warning sign that the architecture is not scaling. The affected code
should be refactored before it becomes a larger problem.
</p>
<h3>Only what you ask for</h3>
<p>
In many cases, events happen in groups (`mousedown`, `mouseup`, `click`, or
`keydown`, `keyup`, `keypress`). If you simulate an event that is
typically part of a group or is often followed by other events, <em>the
other events will NOT be generated</em> for free.
</p>
<p>
For example, if you simulate a `click` event on a submit button, you only
simulate the `click` event. The preceding `mousedown` and `mouseup`, as
well as the subsequently expected 'submit' are neither simulated or fired
natively.
</p>
<h3>No touch events yet</h3>
<p>
Currently, there's no support for simulating touch events or other events
not noted explicitly above.
</p>
<h3>No synthetic event simulation yet</h3>
<p>
The <a href="synths.html">Synthetic event system</a> doesn't yet support
defining simulation. In most cases, though, synthetic events are triggered
by other DOM events that can be simulated, so it's often possible to
trigger them by simulating the underlying events. But that ignores the
point that synthetic events are supposed to mask that abstraction for your
benefit.
</p>
<p>
Support for synthetic event simulation is on the roadmap.
</p>