2 * Copyright 2013-2015 Canonical Ltd.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19import Ubuntu.Components 0.1
20import Unity.Test 0.1 as UT
26 // This is needed for waitForRendering calls to return
27 // if the watched element already got rendered
31 parent: testCase.parent
32 border { width: units.dp(1); color: "black" }
35 visible: testCase.running
37 RotationAnimation on rotation {
38 running: parent.visible
41 loops: Animation.Infinite
46 // Fake implementation to be provided to items under test
47 property var fakeDateTime: new function() {
48 this.currentTimeMs = 0
49 this.getCurrentTimeMs = function() {return this.currentTimeMs}
52 // TODO This function can be removed altogether once we use Qt 5.5 which has the same feature
53 function mouseClick(item, x, y, button, modifiers, delay) {
54 if (button === undefined)
55 button = Qt.LeftButton;
56 if (modifiers === undefined)
57 modifiers = Qt.NoModifier;
58 if (delay === undefined)
64 if (!qtest_events.mouseClick(item, x, y, button, modifiers, delay))
65 qtest_fail("window not shown", 2);
68 // TODO This function can be removed altogether once we use Qt 5.5 which has the same feature
69 function mouseDoubleClick(item, x, y, button, modifiers, delay) {
70 if (button === undefined)
71 button = Qt.LeftButton;
72 if (modifiers === undefined)
73 modifiers = Qt.NoModifier;
74 if (delay === undefined)
80 if (!qtest_events.mouseDoubleClick(item, x, y, button, modifiers, delay))
81 qtest_fail("window not shown", 2)
84 // TODO This function can be removed altogether once we use Qt 5.5 which has the same feature
85 function mousePress(item, x, y, button, modifiers, delay) {
86 if (button === undefined)
87 button = Qt.LeftButton;
88 if (modifiers === undefined)
89 modifiers = Qt.NoModifier;
90 if (delay === undefined)
96 if (!qtest_events.mousePress(item, x, y, button, modifiers, delay))
97 qtest_fail("window not shown", 2)
100 // TODO This function can be removed altogether once we use Qt 5.5 which has the same feature
101 function mouseRelease(item, x, y, button, modifiers, delay) {
102 if (button === undefined)
103 button = Qt.LeftButton;
104 if (modifiers === undefined)
105 modifiers = Qt.NoModifier;
106 if (delay === undefined)
112 if (!qtest_events.mouseRelease(item, x, y, button, modifiers, delay))
113 qtest_fail("window not shown", 2)
117 // Flickable won't recognise a single mouse move as dragging the flickable.
118 // Use 5 steps because it's what
119 // Qt uses in QQuickViewTestUtil::flick
120 // speed is in pixels/second
121 function mouseFlick(item, x, y, toX, toY, pressMouse, releaseMouse,
123 pressMouse = ((pressMouse != null) ? pressMouse : true); // Default to true for pressMouse if not present
124 releaseMouse = ((releaseMouse != null) ? releaseMouse : true); // Default to true for releaseMouse if not present
126 // set a default speed if not specified
127 speed = (speed != null) ? speed : units.gu(10);
129 // set a default iterations if not specified
130 iterations = (iterations !== undefined) ? iterations : 5
132 var distance = Math.sqrt(Math.pow(toX - x, 2) + Math.pow(toY - y, 2))
133 var totalTime = (distance / speed) * 1000 /* converting speed to pixels/ms */
135 var timeStep = totalTime / iterations
136 var diffX = (toX - x) / iterations
137 var diffY = (toY - y) / iterations
139 fakeDateTime.currentTimeMs += timeStep
140 mousePress(item, x, y)
142 for (var i = 0; i < iterations; ++i) {
143 fakeDateTime.currentTimeMs += timeStep
144 if (i === iterations - 1) {
145 // Avoid any rounding errors by making the last move be at precisely
146 // the point specified
147 mouseMove(item, toX, toY, iterations / speed)
149 mouseMove(item, x + (i + 1) * diffX, y + (i + 1) * diffY, iterations / speed)
153 fakeDateTime.currentTimeMs += timeStep
154 mouseRelease(item, toX, toY)
159 // Find an object with the given name in the children tree of "obj"
160 function findChild(obj, objectName) {
161 return findChildIn(obj, "children", objectName);
164 // Find an object with the given name in the children tree of "obj"
165 // Including invisible children like animations, timers etc.
166 // Note: you should use findChild if you're not sure you need this
167 // as this tree is much bigger and might contain stuff that goes
169 function findInvisibleChild(obj, objectName) {
170 return findChildIn(obj, "data", objectName);
173 // Find a child in the named property
174 function findChildIn(obj, prop, objectName) {
175 var childs = new Array(0);
177 while (childs.length > 0) {
178 if (childs[0].objectName == objectName) {
181 for (var i in childs[0][prop]) {
182 childs.push(childs[0][prop][i])
189 function findChildsByType(obj, typeName) {
190 var res = new Array(0);
191 for (var i in obj.children) {
192 var c = obj.children[i];
193 if (UT.Util.isInstanceOf(c, typeName)) {
196 res = res.concat(findChildsByType(c, typeName));
201 // Type a full string instead of keyClick letter by letter
202 function typeString(str) {
203 for (var i = 0; i < str.length; i++) {
208 // Keeps executing a given parameter-less function until it returns the given
209 // expected result or the timemout is reached (in which case a test failure
211 function tryCompareFunction(func, expectedResult, timeout) {
213 if (timeout === undefined)
217 while (timeSpent < timeout && !success) {
218 actualResult = func()
219 success = qtest_compareInternal(actualResult, expectedResult)
220 if (success === false) {
226 var act = qtest_results.stringify(actualResult)
227 var exp = qtest_results.stringify(expectedResult)
228 if (!qtest_results.compare(success,
229 "function returned unexpected result",
231 util.callerFile(), util.callerLine())) {
232 throw new Error("QtQuickTest::fail")
236 function flickToYEnd(item) {
238 var x = item.width / 2;
239 var y = item.height - units.gu(1);
240 var toY = units.gu(1);
241 while (i < 5 && !item.atYEnd) {
242 touchFlick(item, x, y, x, toY);
243 tryCompare(item, "moving", false);
246 tryCompare(item, "atYEnd", true);
249 function touchEvent(item) {
250 return UT.Util.touchEvent(item)
253 // speed is in pixels/second
254 function touchFlick(item, x, y, toX, toY, beginTouch, endTouch, speed, iterations) {
255 // Make sure the item is rendered
256 waitForRendering(item);
258 var root = fetchRootItem(item);
259 var rootFrom = item.mapToItem(root, x, y);
260 var rootTo = item.mapToItem(root, toX, toY);
262 // Default to true for beginTouch if not present
263 beginTouch = (beginTouch !== undefined) ? beginTouch : true
265 // Default to true for endTouch if not present
266 endTouch = (endTouch !== undefined) ? endTouch : true
268 // Set a default speed if not specified
269 speed = (speed !== undefined) ? speed : units.gu(10)
271 // Set a default iterations if not specified
272 var iterations = (iterations !== undefined) ? iterations : 10
274 var distance = Math.sqrt(Math.pow(rootTo.x - rootFrom.x, 2) + Math.pow(rootTo.Y - rootFrom.y, 2))
275 var totalTime = (distance / speed) * 1000 /* converting speed to pixels/ms */
277 var timeStep = totalTime / iterations
278 var diffX = (rootTo.x - rootFrom.x) / iterations
279 var diffY = (rootTo.y - rootFrom.y) / iterations
281 fakeDateTime.currentTimeMs += timeStep
283 var event = touchEvent(item)
284 event.press(0 /* touchId */, rootFrom.x, rootFrom.y)
287 for (var i = 0; i < iterations; ++i) {
288 fakeDateTime.currentTimeMs += timeStep
289 if (i === iterations - 1) {
290 // Avoid any rounding errors by making the last move be at precisely
291 // the point specified
292 wait(iterations / speed)
293 var event = touchEvent(item)
294 event.move(0 /* touchId */, rootTo.x, rootTo.y)
297 wait(iterations / speed)
298 var event = touchEvent(item)
299 event.move(0 /* touchId */, rootFrom.x + (i + 1) * diffX, rootFrom.y + (i + 1) * diffY)
304 fakeDateTime.currentTimeMs += timeStep
305 var event = touchEvent(item)
306 event.release(0 /* touchId */, rootTo.x, rootTo.y)
311 // perform a drag in the given direction until the given condition is true
312 // The condition is a function to be evaluated after every step
313 function touchDragUntil(item, startX, startY, stepX, stepY, condition) {
315 var root = fetchRootItem(item);
316 var pos = item.mapToItem(root, startX, startY);
318 // convert step to scene coords
320 var stepStart = item.mapToItem(root, 0, 0);
321 var stepEnd = item.mapToItem(root, stepX, stepY);
323 stepX = stepEnd.x - stepStart.x;
324 stepY = stepEnd.y - stepStart.y;
326 var event = touchEvent(item)
327 event.press(0 /* touchId */, pos.x, pos.y)
330 // we have to stop at some point
334 while (!condition() && stepsDone < maxSteps) {
336 fakeDateTime.currentTimeMs += 25;
341 event = touchEvent(item);
342 event.move(0 /* touchId */, pos.x, pos.y);
348 event = touchEvent(item)
349 event.release(0 /* touchId */, pos.x, pos.y)
353 function touchPinch(item, x1Start, y1Start, x1End, y1End, x2Start, y2Start, x2End, y2End) {
354 // Make sure the item is rendered
355 waitForRendering(item);
357 var event1 = touchEvent(item);
359 event1.press(0, x1Start, y1Start);
362 event1.move(0, x1Start, y1Start);
363 event1.press(1, x2Start, y2Start);
367 for (var i = 0.0; i < 1.0; i += 0.02) {
368 event1.move(0, x1Start + (x1End - x1Start) * i, y1Start + (y1End - y1Start) * i);
369 event1.move(1, x2Start + (x2End - x2Start) * i, y2Start + (y2End - y2Start) * i);
374 event1.release(0, x1End, y1End);
375 event1.release(1, x2End, y2End);
379 function fetchRootItem(item) {
381 return fetchRootItem(item.parent)
386 function touchPress(item, x, y) {
387 var root = fetchRootItem(item)
388 var rootPoint = item.mapToItem(root, x, y)
390 var event = touchEvent(item)
391 event.press(0 /* touchId */, rootPoint.x, rootPoint.y)
395 function touchRelease(item, x, y) {
396 var root = fetchRootItem(item)
397 var rootPoint = item.mapToItem(root, x, y)
399 var event = touchEvent(item)
400 event.release(0 /* touchId */, rootPoint.x, rootPoint.y)
404 /*! \brief Tap the item with a touch event.
406 \param item The item to be tapped
407 \param x The x coordinate of the tap, defaults to horizontal center
408 \param y The y coordinate of the tap, defaults to vertical center
410 function tap(item, x, y) {
411 if (typeof x !== "number") x = item.width / 2;
412 if (typeof y !== "number") y = item.height / 2;
414 var root = fetchRootItem(item)
415 var rootPoint = item.mapToItem(root, x, y)
417 var event = touchEvent(item)
418 event.press(0 /* touchId */, rootPoint.x, rootPoint.y)
421 event = touchEvent(item)
422 event.release(0 /* touchId */, rootPoint.x, rootPoint.y)
426 Component.onCompleted: {
427 UT.Util.ensureTouchRegistryInstalled();
429 var rootItem = parent;
430 while (rootItem.parent != undefined) {
431 rootItem = rootItem.parent;
433 removeTimeConstraintsFromDirectionalDragAreas(rootItem);
437 In qmltests, sequences of touch events are sent all at once, unlike in "real life".
438 Also qmltests might run really slowly, e.g. when run from inside virtual machines.
439 Thus to remove a variable that qmltests cannot really control, namely time, this
440 function removes all constraints from DirectionalDragAreas that are sensible to
443 This effectively makes DirectionalDragAreas easier to fool.
445 function removeTimeConstraintsFromDirectionalDragAreas(item) {
447 // use duck-typing to identify a DirectionalDragArea
448 if (item.removeTimeConstraints != undefined) {
449 item.removeTimeConstraints();
451 for (var i in item.children) {
452 removeTimeConstraintsFromDirectionalDragAreas(item.children[i]);
457 // TODO This function can be removed altogether once we use Qt 5.5 which has the same feature
458 function waitForRendering(item, timeout) {
459 if (timeout === undefined)
462 qtest_fail("No item given to waitForRendering", 1);
463 return qtest_results.waitForRendering(item, timeout);
467 Wait until any transition animation has finished for the given StateGroup or Item
469 function waitUntilTransitionsEnd(stateGroup) {
470 var transitions = stateGroup.transitions;
471 for (var i = 0; i < transitions.length; ++i) {
472 var transition = transitions[i];
473 tryCompare(transition, "running", false, 2000);
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list