@@ -0,0 +1,286 @@
1+/*
2+ * Copyright (C) 2013,2014 Canonical, Ltd.
3+ *
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.
7+ *
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.
12+ *
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/>.
15+ */
16+
17+import QtQuick 2.0
18+import QtTest 1.0
19+import AccountsService 0.1
20+import LightDM 0.1 as LightDM
21+import Ubuntu.Components 1.1
22+import Unity.Application 0.1
23+import Unity.Test 0.1 as UT
24+
25+import "../../../qml"
26+
27+Item {
28+ id: root
29+ width: shellLoader.width + buttons.width
30+ height: shellLoader.height
31+
32+ QtObject {
33+ id: applicationArguments
34+
35+ function hasGeometry() {
36+ return false;
37+ }
38+
39+ function width() {
40+ return 0;
41+ }
42+
43+ function height() {
44+ return 0;
45+ }
46+ }
47+
48+ Component.onCompleted: {
49+ // must set the mock mode before loading the Shell
50+ LightDM.Greeter.mockMode = "single-pin";
51+ LightDM.Users.mockMode = "single-pin";
52+ shellLoader.active = true;
53+ }
54+
55+ Row {
56+ spacing: 0
57+ anchors.fill: parent
58+
59+ Loader {
60+ id: shellLoader
61+
62+ active: false
63+ width: units.gu(40)
64+ height: units.gu(71)
65+
66+ property bool itemDestroyed: false
67+ sourceComponent: Component {
68+ Shell {
69+ property string indicatorProfile: "phone"
70+
71+ Component.onDestruction: {
72+ shellLoader.itemDestroyed = true;
73+ }
74+ }
75+ }
76+ }
77+
78+ Rectangle {
79+ id: buttons
80+ color: "white"
81+ width: units.gu(30)
82+ height: shellLoader.height
83+
84+ Column {
85+ anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
86+ spacing: units.gu(1)
87+ Row {
88+ anchors { left: parent.left; right: parent.right }
89+ Button {
90+ text: "Restart Tutorial"
91+ onClicked: {
92+ if (shellLoader.status !== Loader.Ready)
93+ return;
94+
95+ AccountsService.demoEdges = false;
96+ AccountsService.demoEdges = true;
97+ }
98+ }
99+ }
100+ }
101+ }
102+ }
103+
104+ UT.UnityTestCase {
105+ id: testCase
106+ name: "Tutorial"
107+ when: windowShown
108+
109+ property Item shell: shellLoader.status === Loader.Ready ? shellLoader.item : null
110+ property real halfWidth: shell ? shell.width / 2 : 0
111+ property real halfHeight: shell ? shell.height / 2 : 0
112+
113+ function init() {
114+ tryCompare(shell, "enabled", true); // enabled by greeter when ready
115+ swipeAwayGreeter();
116+ AccountsService.demoEdges = false;
117+ AccountsService.demoEdges = true;
118+ }
119+
120+ function cleanup() {
121+ shellLoader.itemDestroyed = false;
122+
123+ shellLoader.active = false;
124+
125+ tryCompare(shellLoader, "status", Loader.Null);
126+ tryCompare(shellLoader, "item", null);
127+ // Loader.status might be Loader.Null and Loader.item might be null but the Loader
128+ // item might still be alive. So if we set Loader.active back to true
129+ // again right now we will get the very same Shell instance back. So no reload
130+ // actually took place. Likely because Loader waits until the next event loop
131+ // iteration to do its work. So to ensure the reload, we will wait until the
132+ // Shell instance gets destroyed.
133+ tryCompare(shellLoader, "itemDestroyed", true);
134+
135+ // kill all (fake) running apps
136+ killApps();
137+
138+ // reload our test subject to get it in a fresh state once again
139+ shellLoader.active = true;
140+
141+ tryCompare(shellLoader, "status", Loader.Ready);
142+ removeTimeConstraintsFromDirectionalDragAreas(shellLoader.item);
143+ }
144+
145+ function killApps() {
146+ while (ApplicationManager.count > 1) {
147+ var appIndex = ApplicationManager.get(0).appId == "unity8-dash" ? 1 : 0
148+ ApplicationManager.stopApplication(ApplicationManager.get(appIndex).appId);
149+ }
150+ compare(ApplicationManager.count, 1)
151+ }
152+
153+ function swipeAwayGreeter() {
154+ var greeter = findChild(shell, "greeter");
155+ tryCompare(greeter, "showProgress", 1);
156+
157+ touchFlick(shell, halfWidth, halfHeight, shell.width, halfHeight);
158+
159+ // wait until the animation has finished
160+ tryCompare(greeter, "showProgress", 0);
161+ waitForRendering(greeter);
162+ }
163+
164+ function waitForPage(name) {
165+ tryCompareFunction(function() { return findChild(shell, name) !== null; }, true);
166+ waitForRendering(findChild(shell, name));
167+ var page = findChild(shell, name);
168+ tryCompare(page, "shown", true);
169+ tryCompare(page.showAnimation, "running", false);
170+ return page;
171+ }
172+
173+ function checkTopEdge() {
174+ touchFlick(shell, halfWidth, 0, halfWidth, halfHeight);
175+
176+ var panel = findChild(shell, "panel");
177+ tryCompare(panel.indicators, "fullyClosed", true);
178+ }
179+
180+ function checkLeftEdge() {
181+ touchFlick(shell, 0, halfHeight, halfWidth, halfHeight);
182+
183+ var launcher = findChild(shell, "launcher");
184+ tryCompare(launcher, "state", "");
185+ }
186+
187+ function checkRightEdge() {
188+ touchFlick(shell, shell.width, halfHeight, halfWidth, halfHeight);
189+
190+ var stage = findChild(shell, "stage");
191+ var spreadView = findChild(stage, "spreadView");
192+ tryCompare(spreadView, "phase", 0);
193+ }
194+
195+ function checkBottomEdge() {
196+ // Can't actually check effect of swipe, since dash isn't really loaded
197+ var applicationsDisplayLoader = findChild(shell, "applicationsDisplayLoader");
198+ tryCompare(applicationsDisplayLoader.item, "interactive", false);
199+ }
200+
201+ function checkFinished() {
202+ tryCompare(AccountsService, "demoEdges", false);
203+
204+ var tutorial = findChild(shell, "tutorial");
205+ tryCompare(tutorial, "running", false);
206+
207+ var launcher = findChild(shell, "launcher");
208+ tryCompare(launcher, "shown", false);
209+ }
210+
211+ function goToPage(name) {
212+ var page = waitForPage("tutorialLeft");
213+ checkTopEdge();
214+ checkRightEdge();
215+ checkBottomEdge();
216+ if (name === "tutorialLeft") return page;
217+ touchFlick(shell, 0, halfHeight, halfWidth, halfHeight);
218+
219+ page = waitForPage("tutorialLeftFinish");
220+ if (name === "tutorialLeftFinish") return page;
221+ var tick = findChild(page, "tick");
222+ tap(tick);
223+
224+ checkFinished();
225+ return null;
226+ }
227+
228+ function test_walkthrough() {
229+ goToPage(null);
230+ }
231+
232+ function test_launcherShortDrag() {
233+ // goToPage does a normal launcher pull. But here we want to test
234+ // just barely pulling the launcher out and letting go (i.e. not
235+ // triggering the "progress" property of Launcher).
236+
237+ var left = goToPage("tutorialLeft");
238+
239+ // Make sure we don't do anything if we don't pull the launcher
240+ // out much.
241+ var launcher = findChild(shell, "launcher");
242+ touchFlick(shell, 0, halfHeight, launcher.panelWidth * 0.4, halfHeight);
243+ tryCompare(launcher, "state", ""); // should remain hidden
244+ tryCompare(left, "shown", true); // and we should still be on left
245+
246+ // Now drag out but not past launcher itself
247+ touchFlick(shell, 0, halfHeight, launcher.panelWidth * 0.9, halfHeight);
248+
249+ waitForPage("tutorialLeftFinish");
250+ }
251+
252+ function test_launcherLongDrag() {
253+ // goToPage does a normal launcher pull. But here we want to test
254+ // a full pull across the page.
255+
256+ var left = goToPage("tutorialLeft");
257+
258+ var launcher = findChild(shell, "launcher");
259+ touchFlick(shell, 0, halfHeight, shell.width, halfHeight);
260+
261+ var errorTextLabel = findChild(left, "errorTextLabel");
262+ var errorTitleLabel = findChild(left, "errorTitleLabel");
263+ tryCompare(launcher, "state", ""); // launcher goes away
264+ tryCompare(left, "shown", true); // still on left page
265+ tryCompare(errorTextLabel, "opacity", 1); // show error
266+ tryCompare(errorTitleLabel, "opacity", 1); // show error
267+ }
268+
269+ function test_launcherDragBack() {
270+ // goToPage does a full launcher pull. But here we test pulling
271+ // all the way out, then dragging back into place.
272+
273+ var left = goToPage("tutorialLeft");
274+ touchFlick(shell, 0, halfHeight, halfWidth, halfHeight, true, false);
275+ touchFlick(shell, halfWidth, halfHeight, 0, halfHeight, false, true);
276+
277+ tryCompare(left, "shown", true); // and we should still be on left
278+ }
279+
280+ function test_interrupted() {
281+ goToPage("tutorialLeft");
282+ ApplicationManager.startApplication("dialer-app");
283+ checkFinished();
284+ }
285+ }
286+}