2 * Copyright (C) 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 AccountsService 0.1
20import LightDM.IntegratedLightDM 0.1 as LightDM
21import Ubuntu.Components 1.3
22import Ubuntu.Components.ListItems 1.3
23import Ubuntu.Telephony 0.1 as Telephony
24import Unity.Application 0.1
25import Unity.Notifications 1.0
26import Unity.Test 0.1 as UT
30import "../../../qml/Components"
34 color: UbuntuColors.lightGrey
35 width: units.gu(100) + buttons.width
39 id: applicationArguments
41 function hasGeometry() {
56 phoneNumber: "+447812221111"
65 id: mockNotificationsModel
68 return mockNotification.createObject(mockNotificationsModel)
72 function addNotification() {
74 type: Notification.Confirmation,
83 mockNotificationsModel.append(n);
86 Component.onCompleted: {
87 // must set the mock mode before loading the Shell
88 LightDM.Greeter.mockMode = "single-pin";
89 LightDM.Users.mockMode = "single-pin";
90 shellLoader.active = true;
95 anchors.left: root.left
96 anchors.right: buttons.left
98 anchors.bottom: root.bottom
104 anchors.horizontalCenter: parent.horizontalCenter
105 anchors.top: parent.top
106 anchors.bottom: parent.bottom
108 property int shellOrientation: Qt.PortraitOrientation
109 property int nativeOrientation: Qt.PortraitOrientation
110 property int primaryOrientation: Qt.PortraitOrientation
112 state: modeSelector.model[modeSelector.selectedIndex]
126 shellOrientation: Qt.LandscapeOrientation
127 nativeOrientation: Qt.LandscapeOrientation
128 primaryOrientation: Qt.LandscapeOrientation
140 property bool itemDestroyed: false
141 sourceComponent: Component {
143 usageScenario: shellLoader.state
146 property string indicatorProfile: "phone"
147 orientation: shellLoader.shellOrientation
148 orientations: Orientations {
149 native_: shellLoader.nativeOrientation
150 primary: shellLoader.primaryOrientation
153 Component.onDestruction: {
154 shellLoader.itemDestroyed = true;
163 color: UbuntuColors.darkGrey
165 anchors.top: root.top
166 anchors.bottom: root.bottom
167 anchors.right: root.right
170 anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
173 anchors { left: parent.left; right: parent.right }
177 if (shellLoader.status !== Loader.Ready)
180 var greeter = testCase.findChild(shellLoader.item, "greeter");
189 anchors { left: parent.left; right: parent.right }
191 text: "Restart Tutorial"
193 if (shellLoader.status !== Loader.Ready)
196 AccountsService.demoEdges = false;
197 AccountsService.demoEdgesCompleted = [];
198 AccountsService.demoEdges = true;
204 anchors { left: parent.left; right: parent.right }
208 callManager.foregroundCall = phoneCall;
210 callManager.foregroundCall = null;
216 anchors.verticalCenter: parent.verticalCenter
221 anchors { left: parent.left; right: parent.right }
223 activeFocusOnPress: false
225 var surface = SurfaceManager.inputMethodSurface;
227 surface.setState(Mir.RestoredState);
229 surface.setState(Mir.MinimizedState);
235 anchors.verticalCenter: parent.verticalCenter
241 anchors { left: parent.left; right: parent.right }
242 activeFocusOnPress: false
244 model: ["phone", "tablet", "desktop"]
254 property Item shell: shellLoader.status === Loader.Ready ? shellLoader.item : null
255 property real halfWidth: shell ? shell.width / 2 : 0
256 property real halfHeight: shell ? shell.height / 2 : 0
261 var tutorialLeft = findChild(shell, "tutorialLeft");
262 var tutorialLeftTimer = findInvisibleChild(tutorialLeft, "tutorialLeftTimer");
263 tutorialLeftTimer.interval = 0;
264 tryCompare(tutorialLeft, "opacity", 1);
268 resetLoader("phone");
271 function resetLoader(state) {
272 shellLoader.itemDestroyed = false;
274 shellLoader.active = false;
275 shellLoader.state = state;
277 tryCompare(shellLoader, "status", Loader.Null);
278 tryCompare(shellLoader, "item", null);
279 // Loader.status might be Loader.Null and Loader.item might be null but the Loader
280 // item might still be alive. So if we set Loader.active back to true
281 // again right now we will get the very same Shell instance back. So no reload
282 // actually took place. Likely because Loader waits until the next event loop
283 // iteration to do its work. So to ensure the reload, we will wait until the
284 // Shell instance gets destroyed.
285 tryCompare(shellLoader, "itemDestroyed", true);
287 // kill all (fake) running apps
290 // reload our test subject to get it in a fresh state once again
291 shellLoader.active = true;
293 mockNotificationsModel.clear();
294 tryCompare(shellLoader, "status", Loader.Ready);
295 removeTimeConstraintsFromSwipeAreas(shellLoader.item);
298 function prepareShell() {
299 tryCompare(shell, "waitingOnGreeter", false); // reset by greeter when ready
301 WindowStateStorage.clear();
302 SurfaceManager.inputMethodSurface.setState(Mir.MinimizedState);
303 callManager.foregroundCall = null;
304 AccountsService.demoEdges = false;
305 AccountsService.demoEdgesCompleted = [];
306 AccountsService.demoEdges = true;
308 LightDM.Greeter.hideGreeter();
311 function loadShell(state) {
316 function swipeAwayGreeter() {
317 var coverPage = findChild(shell, "coverPage");
318 tryCompare(coverPage, "showProgress", 1);
320 touchFlick(shell, halfWidth, halfHeight, shell.width, halfHeight);
322 // wait until the animation has finished
323 var greeter = findChild(shell, "greeter");
324 tryCompare(greeter, "required", false);
325 waitForRendering(greeter);
328 function openTutorialTop() {
329 var tutorialLeftLoader = findChild(shell, "tutorialLeftLoader");
330 var tutorialTop = findChild(shell, "tutorialTop");
331 var tutorialTopTimer = findInvisibleChild(tutorialTop, "tutorialTopTimer");
333 tutorialTopTimer.interval = 1;
334 AccountsService.demoEdgesCompleted = ["left"];
336 tryCompare(tutorialLeftLoader, "active", false);
337 tryCompare(tutorialTop, "shown", true);
338 tryCompare(tutorialTop, "opacity", 1);
341 function openTutorialLeftLong() {
342 var tutorialLeftLong = findChild(shell, "tutorialLeftLong");
343 var tutorialLeftLongTimer = findChild(tutorialLeftLong, "tutorialLeftLongTimer");
345 AccountsService.demoEdgesCompleted = ["left", "top"];
346 ApplicationManager.startApplication("gallery-app");
348 tutorialLeftLongTimer.interval = 1;
349 tryCompare(tutorialLeftLong, "shown", true);
350 tryCompare(tutorialLeftLong, "opacity", 1);
353 function openTutorialRight() {
354 var tutorialLeftLoader = findChild(shell, "tutorialLeftLoader");
355 var tutorialRight = findChild(shell, "tutorialRight");
356 var tutorialRightTimer = findChild(tutorialRight, "tutorialRightTimer");
358 AccountsService.demoEdgesCompleted = ["left", "top", "left-long"];
359 ApplicationManager.startApplication("gallery-app");
360 ApplicationManager.startApplication("facebook-webapp");
361 ApplicationManager.startApplication("camera-app");
363 tryCompare(tutorialLeftLoader, "active", false);
364 tutorialRightTimer.interval = 1;
365 tryCompare(tutorialRight, "shown", true);
366 tryCompare(tutorialRight, "opacity", 1);
369 function test_tutorialLeftEdges() {
370 var tutorial = findChild(shell, "tutorial");
371 var tutorialLeft = findChild(tutorial, "tutorialLeft");
372 var launcher = findChild(shell, "launcher");
373 var stage = findChild(shell, "stage");
374 var panel = findChild(shell, "panel");
376 verify(tutorial.running);
377 verify(tutorial.launcherEnabled);
378 verify(!tutorial.spreadEnabled);
379 verify(!tutorial.panelEnabled);
380 verify(tutorialLeft.shown);
381 verify(launcher.available);
382 verify(!stage.spreadEnabled);
383 verify(!panel.indicators.available);
386 function test_tutorialLeftFinish() {
387 var tutorial = findChild(shell, "tutorial");
388 var tutorialLeftLoader = findChild(tutorial, "tutorialLeftLoader");
389 var launcher = findChild(shell, "launcher");
391 touchFlick(shell, 0, halfHeight, halfWidth, halfHeight);
393 tryCompare(tutorialLeftLoader, "shown", false);
394 tryCompare(AccountsService, "demoEdgesCompleted", ["left"]);
395 tryCompare(launcher, "state", "visible");
398 function test_tutorialLeftShortDrag() {
399 // Here we want to test just barely pulling the launcher out and
400 // letting go (i.e. not triggering the "progress" property of
402 var tutorialLeft = findChild(shell, "tutorialLeft");
403 var tutorialLeftLoader = findChild(shell, "tutorialLeftLoader");
404 var launcher = findChild(shell, "launcher");
406 // Confirm fade during drag
407 touchFlick(shell, 0, halfHeight, launcher.panelWidth * 0.4, halfHeight, true, false);
408 // compare opacity with a bound rather than hard 0.6 because progress doesn't
409 // always match the drag perfectly (takes a moment for drag to kick in)
410 tryCompareFunction(function() {
411 return tutorialLeft.opacity >= 0.6 && tutorialLeft.opacity < 0.8;
413 touchFlick(shell, 0, halfHeight, launcher.panelWidth * 0.4, halfHeight, false, true);
416 // Make sure we don't do anything if we don't pull the launcher
418 touchFlick(shell, 0, halfHeight, launcher.panelWidth * 0.4, halfHeight);
419 tryCompare(launcher, "state", ""); // should remain hidden
420 tryCompare(tutorialLeftLoader, "shown", true); // and we should still be on left
423 // Now drag out but not past launcher itself
424 touchFlick(shell, 0, halfHeight, launcher.panelWidth * 0.9, halfHeight);
426 tryCompare(tutorialLeftLoader, "shown", false);
427 tryCompare(AccountsService, "demoEdgesCompleted", ["left"]);
428 tryCompare(launcher, "state", "visible");
431 function test_tutorialLeftLongFinish() {
432 AccountsService.demoEdgesCompleted = ["left", "top"];
434 var tutorialLeftLongTimer = findInvisibleChild(shell, "tutorialLeftLongTimer");
435 tutorialLeftLongTimer.interval = 1;
437 ApplicationManager.startApplication("gallery-app");
439 var tutorialLeftLongLoader = findChild(shell, "tutorialLeftLongLoader");
440 tryCompare(tutorialLeftLongLoader, "shown", true);
442 touchFlick(shell, 0, halfHeight, shell.width, halfHeight);
444 tryCompare(tutorialLeftLongLoader, "shown", false);
445 tryCompare(AccountsService, "demoEdgesCompleted", ["left", "top", "left-long"]);
448 function test_tutorialLeftAutoSkipped() {
449 // Test that we skip the tutorial if user uses left edge themselves
451 var tutorialLeft = findChild(shell, "tutorialLeft");
452 LightDM.Greeter.showGreeter();
453 tryCompare(tutorialLeft, "visible", false);
454 compare(AccountsService.demoEdgesCompleted, []);
456 touchFlick(shell, 0, halfHeight, halfWidth, halfHeight);
457 tryCompare(AccountsService, "demoEdgesCompleted", ["left"]);
460 function test_tutorialLongLeftSwipeDisabled() {
461 // Test that a long left swipe is disabled until we get to or pass
462 // the long left tutorial.
463 var tutorial = findChild(shell, "tutorial");
465 verify(!tutorial.launcherLongSwipeEnabled);
467 openTutorialLeftLong();
468 verify(tutorial.launcherLongSwipeEnabled);
471 verify(tutorial.launcherLongSwipeEnabled);
473 AccountsService.demoEdges = false;
474 tryCompare(tutorial, "running", false);
475 verify(tutorial.launcherLongSwipeEnabled);
478 function test_tutorialTopEdges() {
479 var tutorial = findChild(shell, "tutorial");
480 var tutorialTop = findChild(tutorial, "tutorialTop");
481 var launcher = findChild(shell, "launcher");
482 var stage = findChild(shell, "stage");
483 var panel = findChild(shell, "panel");
487 tryCompare(tutorial, "running", true);
488 verify(!tutorial.launcherEnabled);
489 verify(!tutorial.spreadEnabled);
490 verify(tutorial.panelEnabled);
491 verify(tutorialTop.shown);
492 verify(!launcher.available);
493 verify(!stage.spreadEnabled);
494 verify(panel.indicators.available);
497 function test_tutorialTopFinish() {
498 var tutorial = findChild(shell, "tutorial");
499 var tutorialTopLoader = findChild(tutorial, "tutorialTopLoader");
500 var panel = findChild(shell, "panel");
503 touchFlick(shell, halfWidth, 0, halfWidth, shell.height);
505 tryCompare(tutorialTopLoader, "shown", false);
506 tryCompare(AccountsService, "demoEdgesCompleted", ["left", "top"]);
507 tryCompare(panel.indicators, "fullyOpened", true);
510 function test_tutorialTopShortDrag() {
511 var tutorial = findChild(shell, "tutorial");
512 var tutorialTop = findChild(tutorial, "tutorialTop");
513 var panel = findChild(shell, "panel");
516 touchFlick(shell, halfWidth, 0, halfWidth, shell.height * 0.4, true, false);
517 // compare opacity with a bound rather than hard 0.6 because progress doesn't
518 // always match the drag perfectly (takes a moment for drag to kick in)
519 tryCompareFunction(function() {
520 return tutorialTop.opacity >= 0.5 && tutorialTop.opacity < 0.7;
522 touchFlick(shell, halfWidth, 0, halfWidth, shell.height * 0.4, false, true);
524 compare(tutorialTop.shown, true);
527 function test_tutorialTopAutoSkipped() {
528 // Test that we skip the tutorial if user uses top edge themselves
530 var tutorialLeftLoader = findChild(shell, "tutorialLeftLoader");
531 var tutorialTopLoader = findChild(shell, "tutorialTopLoader");
532 AccountsService.demoEdgesCompleted = ["left"];
533 tryCompare(tutorialLeftLoader, "active", false);
534 verify(!tutorialTopLoader.shown);
536 touchFlick(shell, halfWidth, 0, halfWidth, shell.height);
537 tryCompare(AccountsService, "demoEdgesCompleted", ["left", "top"]);
540 function test_tutorialRightEdges() {
541 var tutorial = findChild(shell, "tutorial");
542 var tutorialRight = findChild(tutorial, "tutorialRight");
543 var launcher = findChild(shell, "launcher");
544 var stage = findChild(shell, "stage");
545 var panel = findChild(shell, "panel");
549 tryCompare(tutorial, "running", true);
550 verify(!tutorial.launcherEnabled);
551 verify(tutorial.spreadEnabled);
552 verify(!tutorial.panelEnabled);
553 verify(tutorialRight.shown);
554 verify(!launcher.available);
555 verify(stage.spreadEnabled);
556 verify(!panel.indicators.available);
559 function test_tutorialRightFinish() {
561 touchFlick(shell, shell.width, halfHeight, 0, halfHeight);
563 tryCompare(AccountsService, "demoEdgesCompleted", ["left", "top", "left-long", "right"]);
564 tryCompare(AccountsService, "demoEdges", false);
567 function test_tutorialRightShortDrag() {
568 var tutorial = findChild(shell, "tutorial");
569 var tutorialRight = findChild(tutorial, "tutorialRight");
570 var stage = findChild(shell, "stage");
573 touchFlick(shell, shell.width, halfHeight, shell.width * 0.8, halfHeight, true, false);
574 // compare opacity with a bound rather than hard 0.6 because progress doesn't
575 // always match the drag perfectly (takes a moment for drag to kick in)
576 tryCompareFunction(function() {
577 return tutorialRight.opacity >= 0.6 && tutorialRight.opacity < 0.8;
579 touchFlick(shell, shell.width, halfHeight, shell.width * 0.8, halfHeight, false, true);
581 compare(tutorialRight.shown, true);
584 function test_tutorialRightDelay() {
585 // Test that if we exit the top tutorial, we don't immediately
586 // jump into right tutorial.
587 var tutorialRightLoader = findChild(shell, "tutorialRightLoader");
588 var tutorialRightTimer = findInvisibleChild(tutorialRightLoader, "tutorialRightTimer");
591 ApplicationManager.startApplication("gallery-app");
592 ApplicationManager.startApplication("facebook-webapp");
593 ApplicationManager.startApplication("camera-app");
594 tryCompare(ApplicationManager, "count", 4);
596 AccountsService.demoEdgesCompleted = ["left", "top", "left-long"];
597 verify(tutorialRightTimer.running);
598 verify(!tutorialRightLoader.shown);
599 tutorialRightTimer.interval = 1;
600 tryCompare(tutorialRightLoader, "shown", true);
603 function test_tutorialRightAutoSkipped() {
604 // Test that we skip the tutorial if user uses right edge themselves
606 var tutorialLeftLoader = findChild(shell, "tutorialLeftLoader");
607 AccountsService.demoEdgesCompleted = ["left"];
608 tryCompare(tutorialLeftLoader, "active", false);
610 touchFlick(shell, shell.width, halfHeight, 0, halfHeight);
611 tryCompare(AccountsService, "demoEdgesCompleted", ["left", "right"]);
614 function test_activeCallInterruptsTutorial() {
615 var tutorialLeft = findChild(shell, "tutorialLeft");
616 verify(tutorialLeft.shown);
617 verify(!tutorialLeft.paused);
619 callManager.foregroundCall = phoneCall;
620 verify(!tutorialLeft.shown);
621 verify(tutorialLeft.paused);
622 tryCompare(tutorialLeft, "visible", false);
624 callManager.foregroundCall = null;
625 tryCompare(tutorialLeft, "shown", true);
626 verify(!tutorialLeft.paused);
629 function test_greeterInterruptsTutorial() {
630 var tutorialLeft = findChild(shell, "tutorialLeft");
631 verify(tutorialLeft.shown);
632 verify(!tutorialLeft.paused);
634 LightDM.Greeter.showGreeter();
635 verify(!tutorialLeft.shown);
636 verify(tutorialLeft.paused);
637 tryCompare(tutorialLeft, "visible", false);
639 LightDM.Greeter.hideGreeter();
640 tryCompare(tutorialLeft, "shown", true);
641 verify(!tutorialLeft.paused);
644 function test_interruptionChecksReadyStateWhenDone() {
645 // If we're done with an interruption (like active call), make sure
646 // that we don't blindly resume the tutorial -- our trigger
647 // conditions still need to be met. For example, there need to be
648 // enough apps open for the right edge tutorial.
652 var tutorialRight = findChild(shell, "tutorialRight");
653 verify(tutorialRight.isReady);
654 verify(tutorialRight.shown);
655 verify(!tutorialRight.paused);
657 callManager.foregroundCall = phoneCall;
659 callManager.foregroundCall = null;
661 verify(!tutorialRight.isReady);
662 verify(!tutorialRight.shown);
663 verify(!tutorialRight.paused);
664 compare(AccountsService.demoEdgesCompleted, ["left", "top", "left-long"]);
667 function test_desktopOnlyShowsTutorialRight() {
668 loadShell("desktop");
670 var tutorialLeftLoader = findChild(shell, "tutorialLeftLoader");
671 var tutorialTopLoader = findChild(shell, "tutorialTopLoader");
672 var tutorialLeftLongLoader = findChild(shell, "tutorialLeftLongLoader");
673 var tutorialRightLoader = findChild(shell, "tutorialRightLoader");
674 verify(!tutorialLeftLoader.active);
675 verify(!tutorialTopLoader.active);
676 verify(!tutorialLeftLongLoader.active);
677 verify(tutorialRightLoader.active);
678 compare(AccountsService.demoEdgesCompleted, []);
680 var tutorialRightTimer = findInvisibleChild(tutorialRightLoader, "tutorialRightTimer");
681 tutorialRightTimer.interval = 1;
683 ApplicationManager.startApplication("dialer-app");
684 ApplicationManager.startApplication("camera-app");
685 ApplicationManager.startApplication("facebook-webapp");
686 tryCompare(tutorialRightLoader.item, "isReady", true);
688 tryCompare(tutorialRightLoader, "shown", true);
691 function test_desktopTutorialRightFinish() {
692 loadShell("desktop");
694 var tutorialRightLoader = findChild(shell, "tutorialRightLoader");
695 var tutorialRightTimer = findInvisibleChild(tutorialRightLoader, "tutorialRightTimer");
696 tutorialRightTimer.interval = 1;
697 ApplicationManager.startApplication("dialer-app");
698 ApplicationManager.startApplication("camera-app");
699 ApplicationManager.startApplication("facebook-webapp");
700 tryCompare(tutorialRightLoader, "shown", true);
702 var stage = findChild(shell, "stage");
703 mouseMove(shell, shell.width, shell.height / 2);
704 stage.pushRightEdge(units.gu(8));
705 tryCompare(tutorialRightLoader, "shown", false);
707 tryCompare(AccountsService, "demoEdges", false);
710 function test_oskDoesNotHideTutorial() {
711 var tutorialLeftLoader = findChild(shell, "tutorialLeftLoader");
712 verify(tutorialLeftLoader.shown);
714 var surface = SurfaceManager.inputMethodSurface;
715 surface.setState(Mir.RestoredState);
717 var inputMethod = findInvisibleChild(shell, "inputMethod");
718 tryCompare(inputMethod, "visible", true);
720 verify(tutorialLeftLoader.shown);
723 function test_oskDelaysTutorial() {
724 var tutorial = findChild(shell, "tutorial");
725 verify(!tutorial.delayed);
727 SurfaceManager.inputMethodSurface.setState(Mir.RestoredState);
729 tryCompare(tutorial, "delayed", true);
732 function test_notificationDelaysTutorial() {
733 var tutorial = findChild(shell, "tutorial");
734 verify(!tutorial.delayed);
736 var notifications = findChild(shell, "notificationList");
737 notifications.model = mockNotificationsModel;
738 addNotification(); // placeholder
741 tryCompare(tutorial, "delayed", true);
744 function test_dialogDelaysTutorial() {
745 var tutorial = findChild(shell, "tutorial");
746 verify(!tutorial.delayed);
748 var dialogs = findChild(shell, "dialogs");
749 dialogs.showPowerDialog();
751 verify(tutorial.delayed);
754 function test_delayedTutorial() {
755 var tutorial = findChild(shell, "tutorial");
756 var tutorialTop = findChild(tutorial, "tutorialTop");
757 var tutorialTopTimer = findChild(tutorialTop, "tutorialTopTimer");
759 // Get top tutorial ready
760 AccountsService.demoEdgesCompleted = ["left"];
761 verify(tutorialTop.isReady);
762 verify(tutorialTopTimer.running);
764 // Confirm that we become unready when delayed, but timer still goes
765 tutorial.delayed = true;
766 verify(!tutorialTop.isReady);
767 verify(tutorialTopTimer.running);
769 // Confirm that we don't open the tutorial when delayed
770 tutorialTopTimer.interval = 1;
772 verify(!tutorialTop.shown);
774 // Confirm we go back to normal when undelayed
775 tutorial.delayed = false;
776 tryCompare(tutorialTop, "shown", true);
779 function test_accountsServiceSettings() {
780 var tutorialLeftLoader = findChild(shell, "tutorialLeftLoader");
781 verify(tutorialLeftLoader.shown);
783 AccountsService.demoEdges = false;
784 verify(findChild(shell, "tutorialLeftLoader") == null);
786 AccountsService.demoEdges = true;
787 tutorialLeftLoader = findChild(shell, "tutorialLeftLoader");
788 var tutorialLeftTimer = findChild(tutorialLeftLoader, "tutorialLeftTimer");
789 verify(tutorialLeftTimer.running);
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