blob: cac4f7631fe42589cc856d5f79837c3c006dbccf [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package {
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.display.InteractiveObject;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.geom.Point;
import flash.text.TextField;
import flash.utils.Timer;
import mx.core.mx_internal;
import mx.utils.GetTimerUtil;
use namespace mx_internal;
/**
* Instead of a property, we use an event so the MXML compiler
* will compile the valueExpression string into ActionScript for us
*/
[Event(name="valueExpression", type="flash.events.Event")]
[DefaultProperty("value")]
/**
* The test step that fakes a sequence of mouse events that correspond to a drag or throw scroll.
*
* The default waitEvent is simulationComplete which fires after all mouse events have been fired.
* However when doing drag or throw scrolls you typically want to wait for the touchInteractionEnd
* event that fires after the scroll is completed and all related effects have completed
*
* TODO: Code review from Brian
*
* https://zerowing.corp.adobe.com/display/flexsdk/SimulateMouseGesture
*
* MXML attributes:
* target
* value (default property)
* recordedDPI
* dragXFrom
* dragYFrom
* dragXTo
* dragYTo
*/
public class SimulateMouseGesture extends TestStep
{
/**
* @private
*/
override public function execute(root:DisplayObject, context:UnitTester, testCase:TestCase, testResult:TestResult):Boolean
{
this.root = root;
this.context = context;
this.testCase = testCase;
this.testResult = testResult;
UnitTester.blockFocusEvents = false;
var actualTarget:Object = context.stringToObject(target);
if (!actualTarget)
{
testResult.doFail("Target " + target + " not found");
UnitTester.blockFocusEvents = true;
return false;
}
// make sure we have a wait target
if (waitTarget == null)
waitTarget = target;
// listen for when to finish this test step which is either
// after the given waitEvent, or if that isn't specified then
// after SIMULATION_COMPLETE which is fired after
// each event in the list is fired.
if (waitEvent == null)
waitEvent = TouchScrollingUtil.SIMULATION_COMPLETE;
// setup the waitEvent listener
trace("SimulateMouseGesture will wait for", waitEvent);
actualTarget.addEventListener(waitEvent, waitEventHandler);
// if this step defines a valueExpression then pull the events array from that
try
{
if (hasEventListener("valueExpression"))
{
context.resetValue();
dispatchEvent(new RunCodeEvent("valueExpression", root["document"], context, testCase, testResult));
value = context.value as Array;
if (!context.valueChanged)
TestOutput.logResult("WARNING: value was not set by valueExpression. 'value=' missing from expression?");
}
}
catch (e:Error)
{
TestOutput.logResult("Exception thrown evaluating value expression.");
testResult.doFail (e.getStackTrace());
return false;
}
try
{
// When no array of mouseEvents is provided then one is created based on dragXFrom/dragXTo/etc.
// This delay is the amount of fake time in between each of those generated events.
//
// This was once a default of 17, but was increased to 45 based on some changes Eric made
// I dont think I ever figured out why it was needed, but it doesn't really matter for this
// convenience case with no events array defined.
var delay:Number = 45;
// The dragXFrom/dragYFrom/dragXTo/dragYTo convenience properties are typed as Object
// so they can be expressed as an integer or as a percentage.
// If a percentage was requested then adjust these values by the width of the target
// TODO: Fix documentation on the convenience properties
var actualDragXFrom:Number = Number(dragXFrom);
var actualDragYFrom:Number = Number(dragYFrom);
var actualDragXTo:Number = Number(dragXTo);
var actualDragYTo:Number = Number(dragYTo);
// dragXFrom was not an obvious number so treat it as a percentage string
if (isNaN(actualDragXFrom))
actualDragXFrom = Math.round(actualTarget.width * getPercentage(dragXFrom));
// dragYFrom was not an obvious number so treat it as a percentage string
if (isNaN(actualDragYFrom))
actualDragYFrom = Math.round(actualTarget.height * getPercentage(dragYFrom));
// dragXTo was not an obvious number so treat it as a percentage string
if (isNaN(actualDragXTo))
actualDragXTo = Math.round(actualTarget.width * getPercentage(dragXTo));
// dragYTo was not an obvious number so treat it as a percentage string
if (isNaN(actualDragYTo))
actualDragYTo = Math.round(actualTarget.height * getPercentage(dragYTo));
// TouchScrollingUtil provides two ways of simulating an array of events. One is timer-based the other is frame-based.
// When running in Mustella we must use the frame-based option.
TouchScrollingUtil.simulateTouchScrollFrameBased(actualTarget, value, recordedDPI,
actualDragXFrom, actualDragYFrom, actualDragXTo, actualDragYTo, delay);
}
catch (e:Error)
{
TestOutput.logResult("Exception thrown in SimulateMouseGesture.");
testResult.doFail(e.getStackTrace());
}
UnitTester.blockFocusEvents = true;
// this test step always has a waitEvent so execute() should return false
return false;
}
/** TODO */
private function getPercentage(o:Object):Number
{
var s:String = String(o);
return Number((String(s)).split("%")[0]) / 100;
}
/**
* Call the normal stepComplete() and null out the value to avoid memory leaks.
*/
override protected function waitEventHandler(event:Event):void
{
// finish the test step
stepComplete();
// clean up the array
value = null;
}
/**
* The object that receives the event
*/
public var target:String;
/**
* The value to drag scroll from in the x direction.
*/
public var dragXFrom:Object = null;
/**
* The value to drag scroll from in the y direction.
*/
public var dragYFrom:Object = null;
/**
* The value to drag scroll to in the x direction.
*/
public var dragXTo:Object = null;
/**
* The value to drag scroll to in the y direction.
*/
public var dragYTo:Object = null;
/**
* An array of MouseEventEntry objects that represent a sequence of mouse events to dispatch.
* Use this for realistic simulation since you can control the sequence of, type, location,
* and time of each event.
*
* These events should be defined as an array of MouseEventEntry objects in this form:
*
* <MouseEventEntry type="mouseDown" localX="150" localY="150" fakeTimeValue="0" />
* <MouseEventEntry type="mouseMove" localX="149" localY="149" fakeTimeValue="16" />
* ...
* <MouseEventEntry type="mouseUp" localX="100" localY="100" fakeTimeValue="343" />
*
* If this property is not null then it takes precedence over any
* dragX/dragY values that might also be defined.
*
* This is the default property.
*/
public var value:Array = null;
/**
* When this value is set to something other than NaN then the localX/localY properties
* on each of the MouseEventEntry objects will get scaled by a dpi factor.
*
* That factor is the exact DPI of the running device divided by the exact value of the
* DPI that the sequence was recorded on.
*
* This allows this tag to simulate drags/throws over a physical distance (inches)
* rather than over a number of pixels.
*
* If you want the test to scroll the exact same number of pixels on every device it runs
* on (say 30 pixels) then don't set the recordedDPI property.
*
* If you want the test to scroll by a physical distance (say 1.5 inches) then set the recordedDPI
* to the value of Capabilities.screenDPI of the device you used to record/author this sequence
* of events.
*/
public var recordedDPI:Number = NaN;
/**
* customize string representation
*/
override public function toString():String
{
var s:String = "SimulateMouseGesture: target = ";
s += target;
if (value != null)
s += ", value = " + value.length + " MouseEventEntry";
else
s += ", value = null";
s += ", recordedDPI = " + recordedDPI;
s += ", dragXFrom = " + dragXFrom;
s += ", dragYFrom = " + dragYFrom;
s += ", dragXTo = " + dragXTo;
s += ", dragYTo = " + dragYTo;
return s;
}
}
}