Merge pull request #2664 from sebv/master

Various test fixes and improvements
This commit is contained in:
seb vincent
2014-05-24 11:04:44 -07:00
33 changed files with 219 additions and 189 deletions

View File

@@ -100,9 +100,9 @@ if $android_only || $all_tests; then
fi
if $android_chrome; then
echo "RUNNING ANDROID (ARM) TESTS"
echo "RUNNING ANDROID CHROME TESTS"
echo "---------------------"
DEVICE=android time $appåium_mocha \
DEVICE=android time $appium_mocha \
-g '@skip-chrome|@skip-android-all' -i \
test/functional/android/chrome
fi
@@ -119,12 +119,8 @@ if $gappium_only || $all_tests; then
echo "---------------------"
DEVICE=ios71 time $appium_mocha test/functional/gappium
DEVICE=ios6 time $appium_mocha test/functional/gappium
# TODO: fix android/gappium test, no webview context found, investigate
# echo "Start the android emulator and press Enter."
# read
# DEVICE=android time $appium_mocha test/functional/gappium
# TODO: the gappium app does not work on selendroid, investigate
# echo "Start the android emulator and press Enter."
# read
# DEVICE=selendroid time $appium_mocha test/functional/gappium
echo "Start the android emulator api 19 and press Enter."
read
DEVICE=android time $appium_mocha test/functional/gappium
DEVICE=selendroid time $appium_mocha test/functional/gappium
fi

View File

@@ -1,7 +1,6 @@
"use strict";
var env = require('../../../helpers/env')
, setup = require("../../common/setup-base")
var setup = require("../../common/setup-base")
, desired = require("./desired");
describe("apidemos - attributes", function () {
@@ -9,12 +8,6 @@ describe("apidemos - attributes", function () {
var driver;
setup(this, desired).then(function (d) { driver = d; });
if (env.FAST_TESTS) {
beforeEach(function (done) {
driver.resetApp().nodeify(done);
});
}
it('should be able to find text attribute', function (done) {
driver
.elementByName('Animation').getAttribute('text')

View File

@@ -201,7 +201,7 @@ describe("apidemo - basic @skip-ci", function () {
pids.length.should.equal(1);
done();
});
}, 2000);
}, 5000);
});
});

View File

@@ -3,6 +3,7 @@
var env = require('../../../../helpers/env')
, setup = require("../../../common/setup-base")
, desired = require("../desired")
, reset = require("../reset")
, atv = 'android.widget.TextView';
describe("apidemo - find - basics", function () {
@@ -11,8 +12,8 @@ describe("apidemo - find - basics", function () {
setup(this, desired).then(function (d) { driver = d; });
if (env.FAST_TESTS) {
beforeEach(function (done) {
driver.resetApp().nodeify(done);
beforeEach(function () {
return reset(driver);
});
}

View File

@@ -1,7 +1,6 @@
"use strict";
var env = require('../../../../helpers/env')
, setup = require("../../../common/setup-base")
var setup = require("../../../common/setup-base")
, desired = require("../desired");
describe("apidemo - find - by accessibility id", function () {
@@ -9,12 +8,6 @@ describe("apidemo - find - by accessibility id", function () {
var driver;
setup(this, desired).then(function (d) { driver = d; });
if (env.FAST_TESTS) {
beforeEach(function (done) {
driver.resetApp().nodeify(done);
});
}
it('should find an element by name', function (done) {
driver.element('accessibility id', 'Animation').then(function (el) {
el.should.exist;

View File

@@ -1,7 +1,6 @@
"use strict";
var env = require('../../../../helpers/env')
, setup = require("../../../common/setup-base")
var setup = require("../../../common/setup-base")
, desired = require("../desired");
describe("apidemo - find elements - by uiautomator", function () {
@@ -9,12 +8,6 @@ describe("apidemo - find elements - by uiautomator", function () {
var driver;
setup(this, desired).then(function (d) { driver = d; });
if (env.FAST_TESTS) {
beforeEach(function (done) {
driver.resetApp().nodeify(done);
});
}
it('should find elements with a boolean argument', function (done) {
driver.elements('-android uiautomator', 'new UiSelector().clickable(true)').then(function (els) {
els.length.should.be.above(11);

View File

@@ -1,7 +1,6 @@
"use strict";
var env = require('../../../../helpers/env')
, setup = require("../../../common/setup-base")
var setup = require("../../../common/setup-base")
, desired = require("../desired")
, atv = 'android.widget.TextView'
, alv = 'android.widget.ListView';
@@ -11,15 +10,14 @@ describe("apidemo - find - by xpath", function () {
var driver;
setup(this, desired).then(function (d) { driver = d; });
if (env.FAST_TESTS) {
beforeEach(function (done) {
driver.resetApp().nodeify(done);
});
}
var f = "android.widget.FrameLayout";
var l = alv;
var t = atv;
before(function (done) {
driver.sleep(1000).nodeify(done);
});
it('should find element by type', function (done) {
driver
.elementByXPath('//' + t).text()

View File

@@ -1,7 +1,6 @@
"use strict";
var env = require('../../../../helpers/env')
, setup = require("../../../common/setup-base")
var setup = require("../../../common/setup-base")
, desired = require("../desired");
describe("apidemo - find - complex", function () {
@@ -9,12 +8,6 @@ describe("apidemo - find - complex", function () {
var driver;
setup(this, desired).then(function (d) { driver = d; });
if (env.FAST_TESTS) {
beforeEach(function (done) {
driver.resetApp().nodeify(done);
});
}
it('should scroll to an element by text or content desc', function (done) {
driver
.complexFind(["scroll", [[3, "views"]], [[7, "views"]]]).text()

View File

@@ -1,7 +1,6 @@
"use strict";
var env = require('../../../../helpers/env')
, setup = require("../../../common/setup-base")
var setup = require("../../../common/setup-base")
, desired = require("../desired")
, atv = 'android.widget.TextView'
, alv = 'android.widget.ListView';
@@ -11,12 +10,6 @@ describe("apidemo - find - from element", function () {
var driver;
setup(this, desired).then(function (d) { driver = d; });
if (env.FAST_TESTS) {
beforeEach(function (done) {
driver.resetApp().nodeify(done);
});
}
it('should find a single element by tag name', function (done) {
driver.elementByClassName(alv).then(function (el) {
return el

View File

@@ -1,7 +1,6 @@
"use strict";
var env = require('../../../../helpers/env')
, setup = require("../../../common/setup-base")
var setup = require("../../../common/setup-base")
, desired = require("../desired");
describe("apidemo - find - invalid strategy", function () {
@@ -9,12 +8,6 @@ describe("apidemo - find - invalid strategy", function () {
var driver;
setup(this, desired).then(function (d) { driver = d; });
if (env.FAST_TESTS) {
beforeEach(function (done) {
driver.resetApp().nodeify(done);
});
}
it('should not accept -ios uiautomation locator strategy', function (done) {
driver
.elements('-ios uiautomation', '.elements()').catch(function (err) {

View File

@@ -3,6 +3,7 @@
var env = require('../../../../helpers/env')
, setup = require("../../../common/setup-base")
, desired = require("../desired")
, reset = require("../reset")
, droidText = 'android.widget.TextView';
describe("apidemo - gestures - click", function () {
@@ -10,10 +11,8 @@ describe("apidemo - gestures - click", function () {
setup(this, desired).then(function (d) { driver = d; });
if (env.FAST_TESTS) {
beforeEach(function (done) {
driver.resetApp()
.then(function () { return driver.sleep(3000); })
.nodeify(done);
beforeEach(function () {
return reset(driver);
});
}

View File

@@ -3,6 +3,7 @@
var env = require('../../../../helpers/env')
, setup = require("../../../common/setup-base")
, desired = require("../desired")
, reset = require("../reset")
, droidText = 'android.widget.TextView'
, droidList = 'android.widget.ListView'
, Q = require("q");
@@ -12,10 +13,8 @@ describe("apidemo - gestures - drag", function () {
setup(this, desired).then(function (d) { driver = d; });
if (env.FAST_TESTS) {
beforeEach(function (done) {
driver.resetApp()
.then(function () { return driver.sleep(3000); })
.nodeify(done);
beforeEach(function () {
return reset(driver);
});
}

View File

@@ -3,6 +3,7 @@
var env = require('../../../../helpers/env')
, setup = require("../../../common/setup-base")
, desired = require("../desired")
, reset = require("../reset")
, droidText = 'android.widget.TextView';
describe("apidemo - gestures - execute", function () {
@@ -10,10 +11,8 @@ describe("apidemo - gestures - execute", function () {
setup(this, desired).then(function (d) { driver = d; });
if (env.FAST_TESTS) {
beforeEach(function (done) {
driver.resetApp()
.then(function () { return driver.sleep(3000); })
.nodeify(done);
beforeEach(function () {
return reset(driver);
});
}

View File

@@ -2,17 +2,16 @@
var env = require('../../../../helpers/env')
, setup = require("../../../common/setup-base")
, desired = require("../desired");
, desired = require("../desired")
, reset = require("../reset");
describe("apidemo - gestures - flick", function () {
var driver;
setup(this, desired).then(function (d) { driver = d; });
if (env.FAST_TESTS) {
beforeEach(function (done) {
driver.resetApp()
.then(function () { return driver.sleep(3000); })
.nodeify(done);
beforeEach(function () {
return reset(driver);
});
}

View File

@@ -3,17 +3,36 @@
var env = require('../../../../helpers/env')
, setup = require("../../../common/setup-base")
, desired = require("../desired")
, droidText = 'android.widget.TextView';
, reset = require("../reset")
, droidText = 'android.widget.TextView'
, Q = require('q');
describe("apidemo - gestures - long click", function () {
var driver;
setup(this, desired).then(function (d) { driver = d; });
if (env.FAST_TESTS) {
beforeEach(function () {
return reset(driver);
});
}
if (env.FAST_TESTS) {
beforeEach(function (done) {
driver.resetApp()
.then(function () { return driver.sleep(3000); })
.nodeify(done);
function back(depth) {
if (depth < 0) return new Q();
return driver
.elementByNameOrNull("Animation")
.then(function (el) {
if (el) return;
else {
return driver.back().then(function () {
back(depth - 1);
});
}
});
}
back(3).nodeify(done);
});
}

View File

@@ -1,7 +1,6 @@
"use strict";
var env = require('../../../../helpers/env')
, setup = require("../../../common/setup-base")
var setup = require("../../../common/setup-base")
, desired = require("../desired")
, droidText = 'android.widget.TextView'
, droidList = 'android.widget.ListView';
@@ -10,14 +9,6 @@ describe("apidemo - gestures - pinch", function () {
var driver;
setup(this, desired).then(function (d) { driver = d; });
if (env.FAST_TESTS) {
beforeEach(function (done) {
driver.resetApp()
.then(function () { return driver.sleep(3000); })
.nodeify(done);
});
}
// todo fix this: got Error response status: 13, Could not scroll element into view: Views
it('should pinch out/in @skip-android-all', function (done) {
var scrollOpts;

View File

@@ -1,7 +1,6 @@
"use strict";
var env = require('../../../../helpers/env')
, setup = require("../../../common/setup-base")
var setup = require("../../../common/setup-base")
, desired = require("../desired")
, droidList = 'android.widget.ListView';
@@ -9,14 +8,6 @@ describe("apidemo - gestures - scroll", function () {
var driver;
setup(this, desired).then(function (d) { driver = d; });
if (env.FAST_TESTS) {
beforeEach(function (done) {
driver.resetApp()
.then(function () { return driver.sleep(3000); })
.nodeify(done);
});
}
// todo fix this: got Error response status: 13, Could not scroll element into view: Views
it('should bring the element into view @skip-android-all', function (done) {
driver

View File

@@ -1,21 +1,12 @@
"use strict";
var env = require('../../../../helpers/env')
, setup = require("../../../common/setup-base")
var setup = require("../../../common/setup-base")
, desired = require("../desired");
describe("apidemo - gestures - swipe", function () {
var driver;
setup(this, desired).then(function (d) { driver = d; });
if (env.FAST_TESTS) {
beforeEach(function (done) {
driver.resetApp()
.then(function () { return driver.sleep(3000); })
.nodeify(done);
});
}
// todo fix this: got Error response status: 13, The swipe did not complete successfully
it('should swipe screen by pixels @skip-android-all', function (done) {
var swipeOpts = {

View File

@@ -2,44 +2,44 @@
var setup = require("../../common/setup-base")
, desired = require("./desired")
, safeClear = require('../../../helpers/safe-clear')
, _ = require('underscore');
describe("apidemo - keyboard", function () {
// TODO: fix clear logic
describe("apidemo - keyboard @skip-ci", function () {
var driver;
var runTextEditTest = function (testText, done) {
var el = function () {
return driver.waitForElementByClassName('android.widget.EditText');
};
var el;
driver
.resolve(el()).clear().text().should.become('')
.then(el).sendKeys(testText).text().should.become(testText)
.waitForElementByClassName('android.widget.EditText')
.then(function (_el) { el = _el; })
.then(function () { return safeClear(el); })
.then(function () { return el.sendKeys(testText); })
.then(function () { return el.text().should.become(testText); })
.nodeify(done);
};
setup(this, _.defaults({appActivity: "view.Controls1" }, desired))
.then(function (d) { driver = d; });
beforeEach(function (done) {
driver.resetApp().nodeify(done);
});
it('should be able to edit a text field', function (done) {
var testText = "this is awesome!";
var testText = "Life, the Universe and Everything.";
runTextEditTest(testText, done);
});
// TODO: clear is not reliable
it('should be able to edit and clear a text field @skip-android-all', function (done) {
var testText = "this is awesome!";
var el = function () {
return driver.waitForElementByClassName('android.widget.EditText');
};
it('should be able to edit and clear a text field', function (done) {
var testText = "The answer is 42.", el;
driver
.resolve(el()).clear().text().should.become("")
.then(el).sendKeys(testText).text().should.become(testText)
.sleep(2000)
.then(el).clear().text().should.become("")
.waitForElementByClassName('android.widget.EditText')
.then(function (_el) { el = _el; })
.then(function () { return safeClear(el); })
.then(function () { return el.sendKeys(testText).text().should.become(testText); })
.then(function () { return safeClear(el); })
// TODO: there is a bug here we should not need safeClear
// workaround for now.
.then(function () { return el.text().should.become(""); })
.nodeify(done);
});

View File

@@ -2,15 +2,16 @@
var setup = require("../../common/setup-base")
, env = require('../../../helpers/env')
, desired = require("./desired");
, desired = require("./desired")
, reset = require("./reset");
describe("apidemos - orientation", function () {
var driver;
setup(this, desired).then(function (d) { driver = d; });
if (env.FAST_TESTS) {
beforeEach(function (done) {
driver.resetApp().nodeify(done);
beforeEach(function () {
return reset(driver);
});
}

View File

@@ -0,0 +1,27 @@
"use strict";
var env = require('../../../helpers/env'),
Q = require('q');
module.exports = function (driver) {
function back(driver, depth) {
if (depth < 0) return new Q();
return driver
.setImplicitWaitTimeout(0)
.elementByNameOrNull("Animation")
.then(function (el) {
if (el) return;
else {
return driver.back().then(function () {
back(driver, depth - 1);
});
}
});
}
return back(driver, 3).setImplicitWaitTimeout(env.IMPLICIT_WAIT_TIMEOUT);
};
// module.exports = function (driver) {
// return driver.resetApp();
// };

View File

@@ -3,6 +3,7 @@
var env = require('../../../../helpers/env')
, setup = require("../../../common/setup-base")
, desired = require("../desired")
, reset = require("../reset")
, wd = require("wd")
, TouchAction = wd.TouchAction;
@@ -12,8 +13,8 @@ describe("apidemo - touch - drag", function () {
setup(this, desired).then(function (d) { driver = d; });
if (env.FAST_TESTS) {
beforeEach(function (done) {
driver.resetApp().nodeify(done);
beforeEach(function () {
return reset(driver);
});
}

View File

@@ -15,8 +15,8 @@ describe("apidemo - touch - multi-actions", function () {
setup(this, desired).then(function (d) { driver = d; });
if (env.FAST_TESTS) {
beforeEach(function (done) {
driver.resetApp().nodeify(done);
beforeEach(function () {
return driver.resetApp();
});
}

View File

@@ -12,8 +12,8 @@ describe("apidemo - touch - press", function () {
setup(this, desired).then(function (d) { driver = d; });
if (env.FAST_TESTS) {
beforeEach(function (done) {
driver.resetApp().nodeify(done);
beforeEach(function () {
return driver.resetApp();
});
}

View File

@@ -3,6 +3,7 @@
var env = require('../../../../helpers/env')
, setup = require("../../../common/setup-base")
, desired = require("../desired")
, reset = require("../reset")
, wd = require("wd")
, TouchAction = wd.TouchAction;
@@ -12,8 +13,8 @@ describe("apidemo - touch - swipe", function () {
setup(this, desired).then(function (d) { driver = d; });
if (env.FAST_TESTS) {
beforeEach(function (done) {
driver.resetApp().nodeify(done);
beforeEach(function () {
return reset(driver);
});
}

View File

@@ -13,8 +13,8 @@ describe("apidemo - touch - tap", function () {
setup(this, desired).then(function (d) { driver = d; });
if (env.FAST_TESTS) {
beforeEach(function (done) {
driver.resetApp().nodeify(done);
beforeEach(function () {
return driver.resetApp();
});
}

View File

@@ -4,4 +4,4 @@ var androidWebviewTests = require('../common/android-webview-base');
// TODO: androidWebviewTests is using an app built by selendroid. Need to build it once
// and save it into asset so that it can be used by android tests
describe('android - web_view @skip-ci @skip-android-all', androidWebviewTests);
describe('android - web_view @skip-ci', androidWebviewTests);

View File

@@ -3,7 +3,7 @@
var env = require('../../helpers/env')
, setup = require("./setup-base")
, Asserter = require('wd').Asserter;
, safeClear = require('../../helpers/safe-clear');
var desired = {
app: "sample-code/apps/selendroid-test-app.apk",
@@ -15,18 +15,21 @@ module.exports = function () {
var driver;
setup(this, desired).then(function (d) { driver = d; });
var webviewContextAvailable = new Asserter(
function (driver) {
return driver
.contexts().should.eventually.have.length(2);
}
);
beforeEach(function (done) {
driver
.waitForElementByName('buttonStartWebviewCD').click()
.waitFor(webviewContextAvailable, 1000, 100)
.context('WEBVIEW')
.setImplicitWaitTimeout(0)
.elementByName('buttonStartWebviewCD')
.then(function (el) {
if (el) return;
else return driver.back();
})
.setImplicitWaitTimeout(env.IMPLICIT_WAIT_TIMEOUT)
.elementByName('buttonStartWebviewCD').click()
.then(function () {
if (env.SELENDROID) return driver.waitForElementById('mainWebView');
else return driver.waitForElementByXPath(
"//android.widget.TextView[@text='Web View Interaction']");
}).context('WEBVIEW')
.nodeify(done);
});
@@ -47,14 +50,13 @@ module.exports = function () {
});
}
it('should be web view', function (done) {
// todo: add some sort of check here
done();
it('should be able to switch to view', function (done) {
driver.context('WEBVIEW').nodeify(done);
});
it('should list all contexts', function (done) {
driver
.contexts().should.eventually.have.length.above(0)
.contexts().should.eventually.have.length(2)
.nodeify(done);
});
@@ -73,18 +75,26 @@ module.exports = function () {
.nodeify(done);
});
// selendroid test app is busted
// TODO: clear does not work on selendroid
it('should clear input @skip-selendroid-all', function (done) {
var el;
driver
.elementById('name_input').click().clear().getValue().should.become("")
.waitForElementById('name_input', 10000, 500)
.then(function (_el) { el = _el; })
.then(function () { return safeClear(el); })
.then(function () { return el.getValue().should.become(""); })
.nodeify(done);
});
// selendroid test app is busted
// TODO: clear does not work on selendroid
it('should find and enter key sequence in input @skip-selendroid-all', function (done) {
var el;
driver
.elementById('name_input').clear()
.type("Mathieu").getValue().should.become("Mathieu")
.elementById('name_input')
.then(function (_el) { el = _el; })
.then(function () { return safeClear(el); })
.then(function () { return el.type("Mathieu")
.getValue().should.become("Mathieu"); })
.nodeify(done);
});
@@ -94,6 +104,7 @@ module.exports = function () {
it('should get web source', function (done) {
driver
.waitForElementById('name_input') // making sure webview has been loaded
.source().should.eventually.include("<title>Say Hello Demo<")
.nodeify(done);
});

View File

@@ -2,9 +2,11 @@
"use strict";
var env = require("../../helpers/env")
, setup = require("../common/setup-base");
, setup = require("../common/setup-base")
, ChaiAsserter = require("../../helpers/asserter").ChaiAsserter
, _ = require('underscore')
, desired;
var desired;
if (env.DEVICE === 'selendroid' || env.DEVICE === 'android') {
var appPath = 'sample-code/apps/' +
'io.appium.gappium.sampleapp/platforms/android/ant-build/' +
@@ -24,17 +26,24 @@ if (env.DEVICE === 'selendroid' || env.DEVICE === 'android') {
}
var activateWebView = function (driver) {
return driver.contexts().then(function (ctxs) {
for (var idx in ctxs) {
var ctx = ctxs[idx];
if (ctx.indexOf('WEBVIEW') !== -1) {
return ctx;
}
}
return 'WEBVIEW_1';
}).then(function (ctx) {
return driver.context(ctx).catch(function () {});
var webContextReady = new ChaiAsserter(function (driver) {
return driver
.contexts()
.then(function (ctxs) {
var webviewCtx = _(ctxs).find(function (ctx) {
return ctx.indexOf('WEBVIEW') >= 0;
});
webviewCtx.should.exist;
return webviewCtx;
});
});
return driver
//TODO: how to detect app is ready on android, spinning doesn't work.
.sleep(env.ANDROID || env.SELENDROID ? 45000 : 5000) // yup takes time to load
.waitFor(webContextReady, 10000, 500)
.then(function (webviewCtx) {
return driver.context(webviewCtx);
});
};
describe("gappium", function () {
@@ -48,8 +57,7 @@ describe("gappium", function () {
it('should open the app and navigate through the dialogs', function (done) {
driver
.sleep(3000) // timeout to visualize test execution
.elementByCssSelector('.search-key')
.waitForElementByCssSelector('.search-key', 60000, 10000)
.sendKeys('j')
.elementsByCssSelector('.topcoat-list a')
.then(function (employees) {

16
test/helpers/asserter.js Normal file
View File

@@ -0,0 +1,16 @@
"use strict";
var chai = require('chai'),
Asserter = require('wd').Asserter;
var tagChaiAssertionError = function (err) {
err.retriable = err instanceof chai.AssertionError;
throw err;
};
exports.tagChaiAssertionError = tagChaiAssertionError;
exports.ChaiAsserter = function (assertFunc) {
return new Asserter(function (driver) {
return assertFunc(driver).catch(tagChaiAssertionError);
});
};

View File

@@ -4,6 +4,8 @@ var path = require('path');
var env = {};
env.IMPLICIT_WAIT_TIMEOUT = 5000;
// local config
env.APPIUM_HOST = process.env.APPIUM_HOST || '127.0.0.1';
env.APPIUM_PORT = parseInt(process.env.APPIUM_PORT || 4723, 10);
@@ -128,6 +130,7 @@ env.IOS6 = env.DEVICE.match(/ios6/i);
env.IOS7 = env.DEVICE.match(/ios7/i);
env.IOS71 = env.DEVICE.match(/ios71/i);
env.ANDROID = env.DEVICE.match(/android/i);
env.SELENDROID = env.DEVICE.match(/selendroid/i);
// better timeout settings for 71
env.LAUNCH_TIMEOUT = process.env.LAUNCH_TIMEOUT ? JSON.parse(process.env.LAUNCH_TIMEOUT) :

View File

@@ -0,0 +1,21 @@
"use strict";
var ChaiAsserter = require('./asserter').ChaiAsserter;
function textCleared(el) {
return new ChaiAsserter(function () {
return el.text().should.become(''); });
}
var safeClear = function (el ,remainingAttempts) {
if (typeof remainingAttempts !== 'number') remainingAttempts = 3;
return el
.clear()
.waitFor(textCleared(el), 3000)
.catch(function (err) {
if (remainingAttempts <= 0) throw err;
return safeClear(el, remainingAttempts - 1);
});
};
module.exports = safeClear;

View File

@@ -125,7 +125,7 @@ module.exports.initSession = function (desired, opts) {
}
}).then(function () { return init(attempts); })
.then(function () { initialized = true; })
.setImplicitWaitTimeout(5000);
.setImplicitWaitTimeout(env.IMPLICIT_WAIT_TIMEOUT);
},
tearDown: function (passed) {
return browser.chain()