# lib/webdriver/testing/asserts.js

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