Compare commits

...
Author SHA1 Message Date
dan@saucelabs.com b0f1e56ede Prepare for v1.8.0-beta2 2018-01-29 13:10:14 -08:00
Mykola Mokhnach b0857eefb1 Use uia2 backend by default if platform version is greater or equal to 6 (#10073)
* Use uia2 backend by default if platform version is greater or equal to 6

* Allow to force set the backend to UIA1

* Add unit tests

* Tune the log message

* Print a warning message instead of changing the driver type

* Remove redundant imports

* Tune the message

* Address PR comments
2018-01-29 11:31:37 -05:00
Dan Graham 8efff6895e Test content-type in errors (#10077) 2018-01-29 11:31:29 -05:00
Dan Graham 69eed603c3 Remove unnecessary 'finally' block (#10076)
* Shouldn't have had finally block because then it does two checks to fall back to MJSONWP
* Also fixed outdated tests
2018-01-29 11:31:20 -05:00
Dan Graham f91c6b50aa Fall back to MJSONWP if W3C is invalid (#10034)
* If processCapabilities throws error, then log a warning that it was invalid and log the message and fall back to using jsonwpCaps
2018-01-29 11:31:10 -05:00
Dan Graham 46395d7c46 Use MJSONWP if dcaps have extraneous params (#10019)
* Update `parseCapsForInnerDriver` so that now if it finds extraneous keys in `jsonwpCaps`, fall back to using MJSONWP instead of W3C
* After getting processed caps, check the protocol again because if `processedW3CCapabilities` was set to null, it should be JWP
* Removed tests that tested for capabilities being merged together (those are no longer needed)
* Added tests (unit test and e2e test) that check that creation of a new session will fall back to JSONWP when there are extraneous keys
2018-01-29 11:30:59 -05:00
Isaac A. Murchie 5a2cf8d1c4 Get rid of arrow functions in mocha aparatus (#10013) 2018-01-29 11:30:49 -05:00
Isaac A. Murchie 281b3cfdeb Add 2.34 and 2.35 to Chromedriver compatibility doc (#10012) 2018-01-29 11:30:39 -05:00
13 changed files with 326 additions and 270 deletions
+6
View File
@@ -1,3 +1,9 @@
CHANGES IN VERSION 1.8.0-beta2 (from 1.8.0-beta)
===================================
* Use MJSONWP if desiredCapabilities have extraneuous parameters
* Fall back to MJSONWP if session request for W3C Capabilities throws an exception
CHANGES IN VERSION 1.8.0-beta (from 1.7.2)
===================================
@@ -42,6 +42,8 @@ Chrome version that is automatable:
| Version | Minimum Chrome Version | Link to Chromedriver |
|---------|------------------------|-----------------------------------------------------------------------------------|
| 2.35 | 62.0.3202.0 | [v2.35 (link)](https://chromedriver.storage.googleapis.com/index.html?path=2.35/) |
| 2.34 | 61.0.3163.0 | [v2.34 (link)](https://chromedriver.storage.googleapis.com/index.html?path=2.34/) |
| 2.33 | 60.0.3112.0 | [v2.33 (link)](https://chromedriver.storage.googleapis.com/index.html?path=2.33/) |
| 2.32 | 59.0.3071.0 | [v2.32 (link)](https://chromedriver.storage.googleapis.com/index.html?path=2.32/) |
| 2.31 | 58.0.3029.0 | [v2.31 (link)](https://chromedriver.storage.googleapis.com/index.html?path=2.31/) |
+22 -10
View File
@@ -16,6 +16,7 @@ import { EspressoDriver } from 'appium-espresso-driver';
import B from 'bluebird';
import AsyncLock from 'async-lock';
import { inspectObject, parseCapsForInnerDriver } from './utils';
import semver from 'semver';
const sessionsListGuard = new AsyncLock();
const pendingDriversGuard = new AsyncLock();
@@ -88,18 +89,25 @@ class AppiumDriver extends BaseDriver {
}
if (caps.platformName.toLowerCase() === 'android') {
const platformVersion = semver.valid(semver.coerce(caps.platformVersion));
if (platformVersion && semver.satisfies(platformVersion, '>=6.0.0')) {
log.warn("Consider setting 'automationName' capability to " +
`'${this.validAutomations.UIAUTOMATOR2.toLowerCase()}' ` +
"on Android >= 6, since UIAutomator framework " +
"is not maintained anymore by the OS vendor.");
}
return AndroidDriver;
}
if (caps.platformName.toLowerCase() === 'ios') {
if (caps.platformVersion) {
let majorVer = caps.platformVersion.toString().split(".")[0];
if (parseInt(majorVer, 10) >= 10) {
log.info("Requested iOS support with version >= 10, using XCUITest " +
"driver instead of UIAutomation-based driver, since the " +
"latter is unsupported on iOS 10 and up.");
return XCUITestDriver;
}
const platformVersion = semver.valid(semver.coerce(caps.platformVersion));
if (platformVersion && semver.satisfies(platformVersion, '>=10.0.0')) {
log.info("Requested iOS support with version >= 10, " +
`using '${this.validAutomations.XCUITEST.toLowerCase()}' ` +
"driver instead of UIAutomation-based driver, since the " +
"latter is unsupported on iOS 10 and up.");
return XCUITestDriver;
}
return IosDriver;
@@ -182,11 +190,15 @@ class AppiumDriver extends BaseDriver {
let {defaultCapabilities} = this.args;
// Parse the caps into a format that the InnerDriver will accept
let {desiredCaps, processedJsonwpCaps, processedW3CCapabilities} = parseCapsForInnerDriver(
let {desiredCaps, processedJsonwpCapabilities, processedW3CCapabilities} = parseCapsForInnerDriver(
jsonwpCaps,
w3cCapabilities,
this.desiredCapConstraints, defaultCapabilities
);
// Since the processed caps may be different from the payload, update the protocol accordingly
this.protocol = BaseDriver.determineProtocol(processedJsonwpCapabilities, reqCaps, processedW3CCapabilities);
let InnerDriver = this.getDriverForCaps(desiredCaps);
this.printNewSessionAnnouncement(InnerDriver, desiredCaps);
@@ -220,7 +232,7 @@ class AppiumDriver extends BaseDriver {
let innerSessionId, dCaps;
try {
[innerSessionId, dCaps] = await d.createSession(
processedJsonwpCaps,
processedJsonwpCapabilities,
reqCaps,
processedW3CCapabilities,
[...runningDriversData, ...otherPendingDriversData]
+27 -32
View File
@@ -64,55 +64,50 @@ function parseCapsForInnerDriver (jsonwpCaps, w3cCapabilities, constraints={}, d
// Get MJSONWP caps
let desiredCaps = {};
let processedJsonwpCapabilities = null;
if (hasJSONWPCaps) {
desiredCaps = jsonwpCaps;
processedJsonwpCapabilities = {...desiredCaps};
}
// Get W3C caps
let processedW3CCapabilities = null;
if (hasW3CCaps) {
// Call the process capabilities algorithm to find matching caps on the W3C
// (see: https://github.com/jlipps/simple-wd-spec#processing-capabilities)
let matchingW3CCaps = processCapabilities(w3cCapabilities, constraints, true);
if (hasJSONWPCaps) {
let jsonwpKeys = _.keys(desiredCaps);
let matchingW3CCapsKeys = _.keys(matchingW3CCaps);
// If JSONWP has keys that W3C doesn't have, log a warning message
let differingKeys = _.differenceWith(jsonwpKeys, matchingW3CCapsKeys);
if (!_.isEmpty(differingKeys)) {
logger.warn(`The following capabilities were provided in the JSONWP desired capabilities but
not the W3C capabilities: ${JSON.stringify(differingKeys)}`);
let matchingW3CCaps;
try {
matchingW3CCaps = processCapabilities(w3cCapabilities, constraints, true);
} catch (err) {
if (jsonwpCaps) {
logger.warn(`Could not parse W3C capabilities: ${err.message}. Falling back to JSONWP protocol.`);
return {desiredCaps, processedJsonwpCapabilities, processedW3CCapabilities};
} else {
throw err;
}
}
// If JSONWP caps and W3C caps were provided and there are discrepancies between them
// we'll be forgiving for now and just merge the two. But in the future, the clients
// should not be sending discrepant caps and Appium should ignore the extraneous MJSONWP caps
desiredCaps = {
...desiredCaps, // TODO: This line should be removed once we decide to not allow discrepent caps
...matchingW3CCaps,
};
}
desiredCaps = matchingW3CCaps;
let processedJsonwpCaps = null;
let processedW3CCapabilities = null;
// Create new JSONWP desired capabilities and W3C 'capabilities' objects that have the reconciled attributes
if (hasJSONWPCaps) {
processedJsonwpCaps = {...desiredCaps};
}
// Translate the matched W3C caps back into W3C capabilities object so that it
// can be proxied to the inner driver
if (hasW3CCaps) {
// Create a new w3c capabilities payload that contains only the matching caps in `alwaysMatch`
processedW3CCapabilities = {
alwaysMatch: {...insertAppiumPrefixes(desiredCaps)}, // Insert 'appium:' prefix to non-prefixed caps so that the Inner Driver doesn't complain about bad W3C prefixes
alwaysMatch: {...insertAppiumPrefixes(desiredCaps)},
firstMatch: [{}],
};
// If we found extraneuous keys in JSONWP caps, fall back to JSONWP
if (hasJSONWPCaps) {
let differingKeys = _.difference(_.keys(jsonwpCaps), _.keys(matchingW3CCaps));
if (!_.isEmpty(differingKeys)) {
logger.warn(`The following capabilities were provided in the JSONWP desired capabilities that are missing ` +
`in W3C capabilities: ${JSON.stringify(differingKeys)}. Falling back to JSONWP protocol.`);
desiredCaps = jsonwpCaps;
return {desiredCaps, processedJsonwpCapabilities, processedW3CCapabilities: null};
}
}
}
return {desiredCaps, processedJsonwpCaps, processedW3CCapabilities};
return {desiredCaps, processedJsonwpCapabilities, processedW3CCapabilities};
}
+3 -2
View File
@@ -11,7 +11,7 @@
"firefoxos",
"testing"
],
"version": "1.8.0-beta",
"version": "1.8.0-beta2",
"author": "https://github.com/appium",
"license": "Apache-2.0",
"repository": {
@@ -35,7 +35,7 @@
},
"dependencies": {
"appium-android-driver": "1.x",
"appium-base-driver": "^2.20.0",
"appium-base-driver": "^2.20.2",
"appium-espresso-driver": "^1.0.0-beta.3",
"appium-fake-driver": "^0.3.0",
"appium-ios-driver": "1.x",
@@ -58,6 +58,7 @@
"npmlog": "2.x",
"request": "^2.81.0",
"request-promise": "1.x",
"semver": "^5.5.0",
"source-map-support": "0.x",
"teen_process": "1.x",
"winston": "2.x"
+76 -76
View File
@@ -15,9 +15,9 @@ let should = chai.should();
chai.use(chaiAsPromised);
describe('Config', () => {
describe('getGitRev', () => {
it('should get a reasonable git revision', async () => {
describe('Config', function () {
describe('getGitRev', function () {
it('should get a reasonable git revision', async function () {
let rev = await getGitRev();
rev.should.be.a('string');
rev.length.should.be.equal(40);
@@ -25,9 +25,9 @@ describe('Config', () => {
});
});
describe('Appium config', () => {
describe('getAppiumConfig', () => {
it('should get a configuration object', async () => {
describe('Appium config', function () {
describe('getAppiumConfig', function () {
it('should get a configuration object', async function () {
let config = await getAppiumConfig();
config.should.be.an('object');
should.exist(config['git-sha']);
@@ -35,11 +35,11 @@ describe('Config', () => {
should.exist(config.version);
});
});
describe('showConfig', () => {
before(() => {
describe('showConfig', function () {
before(function () {
sinon.spy(console, "log");
});
it('should log the config to console', async () => {
it('should log the config to console', async function () {
let config = await getAppiumConfig();
await showConfig();
console.log.calledOnce.should.be.true; // eslint-disable-line no-console
@@ -48,9 +48,9 @@ describe('Config', () => {
});
});
describe('node.js config', () => {
describe('node.js config', function () {
let _process = process;
before(() => {
before(function () {
// need to be able to write to process.version
// but also to have access to process methods
// so copy them over to a writable object
@@ -60,11 +60,11 @@ describe('Config', () => {
}
process = tempProcess;
});
after(() => {
after(function () {
process = _process;
});
describe('checkNodeOk', () => {
it('should fail if node is below 4', () => {
describe('checkNodeOk', function () {
it('should fail if node is below 4', function () {
process.version = 'v4.4.7';
checkNodeOk.should.throw();
process.version = 'v0.9.12';
@@ -76,53 +76,53 @@ describe('Config', () => {
process.version = 'v0.12.14';
checkNodeOk.should.throw();
});
it('should succeed if node is 5+', () => {
it('should succeed if node is 5+', function () {
process.version = 'v5.7.0';
checkNodeOk.should.not.throw();
});
it('should succeed if node is 6+', () => {
it('should succeed if node is 6+', function () {
process.version = 'v6.3.1';
checkNodeOk.should.not.throw();
});
it('should succeed if node is 7+', () => {
it('should succeed if node is 7+', function () {
process.version = 'v7.1.1';
checkNodeOk.should.not.throw();
});
it('should succeed if node is 8+', () => {
it('should succeed if node is 8+', function () {
process.version = 'v8.1.2';
checkNodeOk.should.not.throw();
});
});
describe('warnNodeDeprecations', () => {
describe('warnNodeDeprecations', function () {
let spy;
before(() => {
before(function () {
spy = sinon.spy(logger, "warn");
});
beforeEach(() => {
beforeEach(function () {
spy.reset();
});
it('should log a warning if node is below 4', () => {
it('should log a warning if node is below 4', function () {
process.version = 'v0.9.12';
warnNodeDeprecations();
logger.warn.callCount.should.equal(1);
});
it('should log a warning if node is 0.12', () => {
it('should log a warning if node is 0.12', function () {
process.version = 'v0.12.0';
warnNodeDeprecations();
logger.warn.callCount.should.equal(1);
});
it('should not log a warning if node is 4+', () => {
it('should not log a warning if node is 4+', function () {
process.version = 'v4.4.7';
warnNodeDeprecations();
logger.warn.callCount.should.equal(0);
});
it('should not log a warning if node is 5+', () => {
it('should not log a warning if node is 5+', function () {
process.version = 'v5.7.0';
warnNodeDeprecations();
logger.warn.callCount.should.equal(0);
});
it('should not log a warning if node is 6+', () => {
it('should not log a warning if node is 6+', function () {
process.version = 'v6.3.1';
warnNodeDeprecations();
logger.warn.callCount.should.equal(0);
@@ -130,22 +130,22 @@ describe('Config', () => {
});
});
describe('server arguments', () => {
describe('server arguments', function () {
let parser = getParser();
parser.debug = true; // throw instead of exit on error; pass as option instead?
let args = {};
beforeEach(() => {
beforeEach(function () {
// give all the defaults
for (let rawArg of parser.rawArgs) {
args[rawArg[1].dest] = rawArg[1].defaultValue;
}
});
describe('getNonDefaultArgs', () => {
it('should show none if we have all the defaults', () => {
describe('getNonDefaultArgs', function () {
it('should show none if we have all the defaults', function () {
let nonDefaultArgs = getNonDefaultArgs(parser, args);
_.keys(nonDefaultArgs).length.should.equal(0);
});
it('should catch a non-default argument', () => {
it('should catch a non-default argument', function () {
args.isolateSimDevice = true;
let nonDefaultArgs = getNonDefaultArgs(parser, args);
_.keys(nonDefaultArgs).length.should.equal(1);
@@ -153,18 +153,18 @@ describe('Config', () => {
});
});
describe('getDeprecatedArgs', () => {
it('should show none if we have no deprecated arguments', () => {
describe('getDeprecatedArgs', function () {
it('should show none if we have no deprecated arguments', function () {
let deprecatedArgs = getDeprecatedArgs(parser, args);
_.keys(deprecatedArgs).length.should.equal(0);
});
it('should catch a deprecated argument', () => {
it('should catch a deprecated argument', function () {
args.showIOSLog = true;
let deprecatedArgs = getDeprecatedArgs(parser, args);
_.keys(deprecatedArgs).length.should.equal(1);
should.exist(deprecatedArgs['--show-ios-log']);
});
it('should catch a non-boolean deprecated argument', () => {
it('should catch a non-boolean deprecated argument', function () {
args.calendarFormat = 'orwellian';
let deprecatedArgs = getDeprecatedArgs(parser, args);
_.keys(deprecatedArgs).length.should.equal(1);
@@ -173,58 +173,58 @@ describe('Config', () => {
});
});
describe('checkValidPort', () => {
it('should be false for port too high', () => {
describe('checkValidPort', function () {
it('should be false for port too high', function () {
checkValidPort(65536).should.be.false;
});
it('should be false for port too low', () => {
it('should be false for port too low', function () {
checkValidPort(0).should.be.false;
});
it('should be true for port 1', () => {
it('should be true for port 1', function () {
checkValidPort(1).should.be.true;
});
it('should be true for port 65535', () => {
it('should be true for port 65535', function () {
checkValidPort(65535).should.be.true;
});
});
describe('validateTmpDir', () => {
it('should fail to use a tmp dir with incorrect permissions', async () => {
describe('validateTmpDir', function () {
it('should fail to use a tmp dir with incorrect permissions', async function () {
validateTmpDir('/private/if_you_run_with_sudo_this_wont_fail').should.be.rejectedWith(/could not ensure/);
});
it('should fail to use an undefined tmp dir', async () => {
it('should fail to use an undefined tmp dir', async function () {
validateTmpDir().should.be.rejectedWith(/could not ensure/);
});
it('should be able to use a tmp dir with correct permissions', async () => {
it('should be able to use a tmp dir with correct permissions', async function () {
validateTmpDir('/tmp/test_tmp_dir/with/any/number/of/levels').should.not.be.rejected;
});
});
describe('parsing args with empty argv[1]', () => {
describe('parsing args with empty argv[1]', function () {
let argv1;
before(() => {
before(function () {
argv1 = process.argv[1];
});
after(() => {
after(function () {
process.argv[1] = argv1;
});
it('should not fail if process.argv[1] is undefined', () => {
it('should not fail if process.argv[1] is undefined', function () {
process.argv[1] = undefined;
let args = getParser();
args.prog.should.be.equal('Appium');
});
it('should set "prog" to process.argv[1]', () => {
it('should set "prog" to process.argv[1]', function () {
process.argv[1] = 'Hello World';
let args = getParser();
args.prog.should.be.equal('Hello World');
});
});
describe('validateServerArgs', () => {
describe('validateServerArgs', function () {
let parser = getParser();
parser.debug = true; // throw instead of exit on error; pass as option instead?
const defaultArgs = {};
@@ -233,98 +233,98 @@ describe('Config', () => {
defaultArgs[rawArg[1].dest] = rawArg[1].defaultValue;
}
let args = {};
beforeEach(() => {
beforeEach(function () {
args = _.clone(defaultArgs);
});
describe('mutually exclusive server arguments', () => {
describe('noReset and fullReset', () => {
it('should not allow both', () => {
describe('mutually exclusive server arguments', function () {
describe('noReset and fullReset', function () {
it('should not allow both', function () {
(() => {
args.noReset = args.fullReset = true;
validateServerArgs(parser, args);
}).should.throw();
});
it('should allow noReset', () => {
it('should allow noReset', function () {
(() => {
args.noReset = true;
validateServerArgs(parser, args);
}).should.not.throw();
});
it('should allow fullReset', () => {
it('should allow fullReset', function () {
(() => {
args.fullReset = true;
validateServerArgs(parser, args);
}).should.not.throw();
});
});
describe('ipa and safari', () => {
it('should not allow both', () => {
describe('ipa and safari', function () {
it('should not allow both', function () {
(() => {
args.ipa = args.safari = true;
validateServerArgs(parser, args);
}).should.throw();
});
it('should allow ipa', () => {
it('should allow ipa', function () {
(() => {
args.ipa = true;
validateServerArgs(parser, args);
}).should.not.throw();
});
it('should allow safari', () => {
it('should allow safari', function () {
(() => {
args.safari = true;
validateServerArgs(parser, args);
}).should.not.throw();
});
});
describe('app and safari', () => {
it('should not allow both', () => {
describe('app and safari', function () {
it('should not allow both', function () {
(() => {
args.app = args.safari = true;
validateServerArgs(parser, args);
}).should.throw();
});
it('should allow app', () => {
it('should allow app', function () {
(() => {
args.app = true;
validateServerArgs(parser, args);
}).should.not.throw();
});
});
describe('forceIphone and forceIpad', () => {
it('should not allow both', () => {
describe('forceIphone and forceIpad', function () {
it('should not allow both', function () {
(() => {
args.forceIphone = args.forceIpad = true;
validateServerArgs(parser, args);
}).should.throw();
});
it('should allow forceIphone', () => {
it('should allow forceIphone', function () {
(() => {
args.forceIphone = true;
validateServerArgs(parser, args);
}).should.not.throw();
});
it('should allow forceIpad', () => {
it('should allow forceIpad', function () {
(() => {
args.forceIpad = true;
validateServerArgs(parser, args);
}).should.not.throw();
});
});
describe('deviceName and defaultDevice', () => {
it('should not allow both', () => {
describe('deviceName and defaultDevice', function () {
it('should not allow both', function () {
(() => {
args.deviceName = args.defaultDevice = true;
validateServerArgs(parser, args);
}).should.throw();
});
it('should allow deviceName', () => {
it('should allow deviceName', function () {
(() => {
args.deviceName = true;
validateServerArgs(parser, args);
}).should.not.throw();
});
it('should allow defaultDevice', () => {
it('should allow defaultDevice', function () {
(() => {
args.defaultDevice = true;
validateServerArgs(parser, args);
@@ -332,19 +332,19 @@ describe('Config', () => {
});
});
});
describe('validated arguments', () => {
describe('validated arguments', function () {
// checking ports is already done.
// the only argument left is `backendRetries`
describe('backendRetries', () => {
it('should fail with value less than 0', () => {
describe('backendRetries', function () {
it('should fail with value less than 0', function () {
args.backendRetries = -1;
(() => {validateServerArgs(parser, args);}).should.throw();
});
it('should succeed with value of 0', () => {
it('should succeed with value of 0', function () {
args.backendRetries = 0;
(() => {validateServerArgs(parser, args);}).should.not.throw();
});
it('should succeed with value above 0', () => {
it('should succeed with value above 0', function () {
args.backendRetries = 100;
(() => {validateServerArgs(parser, args);}).should.not.throw();
});
+71 -23
View File
@@ -15,23 +15,23 @@ const should = chai.should();
const shouldStartServer = process.env.USE_RUNNING_SERVER !== "0";
const caps = {platformName: "Fake", deviceName: "Fake", app: TEST_FAKE_APP};
describe('FakeDriver - via HTTP', () => {
describe('FakeDriver - via HTTP', function () {
let server = null;
const baseUrl = `http://${TEST_HOST}:${TEST_PORT}/wd/hub/session`;
before(async () => {
before(async function () {
if (shouldStartServer) {
let args = {port: TEST_PORT, host: TEST_HOST};
server = await appiumServer(args);
}
});
after(async () => {
after(async function () {
if (server) {
await server.close();
}
});
describe('session handling', () => {
it('should start and stop a session', async () => {
describe('session handling', function () {
it('should start and stop a session', async function () {
let driver = wd.promiseChainRemote(TEST_HOST, TEST_PORT);
let [sessionId] = await driver.init(caps);
should.exist(sessionId);
@@ -40,7 +40,7 @@ describe('FakeDriver - via HTTP', () => {
await driver.title().should.eventually.be.rejectedWith(/terminated/);
});
it('should be able to run two FakeDriver sessions simultaneously', async () => {
it('should be able to run two FakeDriver sessions simultaneously', async function () {
let driver1 = wd.promiseChainRemote(TEST_HOST, TEST_PORT);
let [sessionId1] = await driver1.init(caps);
should.exist(sessionId1);
@@ -54,7 +54,7 @@ describe('FakeDriver - via HTTP', () => {
await driver2.quit();
});
it('should not be able to run two FakeDriver sessions simultaneously when one is unique', async () => {
it('should not be able to run two FakeDriver sessions simultaneously when one is unique', async function () {
let uniqueCaps = _.clone(caps);
uniqueCaps.uniqueApp = true;
let driver1 = wd.promiseChainRemote(TEST_HOST, TEST_PORT);
@@ -66,7 +66,7 @@ describe('FakeDriver - via HTTP', () => {
await driver1.quit();
});
it('should use the newCommandTimeout of the inner Driver on session creation', async () => {
it('should use the newCommandTimeout of the inner Driver on session creation', async function () {
let driver = wd.promiseChainRemote(TEST_HOST, TEST_PORT);
caps.newCommandTimeout = 0.25;
@@ -78,7 +78,7 @@ describe('FakeDriver - via HTTP', () => {
await driver.source().should.eventually.be.rejectedWith(/terminated/);
});
it('should accept valid W3C capabilities and start a W3C session', async () => {
it('should accept valid W3C capabilities and start a W3C session', async function () {
// Try with valid capabilities and check that it returns a session ID
const w3cCaps = {
capabilities: {
@@ -105,15 +105,18 @@ describe('FakeDriver - via HTTP', () => {
screenshotValue.should.equal('hahahanotreallyascreenshot');
// Now use that sessionID to call an arbitrary W3C-only endpoint that isn't implemented to see if it responds with correct error
const {statusCode, message} = await request.post({url: `${baseUrl}/${value.sessionId}/execute/async`, json: {script: '', args: ['a']}}).should.eventually.be.rejected;
const {statusCode, error} = await request.post({url: `${baseUrl}/${value.sessionId}/execute/async`, json: {script: '', args: ['a']}}).should.eventually.be.rejected;
statusCode.should.equal(404);
const {error:errorMessage, message, stacktrace} = error.value;
errorMessage.should.match(/A command could not be executed/);
message.should.match(/Method has not yet been implemented/);
stacktrace.should.match(/FakeDriver.executeCommand/);
// End session
await request.delete({url: `${baseUrl}/${value.sessionId}`}).should.eventually.be.resolved;
});
it('should reject invalid W3C capabilities and respond with a 400 Bad Parameters error', async () => {
it('should reject invalid W3C capabilities and respond with a 400 Bad Parameters error', async function () {
const badW3Ccaps = {
capabilities: {
alwaysMatch: {},
@@ -121,16 +124,15 @@ describe('FakeDriver - via HTTP', () => {
}
};
const {statusCode, message} = await request.post({url: baseUrl, json: badW3Ccaps}).should.eventually.be.rejected;
const {statusCode, error} = await request.post({url: baseUrl, json: badW3Ccaps}).should.eventually.be.rejected;
statusCode.should.equal(400);
message.should.match(/can't be blank/);
error.value.message.should.match(/can't be blank/);
});
it('should accept a combo of W3C and JSONWP capabilities but default to W3C', async () => {
it('should accept a combo of W3C and JSONWP capabilities but default to W3C', async function () {
const combinedCaps = {
"desiredCapabilities": {
...caps,
mjsonwpParam: 'mjsonwpParam',
},
"capabilities": {
"alwaysMatch": {...caps},
@@ -147,11 +149,36 @@ describe('FakeDriver - via HTTP', () => {
value.capabilities.should.deep.equal({
...caps,
w3cParam: 'w3cParam',
mjsonwpParam: 'mjsonwpParam', // Note: For now we're accepting a mix of the two to alleviate client issues. This ought to not be supported in the future though.
});
});
it('should reject bad W3C capabilities with a BadParametersError (400)', async () => {
it('should accept a combo of W3C and JSONWP but use JSONWP if desiredCapabilities contains extraneous keys', async function () {
const combinedCaps = {
"desiredCapabilities": {
...caps,
automationName: 'Fake',
anotherParam: 'Hello',
},
"capabilities": {
"alwaysMatch": {...caps},
"firstMatch": [{
w3cParam: 'w3cParam',
}],
}
};
const {status, sessionId, value} = await request.post({url: baseUrl, json: combinedCaps});
status.should.exist;
sessionId.should.exist;
should.not.exist(value.sessionId);
value.should.deep.equal({
...caps,
automationName: 'Fake',
anotherParam: 'Hello',
});
});
it('should reject bad W3C capabilities with a BadParametersError (400)', async function () {
const w3cCaps = {
"capabilities": {
"alwaysMatch": {
@@ -160,12 +187,14 @@ describe('FakeDriver - via HTTP', () => {
}
},
};
const {message, statusCode} = await request.post({url: baseUrl, json: w3cCaps}).should.eventually.be.rejected;
const {error, statusCode, response} = await request.post({url: baseUrl, json: w3cCaps}).should.eventually.be.rejected;
response.headers['content-type'].should.match(/application\/json/);
const {message} = error.value;
message.should.match(/BadAutomationName not part of/);
statusCode.should.equal(400);
});
it('should accept capabilities that are provided in the firstMatch array', async () => {
it('should accept capabilities that are provided in the firstMatch array', async function () {
const w3cCaps = {
"capabilities": {
"alwaysMatch": {},
@@ -179,10 +208,29 @@ describe('FakeDriver - via HTTP', () => {
should.not.exist(sessionId);
value.capabilities.should.deep.equal(caps);
});
it('should fall back to MJSONWP if w3c caps are invalid', async function () {
const combinedCaps = {
"desiredCapabilities": {
...caps,
},
"capabilities": {
"alwaysMatch": {},
"firstMatch": [{}, {
...caps,
deviceName: null,
}],
},
};
const {value, sessionId, status} = await request.post({url: baseUrl, json: combinedCaps});
status.should.exist;
sessionId.should.exist;
value.should.deep.equal(caps);
});
});
});
describe('Logsink', () => {
describe('Logsink', function () {
let server = null;
let logs = [];
let logHandler = (level, message) => {
@@ -190,15 +238,15 @@ describe('Logsink', () => {
};
let args = {port: TEST_PORT, host: TEST_HOST, logHandler};
before(async () => {
before(async function () {
server = await appiumServer(args);
});
after(async () => {
after(async function () {
await server.close();
});
it('should send logs to a logHandler passed in by a parent package', async () => {
it('should send logs to a logHandler passed in by a parent package', async function () {
logs.length.should.be.above(1);
logs[0].length.should.equal(2);
logs[0][1].should.include("Welcome to Appium");
+58 -36
View File
@@ -17,15 +17,15 @@ chai.use(chaiAsPromised);
const SESSION_ID = 1;
describe('AppiumDriver', () => {
describe('getAppiumRouter', () => {
it('should return a route configuring function', async () => {
describe('AppiumDriver', function () {
describe('getAppiumRouter', function () {
it('should return a route configuring function', async function () {
let routeConfiguringFunction = getAppiumRouter({});
routeConfiguringFunction.should.be.a.function;
});
});
describe('AppiumDriver', () => {
describe('AppiumDriver', function () {
function getDriverAndFakeDriver () {
let appium = new AppiumDriver({});
let fakeDriver = new FakeDriver();
@@ -37,25 +37,25 @@ describe('AppiumDriver', () => {
};
return [appium, mockFakeDriver];
}
describe('createSession', () => {
describe('createSession', function () {
let appium;
let mockFakeDriver;
beforeEach(() => {
beforeEach(function () {
[appium, mockFakeDriver] = getDriverAndFakeDriver();
});
afterEach(async () => {
afterEach(async function () {
mockFakeDriver.restore();
await appium.deleteSession(SESSION_ID);
});
it('should call inner driver\'s createSession with desired capabilities', async () => {
it('should call inner driver\'s createSession with desired capabilities', async function () {
mockFakeDriver.expects("createSession")
.once().withExactArgs(BASE_CAPS, undefined, null, [])
.returns([SESSION_ID, BASE_CAPS]);
await appium.createSession(BASE_CAPS);
mockFakeDriver.verify();
});
it('should call inner driver\'s createSession with desired and default capabilities', async () => {
it('should call inner driver\'s createSession with desired and default capabilities', async function () {
let defaultCaps = {deviceName: 'Emulator'}
, allCaps = _.extend(_.clone(defaultCaps), BASE_CAPS);
appium.args.defaultCapabilities = defaultCaps;
@@ -65,7 +65,7 @@ describe('AppiumDriver', () => {
await appium.createSession(BASE_CAPS);
mockFakeDriver.verify();
});
it('should call inner driver\'s createSession with desired and default capabilities without overriding caps', async () => {
it('should call inner driver\'s createSession with desired and default capabilities without overriding caps', async function () {
// a default capability with the same key as a desired capability
// should do nothing
let defaultCaps = {platformName: 'Ersatz'};
@@ -76,7 +76,7 @@ describe('AppiumDriver', () => {
await appium.createSession(BASE_CAPS);
mockFakeDriver.verify();
});
it('should kill all other sessions if sessionOverride is on', async () => {
it('should kill all other sessions if sessionOverride is on', async function () {
appium.args.sessionOverride = true;
// mock three sessions that should be removed when the new one is created
@@ -139,17 +139,39 @@ describe('AppiumDriver', () => {
await appium.createSession(undefined, undefined, w3cCaps);
mockFakeDriver.verify();
});
it('should call "createSession" with JSONWP capabilities if W3C has incomplete capabilities', async function () {
let w3cCaps = {
...W3C_CAPS,
alwaysMatch: {
...W3C_CAPS.alwaysMatch,
'appium:someOtherParm': 'someOtherParm',
},
};
let jsonwpCaps = {
...BASE_CAPS,
automationName: 'Fake',
someOtherParam: 'someOtherParam',
};
mockFakeDriver.expects("createSession")
.once().withArgs(jsonwpCaps, undefined, null)
.returns([SESSION_ID, jsonwpCaps]);
await appium.createSession(jsonwpCaps, undefined, w3cCaps);
mockFakeDriver.verify();
});
});
describe('deleteSession', () => {
describe('deleteSession', function () {
let appium;
let mockFakeDriver;
beforeEach(() => {
beforeEach(function () {
[appium, mockFakeDriver] = getDriverAndFakeDriver();
});
afterEach(() => {
afterEach(function () {
mockFakeDriver.restore();
});
it('should remove the session if it is found', async () => {
it('should remove the session if it is found', async function () {
let [sessionId] = await appium.createSession(BASE_CAPS);
let sessions = await appium.getSessions();
sessions.should.have.length(1);
@@ -157,7 +179,7 @@ describe('AppiumDriver', () => {
sessions = await appium.getSessions();
sessions.should.have.length(0);
});
it('should call inner driver\'s deleteSession method', async () => {
it('should call inner driver\'s deleteSession method', async function () {
const [sessionId] = await appium.createSession(BASE_CAPS);
mockFakeDriver.expects("deleteSession")
.once().withExactArgs(sessionId, [])
@@ -169,23 +191,23 @@ describe('AppiumDriver', () => {
await mockFakeDriver.object.deleteSession();
});
});
describe('getSessions', () => {
describe('getSessions', function () {
let appium;
let sessions;
before(() => {
before(function () {
appium = new AppiumDriver({});
});
afterEach(async () => {
afterEach(async function () {
for (let session of sessions) {
await appium.deleteSession(session.id);
}
});
it('should return an empty array of sessions', async () => {
it('should return an empty array of sessions', async function () {
sessions = await appium.getSessions();
sessions.should.be.an.array;
sessions.should.be.empty;
});
it('should return sessions created', async () => {
it('should return sessions created', async function () {
let session1 = await appium.createSession(_.extend(_.clone(BASE_CAPS), {cap: 'value'}));
let session2 = await appium.createSession(_.extend(_.clone(BASE_CAPS), {cap: 'other value'}));
@@ -198,32 +220,32 @@ describe('AppiumDriver', () => {
sessions[1].capabilities.should.eql(session2[1]);
});
});
describe('getStatus', () => {
describe('getStatus', function () {
let appium;
before(() => {
before(function () {
appium = new AppiumDriver({});
});
it('should return a status', async () => {
it('should return a status', async function () {
let status = await appium.getStatus();
status.build.should.exist;
status.build.version.should.exist;
});
});
describe('sessionExists', () => {
describe('sessionExists', function () {
});
describe('attachUnexpectedShutdownHandler', () => {
describe('attachUnexpectedShutdownHandler', function () {
let appium
, mockFakeDriver;
beforeEach(() => {
beforeEach(function () {
[appium, mockFakeDriver] = getDriverAndFakeDriver();
});
afterEach(async () => {
afterEach(async function () {
await mockFakeDriver.object.deleteSession();
mockFakeDriver.restore();
appium.args.defaultCapabilities = {};
});
it('should remove session if inner driver unexpectedly exits with an error', async () => {
it('should remove session if inner driver unexpectedly exits with an error', async function () {
let [sessionId,] = await appium.createSession(_.clone(BASE_CAPS)); // eslint-disable-line comma-spacing
_.keys(appium.sessions).should.contain(sessionId);
appium.sessions[sessionId].unexpectedShutdownDeferred.reject(new Error("Oops"));
@@ -231,7 +253,7 @@ describe('AppiumDriver', () => {
await sleep(1);
_.keys(appium.sessions).should.not.contain(sessionId);
});
it('should remove session if inner driver unexpectedly exits with no error', async () => {
it('should remove session if inner driver unexpectedly exits with no error', async function () {
let [sessionId,] = await appium.createSession(_.clone(BASE_CAPS)); // eslint-disable-line comma-spacing
_.keys(appium.sessions).should.contain(sessionId);
appium.sessions[sessionId].unexpectedShutdownDeferred.resolve();
@@ -239,7 +261,7 @@ describe('AppiumDriver', () => {
await sleep(1);
_.keys(appium.sessions).should.not.contain(sessionId);
});
it('should not remove session if inner driver cancels unexpected exit', async () => {
it('should not remove session if inner driver cancels unexpected exit', async function () {
let [sessionId,] = await appium.createSession(_.clone(BASE_CAPS)); // eslint-disable-line comma-spacing
_.keys(appium.sessions).should.contain(sessionId);
appium.sessions[sessionId].onUnexpectedShutdown.cancel();
@@ -248,12 +270,12 @@ describe('AppiumDriver', () => {
_.keys(appium.sessions).should.contain(sessionId);
});
});
describe('getDriverForCaps', () => {
it('should not blow up if user does not provide platformName', () => {
describe('getDriverForCaps', function () {
it('should not blow up if user does not provide platformName', function () {
let appium = new AppiumDriver({});
(() => { appium.getDriverForCaps({}); }).should.throw(/platformName/);
});
it('should get XCUITestDriver driver for automationName of XCUITest', () => {
it('should get XCUITestDriver driver for automationName of XCUITest', function () {
let appium = new AppiumDriver({});
let driver = appium.getDriverForCaps({
platformName: 'iOS',
@@ -262,7 +284,7 @@ describe('AppiumDriver', () => {
driver.should.be.an.instanceof(Function);
driver.should.equal(XCUITestDriver);
});
it('should get iosdriver for ios < 10', () => {
it('should get iosdriver for ios < 10', function () {
let appium = new AppiumDriver({});
let caps = {
platformName: 'iOS',
@@ -292,7 +314,7 @@ describe('AppiumDriver', () => {
driver = appium.getDriverForCaps(caps);
driver.should.equal(IosDriver);
});
it('should get xcuitestdriver for ios >= 10', () => {
it('should get xcuitestdriver for ios >= 10', function () {
let appium = new AppiumDriver({});
let caps = {
platformName: 'iOS',
+2 -2
View File
@@ -12,12 +12,12 @@ const TEST_FAKE_APP = path.resolve(__dirname, "..", "..", "node_modules",
function initSession (caps) {
let resolve = () => {};
let driver;
before(async () => {
before(async function () {
driver = wd.promiseChainRemote({host: TEST_HOST, port: TEST_PORT});
resolve(driver);
await driver.init(caps);
});
after(async () => {
after(async function () {
await driver.quit();
});
return new B((_resolve) => {
+7 -7
View File
@@ -10,19 +10,19 @@ let forceLogs = process.env._FORCE_LOGS;
process.env._FORCE_LOGS = 1;
let log = logger.getLogger('Appium');
describe('logging', () => {
describe('logging', function () {
let stderrSpy;
let stdoutSpy;
beforeEach(() => {
beforeEach(function () {
stderrSpy = sinon.spy(process.stderr, 'write');
stdoutSpy = sinon.spy(process.stdout, 'write');
logsinkClear();
});
afterEach(() => {
afterEach(function () {
stderrSpy.restore();
stdoutSpy.restore();
});
after(() => {
after(function () {
process.env._FORCE_LOGS = forceLogs;
});
@@ -36,7 +36,7 @@ describe('logging', () => {
log.debug(debugMsg);
}
it('should send error, info and debug when loglevel is debug', async () => {
it('should send error, info and debug when loglevel is debug', async function () {
await logsinkInit({loglevel: 'debug'});
doLogging();
@@ -48,7 +48,7 @@ describe('logging', () => {
stdoutSpy.args[0][0].should.include(warnMsg);
stdoutSpy.args[1][0].should.include(debugMsg);
});
it('should send error and info when loglevel is info', async () => {
it('should send error and info when loglevel is info', async function () {
await logsinkInit({loglevel: 'info'});
doLogging();
@@ -59,7 +59,7 @@ describe('logging', () => {
stdoutSpy.callCount.should.equal(1);
stdoutSpy.args[0][0].should.include(warnMsg);
});
it('should send error when loglevel is error', async () => {
it('should send error when loglevel is error', async function () {
await logsinkInit({loglevel: 'error'});
doLogging();
+9 -9
View File
@@ -5,43 +5,43 @@ import chai from 'chai';
const should = chai.should();
describe('Parser', () => {
describe('Parser', function () {
let p = getParser();
p.debug = true; // throw instead of exit on error; pass as option instead?
it('should return an arg parser', () => {
it('should return an arg parser', function () {
should.exist(p.parseArgs);
p.parseArgs([]).should.have.property('port');
});
it('should keep the raw server flags array', () => {
it('should keep the raw server flags array', function () {
should.exist(p.rawArgs);
});
it('should have help for every arg', () => {
it('should have help for every arg', function () {
for (let arg of p.rawArgs) {
arg[1].should.have.property('help');
}
});
it('should throw an error with unknown argument', () => {
it('should throw an error with unknown argument', function () {
(() => {p.parseArgs(['--apple']);}).should.throw();
});
it('should parse default capabilities correctly from a string', () => {
it('should parse default capabilities correctly from a string', function () {
let defaultCapabilities = {a: 'b'};
let args = p.parseArgs(['--default-capabilities',
JSON.stringify(defaultCapabilities)]);
args.defaultCapabilities.should.eql(defaultCapabilities);
});
it('should parse default capabilities correctly from a file', () => {
it('should parse default capabilities correctly from a file', function () {
let defaultCapabilities = {a: 'b'};
let args = p.parseArgs(['--default-capabilities',
'test/fixtures/caps.json']);
args.defaultCapabilities.should.eql(defaultCapabilities);
});
it('should throw an error with invalid arg to default capabilities', () => {
it('should throw an error with invalid arg to default capabilities', function () {
(() => {p.parseArgs(['-dc', '42']);}).should.throw();
(() => {p.parseArgs(['-dc', 'false']);}).should.throw();
(() => {p.parseArgs(['-dc', 'null']);}).should.throw();
(() => {p.parseArgs(['-dc', 'does/not/exist.json']);}).should.throw();
});
it('should parse args that are caps into default capabilities', () => {
it('should parse args that are caps into default capabilities', function () {
let defaultCapabilities = {localizableStringsDir: '/my/dir'};
let args = p.parseArgs(['--localizable-strings-dir', '/my/dir']);
args.defaultCapabilities.should.eql(defaultCapabilities);
+3 -3
View File
@@ -8,12 +8,12 @@ import chaiAsPromised from 'chai-as-promised';
chai.use(chaiAsPromised);
const expect = chai.expect;
describe.skip('shrinkwrap checks', () => {
it('shrinkwrap file should exist', async () => {
describe.skip('shrinkwrap checks', function () {
it('shrinkwrap file should exist', async function () {
require('../../npm-shrinkwrap.json');
});
it('shrinkwrap should not include fsevents', async () => {
it('shrinkwrap should not include fsevents', async function () {
// fsevents is an optional dep that only works on Mac.
// if it's in shrinkwrap, non-Mac hosts won't be able to install appium
let shrinkwrap = require('../../npm-shrinkwrap.json');
+40 -70
View File
@@ -8,91 +8,33 @@ const should = chai.should();
chai.use(chaiAsPromised);
describe('utils', function () {
describe('parseCapsForInnerDriver()', () => {
describe('parseCapsForInnerDriver()', function () {
it('should return JSONWP caps unchanged if only JSONWP caps provided', function () {
let {desiredCaps, processedJsonwpCaps, processedW3CCapabilities} = parseCapsForInnerDriver(BASE_CAPS);
let {desiredCaps, processedJsonwpCapabilities, processedW3CCapabilities} = parseCapsForInnerDriver(BASE_CAPS);
desiredCaps.should.deep.equal(BASE_CAPS);
processedJsonwpCaps.should.deep.equal(BASE_CAPS);
processedJsonwpCapabilities.should.deep.equal(BASE_CAPS);
should.not.exist(processedW3CCapabilities);
});
it('should return W3C caps unchanged if only W3C caps were provided', function () {
let {desiredCaps, processedJsonwpCaps, processedW3CCapabilities} = parseCapsForInnerDriver(undefined, W3C_CAPS);
let {desiredCaps, processedJsonwpCapabilities, processedW3CCapabilities} = parseCapsForInnerDriver(undefined, W3C_CAPS);
desiredCaps.should.deep.equal(BASE_CAPS);
should.not.exist(processedJsonwpCaps);
should.not.exist(processedJsonwpCapabilities);
processedW3CCapabilities.should.deep.equal(W3C_CAPS);
});
it('should return JSONWP and W3C caps if both were provided', function () {
let {desiredCaps, processedJsonwpCaps, processedW3CCapabilities} = parseCapsForInnerDriver(BASE_CAPS, W3C_CAPS);
let {desiredCaps, processedJsonwpCapabilities, processedW3CCapabilities} = parseCapsForInnerDriver(BASE_CAPS, W3C_CAPS);
desiredCaps.should.deep.equal(BASE_CAPS);
processedJsonwpCaps.should.deep.equal(BASE_CAPS);
processedJsonwpCapabilities.should.deep.equal(BASE_CAPS);
processedW3CCapabilities.should.deep.equal(W3C_CAPS);
});
it('should merge the capabilities together if some are different', function () {
let jsonwpCaps = {
...BASE_CAPS,
foo: 'bar',
};
let w3cCaps = {
...W3C_CAPS,
alwaysMatch: {
...W3C_CAPS.alwaysMatch,
'appium:hello': 'world',
}
};
let {desiredCaps, processedJsonwpCaps, processedW3CCapabilities} = parseCapsForInnerDriver(jsonwpCaps, w3cCaps);
let expectedCaps = {
...jsonwpCaps,
'hello': 'world'
};
desiredCaps.should.deep.equal(expectedCaps);
processedJsonwpCaps.should.deep.equal(expectedCaps);
processedW3CCapabilities.should.deep.equal({
alwaysMatch: {...insertAppiumPrefixes(expectedCaps)},
firstMatch: [{}],
});
});
it('should merge the capabilities together and give preference to W3C if some are matching', function () {
// Add caps to JSONWP caps
let jsonwpCaps = {
foo: 'bar',
...BASE_CAPS,
};
// Add caps to W3C caps
let w3cCaps = {
alwaysMatch: {
hello: 'world',
foo: 'BAR',
...BASE_CAPS,
},
firstMatch: [{}],
};
// Expected result is that w3c caps override jsonwp caps
let expectedDesiredCaps = {
...jsonwpCaps,
...w3cCaps.alwaysMatch,
};
let {desiredCaps, processedJsonwpCaps, processedW3CCapabilities} = parseCapsForInnerDriver(jsonwpCaps, w3cCaps);
desiredCaps.foo.should.equal('BAR');
desiredCaps.should.deep.equal(expectedDesiredCaps);
processedJsonwpCaps.should.deep.equal(expectedDesiredCaps);
processedW3CCapabilities.should.deep.equal({
alwaysMatch: insertAppiumPrefixes(expectedDesiredCaps),
firstMatch: [{}],
});
});
it('should include default capabilities in results', function () {
let {desiredCaps, processedJsonwpCaps, processedW3CCapabilities} = parseCapsForInnerDriver(BASE_CAPS, W3C_CAPS, {}, {foo: 'bar'});
let {desiredCaps, processedJsonwpCapabilities, processedW3CCapabilities} = parseCapsForInnerDriver(BASE_CAPS, W3C_CAPS, {}, {foo: 'bar'});
desiredCaps.should.deep.equal({foo: 'bar', ...BASE_CAPS});
processedJsonwpCaps.should.deep.equal({foo: 'bar', ...BASE_CAPS});
processedJsonwpCapabilities.should.deep.equal({foo: 'bar', ...BASE_CAPS});
processedW3CCapabilities.alwaysMatch.should.deep.equal({'appium:foo': 'bar', ...insertAppiumPrefixes(BASE_CAPS)});
});
it('should reject if W3C caps are not passing constraints', function () {
(() => parseCapsForInnerDriver(BASE_CAPS, W3C_CAPS, {hello: {presence: true}})).should.throw(/'hello' can't be blank/);
(() => parseCapsForInnerDriver(undefined, W3C_CAPS, {hello: {presence: true}})).should.throw(/'hello' can't be blank/);
});
it('should only accept W3C caps that have passing constraints', function () {
let w3cCaps = {
@@ -102,10 +44,10 @@ describe('utils', function () {
{hello: 'world'},
],
};
let {desiredCaps, processedJsonwpCaps, processedW3CCapabilities} = parseCapsForInnerDriver(BASE_CAPS, w3cCaps, {hello: {presence: true}});
let {desiredCaps, processedJsonwpCapabilities, processedW3CCapabilities} = parseCapsForInnerDriver(BASE_CAPS, w3cCaps, {hello: {presence: true}});
const expectedResult = {hello: 'world', ...BASE_CAPS};
desiredCaps.should.deep.equal(expectedResult);
processedJsonwpCaps.should.deep.equal(expectedResult);
processedJsonwpCapabilities.should.deep.equal({...BASE_CAPS});
processedW3CCapabilities.alwaysMatch.should.deep.equal(insertAppiumPrefixes(expectedResult));
});
it('should add appium prefixes to W3C caps that are not standard in W3C', function () {
@@ -119,6 +61,34 @@ describe('utils', function () {
firstMatch: [{}],
});
});
it('should fall back to MJSONWP caps if MJSONWP contains extraneous caps that aren not in W3C', function () {
let jsonwpCaps = {
...BASE_CAPS,
automationName: 'Fake',
};
const {desiredCaps, processedJsonwpCapabilities, processedW3CCapabilities} = parseCapsForInnerDriver(jsonwpCaps, {
alwaysMatch: {platformName: 'Fake', propertyName: 'PROP_NAME'},
});
should.not.exist(processedW3CCapabilities);
desiredCaps.should.eql(jsonwpCaps);
processedJsonwpCapabilities.should.eql(jsonwpCaps);
});
it('should fall back to MJSONWP caps if W3C capabilities are invalid', function () {
let w3cCapabilities = {
alwaysMatch: {platformName: 'Fake', propertyName: 'PROP_NAME'},
};
let constraints = {
deviceName: {
presence: true,
}
};
const {desiredCaps, processedJsonwpCapabilities, processedW3CCapabilities} = parseCapsForInnerDriver({...BASE_CAPS}, w3cCapabilities, constraints);
should.not.exist(processedW3CCapabilities);
desiredCaps.should.eql(BASE_CAPS);
processedJsonwpCapabilities.should.eql(BASE_CAPS);
});
});
describe('insertAppiumPrefixes()', function () {