# lib/webdriver/testing/asserts.js

1 | // Copyright 2011 Software Freedom Conservancy. All Rights Reserved.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | /**
16 | * @fileoverview Assertions and expectation utilities for use in WebDriver test
17 | * cases.
18 | */
19 |
20 | goog.provide('webdriver.testing.Assertion');
21 | goog.provide('webdriver.testing.ContainsMatcher');
22 | goog.provide('webdriver.testing.NegatedAssertion');
23 | goog.provide('webdriver.testing.assert');
24 | goog.provide('webdriver.testing.asserts');
25 |
26 | goog.require('goog.array');
27 | goog.require('goog.labs.testing.CloseToMatcher');
28 | goog.require('goog.labs.testing.EndsWithMatcher');
29 | goog.require('goog.labs.testing.EqualToMatcher');
30 | goog.require('goog.labs.testing.EqualsMatcher');
31 | goog.require('goog.labs.testing.GreaterThanEqualToMatcher');
32 | goog.require('goog.labs.testing.GreaterThanMatcher');
33 | goog.require('goog.labs.testing.LessThanEqualToMatcher');
34 | goog.require('goog.labs.testing.LessThanMatcher');
35 | goog.require('goog.labs.testing.InstanceOfMatcher');
36 | goog.require('goog.labs.testing.IsNotMatcher');
37 | goog.require('goog.labs.testing.IsNullMatcher');
38 | goog.require('goog.labs.testing.IsNullOrUndefinedMatcher');
39 | goog.require('goog.labs.testing.IsUndefinedMatcher');
40 | goog.require('goog.labs.testing.Matcher');
41 | goog.require('goog.labs.testing.ObjectEqualsMatcher');
42 | goog.require('goog.labs.testing.RegexMatcher');
43 | goog.require('goog.labs.testing.StartsWithMatcher');
44 | goog.require('goog.labs.testing.assertThat');
45 | goog.require('goog.string');
46 | goog.require('webdriver.promise');
47 |
48 |
49 | /**
50 | * Accepts strins or array-like structures that contain {@code value}.
51 | * @param {*} value The value to check for.
52 | * @constructor
53 | * @implements {goog.labs.testing.Matcher}
54 | */
55 | webdriver.testing.ContainsMatcher = function(value) {
56 | /** @private {*} */
57 | this.value_ = value;
58 | };
59 |
60 |
61 | /** @override */
62 | webdriver.testing.ContainsMatcher.prototype.matches = function(actualValue) {
63 | if (goog.isString(actualValue)) {
64 | return goog.string.contains(
65 | actualValue, /** @type {string} */(this.value_));
66 | } else {
67 | return goog.array.contains(
68 | /** @type {goog.array.ArrayLike} */(actualValue), this.value_);
69 | }
70 | };
71 |
72 |
73 | /** @override */
74 | webdriver.testing.ContainsMatcher.prototype.describe = function(actualValue) {
75 | return actualValue + ' does not contain ' + this.value_;
76 | };
77 |
78 |
79 |
80 | /**
81 | * Utility for performing assertions against a given {@code value}. If the
82 | * value is a {@link webdriver.promise.Promise}, this assertion will wait
83 | * for it to resolve before applying any matchers.
84 | * @param {*} value The value to wrap and apply matchers to.
85 | * @constructor
86 | */
87 | webdriver.testing.Assertion = function(value) {
88 |
89 | /** @private {*} */
90 | this.value_ = value;
91 |
92 | if (!(this instanceof webdriver.testing.NegatedAssertion)) {
93 | /**
94 | * A self reference provided for writing fluent assertions:
95 | * webdriver.testing.assert(x).is.equalTo(y);
96 | * @type {!webdriver.testing.Assertion}
97 | */
98 | this.is = this;
99 |
100 | /**
101 | * Negates any matchers applied to this instance's value:
102 | * webdriver.testing.assert(x).not.equalTo(y);
103 | * @type {!webdriver.testing.NegatedAssertion}
104 | */
105 | this.not = new webdriver.testing.NegatedAssertion(value);
106 | }
107 | };
108 |
109 |
110 | /**
111 | * Wraps an object literal implementing the Matcher interface. This is used
112 | * to appease the Closure compiler, which will not treat an object literal as
113 | * implementing an interface.
114 | * @param {{matches: function(*): boolean, describe: function(): string}} obj
115 | * The object literal to delegate to.
116 | * @constructor
117 | * @implements {goog.labs.testing.Matcher}
118 | * @private
119 | */
120 | webdriver.testing.Assertion.DelegatingMatcher_ = function(obj) {
121 |
122 | /** @override */
123 | this.matches = function(value) {
124 | return obj.matches(value);
125 | };
126 |
127 | /** @override */
128 | this.describe = function() {
129 | return obj.describe();
130 | };
131 | };
132 |
133 |
134 | /**
135 | * Asserts that the given {@code matcher} accepts the value wrapped by this
136 | * instance. If the wrapped value is a promise, this function will defer
137 | * applying the assertion until the value has been resolved. Otherwise, it
138 | * will be applied immediately.
139 | * @param {!goog.labs.testing.Matcher} matcher The matcher to apply
140 | * @param {string=} opt_message A message to include if the matcher does not
141 | * accept the value wrapped by this assertion.
142 | * @return {webdriver.promise.Promise} The deferred assertion result, or
143 | * {@code null} if the assertion was immediately applied.
144 | * @protected
145 | */
146 | webdriver.testing.Assertion.prototype.apply = function(matcher, opt_message) {
147 | var result = null;
148 | if (webdriver.promise.isPromise(this.value_)) {
149 | result = webdriver.promise.when(this.value_, function(value) {
150 | goog.labs.testing.assertThat(value, matcher, opt_message);
151 | });
152 | } else {
153 | goog.labs.testing.assertThat(this.value_, matcher, opt_message);
154 | }
155 | return result;
156 | };
157 |
158 |
159 | /**
160 | * Asserts that the value managed by this assertion is a number strictly
161 | * greater than {@code value}.
162 | * @param {number} value The minimum value.
163 | * @param {string=} opt_message A message to include if the matcher does not
164 | * accept the value wrapped by this assertion.
165 | * @return {webdriver.promise.Promise} The assertion result.
166 | */
167 | webdriver.testing.Assertion.prototype.greaterThan = function(
168 | value, opt_message) {
169 | return this.apply(
170 | new goog.labs.testing.GreaterThanMatcher(value), opt_message);
171 | };
172 |
173 |
174 | /**
175 | * Asserts that the value managed by this assertion is a number >= the given
176 | * value.
177 | * @param {number} value The minimum value.
178 | * @param {string=} opt_message A message to include if the matcher does not
179 | * accept the value wrapped by this assertion.
180 | * @return {webdriver.promise.Promise} The assertion result.
181 | */
182 | webdriver.testing.Assertion.prototype.greaterThanEqualTo = function(
183 | value, opt_message) {
184 | return this.apply(
185 | new goog.labs.testing.GreaterThanEqualToMatcher(value), opt_message);
186 | };
187 |
188 |
189 | /**
190 | * Asserts that the value managed by this assertion is a number strictly less
191 | * than the given value.
192 | * @param {number} value The maximum value.
193 | * @param {string=} opt_message A message to include if the matcher does not
194 | * accept the value wrapped by this assertion.
195 | * @return {webdriver.promise.Promise} The assertion result.
196 | */
197 | webdriver.testing.Assertion.prototype.lessThan = function(value, opt_message) {
198 | return this.apply(
199 | new goog.labs.testing.LessThanMatcher(value), opt_message);
200 | };
201 |
202 |
203 | /**
204 | * Asserts that the value managed by this assertion is a number <= the given
205 | * value.
206 | * @param {number} value The maximum value.
207 | * @param {string=} opt_message A message to include if the matcher does not
208 | * accept the value wrapped by this assertion.
209 | * @return {webdriver.promise.Promise} The assertion result.
210 | */
211 | webdriver.testing.Assertion.prototype.lessThanEqualTo = function(
212 | value, opt_message) {
213 | return this.apply(
214 | new goog.labs.testing.LessThanEqualToMatcher(value), opt_message);
215 | };
216 |
217 |
218 | /**
219 | * Asserts that the wrapped value is a number within a given distance of an
220 | * expected value.
221 | * @param {number} value The expected value.
222 | * @param {number} range The maximum amount the actual value is permitted to
223 | * differ from the expected value.
224 | * @param {string=} opt_message A message to include if the matcher does not
225 | * accept the value wrapped by this assertion.
226 | * @return {webdriver.promise.Promise} The assertion result.
227 | */
228 | webdriver.testing.Assertion.prototype.closeTo = function(
229 | value, range, opt_message) {
230 | return this.apply(
231 | new goog.labs.testing.CloseToMatcher(value, range), opt_message);
232 | };
233 |
234 |
235 | /**
236 | * Asserts that the wrapped value is an instance of the given class.
237 | * @param {!Function} ctor The expected class constructor.
238 | * @param {string=} opt_message A message to include if the matcher does not
239 | * accept the value wrapped by this assertion.
240 | * @return {webdriver.promise.Promise} The assertion result.
241 | */
242 | webdriver.testing.Assertion.prototype.instanceOf = function(ctor, opt_message) {
243 | return this.apply(
244 | new goog.labs.testing.InstanceOfMatcher(ctor), opt_message);
245 | };
246 |
247 |
248 | /**
249 | * Asserts that the wrapped value is null.
250 | * @param {string=} opt_message A message to include if the matcher does not
251 | * accept the value wrapped by this assertion.
252 | * @return {webdriver.promise.Promise} The assertion result.
253 | */
254 | webdriver.testing.Assertion.prototype.isNull = function(opt_message) {
255 | return this.apply(new goog.labs.testing.IsNullMatcher(), opt_message);
256 | };
257 |
258 |
259 | /**
260 | * Asserts that the wrapped value is undefined.
261 | * @param {string=} opt_message A message to include if the matcher does not
262 | * accept the value wrapped by this assertion.
263 | * @return {webdriver.promise.Promise} The assertion result.
264 | */
265 | webdriver.testing.Assertion.prototype.isUndefined = function(opt_message) {
266 | return this.apply(new goog.labs.testing.IsUndefinedMatcher(), opt_message);
267 | };
268 |
269 |
270 | /**
271 | * Asserts that the wrapped value is null or undefined.
272 | * @param {string=} opt_message A message to include if the matcher does not
273 | * accept the value wrapped by this assertion.
274 | * @return {webdriver.promise.Promise} The assertion result.
275 | */
276 | webdriver.testing.Assertion.prototype.isNullOrUndefined = function(
277 | opt_message) {
278 | return this.apply(
279 | new goog.labs.testing.IsNullOrUndefinedMatcher(), opt_message);
280 | };
281 |
282 |
283 | /**
284 | * Asserts that the wrapped value is a string or array-like structure
285 | * containing the given value.
286 | * @param {*} value The expected value.
287 | * @param {string=} opt_message A message to include if the matcher does not
288 | * accept the value wrapped by this assertion.
289 | * @return {webdriver.promise.Promise} The assertion result.
290 | */
291 | webdriver.testing.Assertion.prototype.contains = function(value, opt_message) {
292 | return this.apply(
293 | new webdriver.testing.ContainsMatcher(value), opt_message);
294 | };
295 |
296 |
297 | /**
298 | * Asserts that the wrapped value is a string ending with the given suffix.
299 | * @param {string} suffix The expected suffix.
300 | * @param {string=} opt_message A message to include if the matcher does not
301 | * accept the value wrapped by this assertion.
302 | * @return {webdriver.promise.Promise} The assertion result.
303 | */
304 | webdriver.testing.Assertion.prototype.endsWith = function(
305 | suffix, opt_message) {
306 | return this.apply(
307 | new goog.labs.testing.EndsWithMatcher(suffix), opt_message);
308 | };
309 |
310 |
311 | /**
312 | * Asserts that the wrapped value is a string starting with the given prefix.
313 | * @param {string} prefix The expected prefix.
314 | * @param {string=} opt_message A message to include if the matcher does not
315 | * accept the value wrapped by this assertion.
316 | * @return {webdriver.promise.Promise} The assertion result.
317 | */
318 | webdriver.testing.Assertion.prototype.startsWith = function(
319 | prefix, opt_message) {
320 | return this.apply(
321 | new goog.labs.testing.StartsWithMatcher(prefix), opt_message);
322 | };
323 |
324 |
325 | /**
326 | * Asserts that the wrapped value is a string that matches the given RegExp.
327 | * @param {!RegExp} regex The regex to test.
328 | * @param {string=} opt_message A message to include if the matcher does not
329 | * accept the value wrapped by this assertion.
330 | * @return {webdriver.promise.Promise} The assertion result.
331 | */
332 | webdriver.testing.Assertion.prototype.matches = function(regex, opt_message) {
333 | return this.apply(new goog.labs.testing.RegexMatcher(regex), opt_message);
334 | };
335 |
336 |
337 | /**
338 | * Asserts that the value managed by this assertion is strictly equal to the
339 | * given {@code value}.
340 | * @param {*} value The expected value.
341 | * @param {string=} opt_message A message to include if the matcher does not
342 | * accept the value wrapped by this assertion.
343 | * @return {webdriver.promise.Promise} The assertion result.
344 | */
345 | webdriver.testing.Assertion.prototype.equalTo = function(value, opt_message) {
346 | return this.apply(webdriver.testing.asserts.equalTo(value), opt_message);
347 | };
348 |
349 |
350 | /**
351 | * Asserts that the value managed by this assertion is strictly true.
352 | * @return {webdriver.promise.Promise} The assertion result.
353 | */
354 | webdriver.testing.Assertion.prototype.isTrue = function() {
355 | return this.equalTo(true);
356 | };
357 |
358 |
359 | /**
360 | * Asserts that the value managed by this assertion is strictly false.
361 | * @return {webdriver.promise.Promise} The assertion result.
362 | */
363 | webdriver.testing.Assertion.prototype.isFalse = function() {
364 | return this.equalTo(false);
365 | };
366 |
367 |
368 |
369 | /**
370 | * An assertion that negates any applied matchers.
371 | * @param {*} value The value to perform assertions on.
372 | * @constructor
373 | * @extends {webdriver.testing.Assertion}
374 | */
375 | webdriver.testing.NegatedAssertion = function(value) {
376 | goog.base(this, value);
377 | this.value = value;
378 | };
379 | goog.inherits(
380 | webdriver.testing.NegatedAssertion, webdriver.testing.Assertion);
381 |
382 |
383 | /** @override */
384 | webdriver.testing.NegatedAssertion.prototype.apply = function(
385 | matcher, opt_message) {
386 | matcher = new goog.labs.testing.IsNotMatcher(matcher);
387 | return goog.base(this, 'apply', matcher, opt_message);
388 | };
389 |
390 |
391 |
392 | /**
393 | * Creates a new assertion.
394 | * @param {*} value The value to perform an assertion on.
395 | * @return {!webdriver.testing.Assertion} The new assertion.
396 | */
397 | webdriver.testing.assert = function(value) {
398 | return new webdriver.testing.Assertion(value);
399 | };
400 |
401 |
402 | /**
403 | * Registers a new assertion to expose from the
404 | * {@link webdriver.testing.Assertion} prototype.
405 | * @param {string} name The assertion name.
406 | * @param {(function(new: goog.labs.testing.Matcher, *)|
407 | * {matches: function(*): boolean,
408 | * describe: function(): string})} matcherTemplate Either the
409 | * matcher constructor to use, or an object literal defining a matcher.
410 | */
411 | webdriver.testing.assert.register = function(name, matcherTemplate) {
412 | webdriver.testing.Assertion.prototype[name] = function(value, opt_message) {
413 | var matcher;
414 | if (goog.isFunction(matcherTemplate)) {
415 | var ctor = /** @type {function(new: goog.labs.testing.Matcher, *)} */ (
416 | matcherTemplate);
417 | matcher = new ctor(value);
418 | } else {
419 | matcher = new webdriver.testing.Assertion.DelegatingMatcher_(value);
420 | }
421 | return this.apply(matcher, opt_message);
422 | };
423 | };
424 |
425 |
426 | /**
427 | * Asserts that a matcher accepts a given value. This function has two
428 | * signatures based on the number of arguments:
429 | *
430 | * Two arguments:
431 | * assertThat(actualValue, matcher)
432 | * Three arguments:
433 | * assertThat(failureMessage, actualValue, matcher)
434 | *
435 | * @param {*} failureMessageOrActualValue Either a failure message or the value
436 | * to apply to the given matcher.
437 | * @param {*} actualValueOrMatcher Either the value to apply to the given
438 | * matcher, or the matcher itself.
439 | * @param {goog.labs.testing.Matcher=} opt_matcher The matcher to use;
440 | * ignored unless this function is invoked with three arguments.
441 | * @return {!webdriver.promise.Promise} The assertion result.
442 | * @deprecated Use webdriver.testing.asserts.assert instead.
443 | */
444 | webdriver.testing.asserts.assertThat = function(
445 | failureMessageOrActualValue, actualValueOrMatcher, opt_matcher) {
446 | var args = goog.array.slice(arguments, 0);
447 |
448 | var message = args.length > 2 ? args.shift() : '';
449 | if (message) message += '\n';
450 |
451 | var actualValue = args.shift();
452 | var matcher = args.shift();
453 |
454 | return webdriver.promise.when(actualValue, function(value) {
455 | goog.labs.testing.assertThat(value, matcher, message);
456 | });
457 | };
458 |
459 |
460 | /**
461 | * Creates an equality matcher.
462 | * @param {*} expected The expected value.
463 | * @return {!goog.labs.testing.Matcher} The new matcher.
464 | */
465 | webdriver.testing.asserts.equalTo = function(expected) {
466 | if (goog.isString(expected)) {
467 | return new goog.labs.testing.EqualsMatcher(expected);
468 | } else if (goog.isNumber(expected)) {
469 | return new goog.labs.testing.EqualToMatcher(expected);
470 | } else {
471 | return new goog.labs.testing.ObjectEqualsMatcher(
472 | /** @type {!Object} */ (expected));
473 | }
474 | };
475 |
476 |
477 | goog.exportSymbol('assertThat', webdriver.testing.asserts.assertThat);
478 | // Mappings for goog.labs.testing matcher functions to the legacy
479 | // webdriver.testing.asserts matchers.
480 | goog.exportSymbol('contains', containsString);
481 | goog.exportSymbol('equalTo', webdriver.testing.asserts.equalTo);
482 | goog.exportSymbol('equals', webdriver.testing.asserts.equalTo);
483 | goog.exportSymbol('is', webdriver.testing.asserts.equalTo);
484 | goog.exportSymbol('not', isNot);
485 | goog.exportSymbol('or', anyOf);