+ When creating automated tests for your application or modules, you need + to be able to mock user events. The DOM supports creating native events + that behave essentially the same as user generated events, though + without the associated browser default behaviors (e.g. following a link + on click). +
+
+ The event-simulate module adds the Y.Event.simulate method for
+ working with raw DOM nodes, but for most cases, the
+ node-event-simulate module is the right choice, since it allows you
+ to call the simulate method directly from the Node.
+
Simulating Mouse Events
+ ++ There are seven mouse events that can be simulated: +
+ +-
+
click
+ dblclick
+ mousedown
+ mouseup
+ mouseover
+ mouseout
+ mousemove
+
+ Each event is fired by calling simulate() and passing in two
+ arguments: the type of event to fire and an optional object specifying
+ additional information for the event. To simulate a click on the document's
+ body element, for example, the following code can be used:
+
YUI().use('node-event-simulate', function(Y) {
+
+ Y.one("body").simulate("click");
+});
+
+
+
+ This code simulates a click with all of the default properties on the
+ event object. To specify additional information, such as the
+ Shift key being down, the second argument must be used and the exact DOM
+ name for the event property specified (there is browser-normalizing logic
+ that translates these into browser-specific properties when necessary):
+
Y.one("body").simulate("click", { shiftKey: true });
+
+
++ In this updated example, a click event is fired on the document's body + while simulating that the Shift key is down. +
+ ++ The extra properties to specify vary depending on the event being simulated + and are limited to this list: +
+ +-
+
detail
+ - + Indicates the number of times a button was clicked (DOM-compliant + browsers only). + + +
screenX,screenY
+ - + Coordinates of the mouse event in relation to the entire screen + (DOM-compliant browsers only). + + +
clientX,clientY
+ - + Coordinates of the mouse event in relation to the browser client + area. + + +
ctrlKey,altKey,shiftKey,metaKey
+ - + The state of the Ctrl, Alt, Shift, and Meta keys, respectively + (true for down, false for up). + + +
button
+ - + The button being used for the event, 0 for left (default), 1 for + right, 2 for center. + + +
relatedTarget
+ -
+ the element the mouse moved from (during a
mouseoverevent) or to + (during amouseoutevent). +
+
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 });
+});
+
+
+Simulating Key Events
+ +There are three key event simulations available:
+ +-
+
keyup
+ keydown
+ keypress
+
+ As with the mouse events, key events are simulated using
+ simulate(). For keyup and keydown,
+ the keyCode property must be specified; for
+ keypress, the charCode property must be included.
+ In many cases, keyCode and charCode may be the
+ same value to represent the same key (97, for instance, represents the
+ "A" key as well as being the ASCII code for the letter
+ "a"). For example:
+
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 });
+});
+
+
+
+ Key events also support the ctrlKey, altKey,
+ shiftKey, and metaKey event properties.
+
+ Note: 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
+ value property are not updated. These differences should go
+ away as browser support for simulated events improves in the future.
+
Simulating UI Events
+ +There are several UI event simulations available:
+ +-
+
blur
+ change
+ focus
+ resize
+ scroll
+ select
+
+ As with the other events, UI events are simulated using
+ simulate(). There are no properties that are required to
+ simulate UI events as these events don't carry extra information. Some
+ examples:
+
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");
+});
+
+
+Simulating Touch Gestures
+
+There are several high level gesture simulations primarily targeted for
+smartphones, tablets, and other touch-enabled devices. Single touch gestures
+such as tap and flick are simulated using Mouse Events on desktop or mobile
+devices where creating Touch Events are not supported. All gesture simulations
+are done by calling the simulateGesture() method against a Node instance. The
+method is asynchronous by default so an optional callback function can be
+passed.
+
-
+
tap
+ - + Single finger gesture to simulate a tap. Default is to simulate + one tap but it can be configured to simulate any number of taps. + + +
doubletap
+ - + Single finger gesture to simulate double taps. + + +
press
+ - + Single finger gesture to simulate a long press. + + +
move
+ - + Single finger gesture to simulate a move. It simulates moving + one finger straight in any direction. + + +
flick
+ - + Single finger gesture to simulate the flick gesture. It simulates + moving one finger with a certain velocity along either an X or Y + axis. + + +
pinch
+ - + Two finger gesture to simulate pinch and spread gestures. + + +
rotate
+ - + Two finger gesture to simulate a rotate. + +
+Gesture can be simulated by calling simulateGesture() and
+passing the following arguments: the name of the gesture to simulate, an
+optional object to define gesture properties, and an optional callback function.
+The available properties vary per gesture.
+
If the location of the finger is not given, the center of the node element is +used by default. This default behavior can be overridden by passing coordinates +into the optional object. The coordinate values are relative to the top/left +corner of the node element. +
+ +Single Touch Gestures: Tap, Double Tab and Press
+ ++The following code simulates tap, double tap and press gestures: +
+ +YUI().use('node-event-simulate', function(Y) {
+
+ var node = Y.one("#myElement");
+
+ //simulate tap gesture
+ node.simulateGesture("tap");
+
+ //simulate double-tap gesture
+ node.simulateGesture("doubletap");
+
+ //simulate press gesture
+ node.simulateGesture("press", {
+ hold: 3000 // press and hold for 3000ms
+ });
+
+ // simulate tap with options and callback
+ node.simulateGesture("tap", {
+ point: [30, 30], // tap (30, 30) relative to the top/left of the node
+ hold: 3000, // hold for 3sec in a tap
+ times: 2, // tap 2 times
+ delay: 500 // delay time before next tap starts
+ }, function() {
+ Y.log("I was called.");
+ });
+});
+
+Valid Options
+ +
+Optional properties for the tap gesture:
+
-
+
point
+ - + Indicates the [x,y] coordinates where the tap should be + simulated. Default is the center of the node element. + +
hold
+ -
+ The hold time in milliseconds. This is the time between
+
touchstartandtouchendevent generation. +
+ times
+ - + Indicates the number of taps. Default is 1. + +
delay
+ -
+ The number of milliseconds before the next tap simulation
+ happens. This is valid only when
timesis more than 1. +
+
+Optional properties for the doubletap gesture:
+
-
+
point
+ - + Indicates the [x, y] coordinates where the doubletap should be + simulated. Default is the center of the node element. + +
+The press gesture is essentially a single tap with the hold property
+defined. Optional properties for the press gesture:
+
-
+
point
+ - + Indicates the [x, y] coordinates where the tap should be + simulated. Default is the center of the node element. + +
hold
+ -
+ The hold time in milliseconds. This is the time between
+
touchstartandtouchendevent generation. +
+
Single Touch Gestures: Move and Flick
+ ++The following code can be used To simulate various gestures of moving one +finger: +
+ +YUI().use('node-event-simulate', function(Y) {
+
+ var node = Y.one("#myElement");
+
+ //simulate moving a finger 200 pixels along the x-axis
+ //to the right for one second (default)
+ node.simulateGesture("move");
+
+ //simulate moving a finger from the center of the node
+ //to a point 70 pixels to the right and 50 pixels down over 2000ms
+ node.simulateGesture("move", {
+ path: {
+ xdist: 70,
+ ydist: -50
+ } ,
+ duration: 2000
+ });
+
+ //simulate a flick to the right (default)
+ node.simulateGesture("flick");
+
+ //simulate a flick down 100 pixels over 50ms
+ node.simulateGesture("flick", {
+ axis: y
+ distance: -100
+ duration: 50
+ });
+
+});
+
+
+Valid Options
+ +
+Optional properties for the move gesture:
+
-
+
path
+ -
+ Indicates the path of the finger movement. It's an object with three
+ optional properties:
point,xdistandydist. Thepointis + the start point and defaults to the center of the node element. +xdistandydistindicate the distance moved in pixels along the + x- and y-axis. A negative distance value indicates moving to left + forxdistand down forydist. +
+ duration
+ - + The duration of the gesture in milliseconds. + +
+Optional properties for the flick gesture:
+
-
+
point
+ - + Indicates the [x, y] coordinates where the flick should be + simulated. Default is the center of the node element. + +
axis
+ - + Valid values are either "x" or "y". Indicates moving axis. The flick + moves in only 4 directions (left, right, up and down). + +
distance
+ - + Distance to move (in pixels). + +
duration
+ - + The duration of the gesture in milliseconds. This value may be + adjusted if it is below the minimum velocity to be a flick gesture. + +
Two Finger Gestures: Pinch and Rotate
+ +
+The pinch gesture is used to simulate the pinching and spreading of two
+fingers. During a pinch simulation, rotation is also possible. Essentially
+pinch and rotate simulations share the same base implementation to allow
+both pinching and rotation at the same time. The only difference is pinch
+requires start and end option properties while rotate requires rotation
+option property.
+
+The pinch and rotate gestures can be described as placing 2 fingers along a
+circle. Pinching and spreading can be described by start and end circles while
+rotation occurs on a single circle. If the radius of the start circle is greater
+than the end circle, the gesture becomes a pinch, otherwise it is a spread spread.
+
+The following code can be used to simulate two finger gestures: +
+ +YUI().use('node-event-simulate', function(Y) {
+
+ var node = Y.one("#myElement");
+
+ //simulate a pinch: "r1" and "r2" are required
+ node.simulateGesture("pinch", {
+ r1: 100, // start circle radius at the center of the node
+ r2: 50 // end circle radius at the center of the node
+ });
+
+ //simulate a spread: same as "pinch" gesture but r2>r1
+ node.simulateGesture("pinch", {
+ r1: 50,
+ r2: 100
+ });
+
+ //simulate rotating a node 75 degrees counter-clockwise
+ node.simulateGesture("rotate", {
+ rotation: -75
+ });
+
+ //simulate a pinch and a rotation at the same time.
+ //fingers start on a circle of radius 100 px, placed at top/bottom
+ //fingers end on a circle of radius 50px, placed at right/left
+ node.simulateGesture("pinch", {
+ r1: 100,
+ r2: 50,
+ start: 0
+ rotation: 90
+ });
+});
+
+Valid Options
+ +
+The optional properties available for pinch and rotate gestures are the
+same:
+
-
+
center
+ - + The center of the circle where the two fingers are placed. Default + is the center of the node element. + +
r1
+ -
+ Required for
pinchgestures but optional forrotate. Pixel radius + of the start circle. If omitted inrotategestures, default is + a fourth of the node element width or height, whichever is smaller. +
+ r2
+ -
+ Required for
pinchgestures but optional forrotategestures. + Pixel radius of the end circle. If omitted inrotategestures, + default is a fourth of the node element width or height, whichever + is smaller. +
+ duration
+ - + The duration of the gesture in milliseconds. + +
start
+ - + Start degree of the first finger for the rotation gesture. Default + is 0 (i.e., 12:00 on a clock). + +
rotation
+ - + Degrees to rotate from the start degree. Negative value means + rotation of counter-clockwise direction. + +
Gesture Simulation on iOS
+
+If the gesture simulation is called in iOS, it generates not only touch events
+but also
+iOS specific gesture events: gesturestart, gesturechange
+and gestureend.
+
Customizing Default Gesture Properties
+ +
+You can define custom default behaviors for gesture simulations by modifying the
+following Y.GestureSimulation.defaults object properties:
+
-
+
- HOLD_TAP +
- DELAY_TAP +
- HOLD_PRESS +
- MIN_HOLD_PRESS +
- MAX_HOLD_PRESS +
- DISTANCE_MOVE +
- DURATION_MOVE +
- MAX_DURATION_MOVE +
- MIN_VELOCITY_FLICK +
- DISTANCE_FLICK +
- DURATION_FLICK +
- MAX_DURATION_FLICK +
- DURATION_PINCH +
+And an example: +
+ +YUI().use('node-event-simulate', function(Y) {
+
+ var node = Y.one("#myElement");
+
+ Y.GestureSimulation.defaults = Y.merge(Y.GestureSimulation.defaults, {
+ HOLD_TAP: 3000
+ });
+
+ //now touchend event will be generated after 3 sec from the touchstart
+ //event generation.
+ node.simulateGesture("tap");
+});
+
+
+Caveats and Coming Soons
+ +Don't use simulation in user facing code
+ ++ Event simulation is for automated testing. Your application should respond + to real user events. For reasons + mentioned below, it can be easy to get + your application into a confused runtime state when some callbacks have + been executed but not others. +
+ ++ 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. +
+ ++ 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 custom events, instead. +
+ ++ 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. +
+ +Only what you ask for
+ +
+ 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, the
+ other events will NOT be generated for free.
+
+ 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.
+
No synthetic event simulation yet
+ ++ The Synthetic event system 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. +
+ ++ Support for synthetic event simulation is on the roadmap. +
+