// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. module AnimationVerifier { "use strict"; export var rectBefore = null; export var rectAfter = null; export function VerifyEachElementStatusChange(f) { /// /// Verify each element using the client rectangle before and after the animation/transition. /// /// /// When verifing translate or scale animations, the input parameters could be either single element or an array of elements. /// This function is used to avoid dupication of code by saying if it is an array, we'll check each element by going through a loop. /// If it is a single element, just check this one. The verification needs the client rectangle of the DOM element(s) /// before and after the animation/transition. /// /// function compareDouble(d1, d2, precision) { if (Math.abs(d1 - d2) <= precision) { return true; } else { return false; } } var ret = true; if (Array.isArray(AnimationVerifier.rectBefore)) { if (AnimationVerifier.rectBefore.length !== AnimationVerifier.rectAfter.length) { ret = false; } else { for (var i = 0; ret && i < AnimationVerifier.rectBefore.length; i++) { ret = f(AnimationVerifier.rectBefore[i], AnimationVerifier.rectAfter[i], compareDouble); } } } else { ret = f(AnimationVerifier.rectBefore, AnimationVerifier.rectAfter, compareDouble); } return ret; } export function VerifyCoordinateTransitionInProgress(startX, startY, destX, destY, currX, currY) { /// /// Verify translation mid-animations state /// /// /// Specifies the starting x-coordinate /// /// /// Specifies the starting y-coordinate /// /// /// Specifies the destination x-coordinate /// /// /// Specifies the destination y-coordinate /// /// /// Specifies the current x-coordinate /// /// /// Specifies the current y-coordinate /// /// if (currX == 0 && currY == 0) { LiveUnit.LoggingCore.logComment("WARNING: Current X,Y Coordinates are (0,0)"); LiveUnit.LoggingCore.logComment("Likely reason for these coordinates: Animation 'complete' promise returned before 'transitionend' fired. Thus, coordinates test in transitionEndTestHandler() will be non-existant -> (0,0)"); return true; } if (destX === startX) { //if (X isn't moving) make sure Y is in between start and destination coordinates return ((currY >= startY && currY <= destY) || (currY <= startY && currY >= destY)); } else if (destY === startY) { //if (Y isn't moving) make sure X is in between start and destination coordinates return ((currX >= startX && currX <= destX) || (currX <= startX && currX >= destX)); } else { //if (both X && Y are moving) make sure X and Y are in between start and destination coordinates return ((currX <= startX && currX >= destX && currY >= startY && currY <= destY) || //(start >= X >= dest) && (start <= Y <= dest) (currX <= startX && currX >= destX && currY <= startY && currY >= destY) || //(start >= X >= dest) && (start >= Y >= dest) (currX >= startX && currX <= destX && currY >= startY && currY <= destY) || //(start <= X <= dest) && (start <= Y <= dest) (currX >= startX && currX <= destX && currY <= startY && currY >= destY) //(start <= X <= dest) && (start >= Y >= dest) ); } } export function VerifyDestinationCoordinates(refX, refY, actX, actY) { /// /// Verify translation end state /// /// /// Specifies the intended destination x-coordinate /// /// /// Specifies the intended destination y-coordinate /// /// /// Specifies the actual destination x-coordinate /// /// /// Specifies the actual destination y-coordinate /// /// var toleranceX = Math.abs(refX * (.05)); var toleranceY = Math.abs(refY * (.05)); var lowerBoundX = refX - toleranceX; var upperBoundX = refX + toleranceX; var lowerBoundY = refY - toleranceY; var upperBoundY = refY + toleranceY; return (lowerBoundX <= actX && upperBoundX >= actX && lowerBoundY <= actY && upperBoundY >= actY); } //Verify translate2D transition, final state should be the same as diffX, diffY export function VerifyTranslate2DTransition(diffX, diffY) { /// /// Verify translate 2D transition /// /// /// Specifies the vertical translate distance /// /// /// Specifies the vertical translate distance /// /// var ret = true; return AnimationVerifier.VerifyEachElementStatusChange(function (before, after, compareDouble) { var hor = after.left - before.left; var ver = after.top - before.top; if (!compareDouble(diffX, hor, 0.05)) { LiveUnit.LoggingCore.logComment("Error:Horizontal move is not correct. should be:" + diffX + " currently:" + hor); ret = false; } if (!compareDouble(diffY, ver, 0.05)) { LiveUnit.LoggingCore.logComment("Error:Vertical move is not correct. Should be:" + diffY + " currently:" + ver); ret = false; } return ret; }); } export function verifyTranslate2DAnimation(diffX, diffY, option) { /// /// Verify translate 2D animation /// /// /// Specifies the vertical translate distance /// /// /// Specifies the horizontal translate distance /// /// /// {isVertical:true/false, isRTL:true/false} /// /// var ret = true; var hor, ver; //For vertical translate, the default setting can be positive or negative. If default is positive, current state must be between 0 and default (0 < current < default). //If default is negative, current state must be between default and 0 (defautl < current < 0). The horizontal movement should be same as diffY. function verifyEachTranslate(hor, ver, diffX, diffY, compareDouble) { if (!option.isVertical) { if ((diffX > 0) && (hor >= diffX || hor <= 0)) { LiveUnit.LoggingCore.logComment("Error:Horizontal move is not correct. Should be between 0 and:" + diffX + " currently:" + hor); ret = false; } if ((diffX < 0) && (hor <= diffX || hor >= 0)) { LiveUnit.LoggingCore.logComment("Error:Horizontal move is not correct. Should be between 0 and:" + diffX + " currently:" + hor); ret = false; } if (!compareDouble(diffY, ver, 0.01)) { LiveUnit.LoggingCore.logComment("ver:" + ver); LiveUnit.LoggingCore.logComment("Error:Veritical move is not correct. Should be: " + diffY + " currently:" + ver); ret = false; } } else { if ((diffY > 0) && (ver >= diffY || ver <= 0)) { LiveUnit.LoggingCore.logComment("Error:Vertical move is not correct. Should be between 0 and:" + diffY + " currently:" + ver); ret = false; } if ((diffY < 0) && (ver <= diffY || ver >= 0)) { LiveUnit.LoggingCore.logComment("Error:Vertical move is not correct. Should be between 0 and:" + diffY + " currently:" + ver); ret = false; } if (!compareDouble(diffX, hor, 0.01)) { LiveUnit.LoggingCore.logComment("Error:Vertical move is not correct. Should be :" + diffX + " currently:" + hor); ret = false; } } return ret; } return AnimationVerifier.VerifyEachElementStatusChange(function (before, after, compareDouble) { // Horizontal offsets are flipped in RTL. if (option.isRTL) { hor = before.left - after.left; LiveUnit.LoggingCore.logComment("before:" + before.left); LiveUnit.LoggingCore.logComment("after:" + after.left); } else { hor = after.left - before.left; } var ver = after.top - before.top; return verifyEachTranslate(hor, ver, diffX, diffY, compareDouble); }); } export function VerifyScale2DTransition(ratioX, ratioY) { /// /// Verify scale 2D transition /// /// /// Specifies the vertical scaling factor /// /// /// Specifies the horizontal scaling factor /// /// var ret = true; return AnimationVerifier.VerifyEachElementStatusChange(function (before, after, compareDouble) { var actualRatioX = (after.right - after.left) / (before.right - before.left); var actualRatioY = (after.bottom - after.top) / (before.bottom - before.top); if (!compareDouble(actualRatioX, ratioX, 0.005)) { LiveUnit.LoggingCore.logComment("Error:Horizontal scale is not correct. should be:" + ratioX + " currently:" + actualRatioX); ret = false; } if (!compareDouble(actualRatioY, ratioY, 0.005)) { LiveUnit.LoggingCore.logComment("Error:Vertical scale is not correct. should be:" + ratioY + " currently:" + actualRatioY); ret = false; } return ret; }); } export function VerifyScale2DAnimation(ratioX, ratioY) { /// /// Verify scale 2D animation /// /// /// Specifies the vertical scaling factor /// /// /// Specifies the horizontal scaling factor /// /// var ret = true; return AnimationVerifier.VerifyEachElementStatusChange(function (before, after, compareDouble) { var actualRatioX = (after.right - after.left) / (before.right - before.left); var actualRatioY = (after.bottom - after.top) / (before.bottom - before.top); if ((actualRatioX === 1) || (actualRatioY === 1)) { LiveUnit.LoggingCore.logComment("Error:Horizontal scale is not correct. should between " + ratioX + " and " + ratioY + "currently ratioX=" + actualRatioX + " ratioY=" + actualRatioY); ret = false; } if (actualRatioX <= ratioX || actualRatioY <= ratioY) { LiveUnit.LoggingCore.logComment("Error:Horizontal scale is not correct. should between " + ratioX + " and " + ratioY + "currently ratioX=" + actualRatioX + " ratioY=" + actualRatioY); ret = false; } return ret; }); } export function VerifyOpacityTransition(elem, value) { /// /// Verify opacity transition. /// /// /// The DOM element(s) need to be verified. /// /// /// Final opacity value. /// /// /// It verify if the opacity change to the expected value after animation. var ret = true; var opacity: number; if (Array.isArray(elem)) { for (var i = 0; i < elem.length; i++) { opacity = +(window.getComputedStyle(elem[i], null).getPropertyValue('opacity')); if (opacity !== value) { var tolerance = .01; if (opacity > (value + tolerance) || opacity < (value - tolerance)) { LiveUnit.LoggingCore.logComment("Opacity is not correct. Should be: " + value + "currently is: " + opacity); ret = false; break; } } } } else { opacity = +(window.getComputedStyle(elem, null).getPropertyValue('opacity')); if (opacity !== value) { var tolerance = .01; if (opacity > (value + tolerance) || opacity < (value - tolerance)) { LiveUnit.LoggingCore.logComment("Opacity is not correct. Should be: " + value + "currently is: " + opacity); ret = false; } } } return ret; } export function VerifyOpacityTransitionInProgress(elem) { /// /// Verify opacity transition. /// /// var ret = true; var opacity: number; if (Array.isArray(elem)) { for (var i = 0; i < elem.length; i++) { opacity = +(window.getComputedStyle(elem[i], null).getPropertyValue('opacity')); if (opacity >= 0 && opacity <= 1) { LiveUnit.LoggingCore.logComment("Opacity is not correct. Should be between 0 and 1, currently is: " + opacity); ret = false; break; } } } else { opacity = +(window.getComputedStyle(elem, null).getPropertyValue('opacity')); if (opacity >= 0 && opacity <= 1) { ret = true; } else { LiveUnit.LoggingCore.logComment("Opacity is not correct. Should be between 0 and 1, currently is: " + opacity); ret = false; } } return ret; } export function VerifyOpacityAnimation(elem) { /// /// Verify opacity transition. /// /// var ret = true; var opacity: number; if (Array.isArray(elem)) { for (var i = 0; i < elem.length; i++) { opacity = +(window.getComputedStyle(elem[i], null).getPropertyValue('opacity')); if (opacity === 0 || opacity === 1) { LiveUnit.LoggingCore.logComment("Opacity is not correct. Should be between 0 and 1, currently is: " + opacity); ret = false; break; } } } else { opacity = +(window.getComputedStyle(elem, null).getPropertyValue('opacity')); LiveUnit.LoggingCore.logComment("opacity:" + opacity); if (opacity === 0 || opacity === 1) { LiveUnit.LoggingCore.logComment("Opacity is not correct. Should be between 0 and 1, currently is: " + opacity); ret = false; } } return ret; } }