Skip to content

Commit 185b364

Browse files
authored
Merge pull request moodlehq#1126 from magician03/gsoc2017
MOBILE-2130 GSoC: Final Work Product Submission for GSoC2017
2 parents c795cfe + 440b088 commit 185b364

File tree

62 files changed

+3426
-1968
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+3426
-1968
lines changed

.travis.yml

+36-10
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ sudo: true
22

33
dist: trusty
44

5+
group: edge
6+
57
addons:
68
apt:
79
sources:
@@ -15,24 +17,48 @@ language: node_js
1517
node_js:
1618
- '6.9.1'
1719

20+
cache:
21+
directories:
22+
- $HOME/www/lib
23+
- $HOME/node_modules
24+
1825
before_install:
1926
- npm cache clean
20-
- npm install -g cordova ionic
27+
- npm install -g cordova ionic@2.2.3
2128
- npm install
2229
- npm install -g bower
2330
- npm install -g gulp
2431
- bower install
25-
- ./node_modules/protractor/bin/webdriver-manager update
32+
33+
addons:
34+
sauce_connect: true
2635

2736
before_script:
28-
- "export DISPLAY=:99.0"
29-
- sh -e /etc/init.d/xvfb start
30-
- sleep 5 # Wait so xvfb can start properly.
3137
- gulp
32-
- gulp e2e-build --target browser
3338
- screen -dm ionic serve -b -a -d --nogulp --address localhost --port 8100 # We use screen here because nohup does not work with ionic serve.
34-
- nohup bash -c "./node_modules/protractor/bin/webdriver-manager start 2>&1 &"
35-
- sleep 5 # Wait a lot here, selenium and ionic must be running.
39+
- sleep 15 # Wait a lot here, selenium and gulp:before task and ionic must be running.
40+
41+
matrix:
42+
fast_finish: false
43+
44+
include:
45+
- script:
46+
- ./node_modules/protractor/bin/protractor e2e/sauce/browser/protractor-sauce-browser-activities-1.js
47+
48+
- script:
49+
- ./node_modules/protractor/bin/protractor e2e/sauce/browser/protractor-sauce-browser-activities-2.js
50+
51+
- script:
52+
- ./node_modules/protractor/bin/protractor e2e/sauce/browser/protractor-sauce-browser-config.js
53+
54+
- script:
55+
- ./node_modules/protractor/bin/protractor e2e/sauce/browser/protractor-sauce-browser-course.js
56+
57+
- script:
58+
- ./node_modules/protractor/bin/protractor e2e/sauce/browser/protractor-sauce-browser-resource.js
59+
60+
- script:
61+
- ./node_modules/protractor/bin/protractor e2e/sauce/browser/protractor-sauce-browser-user.js
3662

37-
script:
38-
- ./node_modules/protractor/bin/protractor e2e/build/protractor.conf.js
63+
- script:
64+
- ./node_modules/protractor/bin/protractor e2e/sauce/browser/protractor-sauce-browser-activities-3.js

e2e/bootstrap.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,5 @@ beforeEach(function() {
3737
return browser.driver.isElementPresent(by.id('mm-login-site')).then(function(e) {
3838
return e === true;
3939
});
40-
}, 50000);
40+
}, 100000);
4141
});

e2e/lib.js

+84-29
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
var waitForCondition = require('./plugins/wait_for_transitions.js').waitForCondition;
1516
var MM = {},
1617
currentNavBar = '.nav-bar-block[nav-bar="active"]',
1718
currentView = 'ion-view[nav-view="active"]';
@@ -25,13 +26,18 @@ var MM = {},
2526
* @param {Element} container The container in which the node should be found.
2627
* @return {Promise}
2728
*/
28-
MM.clickOn = function(text, container) {
29+
MM.clickOn = function (text, container) {
30+
waitForCondition();
2931
var locator = by.xpath('(//a | //button | //*[contains(concat(" ",normalize-space(@class)," ")," item ")])[contains(.,"' + text + '") or contains(@aria-label,"' + text + '")]');
32+
3033
if (container) {
34+
waitForCondition();
35+
browser.wait(EC.presenceOf(container), 5000);
3136
node = container.element(locator);
3237
} else {
3338
node = element(locator);
3439
}
40+
waitForCondition();
3541
return MM.clickOnElement(node);
3642
};
3743

@@ -43,20 +49,49 @@ MM.clickOn = function(text, container) {
4349
* @param {Element} el
4450
* @return {Promise}
4551
*/
46-
MM.clickOnElement = function(el) {
52+
MM.clickOnElement = function (el) {
53+
waitForCondition();
54+
browser.sleep(2000);
55+
browser.wait(EC.presenceOf(el), 50000);
4756
browser.executeScript('arguments[0].scrollIntoView(true)', el.getWebElement());
57+
browser.wait(EC.elementToBeClickable(el), 13000);
4858
return el.click();
4959
};
5060

61+
/**
62+
* Go to bottom of page and Click on a element.
63+
*
64+
* This will scroll the view if required.
65+
*
66+
* @param {Element} text
67+
* @return {Promise}
68+
*/
69+
MM.goToBottomAndClick = function (text) {
70+
waitForCondition();
71+
browser.sleep(2000); // This is must, due to slow page rendering issues.
72+
var locator = by.xpath('(//a | //button | //*[contains(concat(" ",normalize-space(@class)," ")," item ")])[contains(.,"' + text + '") or contains(@aria-label,"' + text + '")]');
73+
browser.wait(EC.presenceOf(element(locator)), 5000);
74+
node = element(locator);
75+
76+
waitForCondition();
77+
browser.sleep(2000);
78+
browser.executeScript('arguments[0].scrollIntoView(false)', node.getWebElement());
79+
browser.wait(EC.elementToBeClickable(node), 15000);
80+
return node.click();
81+
}
82+
5183
/**
5284
* Click on a link in the side menu.
5385
*
5486
* @param {String} text The link name
5587
* @return {Promise}
5688
*/
57-
MM.clickOnInSideMenu = function(text) {
58-
return MM.openSideMenu().then(function() {
89+
MM.clickOnInSideMenu = function (text) {
90+
return MM.openSideMenu().then(function () {
91+
waitForCondition();
5992
var menu = $('ion-side-menu[side="left"]');
93+
browser.wait(EC.visibilityOf(menu), 7000);
94+
browser.wait(EC.elementToBeClickable(menu), 5000);
6095
return MM.clickOn(text, menu);
6196
});
6297
};
@@ -66,7 +101,10 @@ MM.clickOnInSideMenu = function(text) {
66101
*
67102
* @return {Element}
68103
*/
69-
MM.getNavBar = function() {
104+
MM.getNavBar = function () {
105+
waitForCondition();
106+
browser.wait(EC.visibilityOf($(currentNavBar)), 10000);
107+
browser.sleep(7000); // Wait for contents to render.
70108
return $(currentNavBar);
71109
};
72110

@@ -75,7 +113,10 @@ MM.getNavBar = function() {
75113
*
76114
* @return {Element}
77115
*/
78-
MM.getView = function() {
116+
MM.getView = function () {
117+
waitForCondition();
118+
browser.wait(EC.visibilityOf($(currentView)), 50000);
119+
browser.sleep(7000); // Wait for contents to render.
79120
return $(currentView);
80121
};
81122

@@ -84,15 +125,17 @@ MM.getView = function() {
84125
*
85126
* @return {Promise}
86127
*/
87-
MM.goBack = function() {
128+
MM.goBack = function () {
88129
var backBtn = $(currentNavBar + ' .back-button');
89-
return backBtn.isPresent().then(function(present) {
130+
waitForCondition();
131+
browser.wait(EC.visibilityOf(backBtn), 15000);
132+
return backBtn.isPresent().then(function (present) {
90133
if (present) {
91-
return backBtn.isDisplayed().then(function(displayed) {
134+
return backBtn.isDisplayed().then(function (displayed) {
92135
if (displayed) {
93136
return backBtn.click();
94137
}
95-
throw new Error('Could not find the back button.');
138+
throw new Error('Could not find back button.');
96139
});
97140
}
98141
throw new Error('Could not find the back button.');
@@ -106,27 +149,34 @@ MM.goBack = function() {
106149
* @param {String} password The password
107150
* @return {Promise}
108151
*/
109-
MM.loginAs = function(username, password) {
152+
MM.loginAs = function (username, password) {
153+
154+
browser.ignoreSynchronization = true;
155+
browser.waitForAngular();
156+
browser.wait(EC.visibilityOf(element(by.model('siteurl'))), 15000);
157+
110158
element(by.model('siteurl'))
111159
.sendKeys(SITEURL);
112-
160+
browser.wait(EC.elementToBeClickable($('[ng-click="connect(siteurl)"]')), 15000);
113161
return $('[ng-click="connect(siteurl)"]').click()
114-
.then(function() {
115-
element(by.model('credentials.username'))
116-
.sendKeys(username);
117-
element(by.model('credentials.password'))
118-
.sendKeys(password);
119-
120-
return $('[ng-click="login()"]').click();
121-
});
162+
.then(function () {
163+
waitForCondition();
164+
browser.wait(EC.visibilityOf($('[ng-click="login()"]')), 15000);
165+
element(by.model('credentials.username'))
166+
.sendKeys(username);
167+
element(by.model('credentials.password'))
168+
.sendKeys(password);
169+
browser.wait(EC.elementToBeClickable($('[ng-click="login()"]')), 15000);
170+
return $('[ng-click="login()"]').click();
171+
});
122172
};
123173

124174
/**
125175
* Login as admin.
126176
*
127177
* @return {Promise}
128178
*/
129-
MM.loginAsAdmin = function() {
179+
MM.loginAsAdmin = function () {
130180
return MM.loginAs(USERS.ADMIN.LOGIN, USERS.ADMIN.PASSWORD);
131181
};
132182

@@ -135,7 +185,7 @@ MM.loginAsAdmin = function() {
135185
*
136186
* @return {Promise}
137187
*/
138-
MM.loginAsStudent = function() {
188+
MM.loginAsStudent = function () {
139189
return MM.loginAs(USERS.STUDENT.LOGIN, USERS.STUDENT.PASSWORD);
140190
};
141191

@@ -145,7 +195,7 @@ MM.loginAsStudent = function() {
145195
*
146196
* @return {Promise}
147197
*/
148-
MM.loginAsTeacher = function() {
198+
MM.loginAsTeacher = function () {
149199
return MM.loginAs(USERS.TEACHER.LOGIN, USERS.TEACHER.PASSWORD);
150200
};
151201

@@ -154,7 +204,7 @@ MM.loginAsTeacher = function() {
154204
*
155205
* @return {Promise}
156206
*/
157-
MM.logout = function() {
207+
MM.logout = function () {
158208
return MM.clickOnInSideMenu('Change site');
159209
};
160210

@@ -163,17 +213,22 @@ MM.logout = function() {
163213
*
164214
* @return {Promise}
165215
*/
166-
MM.openSideMenu = function() {
216+
MM.openSideMenu = function () {
167217
var menuBtn = $(currentNavBar + ' [menu-toggle="left"]:not(.hide)');
218+
waitForCondition();
219+
browser.wait(EC.visibilityOf(menuBtn), 10000);
220+
browser.wait(EC.elementToBeClickable(menuBtn), 50000);
221+
168222
function navigateBack() {
169-
return MM.goBack().then(function() {
223+
return MM.goBack().then(function () {
170224
return openMenu();
171225
});
172226
}
227+
173228
function openMenu() {
174-
return menuBtn.isPresent().then(function(present) {
229+
return menuBtn.isPresent().then(function (present) {
175230
if (present) {
176-
return menuBtn.isDisplayed().then(function(displayed) {
231+
return menuBtn.isDisplayed().then(function (displayed) {
177232
if (displayed) {
178233
return menuBtn.click();
179234
}
@@ -186,4 +241,4 @@ MM.openSideMenu = function() {
186241
return openMenu();
187242
};
188243

189-
global.MM = global.MM || MM;
244+
global.MM = global.MM || MM;

e2e/plugins/wait_for_transitions.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -67,5 +67,4 @@ exports.waitForCondition = function() {
6767
}).then(function(inTransition) {
6868
return inTransition;
6969
});
70-
};
71-
70+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
exports.config = {
2+
framework: "jasmine2",
3+
jasmineNodeOpts: {
4+
showColors: true,
5+
defaultTimeoutInterval: 100000,
6+
realtimeFailure: true,
7+
showTiming: true,
8+
includeStackTrace: true,
9+
isVerbose: true,
10+
onComplete: null
11+
},
12+
specs: [
13+
"../../../e2e/*.js",
14+
"../../../www/**/e2e/mod_chat.spec.js",
15+
"../../../www/**/e2e/mod_quiz.spec.js",
16+
"../../../www/**/e2e/mod_choice.spec.js",
17+
"../../../www/**/e2e/mod_assign.spec.js",
18+
"../../../www/**/e2e/mod_assign_teacher.spec.js"
19+
],
20+
baseUrl: 'http://localhost:8100/',
21+
seleniumAddress: "http://" + process.env.SAUCE_USERNAME + ":" + process.env.SAUCE_ACCESS_KEY + "@ondemand.saucelabs.com:80/wd/hub",
22+
multiCapabilities: [{
23+
"name": 'chrome',
24+
"browserName": "chrome",
25+
"chromeOptions": {
26+
args: [
27+
"--allow-file-access",
28+
"--allow-file-access-from-files",
29+
"--enable-local-file-accesses",
30+
"--unlimited-storage"
31+
]
32+
},
33+
"platform": "Windows 10",
34+
"version": "56.0",
35+
"username": process.env.SAUCE_USERNAME,
36+
"accessKey": process.env.SAUCE_ACCESS_KEY,
37+
"tunnel-identifier": process.env.TRAVIS_JOB_NUMBER,
38+
"build": process.env.TRAVIS_BUILD_NUMBER
39+
}],
40+
restartBrowserBetweenTests: true,
41+
onPrepare: function () {
42+
var wd = require('wd'),
43+
protractor = require('protractor'),
44+
wdBridge = require('wd-bridge')(protractor, wd);
45+
wdBridge.initFromProtractor(exports.config);
46+
global.EC = protractor.ExpectedConditions;
47+
48+
49+
// Define global variables for our tests.
50+
global.ISANDROID = false;
51+
global.ISBROWSER = true;
52+
global.ISIOS = false;
53+
global.ISTABLET = false;
54+
global.DEVICEURL = 'http://localhost:8100/';
55+
global.DEVICEVERSION = undefined;
56+
global.SITEURL = 'http://school.demo.moodle.net';
57+
global.SITEVERSION = 3.3;
58+
global.SITEHASLM = false;
59+
global.USERS = {
60+
"STUDENT": {
61+
"LOGIN": "student",
62+
"PASSWORD": "moodle"
63+
},
64+
"TEACHER": {
65+
"LOGIN": "teacher",
66+
"PASSWORD": "moodle"
67+
},
68+
"ADMIN": {
69+
"LOGIN": "admin",
70+
"PASSWORD": "test"
71+
}
72+
};
73+
},
74+
getPageTimeout: 15000,
75+
plugins: [{
76+
"path": "../../../e2e/plugins/wait_for_transitions.js"
77+
}]
78+
};

0 commit comments

Comments
 (0)