341 lines
8.1 KiB
JavaScript
341 lines
8.1 KiB
JavaScript
/**
|
|
* Abstract assertion class that will subclass all defined Chai assertions
|
|
*
|
|
* All assertions must implement the following api:
|
|
*
|
|
* - @type {function}
|
|
* executeCommand
|
|
* - @type {string}
|
|
* elementFound
|
|
* - @type {function}
|
|
* elementNotFound
|
|
* - @type {function}
|
|
* retryCommand
|
|
* - @type {string}
|
|
* expected
|
|
* - @type {string}
|
|
* actual
|
|
* - @type {string}
|
|
* message
|
|
* - @type {boolean}
|
|
* passed
|
|
*
|
|
* @constructor
|
|
*/
|
|
var util = require('util');
|
|
var events = require('events');
|
|
var Assertion = require('../../core/assertion.js');
|
|
var chai = require('chai-nightwatch');
|
|
var flag = chai.flag;
|
|
var Utils = require('../../util/utils.js');
|
|
|
|
function BaseAssertion() {
|
|
}
|
|
|
|
BaseAssertion.ASSERT_FLAGS = [
|
|
'be',
|
|
'that',
|
|
'have',
|
|
'which',
|
|
'equal',
|
|
'contains',
|
|
'matches',
|
|
'before',
|
|
'after',
|
|
'waitFor'
|
|
];
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
BaseAssertion.prototype.executeCommand = function(callback) {};
|
|
|
|
BaseAssertion.prototype.setAssertion = function(assertion) {
|
|
this.assertion = assertion;
|
|
return this;
|
|
};
|
|
|
|
BaseAssertion.prototype.flag = function(key, value) {
|
|
if (typeof value == 'undefined') {
|
|
return flag(this.assertion, key);
|
|
}
|
|
|
|
flag(this.assertion, key, value);
|
|
return this;
|
|
};
|
|
|
|
BaseAssertion.prototype.setClient = function(client) {
|
|
this.client = client;
|
|
return this;
|
|
};
|
|
|
|
BaseAssertion.prototype.setProtocol = function(protocol) {
|
|
this.protocol = protocol;
|
|
return this;
|
|
};
|
|
|
|
BaseAssertion.prototype.init = function() {
|
|
this.promise = this.flag('promise');
|
|
this.element = this.flag('element');
|
|
this.selector = this.flag('selector');
|
|
|
|
this.setNegate();
|
|
|
|
this.waitForMs = this.client.api.globals.waitForConditionTimeout || null;
|
|
if (this.waitForMs) {
|
|
this.flag('waitFor', this.waitForMs);
|
|
}
|
|
this.retryInterval = this.client.api.globals.waitForConditionPollInterval || 500;
|
|
this.retries = 0;
|
|
this.messageParts = [];
|
|
this.abortOnFailure = typeof this.client.api.globals.abortOnAssertionFailure == 'undefined' || this.client.api.globals.abortOnAssertionFailure;
|
|
this.passed = false;
|
|
this.expected = null;
|
|
this.elementResult = null;
|
|
this.flags = [];
|
|
};
|
|
|
|
BaseAssertion.prototype.start = function() {
|
|
this.promise.then(this.onPromiseResolved.bind(this), this.onPromiseRejected.bind(this));
|
|
};
|
|
|
|
BaseAssertion.prototype.onPromiseResolved = function(elementResult) {
|
|
if (elementResult) {
|
|
this.elementResult = elementResult;
|
|
}
|
|
|
|
this.executeCommand(function(result) {
|
|
this.resultValue = result.value;
|
|
this.resultStatus = result.status;
|
|
this.resultErrorStatus = result.errorStatus;
|
|
|
|
this.processFlags();
|
|
this.elementFound();
|
|
|
|
if (!this.passed && this.shouldRetry()) {
|
|
this.scheduleRetry();
|
|
} else {
|
|
this.done();
|
|
}
|
|
}.bind(this));
|
|
};
|
|
|
|
BaseAssertion.prototype.onPromiseRejected = function(response) {
|
|
this.processFlags();
|
|
|
|
if (this.shouldRetry() && !this.negate) {
|
|
this.scheduleRetry();
|
|
return;
|
|
}
|
|
|
|
this.messageParts.push(' - element was not found');
|
|
this.actual = 'not present';
|
|
this.expected = 'present';
|
|
|
|
this.elementNotFound();
|
|
this.done();
|
|
};
|
|
|
|
BaseAssertion.prototype.processFlags = function() {
|
|
BaseAssertion.ASSERT_FLAGS.forEach(function(entry) {
|
|
var value = this.flag(entry);
|
|
if ((typeof value != 'undefined') && (typeof this['@' + entry + 'Flag'] == 'function')) {
|
|
this.flags.push([entry, value]);
|
|
this['@' + entry + 'Flag'](value);
|
|
}
|
|
}.bind(this));
|
|
};
|
|
|
|
BaseAssertion.prototype.hasFlag = function(type) {
|
|
return this.flags.some(function(flag) {
|
|
return flag[0] === type;
|
|
});
|
|
};
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
BaseAssertion.prototype.elementFound = function() {};
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
BaseAssertion.prototype.elementNotFound = function() {};
|
|
|
|
BaseAssertion.prototype.done = function() {
|
|
this.formatMessage();
|
|
var stackTrace = this.flag('element')._stackTrace;
|
|
|
|
Assertion.assert(
|
|
this.passed,
|
|
this.actual,
|
|
this.expected,
|
|
this.message,
|
|
this.abortOnFailure,
|
|
stackTrace
|
|
);
|
|
|
|
this.element.emitter.emit('complete');
|
|
};
|
|
|
|
BaseAssertion.prototype.getResult = function(value, fn) {
|
|
var result = fn.call(this);
|
|
this.setNegate();
|
|
return this.negate ? !result : result;
|
|
};
|
|
|
|
BaseAssertion.prototype.shouldRetryLocateElement = function() {
|
|
return (!this.elementResult || this.resultStatus === 10 || this.resultErrorStatus === 10);
|
|
};
|
|
|
|
BaseAssertion.prototype.shouldRetry = function() {
|
|
if (!this.waitForMs) {
|
|
return false;
|
|
}
|
|
|
|
this.elapsedTime = this.getElapsedTime();
|
|
return (this.elapsedTime < this.waitForMs);
|
|
};
|
|
|
|
BaseAssertion.prototype.getElapsedTime = function() {
|
|
var timeNow = new Date().getTime();
|
|
return timeNow - this.element.startTime;
|
|
};
|
|
|
|
BaseAssertion.prototype.scheduleRetry = function() {
|
|
this.retries++;
|
|
setTimeout(this.retryCommand.bind(this), this.retryInterval);
|
|
};
|
|
|
|
BaseAssertion.prototype.formatMessage = function() {
|
|
this.message = Utils.format(this.message || this.message, this.selector);
|
|
this.message += this.messageParts.join('');
|
|
};
|
|
|
|
BaseAssertion.prototype['@containsFlag'] = function(value) {
|
|
var verb = (this.hasFlag('that') || this.hasFlag('which')) ? 'contains' : 'contain';
|
|
this.conditionFlag(value, function() {
|
|
return this.resultValue ? this.resultValue.indexOf(value) > -1 : false;
|
|
}, [
|
|
'not ' + verb,
|
|
verb
|
|
]);
|
|
|
|
return this;
|
|
};
|
|
|
|
BaseAssertion.prototype['@equalFlag'] = function(value) {
|
|
var verb;
|
|
if (this.hasFlag('have')) {
|
|
verb = (this.hasFlag('that') || this.hasFlag('which')) ? 'equals' : 'equal to';
|
|
} else {
|
|
verb = 'equal';
|
|
}
|
|
this.conditionFlag(value, function() {
|
|
return this.resultValue == value;
|
|
}, [
|
|
'not ' + verb,
|
|
verb
|
|
]);
|
|
|
|
return this;
|
|
};
|
|
|
|
BaseAssertion.prototype['@matchesFlag'] = function(re) {
|
|
var adverb = this.hasFlag('that') || this.hasFlag('which');
|
|
var verb = adverb ? 'matches' : 'match';
|
|
this.conditionFlag(re, function() {
|
|
return re.test(this.resultValue);
|
|
}, [
|
|
(adverb ? 'does ' : '') + 'not match',
|
|
verb
|
|
]);
|
|
|
|
return this;
|
|
};
|
|
|
|
BaseAssertion.prototype.conditionFlag = function(value, conditionFn, arrverb) {
|
|
this.passed = this.getResult(value, conditionFn);
|
|
var verb = this.negate ? arrverb[0]: arrverb[1];
|
|
this.expected = verb + ' \'' + value + '\'';
|
|
this.actual = this.resultValue;
|
|
|
|
if (this.retries > 0) {
|
|
return;
|
|
}
|
|
|
|
var needsSpace = this.messageParts.length === 0 ? true : this.messageParts[this.messageParts.length-1].slice(-1) != ' ';
|
|
if (needsSpace) {
|
|
verb = ' ' + verb;
|
|
}
|
|
if (!this.customMessage) {
|
|
this.messageParts.push(
|
|
verb,
|
|
': "', value, '"'
|
|
);
|
|
}
|
|
};
|
|
|
|
BaseAssertion.prototype.setNegate = function() {
|
|
this.negate = this.flag('negate') || false;
|
|
return this;
|
|
};
|
|
|
|
BaseAssertion.prototype['@beforeFlag'] = function(value) {};
|
|
|
|
BaseAssertion.prototype['@afterFlag'] = function(value) {};
|
|
|
|
BaseAssertion.prototype['@haveFlag'] = function(value) {};
|
|
BaseAssertion.prototype['@waitForFlag'] = function(value) {
|
|
if (this.waitForMs !== value) {
|
|
this.waitForMs = value;
|
|
if (!this.customMessage) {
|
|
this.messageParts.push(this.checkWaitForMsg(this.waitForMs));
|
|
}
|
|
}
|
|
};
|
|
|
|
BaseAssertion.prototype['@thatFlag'] = function() {
|
|
if (this.retries > 0) {
|
|
return;
|
|
}
|
|
if (!this.customMessage) {
|
|
this.messageParts.push(' that ');
|
|
}
|
|
return this;
|
|
};
|
|
|
|
BaseAssertion.prototype['@whichFlag'] = function() {
|
|
if (this.retries > 0) {
|
|
return;
|
|
}
|
|
if (!this.customMessage) {
|
|
this.messageParts.push(' which ');
|
|
}
|
|
return this;
|
|
};
|
|
|
|
BaseAssertion.prototype['@beFlag'] = function() {};
|
|
|
|
BaseAssertion.prototype.hasCondition = function() {
|
|
return (this.hasFlag('contains') || this.hasFlag('equal') || this.hasFlag('matches'));
|
|
};
|
|
|
|
BaseAssertion.prototype.checkWaitForMsg = function(waitFor) {
|
|
var preposition = this.flag('before') && 'in' ||
|
|
this.flag('after') && 'after' ||
|
|
'in';
|
|
return ' ' + preposition +' ' + waitFor + 'ms';
|
|
};
|
|
|
|
BaseAssertion.prototype.retryCommand = function() {
|
|
if (this.shouldRetryLocateElement()) {
|
|
this.promise = this.element.createPromise();
|
|
this.promise.then(this.onPromiseResolved.bind(this), this.onPromiseRejected.bind(this));
|
|
this.element.locate();
|
|
} else {
|
|
this.onPromiseResolved();
|
|
}
|
|
};
|
|
|
|
module.exports = BaseAssertion; |