2 * Copyright 2013-2016 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 Unity.Application 0.1
20import Ubuntu.Components 1.3
21import Unity.Test 0.1 as UT
26 property var util: TestUtil {id:util}
28 // This is needed for waitForRendering calls to return
29 // if the watched element already got rendered
34 parent: testCase.parent
35 border { width: units.dp(1); color: "black" }
38 visible: testCase.running
40 RotationAnimation on rotation {
41 running: rotatingRectangle.visible
44 loops: Animation.Infinite
49 // Fake implementation to be provided to items under test
50 property var fakeDateTime: new function() {
51 this.currentTimeMs = 0
52 this.getCurrentTimeMs = function() {return this.currentTimeMs}
55 // TODO This function can be removed altogether once we use Qt 5.7 which has the same feature
56 function mouseClick(item, x, y, button, modifiers, delay) {
58 qtest_fail("no item given", 1);
60 if (button === undefined)
61 button = Qt.LeftButton;
62 if (modifiers === undefined)
63 modifiers = Qt.NoModifier;
64 if (delay === undefined)
70 if (!qtest_events.mouseClick(item, x, y, button, modifiers, delay))
71 qtest_fail("window not shown", 2);
74 // TODO This function can be removed altogether once we use Qt 5.7 which has the same feature
75 function mouseDoubleClick(item, x, y, button, modifiers, delay) {
77 qtest_fail("no item given", 1);
79 if (button === undefined)
80 button = Qt.LeftButton;
81 if (modifiers === undefined)
82 modifiers = Qt.NoModifier;
83 if (delay === undefined)
89 if (!qtest_events.mouseDoubleClick(item, x, y, button, modifiers, delay))
90 qtest_fail("window not shown", 2)
93 // TODO This function can be removed altogether once we use Qt 5.7 which has the same feature
94 function mousePress(item, x, y, button, modifiers, delay) {
96 qtest_fail("no item given", 1);
98 if (button === undefined)
99 button = Qt.LeftButton;
100 if (modifiers === undefined)
101 modifiers = Qt.NoModifier;
102 if (delay === undefined)
108 if (!qtest_events.mousePress(item, x, y, button, modifiers, delay))
109 qtest_fail("window not shown", 2)
112 // TODO This function can be removed altogether once we use Qt 5.7 which has the same feature
113 function mouseRelease(item, x, y, button, modifiers, delay) {
115 qtest_fail("no item given", 1);
117 if (button === undefined)
118 button = Qt.LeftButton;
119 if (modifiers === undefined)
120 modifiers = Qt.NoModifier;
121 if (delay === undefined)
127 if (!qtest_events.mouseRelease(item, x, y, button, modifiers, delay))
128 qtest_fail("window not shown", 2)
132 // Flickable won't recognise a single mouse move as dragging the flickable.
133 // Use 5 steps because it's what
134 // Qt uses in QQuickViewTestUtil::flick
135 // speed is in pixels/second
136 function mouseFlick(item, x, y, toX, toY, pressMouse, releaseMouse,
139 qtest_fail("no item given", 1);
141 pressMouse = ((pressMouse != null) ? pressMouse : true); // Default to true for pressMouse if not present
142 releaseMouse = ((releaseMouse != null) ? releaseMouse : true); // Default to true for releaseMouse if not present
144 // set a default speed if not specified
145 speed = (speed != null) ? speed : units.gu(10);
147 // set a default iterations if not specified
148 iterations = (iterations !== undefined) ? iterations : 5
150 var distance = Math.sqrt(Math.pow(toX - x, 2) + Math.pow(toY - y, 2))
151 var totalTime = (distance / speed) * 1000 /* converting speed to pixels/ms */
153 var timeStep = totalTime / iterations
154 var diffX = (toX - x) / iterations
155 var diffY = (toY - y) / iterations
157 fakeDateTime.currentTimeMs += timeStep
158 mousePress(item, x, y)
160 for (var i = 0; i < iterations; ++i) {
161 fakeDateTime.currentTimeMs += timeStep
162 if (i === iterations - 1) {
163 // Avoid any rounding errors by making the last move be at precisely
164 // the point specified
165 mouseMove(item, toX, toY, iterations / speed)
167 mouseMove(item, x + (i + 1) * diffX, y + (i + 1) * diffY, iterations / speed)
171 fakeDateTime.currentTimeMs += timeStep
172 mouseRelease(item, toX, toY)
177 // Find an object with the given name in the children tree of "obj"
178 function findChild(obj, objectName) {
180 qtest_fail("no obj given", 1);
182 return findChildIn(obj, "children", objectName);
185 // Find an object with the given name in the children tree of "obj"
186 // Including invisible children like animations, timers etc.
187 // Note: you should use findChild if you're not sure you need this
188 // as this tree is much bigger and might contain stuff that goes
190 function findInvisibleChild(obj, objectName) {
192 qtest_fail("no obj given", 1);
194 return findChildIn(obj, "data", objectName);
197 // Find a child in the named property
198 function findChildIn(obj, prop, objectName) {
200 qtest_fail("no obj given", 1);
202 var childs = new Array(0);
204 while (childs.length > 0) {
205 if (childs[0].objectName == objectName) {
208 for (var i in childs[0][prop]) {
209 childs.push(childs[0][prop][i])
216 function findChildsByType(obj, typeName) {
218 qtest_fail("no obj given", 1);
220 var res = new Array(0);
221 for (var i in obj.children) {
222 var c = obj.children[i];
223 if (UT.Util.isInstanceOf(c, typeName)) {
226 res = res.concat(findChildsByType(c, typeName));
231 // Type a full string instead of keyClick letter by letter
232 function typeString(str) {
233 for (var i = 0; i < str.length; i++) {
238 // Keeps executing a given parameter-less function until it returns the given
239 // expected result or the timemout is reached (in which case a test failure
241 function tryCompareFunction(func, expectedResult, timeout) {
243 if (timeout === undefined)
247 while (timeSpent < timeout && !success) {
248 actualResult = func()
249 success = qtest_compareInternal(actualResult, expectedResult)
250 if (success === false) {
256 var act = qtest_results.stringify(actualResult)
257 var exp = qtest_results.stringify(expectedResult)
258 if (!qtest_results.compare(success,
259 "function returned unexpected result",
261 util.callerFile(), util.callerLine())) {
262 throw new Error("QtQuickTest::fail")
266 function flickToYEnd(item) {
268 qtest_fail("no item given", 1);
271 var x = item.width / 2;
272 var y = item.height - units.gu(1);
273 var toY = units.gu(1);
274 var maxIterations = 5 + item.contentHeight / item.height;
275 while (i < maxIterations && !item.atYEnd) {
276 touchFlick(item, x, y, x, toY);
277 tryCompare(item, "moving", false);
280 tryCompare(item, "atYEnd", true);
283 function touchEvent(item) {
284 return UT.Util.touchEvent(item)
287 // speed is in pixels/second
288 function touchFlick(item, x, y, toX, toY, beginTouch, endTouch, speed, iterations) {
290 qtest_fail("no item given", 1);
292 // Make sure the item is rendered
293 waitForRendering(item);
295 var root = fetchRootItem(item);
296 var rootFrom = item.mapToItem(root, x, y);
297 var rootTo = item.mapToItem(root, toX, toY);
299 // Default to true for beginTouch if not present
300 beginTouch = (beginTouch !== undefined) ? beginTouch : true
302 // Default to true for endTouch if not present
303 endTouch = (endTouch !== undefined) ? endTouch : true
305 // Set a default speed if not specified
306 speed = (speed !== undefined) ? speed : units.gu(10)
308 // Set a default iterations if not specified
309 var iterations = (iterations !== undefined) ? iterations : 10
311 var distance = Math.sqrt(Math.pow(rootTo.x - rootFrom.x, 2) + Math.pow(rootTo.Y - rootFrom.y, 2))
312 var totalTime = (distance / speed) * 1000 /* converting speed to pixels/ms */
314 var timeStep = totalTime / iterations
315 var diffX = (rootTo.x - rootFrom.x) / iterations
316 var diffY = (rootTo.y - rootFrom.y) / iterations
318 fakeDateTime.currentTimeMs += timeStep
320 var event = touchEvent(item)
321 event.press(0 /* touchId */, rootFrom.x, rootFrom.y)
324 for (var i = 0; i < iterations; ++i) {
325 fakeDateTime.currentTimeMs += timeStep
326 if (i === iterations - 1) {
327 // Avoid any rounding errors by making the last move be at precisely
328 // the point specified
329 wait(iterations / speed)
330 var event = touchEvent(item)
331 event.move(0 /* touchId */, rootTo.x, rootTo.y)
334 wait(iterations / speed)
335 var event = touchEvent(item)
336 event.move(0 /* touchId */, rootFrom.x + (i + 1) * diffX, rootFrom.y + (i + 1) * diffY)
341 fakeDateTime.currentTimeMs += timeStep
342 var event = touchEvent(item)
343 event.release(0 /* touchId */, rootTo.x, rootTo.y)
348 // perform a drag in the given direction until the given condition is true
349 // The condition is a function to be evaluated after every step
350 function touchDragUntil(item, startX, startY, stepX, stepY, condition) {
352 qtest_fail("no item given", 1);
354 multiTouchDragUntil([0], item, startX, startY, stepX, stepY, condition);
357 function multiTouchDragUntil(touchIds, item, startX, startY, stepX, stepY, condition) {
359 qtest_fail("no item given", 1);
361 var root = fetchRootItem(item);
362 var pos = item.mapToItem(root, startX, startY);
364 // convert step to scene coords
366 var stepStart = item.mapToItem(root, 0, 0);
367 var stepEnd = item.mapToItem(root, stepX, stepY);
369 stepX = stepEnd.x - stepStart.x;
370 stepY = stepEnd.y - stepStart.y;
372 var event = touchEvent(item)
373 for (var i = 0; i < touchIds.length; i++) {
374 event.press(touchIds[i], pos.x, pos.y)
378 // we have to stop at some point
382 while (!condition() && stepsDone < maxSteps) {
384 fakeDateTime.currentTimeMs += 25;
389 event = touchEvent(item);
390 for (i = 0; i < touchIds.length; i++) {
391 event.move(touchIds[i], pos.x, pos.y);
398 event = touchEvent(item)
399 for (i = 0; i < touchIds.length; i++) {
400 event.release(touchIds[i], pos.x, pos.y)
405 function touchMove(item, tox, toy) {
407 qtest_fail("no item given", 1);
409 multiTouchMove(0, item, tox, toy);
412 function multiTouchMove(touchId, item, tox, toy) {
414 qtest_fail("no item given", 1);
416 if (typeof touchId !== "number") touchId = 0;
417 var root = fetchRootItem(item)
418 var rootPoint = item.mapToItem(root, tox, toy)
420 var event = touchEvent(item);
421 event.move(touchId, rootPoint.x, rootPoint.y);
425 function touchPinch(item, x1Start, y1Start, x1End, y1End, x2Start, y2Start, x2End, y2End) {
427 qtest_fail("no item given", 1);
429 // Make sure the item is rendered
430 waitForRendering(item);
432 var event1 = touchEvent(item);
434 event1.press(0, x1Start, y1Start);
437 event1.move(0, x1Start, y1Start);
438 event1.press(1, x2Start, y2Start);
442 for (var i = 0.0; i < 1.0; i += 0.02) {
443 event1.move(0, x1Start + (x1End - x1Start) * i, y1Start + (y1End - y1Start) * i);
444 event1.move(1, x2Start + (x2End - x2Start) * i, y2Start + (y2End - y2Start) * i);
449 event1.release(0, x1End, y1End);
450 event1.release(1, x2End, y2End);
454 function fetchRootItem(item) {
456 qtest_fail("no item given", 1);
459 return fetchRootItem(item.parent)
464 function touchPress(item, x, y) {
466 qtest_fail("no item given", 1);
468 multiTouchPress(0, item, x, y, []);
471 /*! \brief Release a touch point
473 \param touchId The touchId to be pressed
475 \param x The x coordinate of the press, defaults to horizontal center
476 \param y The y coordinate of the press, defaults to vertical center
477 \param stationaryPoints An array of touchIds which are "already touched"
479 function multiTouchPress(touchId, item, x, y, stationaryPoints) {
481 qtest_fail("no item given", 1);
483 if (typeof touchId !== "number") touchId = 0;
484 if (typeof x !== "number") x = item.width / 2;
485 if (typeof y !== "number") y = item.height / 2;
486 if (typeof stationaryPoints !== "object") stationaryPoints = []
487 var root = fetchRootItem(item)
488 var rootPoint = item.mapToItem(root, x, y)
490 var event = touchEvent(item)
491 event.press(touchId, rootPoint.x, rootPoint.y)
492 for (var i = 0; i < stationaryPoints.length; i++) {
493 event.stationary(stationaryPoints[i]);
498 function touchRelease(item, x, y) {
500 qtest_fail("no item given", 1);
502 multiTouchRelease(0, item, x, y, []);
505 /*! \brief Release a touch point
507 \param touchId The touchId to be released
509 \param x The x coordinate of the release, defaults to horizontal center
510 \param y The y coordinate of the release, defaults to vertical center
511 \param stationaryPoints An array of touchIds which are "still touched"
513 function multiTouchRelease(touchId, item, x, y, stationaryPoints) {
515 qtest_fail("no item given", 1);
517 if (typeof touchId !== "number") touchId = 0;
518 if (typeof x !== "number") x = item.width / 2;
519 if (typeof y !== "number") y = item.height / 2;
520 if (typeof stationaryPoints !== "object") stationaryPoints = []
521 var root = fetchRootItem(item)
522 var rootPoint = item.mapToItem(root, x, y)
524 var event = touchEvent(item)
525 event.release(touchId, rootPoint.x, rootPoint.y)
526 for (var i = 0; i < stationaryPoints.length; i++) {
527 event.stationary(stationaryPoints[i]);
532 /*! \brief Tap the item with a touch event.
534 \param item The item to be tapped
535 \param x The x coordinate of the tap, defaults to horizontal center
536 \param y The y coordinate of the tap, defaults to vertical center
538 function tap(item, x, y) {
540 qtest_fail("no item given", 1);
542 multiTouchTap([0], item, x, y);
545 function multiTouchTap(touchIds, item, x, y) {
547 qtest_fail("no item given", 1);
549 if (typeof touchIds !== "object") touchIds = [0];
550 if (typeof x !== "number") x = item.width / 2;
551 if (typeof y !== "number") y = item.height / 2;
553 var root = fetchRootItem(item)
554 var rootPoint = item.mapToItem(root, x, y)
556 var event = touchEvent(item)
557 for (var i = 0; i < touchIds.length; i++) {
558 event.press(touchIds[i], rootPoint.x, rootPoint.y)
562 event = touchEvent(item)
563 for (i = 0; i < touchIds.length; i++) {
564 event.release(touchIds[i], rootPoint.x, rootPoint.y)
570 Component.onCompleted: {
571 var rootItem = parent;
572 while (rootItem.parent != undefined) {
573 rootItem = rootItem.parent;
575 removeTimeConstraintsFromDirectionalDragAreas(rootItem);
579 In qmltests, sequences of touch events are sent all at once, unlike in "real life".
580 Also qmltests might run really slowly, e.g. when run from inside virtual machines.
581 Thus to remove a variable that qmltests cannot really control, namely time, this
582 function removes all constraints from DirectionalDragAreas that are sensible to
585 This effectively makes DirectionalDragAreas easier to fool.
587 function removeTimeConstraintsFromDirectionalDragAreas(item) {
589 qtest_fail("no item given", 1);
591 // use duck-typing to identify a DirectionalDragArea
592 if (item.removeTimeConstraints != undefined) {
593 item.removeTimeConstraints();
595 for (var i in item.children) {
596 removeTimeConstraintsFromDirectionalDragAreas(item.children[i]);
601 // TODO This function can be removed altogether once we use Qt 5.5 which has the same feature
602 function waitForRendering(item, timeout) {
603 if (timeout === undefined)
606 qtest_fail("No item given to waitForRendering", 1);
607 return qtest_results.waitForRendering(item, timeout);
611 Wait until any transition animation has finished for the given StateGroup or Item
613 function waitUntilTransitionsEnd(stateGroup) {
614 var transitions = stateGroup.transitions;
615 for (var i = 0; i < transitions.length; ++i) {
616 var transition = transitions[i];
617 tryCompare(transition, "running", false, 2000);
622 kill all (fake) running apps but unity8-dash, bringing Unity.Application back to its initial state
624 function killApps() {
625 while (ApplicationManager.count > 1) {
626 var appIndex = ApplicationManager.get(0).appId == "unity8-dash" ? 1 : 0
627 var application = ApplicationManager.get(appIndex);
628 ApplicationManager.stopApplication(application.appId);
629 // wait until all zombie surfaces are gone. As MirSurfaceItems hold references over them.
630 // They won't be gone until those surface items are destroyed.
631 tryCompareFunction(function() { return application.surfaceList.count }, 0);
632 tryCompare(application, "state", ApplicationInfo.Stopped);
634 compare(ApplicationManager.count, 1);
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