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 Ubuntu.Test 1.0 as UbuntuTest
22import Unity.Test 0.1 as UT
27 property var util: TestUtil {id:util}
29 // This is needed for waitForRendering calls to return
30 // if the watched element already got rendered
35 parent: testCase.parent
36 border { width: units.dp(1); color: "black" }
39 visible: testCase.running
41 RotationAnimation on rotation {
42 running: rotatingRectangle.visible
45 loops: Animation.Infinite
50 // Fake implementation to be provided to items under test
51 property var fakeDateTime: new function() {
52 this.currentTimeMs = 0
53 this.getCurrentTimeMs = function() {return this.currentTimeMs}
56 // TODO This function can be removed altogether once we use Qt 5.5 which has the same feature
57 function mouseClick(item, x, y, button, modifiers, delay) {
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.5 which has the same feature
73 function mouseDoubleClick(item, x, y, button, modifiers, delay) {
74 if (button === undefined)
75 button = Qt.LeftButton;
76 if (modifiers === undefined)
77 modifiers = Qt.NoModifier;
78 if (delay === undefined)
84 if (!qtest_events.mouseDoubleClick(item, x, y, button, modifiers, delay))
85 qtest_fail("window not shown", 2)
88 // TODO This function can be removed altogether once we use Qt 5.5 which has the same feature
89 function mousePress(item, x, y, button, modifiers, delay) {
90 if (button === undefined)
91 button = Qt.LeftButton;
92 if (modifiers === undefined)
93 modifiers = Qt.NoModifier;
94 if (delay === undefined)
100 if (!qtest_events.mousePress(item, x, y, button, modifiers, delay))
101 qtest_fail("window not shown", 2)
104 // TODO This function can be removed altogether once we use Qt 5.5 which has the same feature
105 function mouseRelease(item, x, y, button, modifiers, delay) {
106 if (button === undefined)
107 button = Qt.LeftButton;
108 if (modifiers === undefined)
109 modifiers = Qt.NoModifier;
110 if (delay === undefined)
116 if (!qtest_events.mouseRelease(item, x, y, button, modifiers, delay))
117 qtest_fail("window not shown", 2)
121 // Flickable won't recognise a single mouse move as dragging the flickable.
122 // Use 5 steps because it's what
123 // Qt uses in QQuickViewTestUtil::flick
124 // speed is in pixels/second
125 function mouseFlick(item, x, y, toX, toY, pressMouse, releaseMouse,
127 pressMouse = ((pressMouse != null) ? pressMouse : true); // Default to true for pressMouse if not present
128 releaseMouse = ((releaseMouse != null) ? releaseMouse : true); // Default to true for releaseMouse if not present
130 // set a default speed if not specified
131 speed = (speed != null) ? speed : units.gu(10);
133 // set a default iterations if not specified
134 iterations = (iterations !== undefined) ? iterations : 5
136 var distance = Math.sqrt(Math.pow(toX - x, 2) + Math.pow(toY - y, 2))
137 var totalTime = (distance / speed) * 1000 /* converting speed to pixels/ms */
139 var timeStep = totalTime / iterations
140 var diffX = (toX - x) / iterations
141 var diffY = (toY - y) / iterations
143 fakeDateTime.currentTimeMs += timeStep
144 mousePress(item, x, y)
146 for (var i = 0; i < iterations; ++i) {
147 fakeDateTime.currentTimeMs += timeStep
148 if (i === iterations - 1) {
149 // Avoid any rounding errors by making the last move be at precisely
150 // the point specified
151 mouseMove(item, toX, toY, iterations / speed)
153 mouseMove(item, x + (i + 1) * diffX, y + (i + 1) * diffY, iterations / speed)
157 fakeDateTime.currentTimeMs += timeStep
158 mouseRelease(item, toX, toY)
163 // Find an object with the given name in the children tree of "obj"
164 function findChild(obj, objectName) {
165 return findChildIn(obj, "children", objectName);
168 // Find an object with the given name in the children tree of "obj"
169 // Including invisible children like animations, timers etc.
170 // Note: you should use findChild if you're not sure you need this
171 // as this tree is much bigger and might contain stuff that goes
173 function findInvisibleChild(obj, objectName) {
174 return findChildIn(obj, "data", objectName);
177 // Find a child in the named property
178 function findChildIn(obj, prop, objectName) {
179 var childs = new Array(0);
181 while (childs.length > 0) {
182 if (childs[0].objectName == objectName) {
185 for (var i in childs[0][prop]) {
186 childs.push(childs[0][prop][i])
193 function findChildsByType(obj, typeName) {
194 var res = new Array(0);
195 for (var i in obj.children) {
196 var c = obj.children[i];
197 if (UT.Util.isInstanceOf(c, typeName)) {
200 res = res.concat(findChildsByType(c, typeName));
205 // Type a full string instead of keyClick letter by letter
206 function typeString(str) {
207 for (var i = 0; i < str.length; i++) {
212 // Keeps executing a given parameter-less function until it returns the given
213 // expected result or the timemout is reached (in which case a test failure
215 function tryCompareFunction(func, expectedResult, timeout) {
217 if (timeout === undefined)
221 while (timeSpent < timeout && !success) {
222 actualResult = func()
223 success = qtest_compareInternal(actualResult, expectedResult)
224 if (success === false) {
230 var act = qtest_results.stringify(actualResult)
231 var exp = qtest_results.stringify(expectedResult)
232 if (!qtest_results.compare(success,
233 "function returned unexpected result",
235 util.callerFile(), util.callerLine())) {
236 throw new Error("QtQuickTest::fail")
240 function flickToYEnd(item) {
242 var x = item.width / 2;
243 var y = item.height - units.gu(1);
244 var toY = units.gu(1);
245 var maxIterations = 5 + item.contentHeight / item.height;
246 while (i < maxIterations && !item.atYEnd) {
247 touchFlick(item, x, y, x, toY);
248 tryCompare(item, "moving", false);
251 tryCompare(item, "atYEnd", true);
254 function touchEvent(item) {
255 return UT.Util.touchEvent(item)
258 // speed is in pixels/second
259 function touchFlick(item, x, y, toX, toY, beginTouch, endTouch, speed, iterations) {
260 // Make sure the item is rendered
261 waitForRendering(item);
263 var root = fetchRootItem(item);
264 var rootFrom = item.mapToItem(root, x, y);
265 var rootTo = item.mapToItem(root, toX, toY);
267 // Default to true for beginTouch if not present
268 beginTouch = (beginTouch !== undefined) ? beginTouch : true
270 // Default to true for endTouch if not present
271 endTouch = (endTouch !== undefined) ? endTouch : true
273 // Set a default speed if not specified
274 speed = (speed !== undefined) ? speed : units.gu(10)
276 // Set a default iterations if not specified
277 var iterations = (iterations !== undefined) ? iterations : 10
279 var distance = Math.sqrt(Math.pow(rootTo.x - rootFrom.x, 2) + Math.pow(rootTo.Y - rootFrom.y, 2))
280 var totalTime = (distance / speed) * 1000 /* converting speed to pixels/ms */
282 var timeStep = totalTime / iterations
283 var diffX = (rootTo.x - rootFrom.x) / iterations
284 var diffY = (rootTo.y - rootFrom.y) / iterations
286 fakeDateTime.currentTimeMs += timeStep
288 var event = touchEvent(item)
289 event.press(0 /* touchId */, rootFrom.x, rootFrom.y)
292 for (var i = 0; i < iterations; ++i) {
293 fakeDateTime.currentTimeMs += timeStep
294 if (i === iterations - 1) {
295 // Avoid any rounding errors by making the last move be at precisely
296 // the point specified
297 wait(iterations / speed)
298 var event = touchEvent(item)
299 event.move(0 /* touchId */, rootTo.x, rootTo.y)
302 wait(iterations / speed)
303 var event = touchEvent(item)
304 event.move(0 /* touchId */, rootFrom.x + (i + 1) * diffX, rootFrom.y + (i + 1) * diffY)
309 fakeDateTime.currentTimeMs += timeStep
310 var event = touchEvent(item)
311 event.release(0 /* touchId */, rootTo.x, rootTo.y)
316 // perform a drag in the given direction until the given condition is true
317 // The condition is a function to be evaluated after every step
318 function touchDragUntil(item, startX, startY, stepX, stepY, condition) {
319 multiTouchDragUntil([0], item, startX, startY, stepX, stepY, condition);
322 function multiTouchDragUntil(touchIds, item, startX, startY, stepX, stepY, condition) {
323 var root = fetchRootItem(item);
324 var pos = item.mapToItem(root, startX, startY);
326 // convert step to scene coords
328 var stepStart = item.mapToItem(root, 0, 0);
329 var stepEnd = item.mapToItem(root, stepX, stepY);
331 stepX = stepEnd.x - stepStart.x;
332 stepY = stepEnd.y - stepStart.y;
334 var event = touchEvent(item)
335 for (var i = 0; i < touchIds.length; i++) {
336 event.press(touchIds[i], pos.x, pos.y)
340 // we have to stop at some point
344 while (!condition() && stepsDone < maxSteps) {
346 fakeDateTime.currentTimeMs += 25;
351 event = touchEvent(item);
352 for (i = 0; i < touchIds.length; i++) {
353 event.move(touchIds[i], pos.x, pos.y);
360 event = touchEvent(item)
361 for (i = 0; i < touchIds.length; i++) {
362 event.release(touchIds[i], pos.x, pos.y)
367 function touchMove(item, tox, toy) { multiTouchMove(0, item, tox, toy); }
369 function multiTouchMove(touchId, item, tox, toy) {
370 if (typeof touchId !== "number") touchId = 0;
371 var root = fetchRootItem(item)
372 var rootPoint = item.mapToItem(root, tox, toy)
374 var event = touchEvent(item);
375 event.move(touchId, rootPoint.x, rootPoint.y);
379 function touchPinch(item, x1Start, y1Start, x1End, y1End, x2Start, y2Start, x2End, y2End) {
380 // Make sure the item is rendered
381 waitForRendering(item);
383 var event1 = touchEvent(item);
385 event1.press(0, x1Start, y1Start);
388 event1.move(0, x1Start, y1Start);
389 event1.press(1, x2Start, y2Start);
393 for (var i = 0.0; i < 1.0; i += 0.02) {
394 event1.move(0, x1Start + (x1End - x1Start) * i, y1Start + (y1End - y1Start) * i);
395 event1.move(1, x2Start + (x2End - x2Start) * i, y2Start + (y2End - y2Start) * i);
400 event1.release(0, x1End, y1End);
401 event1.release(1, x2End, y2End);
405 function fetchRootItem(item) {
407 return fetchRootItem(item.parent)
412 function touchPress(item, x, y) { multiTouchPress(0, item, x, y, []); }
414 /*! \brief Release a touch point
416 \param touchId The touchId to be pressed
418 \param x The x coordinate of the press, defaults to horizontal center
419 \param y The y coordinate of the press, defaults to vertical center
420 \param stationaryPoints An array of touchIds which are "already touched"
422 function multiTouchPress(touchId, item, x, y, stationaryPoints) {
423 if (typeof touchId !== "number") touchId = 0;
424 if (typeof x !== "number") x = item.width / 2;
425 if (typeof y !== "number") y = item.height / 2;
426 if (typeof stationaryPoints !== "object") stationaryPoints = []
427 var root = fetchRootItem(item)
428 var rootPoint = item.mapToItem(root, x, y)
430 var event = touchEvent(item)
431 event.press(touchId, rootPoint.x, rootPoint.y)
432 for (var i = 0; i < stationaryPoints.length; i++) {
433 event.stationary(stationaryPoints[i]);
438 function touchRelease(item, x, y) { multiTouchRelease(0, item, x, y, []); }
440 /*! \brief Release a touch point
442 \param touchId The touchId to be released
444 \param x The x coordinate of the release, defaults to horizontal center
445 \param y The y coordinate of the release, defaults to vertical center
446 \param stationaryPoints An array of touchIds which are "still touched"
448 function multiTouchRelease(touchId, item, x, y, stationaryPoints) {
449 if (typeof touchId !== "number") touchId = 0;
450 if (typeof x !== "number") x = item.width / 2;
451 if (typeof y !== "number") y = item.height / 2;
452 if (typeof stationaryPoints !== "object") stationaryPoints = []
453 var root = fetchRootItem(item)
454 var rootPoint = item.mapToItem(root, x, y)
456 var event = touchEvent(item)
457 event.release(touchId, rootPoint.x, rootPoint.y)
458 for (var i = 0; i < stationaryPoints.length; i++) {
459 event.stationary(stationaryPoints[i]);
464 /*! \brief Tap the item with a touch event.
466 \param item The item to be tapped
467 \param x The x coordinate of the tap, defaults to horizontal center
468 \param y The y coordinate of the tap, defaults to vertical center
470 function tap(item, x, y) {
471 multiTouchTap([0], item, x, y);
474 function multiTouchTap(touchIds, item, x, y) {
475 if (typeof touchIds !== "object") touchIds = [0];
476 if (typeof x !== "number") x = item.width / 2;
477 if (typeof y !== "number") y = item.height / 2;
479 var root = fetchRootItem(item)
480 var rootPoint = item.mapToItem(root, x, y)
482 var event = touchEvent(item)
483 for (var i = 0; i < touchIds.length; i++) {
484 event.press(touchIds[i], rootPoint.x, rootPoint.y)
488 event = touchEvent(item)
489 for (i = 0; i < touchIds.length; i++) {
490 event.release(touchIds[i], rootPoint.x, rootPoint.y)
496 Component.onCompleted: {
497 var rootItem = parent;
498 while (rootItem.parent != undefined) {
499 rootItem = rootItem.parent;
501 removeTimeConstraintsFromSwipeAreas(rootItem);
505 In qmltests, sequences of touch events are sent all at once, unlike in "real life".
506 Also qmltests might run really slowly, e.g. when run from inside virtual machines.
507 Thus to remove a variable that qmltests cannot really control, namely time, this
508 function removes all constraints from SwipeAreas that are sensible to
511 This effectively makes SwipeAreas easier to fool.
513 function removeTimeConstraintsFromSwipeAreas(item) {
514 if (UT.Util.isInstanceOf(item, "UCSwipeArea")) {
515 UbuntuTest.TestExtras.removeTimeConstraintsFromSwipeArea(item);
517 for (var i in item.children) {
518 removeTimeConstraintsFromSwipeAreas(item.children[i]);
523 // TODO This function can be removed altogether once we use Qt 5.5 which has the same feature
524 function waitForRendering(item, timeout) {
525 if (timeout === undefined)
528 qtest_fail("No item given to waitForRendering", 1);
529 return qtest_results.waitForRendering(item, timeout);
533 Wait until any transition animation has finished for the given StateGroup or Item
535 function waitUntilTransitionsEnd(stateGroup) {
536 var transitions = stateGroup.transitions;
537 for (var i = 0; i < transitions.length; ++i) {
538 var transition = transitions[i];
539 tryCompare(transition, "running", false, 2000);
544 kill all (fake) running apps but unity8-dash, bringing Unity.Application back to its initial state
546 function killApps() {
547 while (ApplicationManager.count > 1) {
548 var appIndex = ApplicationManager.get(0).appId == "unity8-dash" ? 1 : 0
549 var application = ApplicationManager.get(appIndex);
550 ApplicationManager.stopApplication(application.appId);
551 // wait until all zombie surfaces are gone. As MirSurfaceItems hold references over them.
552 // They won't be gone until those surface items are destroyed.
553 tryCompareFunction(function() { return application.surfaceList.count }, 0);
554 tryCompare(application, "state", ApplicationInfo.Stopped);
556 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