You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

486 lines
16 KiB

// Copyright 2011 Software Freedom Conservancy. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Assertions and expectation utilities for use in WebDriver test
* cases.
*/
goog.provide('webdriver.testing.Assertion');
goog.provide('webdriver.testing.ContainsMatcher');
goog.provide('webdriver.testing.NegatedAssertion');
goog.provide('webdriver.testing.assert');
goog.provide('webdriver.testing.asserts');
goog.require('goog.array');
goog.require('goog.labs.testing.CloseToMatcher');
goog.require('goog.labs.testing.EndsWithMatcher');
goog.require('goog.labs.testing.EqualToMatcher');
goog.require('goog.labs.testing.EqualsMatcher');
goog.require('goog.labs.testing.GreaterThanEqualToMatcher');
goog.require('goog.labs.testing.GreaterThanMatcher');
goog.require('goog.labs.testing.LessThanEqualToMatcher');
goog.require('goog.labs.testing.LessThanMatcher');
goog.require('goog.labs.testing.InstanceOfMatcher');
goog.require('goog.labs.testing.IsNotMatcher');
goog.require('goog.labs.testing.IsNullMatcher');
goog.require('goog.labs.testing.IsNullOrUndefinedMatcher');
goog.require('goog.labs.testing.IsUndefinedMatcher');
goog.require('goog.labs.testing.Matcher');
goog.require('goog.labs.testing.ObjectEqualsMatcher');
goog.require('goog.labs.testing.RegexMatcher');
goog.require('goog.labs.testing.StartsWithMatcher');
goog.require('goog.labs.testing.assertThat');
goog.require('goog.string');
goog.require('webdriver.promise');
/**
* Accepts strins or array-like structures that contain {@code value}.
* @param {*} value The value to check for.
* @constructor
* @implements {goog.labs.testing.Matcher}
*/
webdriver.testing.ContainsMatcher = function(value) {
/** @private {*} */
this.value_ = value;
};
/** @override */
webdriver.testing.ContainsMatcher.prototype.matches = function(actualValue) {
if (goog.isString(actualValue)) {
return goog.string.contains(
actualValue, /** @type {string} */(this.value_));
} else {
return goog.array.contains(
/** @type {goog.array.ArrayLike} */(actualValue), this.value_);
}
};
/** @override */
webdriver.testing.ContainsMatcher.prototype.describe = function(actualValue) {
return actualValue + ' does not contain ' + this.value_;
};
/**
* Utility for performing assertions against a given {@code value}. If the
* value is a {@link webdriver.promise.Promise}, this assertion will wait
* for it to resolve before applying any matchers.
* @param {*} value The value to wrap and apply matchers to.
* @constructor
*/
webdriver.testing.Assertion = function(value) {
/** @private {*} */
this.value_ = value;
if (!(this instanceof webdriver.testing.NegatedAssertion)) {
/**
* A self reference provided for writing fluent assertions:
* webdriver.testing.assert(x).is.equalTo(y);
* @type {!webdriver.testing.Assertion}
*/
this.is = this;
/**
* Negates any matchers applied to this instance's value:
* webdriver.testing.assert(x).not.equalTo(y);
* @type {!webdriver.testing.NegatedAssertion}
*/
this.not = new webdriver.testing.NegatedAssertion(value);
}
};
/**
* Wraps an object literal implementing the Matcher interface. This is used
* to appease the Closure compiler, which will not treat an object literal as
* implementing an interface.
* @param {{matches: function(*): boolean, describe: function(): string}} obj
* The object literal to delegate to.
* @constructor
* @implements {goog.labs.testing.Matcher}
* @private
*/
webdriver.testing.Assertion.DelegatingMatcher_ = function(obj) {
/** @override */
this.matches = function(value) {
return obj.matches(value);
};
/** @override */
this.describe = function() {
return obj.describe();
};
};
/**
* Asserts that the given {@code matcher} accepts the value wrapped by this
* instance. If the wrapped value is a promise, this function will defer
* applying the assertion until the value has been resolved. Otherwise, it
* will be applied immediately.
* @param {!goog.labs.testing.Matcher} matcher The matcher to apply
* @param {string=} opt_message A message to include if the matcher does not
* accept the value wrapped by this assertion.
* @return {webdriver.promise.Promise} The deferred assertion result, or
* {@code null} if the assertion was immediately applied.
* @protected
*/
webdriver.testing.Assertion.prototype.apply = function(matcher, opt_message) {
var result = null;
if (webdriver.promise.isPromise(this.value_)) {
result = webdriver.promise.when(this.value_, function(value) {
goog.labs.testing.assertThat(value, matcher, opt_message);
});
} else {
goog.labs.testing.assertThat(this.value_, matcher, opt_message);
}
return result;
};
/**
* Asserts that the value managed by this assertion is a number strictly
* greater than {@code value}.
* @param {number} value The minimum value.
* @param {string=} opt_message A message to include if the matcher does not
* accept the value wrapped by this assertion.
* @return {webdriver.promise.Promise} The assertion result.
*/
webdriver.testing.Assertion.prototype.greaterThan = function(
value, opt_message) {
return this.apply(
new goog.labs.testing.GreaterThanMatcher(value), opt_message);
};
/**
* Asserts that the value managed by this assertion is a number >= the given
* value.
* @param {number} value The minimum value.
* @param {string=} opt_message A message to include if the matcher does not
* accept the value wrapped by this assertion.
* @return {webdriver.promise.Promise} The assertion result.
*/
webdriver.testing.Assertion.prototype.greaterThanEqualTo = function(
value, opt_message) {
return this.apply(
new goog.labs.testing.GreaterThanEqualToMatcher(value), opt_message);
};
/**
* Asserts that the value managed by this assertion is a number strictly less
* than the given value.
* @param {number} value The maximum value.
* @param {string=} opt_message A message to include if the matcher does not
* accept the value wrapped by this assertion.
* @return {webdriver.promise.Promise} The assertion result.
*/
webdriver.testing.Assertion.prototype.lessThan = function(value, opt_message) {
return this.apply(
new goog.labs.testing.LessThanMatcher(value), opt_message);
};
/**
* Asserts that the value managed by this assertion is a number <= the given
* value.
* @param {number} value The maximum value.
* @param {string=} opt_message A message to include if the matcher does not
* accept the value wrapped by this assertion.
* @return {webdriver.promise.Promise} The assertion result.
*/
webdriver.testing.Assertion.prototype.lessThanEqualTo = function(
value, opt_message) {
return this.apply(
new goog.labs.testing.LessThanEqualToMatcher(value), opt_message);
};
/**
* Asserts that the wrapped value is a number within a given distance of an
* expected value.
* @param {number} value The expected value.
* @param {number} range The maximum amount the actual value is permitted to
* differ from the expected value.
* @param {string=} opt_message A message to include if the matcher does not
* accept the value wrapped by this assertion.
* @return {webdriver.promise.Promise} The assertion result.
*/
webdriver.testing.Assertion.prototype.closeTo = function(
value, range, opt_message) {
return this.apply(
new goog.labs.testing.CloseToMatcher(value, range), opt_message);
};
/**
* Asserts that the wrapped value is an instance of the given class.
* @param {!Function} ctor The expected class constructor.
* @param {string=} opt_message A message to include if the matcher does not
* accept the value wrapped by this assertion.
* @return {webdriver.promise.Promise} The assertion result.
*/
webdriver.testing.Assertion.prototype.instanceOf = function(ctor, opt_message) {
return this.apply(
new goog.labs.testing.InstanceOfMatcher(ctor), opt_message);
};
/**
* Asserts that the wrapped value is null.
* @param {string=} opt_message A message to include if the matcher does not
* accept the value wrapped by this assertion.
* @return {webdriver.promise.Promise} The assertion result.
*/
webdriver.testing.Assertion.prototype.isNull = function(opt_message) {
return this.apply(new goog.labs.testing.IsNullMatcher(), opt_message);
};
/**
* Asserts that the wrapped value is undefined.
* @param {string=} opt_message A message to include if the matcher does not
* accept the value wrapped by this assertion.
* @return {webdriver.promise.Promise} The assertion result.
*/
webdriver.testing.Assertion.prototype.isUndefined = function(opt_message) {
return this.apply(new goog.labs.testing.IsUndefinedMatcher(), opt_message);
};
/**
* Asserts that the wrapped value is null or undefined.
* @param {string=} opt_message A message to include if the matcher does not
* accept the value wrapped by this assertion.
* @return {webdriver.promise.Promise} The assertion result.
*/
webdriver.testing.Assertion.prototype.isNullOrUndefined = function(
opt_message) {
return this.apply(
new goog.labs.testing.IsNullOrUndefinedMatcher(), opt_message);
};
/**
* Asserts that the wrapped value is a string or array-like structure
* containing the given value.
* @param {*} value The expected value.
* @param {string=} opt_message A message to include if the matcher does not
* accept the value wrapped by this assertion.
* @return {webdriver.promise.Promise} The assertion result.
*/
webdriver.testing.Assertion.prototype.contains = function(value, opt_message) {
return this.apply(
new webdriver.testing.ContainsMatcher(value), opt_message);
};
/**
* Asserts that the wrapped value is a string ending with the given suffix.
* @param {string} suffix The expected suffix.
* @param {string=} opt_message A message to include if the matcher does not
* accept the value wrapped by this assertion.
* @return {webdriver.promise.Promise} The assertion result.
*/
webdriver.testing.Assertion.prototype.endsWith = function(
suffix, opt_message) {
return this.apply(
new goog.labs.testing.EndsWithMatcher(suffix), opt_message);
};
/**
* Asserts that the wrapped value is a string starting with the given prefix.
* @param {string} prefix The expected prefix.
* @param {string=} opt_message A message to include if the matcher does not
* accept the value wrapped by this assertion.
* @return {webdriver.promise.Promise} The assertion result.
*/
webdriver.testing.Assertion.prototype.startsWith = function(
prefix, opt_message) {
return this.apply(
new goog.labs.testing.StartsWithMatcher(prefix), opt_message);
};
/**
* Asserts that the wrapped value is a string that matches the given RegExp.
* @param {!RegExp} regex The regex to test.
* @param {string=} opt_message A message to include if the matcher does not
* accept the value wrapped by this assertion.
* @return {webdriver.promise.Promise} The assertion result.
*/
webdriver.testing.Assertion.prototype.matches = function(regex, opt_message) {
return this.apply(new goog.labs.testing.RegexMatcher(regex), opt_message);
};
/**
* Asserts that the value managed by this assertion is strictly equal to the
* given {@code value}.
* @param {*} value The expected value.
* @param {string=} opt_message A message to include if the matcher does not
* accept the value wrapped by this assertion.
* @return {webdriver.promise.Promise} The assertion result.
*/
webdriver.testing.Assertion.prototype.equalTo = function(value, opt_message) {
return this.apply(webdriver.testing.asserts.equalTo(value), opt_message);
};
/**
* Asserts that the value managed by this assertion is strictly true.
* @return {webdriver.promise.Promise} The assertion result.
*/
webdriver.testing.Assertion.prototype.isTrue = function() {
return this.equalTo(true);
};
/**
* Asserts that the value managed by this assertion is strictly false.
* @return {webdriver.promise.Promise} The assertion result.
*/
webdriver.testing.Assertion.prototype.isFalse = function() {
return this.equalTo(false);
};
/**
* An assertion that negates any applied matchers.
* @param {*} value The value to perform assertions on.
* @constructor
* @extends {webdriver.testing.Assertion}
*/
webdriver.testing.NegatedAssertion = function(value) {
goog.base(this, value);
this.value = value;
};
goog.inherits(
webdriver.testing.NegatedAssertion, webdriver.testing.Assertion);
/** @override */
webdriver.testing.NegatedAssertion.prototype.apply = function(
matcher, opt_message) {
matcher = new goog.labs.testing.IsNotMatcher(matcher);
return goog.base(this, 'apply', matcher, opt_message);
};
/**
* Creates a new assertion.
* @param {*} value The value to perform an assertion on.
* @return {!webdriver.testing.Assertion} The new assertion.
*/
webdriver.testing.assert = function(value) {
return new webdriver.testing.Assertion(value);
};
/**
* Registers a new assertion to expose from the
* {@link webdriver.testing.Assertion} prototype.
* @param {string} name The assertion name.
* @param {(function(new: goog.labs.testing.Matcher, *)|
* {matches: function(*): boolean,
* describe: function(): string})} matcherTemplate Either the
* matcher constructor to use, or an object literal defining a matcher.
*/
webdriver.testing.assert.register = function(name, matcherTemplate) {
webdriver.testing.Assertion.prototype[name] = function(value, opt_message) {
var matcher;
if (goog.isFunction(matcherTemplate)) {
var ctor = /** @type {function(new: goog.labs.testing.Matcher, *)} */ (
matcherTemplate);
matcher = new ctor(value);
} else {
matcher = new webdriver.testing.Assertion.DelegatingMatcher_(value);
}
return this.apply(matcher, opt_message);
};
};
/**
* Asserts that a matcher accepts a given value. This function has two
* signatures based on the number of arguments:
*
* Two arguments:
* assertThat(actualValue, matcher)
* Three arguments:
* assertThat(failureMessage, actualValue, matcher)
*
* @param {*} failureMessageOrActualValue Either a failure message or the value
* to apply to the given matcher.
* @param {*} actualValueOrMatcher Either the value to apply to the given
* matcher, or the matcher itself.
* @param {goog.labs.testing.Matcher=} opt_matcher The matcher to use;
* ignored unless this function is invoked with three arguments.
* @return {!webdriver.promise.Promise} The assertion result.
* @deprecated Use webdriver.testing.asserts.assert instead.
*/
webdriver.testing.asserts.assertThat = function(
failureMessageOrActualValue, actualValueOrMatcher, opt_matcher) {
var args = goog.array.slice(arguments, 0);
var message = args.length > 2 ? args.shift() : '';
if (message) message += '\n';
var actualValue = args.shift();
var matcher = args.shift();
return webdriver.promise.when(actualValue, function(value) {
goog.labs.testing.assertThat(value, matcher, message);
});
};
/**
* Creates an equality matcher.
* @param {*} expected The expected value.
* @return {!goog.labs.testing.Matcher} The new matcher.
*/
webdriver.testing.asserts.equalTo = function(expected) {
if (goog.isString(expected)) {
return new goog.labs.testing.EqualsMatcher(expected);
} else if (goog.isNumber(expected)) {
return new goog.labs.testing.EqualToMatcher(expected);
} else {
return new goog.labs.testing.ObjectEqualsMatcher(
/** @type {!Object} */ (expected));
}
};
goog.exportSymbol('assertThat', webdriver.testing.asserts.assertThat);
// Mappings for goog.labs.testing matcher functions to the legacy
// webdriver.testing.asserts matchers.
goog.exportSymbol('contains', containsString);
goog.exportSymbol('equalTo', webdriver.testing.asserts.equalTo);
goog.exportSymbol('equals', webdriver.testing.asserts.equalTo);
goog.exportSymbol('is', webdriver.testing.asserts.equalTo);
goog.exportSymbol('not', isNot);
goog.exportSymbol('or', anyOf);