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 1.3
20import Unity.Test 0.1 as UT
26 // This is needed for waitForRendering calls to return
27 // if the watched element already got rendered
32 parent: testCase.parent
33 border { width: units.dp(1); color: "black" }
36 visible: testCase.running
38 RotationAnimation on rotation {
39 running: rotatingRectangle.visible
42 loops: Animation.Infinite
47 // Fake implementation to be provided to items under test
48 property var fakeDateTime: new function() {
49 this.currentTimeMs = 0
50 this.getCurrentTimeMs = function() {return this.currentTimeMs}
53 // TODO This function can be removed altogether once we use Qt 5.7 which has the same feature
54 function mouseClick(item, x, y, button, modifiers, delay) {
56 qtest_fail("no item given", 1);
58 if (button === undefined)
59 button = Qt.LeftButton;
60 if (modifiers === undefined)
61 modifiers = Qt.NoModifier;
62 if (delay === undefined)
68 if (!qtest_events.mouseClick(item, x, y, button, modifiers, delay))
69 qtest_fail("window not shown", 2);
72 // TODO This function can be removed altogether once we use Qt 5.7 which has the same feature
73 function mouseDoubleClick(item, x, y, button, modifiers, delay) {
75 qtest_fail("no item given", 1);
77 if (button === undefined)
78 button = Qt.LeftButton;
79 if (modifiers === undefined)
80 modifiers = Qt.NoModifier;
81 if (delay === undefined)
87 if (!qtest_events.mouseDoubleClick(item, x, y, button, modifiers, delay))
88 qtest_fail("window not shown", 2)
91 // TODO This function can be removed altogether once we use Qt 5.7 which has the same feature
92 function mousePress(item, x, y, button, modifiers, delay) {
94 qtest_fail("no item given", 1);
96 if (button === undefined)
97 button = Qt.LeftButton;
98 if (modifiers === undefined)
99 modifiers = Qt.NoModifier;
100 if (delay === undefined)
106 if (!qtest_events.mousePress(item, x, y, button, modifiers, delay))
107 qtest_fail("window not shown", 2)
110 // TODO This function can be removed altogether once we use Qt 5.7 which has the same feature
111 function mouseRelease(item, x, y, button, modifiers, delay) {
113 qtest_fail("no item given", 1);
115 if (button === undefined)
116 button = Qt.LeftButton;
117 if (modifiers === undefined)
118 modifiers = Qt.NoModifier;
119 if (delay === undefined)
125 if (!qtest_events.mouseRelease(item, x, y, button, modifiers, delay))
126 qtest_fail("window not shown", 2)
130 // Flickable won't recognise a single mouse move as dragging the flickable.
131 // Use 5 steps because it's what
132 // Qt uses in QQuickViewTestUtil::flick
133 // speed is in pixels/second
134 function mouseFlick(item, x, y, toX, toY, pressMouse, releaseMouse,
137 qtest_fail("no item given", 1);
139 pressMouse = ((pressMouse != null) ? pressMouse : true); // Default to true for pressMouse if not present
140 releaseMouse = ((releaseMouse != null) ? releaseMouse : true); // Default to true for releaseMouse if not present
142 // set a default speed if not specified
143 speed = (speed != null) ? speed : units.gu(10);
145 // set a default iterations if not specified
146 iterations = (iterations !== undefined) ? iterations : 5
148 var distance = Math.sqrt(Math.pow(toX - x, 2) + Math.pow(toY - y, 2))
149 var totalTime = (distance / speed) * 1000 /* converting speed to pixels/ms */
151 var timeStep = totalTime / iterations
152 var diffX = (toX - x) / iterations
153 var diffY = (toY - y) / iterations
155 fakeDateTime.currentTimeMs += timeStep
156 mousePress(item, x, y)
158 for (var i = 0; i < iterations; ++i) {
159 fakeDateTime.currentTimeMs += timeStep
160 if (i === iterations - 1) {
161 // Avoid any rounding errors by making the last move be at precisely
162 // the point specified
163 mouseMove(item, toX, toY, iterations / speed)
165 mouseMove(item, x + (i + 1) * diffX, y + (i + 1) * diffY, iterations / speed)
169 fakeDateTime.currentTimeMs += timeStep
170 mouseRelease(item, toX, toY)
175 // Find an object with the given name in the children tree of "obj"
176 function findChild(obj, objectName) {
178 qtest_fail("no obj given", 1);
180 return findChildIn(obj, "children", objectName);
183 // Find an object with the given name in the children tree of "obj"
184 // Including invisible children like animations, timers etc.
185 // Note: you should use findChild if you're not sure you need this
186 // as this tree is much bigger and might contain stuff that goes
188 function findInvisibleChild(obj, objectName) {
190 qtest_fail("no obj given", 1);
192 return findChildIn(obj, "data", objectName);
195 // Find a child in the named property
196 function findChildIn(obj, prop, objectName) {
198 qtest_fail("no obj given", 1);
200 var childs = new Array(0);
202 while (childs.length > 0) {
203 if (childs[0].objectName == objectName) {
206 for (var i in childs[0][prop]) {
207 childs.push(childs[0][prop][i])
214 function findChildsByType(obj, typeName) {
216 qtest_fail("no obj given", 1);
218 var res = new Array(0);
219 for (var i in obj.children) {
220 var c = obj.children[i];
221 if (UT.Util.isInstanceOf(c, typeName)) {
224 res = res.concat(findChildsByType(c, typeName));
229 // Type a full string instead of keyClick letter by letter
230 function typeString(str) {
231 for (var i = 0; i < str.length; i++) {
236 // Keeps executing a given parameter-less function until it returns the given
237 // expected result or the timemout is reached (in which case a test failure
239 function tryCompareFunction(func, expectedResult, timeout) {
241 if (timeout === undefined)
245 while (timeSpent < timeout && !success) {
246 actualResult = func()
247 success = qtest_compareInternal(actualResult, expectedResult)
248 if (success === false) {
254 var act = qtest_results.stringify(actualResult)
255 var exp = qtest_results.stringify(expectedResult)
256 if (!qtest_results.compare(success,
257 "function returned unexpected result",
259 util.callerFile(), util.callerLine())) {
260 throw new Error("QtQuickTest::fail")
264 function flickToYEnd(item) {
266 qtest_fail("no item given", 1);
269 var x = item.width / 2;
270 var y = item.height - units.gu(1);
271 var toY = units.gu(1);
272 var maxIterations = 5 + item.contentHeight / item.height;
273 while (i < maxIterations && !item.atYEnd) {
274 touchFlick(item, x, y, x, toY);
275 tryCompare(item, "moving", false);
278 tryCompare(item, "atYEnd", true);
281 function touchEvent(item) {
282 return UT.Util.touchEvent(item)
285 // speed is in pixels/second
286 function touchFlick(item, x, y, toX, toY, beginTouch, endTouch, speed, iterations) {
288 qtest_fail("no item given", 1);
290 // Make sure the item is rendered
291 waitForRendering(item);
293 var root = fetchRootItem(item);
294 var rootFrom = item.mapToItem(root, x, y);
295 var rootTo = item.mapToItem(root, toX, toY);
297 // Default to true for beginTouch if not present
298 beginTouch = (beginTouch !== undefined) ? beginTouch : true
300 // Default to true for endTouch if not present
301 endTouch = (endTouch !== undefined) ? endTouch : true
303 // Set a default speed if not specified
304 speed = (speed !== undefined) ? speed : units.gu(10)
306 // Set a default iterations if not specified
307 var iterations = (iterations !== undefined) ? iterations : 10
309 var distance = Math.sqrt(Math.pow(rootTo.x - rootFrom.x, 2) + Math.pow(rootTo.Y - rootFrom.y, 2))
310 var totalTime = (distance / speed) * 1000 /* converting speed to pixels/ms */
312 var timeStep = totalTime / iterations
313 var diffX = (rootTo.x - rootFrom.x) / iterations
314 var diffY = (rootTo.y - rootFrom.y) / iterations
316 fakeDateTime.currentTimeMs += timeStep
318 var event = touchEvent(item)
319 event.press(0 /* touchId */, rootFrom.x, rootFrom.y)
322 for (var i = 0; i < iterations; ++i) {
323 fakeDateTime.currentTimeMs += timeStep
324 if (i === iterations - 1) {
325 // Avoid any rounding errors by making the last move be at precisely
326 // the point specified
327 wait(iterations / speed)
328 var event = touchEvent(item)
329 event.move(0 /* touchId */, rootTo.x, rootTo.y)
332 wait(iterations / speed)
333 var event = touchEvent(item)
334 event.move(0 /* touchId */, rootFrom.x + (i + 1) * diffX, rootFrom.y + (i + 1) * diffY)
339 fakeDateTime.currentTimeMs += timeStep
340 var event = touchEvent(item)
341 event.release(0 /* touchId */, rootTo.x, rootTo.y)
346 // perform a drag in the given direction until the given condition is true
347 // The condition is a function to be evaluated after every step
348 function touchDragUntil(item, startX, startY, stepX, stepY, condition) {
350 qtest_fail("no item given", 1);
352 multiTouchDragUntil([0], item, startX, startY, stepX, stepY, condition);
355 function multiTouchDragUntil(touchIds, item, startX, startY, stepX, stepY, condition) {
357 qtest_fail("no item given", 1);
359 var root = fetchRootItem(item);
360 var pos = item.mapToItem(root, startX, startY);
362 // convert step to scene coords
364 var stepStart = item.mapToItem(root, 0, 0);
365 var stepEnd = item.mapToItem(root, stepX, stepY);
367 stepX = stepEnd.x - stepStart.x;
368 stepY = stepEnd.y - stepStart.y;
370 var event = touchEvent(item)
371 for (var i = 0; i < touchIds.length; i++) {
372 event.press(touchIds[i], pos.x, pos.y)
376 // we have to stop at some point
380 while (!condition() && stepsDone < maxSteps) {
382 fakeDateTime.currentTimeMs += 25;
387 event = touchEvent(item);
388 for (i = 0; i < touchIds.length; i++) {
389 event.move(touchIds[i], pos.x, pos.y);
396 event = touchEvent(item)
397 for (i = 0; i < touchIds.length; i++) {
398 event.release(touchIds[i], pos.x, pos.y)
403 function touchMove(item, tox, toy) {
405 qtest_fail("no item given", 1);
407 multiTouchMove(0, item, tox, toy);
410 function multiTouchMove(touchId, item, tox, toy) {
412 qtest_fail("no item given", 1);
414 if (typeof touchId !== "number") touchId = 0;
415 var root = fetchRootItem(item)
416 var rootPoint = item.mapToItem(root, tox, toy)
418 var event = touchEvent(item);
419 event.move(touchId, rootPoint.x, rootPoint.y);
423 function touchPinch(item, x1Start, y1Start, x1End, y1End, x2Start, y2Start, x2End, y2End) {
425 qtest_fail("no item given", 1);
427 // Make sure the item is rendered
428 waitForRendering(item);
430 var event1 = touchEvent(item);
432 event1.press(0, x1Start, y1Start);
435 event1.move(0, x1Start, y1Start);
436 event1.press(1, x2Start, y2Start);
440 for (var i = 0.0; i < 1.0; i += 0.02) {
441 event1.move(0, x1Start + (x1End - x1Start) * i, y1Start + (y1End - y1Start) * i);
442 event1.move(1, x2Start + (x2End - x2Start) * i, y2Start + (y2End - y2Start) * i);
447 event1.release(0, x1End, y1End);
448 event1.release(1, x2End, y2End);
452 function fetchRootItem(item) {
454 qtest_fail("no item given", 1);
457 return fetchRootItem(item.parent)
462 function touchPress(item, x, y) {
464 qtest_fail("no item given", 1);
466 multiTouchPress(0, item, x, y, []);
469 /*! \brief Release a touch point
471 \param touchId The touchId to be pressed
473 \param x The x coordinate of the press, defaults to horizontal center
474 \param y The y coordinate of the press, defaults to vertical center
475 \param stationaryPoints An array of touchIds which are "already touched"
477 function multiTouchPress(touchId, item, x, y, stationaryPoints) {
479 qtest_fail("no item given", 1);
481 if (typeof touchId !== "number") touchId = 0;
482 if (typeof x !== "number") x = item.width / 2;
483 if (typeof y !== "number") y = item.height / 2;
484 if (typeof stationaryPoints !== "object") stationaryPoints = []
485 var root = fetchRootItem(item)
486 var rootPoint = item.mapToItem(root, x, y)
488 var event = touchEvent(item)
489 event.press(touchId, rootPoint.x, rootPoint.y)
490 for (var i = 0; i < stationaryPoints.length; i++) {
491 event.stationary(stationaryPoints[i]);
496 function touchRelease(item, x, y) {
498 qtest_fail("no item given", 1);
500 multiTouchRelease(0, item, x, y, []);
503 /*! \brief Release a touch point
505 \param touchId The touchId to be released
507 \param x The x coordinate of the release, defaults to horizontal center
508 \param y The y coordinate of the release, defaults to vertical center
509 \param stationaryPoints An array of touchIds which are "still touched"
511 function multiTouchRelease(touchId, item, x, y, stationaryPoints) {
513 qtest_fail("no item given", 1);
515 if (typeof touchId !== "number") touchId = 0;
516 if (typeof x !== "number") x = item.width / 2;
517 if (typeof y !== "number") y = item.height / 2;
518 if (typeof stationaryPoints !== "object") stationaryPoints = []
519 var root = fetchRootItem(item)
520 var rootPoint = item.mapToItem(root, x, y)
522 var event = touchEvent(item)
523 event.release(touchId, rootPoint.x, rootPoint.y)
524 for (var i = 0; i < stationaryPoints.length; i++) {
525 event.stationary(stationaryPoints[i]);
530 /*! \brief Tap the item with a touch event.
532 \param item The item to be tapped
533 \param x The x coordinate of the tap, defaults to horizontal center
534 \param y The y coordinate of the tap, defaults to vertical center
536 function tap(item, x, y) {
538 qtest_fail("no item given", 1);
540 multiTouchTap([0], item, x, y);
543 function multiTouchTap(touchIds, item, x, y) {
545 qtest_fail("no item given", 1);
547 if (typeof touchIds !== "object") touchIds = [0];
548 if (typeof x !== "number") x = item.width / 2;
549 if (typeof y !== "number") y = item.height / 2;
551 var root = fetchRootItem(item)
552 var rootPoint = item.mapToItem(root, x, y)
554 var event = touchEvent(item)
555 for (var i = 0; i < touchIds.length; i++) {
556 event.press(touchIds[i], rootPoint.x, rootPoint.y)
560 event = touchEvent(item)
561 for (i = 0; i < touchIds.length; i++) {
562 event.release(touchIds[i], rootPoint.x, rootPoint.y)
568 Component.onCompleted: {
569 var rootItem = parent;
570 while (rootItem.parent != undefined) {
571 rootItem = rootItem.parent;
573 removeTimeConstraintsFromDirectionalDragAreas(rootItem);
577 In qmltests, sequences of touch events are sent all at once, unlike in "real life".
578 Also qmltests might run really slowly, e.g. when run from inside virtual machines.
579 Thus to remove a variable that qmltests cannot really control, namely time, this
580 function removes all constraints from DirectionalDragAreas that are sensible to
583 This effectively makes DirectionalDragAreas easier to fool.
585 function removeTimeConstraintsFromDirectionalDragAreas(item) {
587 qtest_fail("no item given", 1);
589 // use duck-typing to identify a DirectionalDragArea
590 if (item.removeTimeConstraints != undefined) {
591 item.removeTimeConstraints();
593 for (var i in item.children) {
594 removeTimeConstraintsFromDirectionalDragAreas(item.children[i]);
599 // TODO This function can be removed altogether once we use Qt 5.5 which has the same feature
600 function waitForRendering(item, timeout) {
601 if (timeout === undefined)
604 qtest_fail("No item given to waitForRendering", 1);
605 return qtest_results.waitForRendering(item, timeout);
609 Wait until any transition animation has finished for the given StateGroup or Item
611 function waitUntilTransitionsEnd(stateGroup) {
612 var transitions = stateGroup.transitions;
613 for (var i = 0; i < transitions.length; ++i) {
614 var transition = transitions[i];
615 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