@@ -21,6 +21,7 @@ import QtQuick 2.0
21import QtTest 1.0
21import QtTest 1.0
22import GSettings 1.0
22import GSettings 1.0
23import LightDM 0.1 as LightDM
23import LightDM 0.1 as LightDM
24+import Ubuntu.Components 1.1
24import Ubuntu.Telephony 0.1 as Telephony
25import Ubuntu.Telephony 0.1 as Telephony
25import Unity.Application 0.1
26import Unity.Application 0.1
26import Unity.Connectivity 0.1
27import Unity.Connectivity 0.1
@@ -29,10 +30,9 @@ import Powerd 0.1
30import "../../qml"
31import "../../qml"
34− width: shell.width
35+ spacing: 0
37 QtObject {
37 QtObject {
38 id: applicationArguments
38 id: applicationArguments
@@ -50,13 +50,52 @@ Item {
54− id: shell
54+ id: shellLoader
56+ // Copied from Shell.qml
57+ property bool tablet: false
58+ width: tablet ? units.gu(160)
59+ : applicationArguments.hasGeometry() ? applicationArguments.width()
61+ height: tablet ? units.gu(100)
62+ : applicationArguments.hasGeometry() ? applicationArguments.height()
65+ property bool itemDestroyed: false
66+ sourceComponent: Component {
68+ Component.onDestruction: {
69+ shellLoader.itemDestroyed = true;
57− Component {
75+ Rectangle {
58− id: shellComponent
76+ color: "white"
59− Shell {}
77+ width: units.gu(30)
78+ height: shellLoader.height
81+ anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
84+ anchors { left: parent.left; right: parent.right }
88+ if (shellLoader.status !== Loader.Ready)
91+ var greeter = testCase.findChild(shellLoader.item, "greeter");
92+ if (!greeter.shown) {
62 SignalSpy {
101 SignalSpy {
@@ -81,10 +120,13 @@ Item {
83 UT.UnityTestCase {
122 UT.UnityTestCase {
84 name: "Shell"
124 name: "Shell"
85 when: windowShown
125 when: windowShown
127+ property Item shell: shellLoader.status === Loader.Ready ? shellLoader.item : null
87− function initTestCase() {
129+ function init() {
88 swipeAwayGreeter();
130 swipeAwayGreeter();
90 sessionSpy.target = findChild(shell, "greeter")
132 sessionSpy.target = findChild(shell, "greeter")
@@ -92,17 +134,30 @@ Item {
94 function cleanup() {
136 function cleanup() {
95− // If a test invoked the greeter, make sure we swipe it away again
137+ shellLoader.itemDestroyed = false;
96− var greeter = findChild(shell, "greeter");
138+
97− if (greeter.shown) {
139+ shellLoader.active = false;
98− swipeAwayGreeter();
140+
99− }
141+ tryCompare(shellLoader, "status", Loader.Null);
142+ tryCompare(shellLoader, "item", null);
143+ // Loader.status might be Loader.Null and Loader.item might be null but the Loader
144+ // item might still be alive. So if we set Loader.active back to true
145+ // again right now we will get the very same Shell instance back. So no reload
146+ // actually took place. Likely because Loader waits until the next event loop
147+ // iteration to do its work. So to ensure the reload, we will wait until the
148+ // Shell instance gets destroyed.
149+ tryCompare(shellLoader, "itemDestroyed", true);
101 // kill all (fake) running apps
151 // kill all (fake) running apps
102 killApps(ApplicationManager);
152 killApps(ApplicationManager);
104− waitForUIToSettle();
154+ unlockAllModemsSpy.clear()
105− hideIndicators();
155+
156+ // reload our test subject to get it in a fresh state once again
157+ shellLoader.active = true;
159+ tryCompare(shellLoader, "status", Loader.Ready);
160+ removeTimeConstraintsFromDirectionalDragAreas(shellLoader.item);
108 function killApps() {
163 function killApps() {
@@ -241,10 +296,27 @@ Item {
241 tryCompare(item, "visible", false);
296 tryCompare(item, "visible", false);
299+ // wait until any transition animation has finished
300+ function waitUntilTransitionsEnd(stateGroup) {
301+ var transitions = stateGroup.transitions;
302+ for (var i = 0; i < transitions.length; ++i) {
303+ var transition = transitions[i];
304+ tryCompare(transition, "running", false, 2000);
308+ // Wait until the ApplicationWindow for the given Application object is fully loaded
309+ // (ie, the real surface has replaced the splash screen)
310+ function waitUntilAppWindowIsFullyLoaded(app) {
311+ var appWindow = findChild(shell, "appWindow_" + app.appId);
312+ var appWindowStateGroup = findInvisibleChild(appWindow, "applicationWindowStateGroup");
313+ tryCompareFunction(function() { return appWindowStateGroup.state === "surface" }, true);
314+ waitUntilTransitionsEnd(appWindowStateGroup);
244 function test_surfaceLosesFocusWhilePanelIsOpen() {
317 function test_surfaceLosesFocusWhilePanelIsOpen() {
245 var app = ApplicationManager.startApplication("dialer-app");
318 var app = ApplicationManager.startApplication("dialer-app");
246− // wait until the app is fully loaded (ie, real surface replaces splash screen)
319+ waitUntilAppWindowIsFullyLoaded(app);
247− tryCompareFunction(function() { return app.session !== null && app.session.surface !== null }, true);
249 tryCompare(app.session.surface, "focus", true);
321 tryCompare(app.session.surface, "focus", true);
@@ -465,13 +537,9 @@ Item {
467 function test_unlockAllModemsOnBoot() {
539 function test_unlockAllModemsOnBoot() {
468− unlockAllModemsSpy.clear()
469− // actually create an object so we notice the onCompleted signal
470− var greeter = shellComponent.createObject(root)
471 // TODO reenable when service ready (LP: #1361074)
540 // TODO reenable when service ready (LP: #1361074)
472 expectFail("", "Unlock on boot temporarily disabled");
541 expectFail("", "Unlock on boot temporarily disabled");
473 tryCompare(unlockAllModemsSpy, "count", 1)
542 tryCompare(unlockAllModemsSpy, "count", 1)