Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/testing/recordfunction.js
4503 views
1
/**
2
* @license
3
* Copyright The Closure Library Authors.
4
* SPDX-License-Identifier: Apache-2.0
5
*/
6
7
/**
8
* @fileoverview Helper class for recording the calls of a function.
9
*
10
* Example:
11
* <pre>
12
* var stubs = new goog.testing.PropertyReplacer();
13
*
14
* function tearDown() {
15
* stubs.reset();
16
* }
17
*
18
* function testShuffle() {
19
* stubs.replace(Math, 'random', goog.testing.recordFunction(Math.random));
20
* var arr = shuffle([1, 2, 3, 4, 5]);
21
* assertSameElements([1, 2, 3, 4, 5], arr);
22
* assertEquals(4, Math.random.getCallCount());
23
* }
24
*
25
* function testOpenDialog() {
26
* stubs.replace(goog.ui, 'Dialog',
27
* goog.testing.recordConstructor(goog.ui.Dialog));
28
* openConfirmDialog();
29
* var lastDialogInstance = goog.ui.Dialog.getLastCall().getThis();
30
* assertEquals('confirm', lastDialogInstance.getTitle());
31
* }
32
* </pre>
33
*/
34
35
goog.setTestOnly('goog.testing.FunctionCall');
36
goog.provide('goog.testing.FunctionCall');
37
goog.provide('goog.testing.recordConstructor');
38
goog.provide('goog.testing.recordFunction');
39
40
goog.require('goog.Promise');
41
goog.require('goog.functions');
42
goog.require('goog.promise.Resolver');
43
goog.require('goog.testing.asserts');
44
45
46
/**
47
* A function that represents the return type of recordFunction.
48
* @private
49
* @param {...?} var_args
50
* @return {?}
51
*/
52
goog.testing.recordedFunction_ = function(var_args) {};
53
54
/**
55
* @return {number} Total number of calls.
56
*/
57
goog.testing.recordedFunction_.getCallCount = function() {};
58
59
/**
60
* Asserts that the function was called a certain number of times.
61
* @param {number|string} a The expected number of calls (1 arg) or debug
62
* message (2 args).
63
* @param {number=} opt_b The expected number of calls (2 args only).
64
*/
65
goog.testing.recordedFunction_.assertCallCount = function(a, opt_b) {};
66
67
/**
68
* @return {!Array<!goog.testing.FunctionCall>} All calls of the recorded
69
* function.
70
*/
71
goog.testing.recordedFunction_.getCalls = function() {};
72
73
/**
74
* @return {?goog.testing.FunctionCall} Last call of the recorded function or
75
* null if it hasn't been called.
76
*/
77
goog.testing.recordedFunction_.getLastCall = function() {};
78
79
/**
80
* Returns and removes the last call of the recorded function.
81
* @return {?goog.testing.FunctionCall} Last call of the recorded function or
82
* null if it hasn't been called.
83
*/
84
goog.testing.recordedFunction_.popLastCall = function() {};
85
86
/**
87
* Returns a goog.Promise that resolves when the recorded function has equal
88
* to or greater than the number of calls.
89
* @param {number} num
90
* @return {!goog.Promise<undefined>}
91
*/
92
goog.testing.recordedFunction_.waitForCalls = function(num) {};
93
94
/**
95
* Resets the recorded function and removes all calls.
96
* @return {void}
97
*/
98
goog.testing.recordedFunction_.reset = function() {};
99
100
/**
101
* Wraps the function into another one which calls the inner function and
102
* records its calls. The recorded function will have 3 static methods:
103
* `getCallCount`, `getCalls` and `getLastCall` but won't
104
* inherit the original function's prototype and static fields.
105
*
106
* @param {!Function=} opt_f The function to wrap and record. Defaults to
107
* goog.functions.UNDEFINED.
108
* @return {!goog.testing.recordFunction.Type} The wrapped function.
109
*/
110
goog.testing.recordFunction = function(opt_f) {
111
'use strict';
112
var f = opt_f || goog.functions.UNDEFINED;
113
var calls = [];
114
/** @type {?goog.promise.Resolver} */
115
var waitForCallsResolver = null;
116
/** @type {number} */
117
var waitForCallsCount = 0;
118
119
function maybeResolveWaitForCalls() {
120
if (waitForCallsResolver && calls.length >= waitForCallsCount) {
121
waitForCallsResolver.resolve();
122
waitForCallsResolver = null;
123
waitForCallsCount = 0;
124
}
125
}
126
127
/** @type {!goog.testing.recordFunction.Type} */
128
function recordedFunction() {
129
var owner = /** @type {?} */ (this);
130
try {
131
var ret = f.apply(owner, arguments);
132
calls.push(new goog.testing.FunctionCall(f, owner, arguments, ret, null));
133
maybeResolveWaitForCalls();
134
return ret;
135
} catch (err) {
136
calls.push(
137
new goog.testing.FunctionCall(f, owner, arguments, undefined, err));
138
maybeResolveWaitForCalls();
139
throw err;
140
}
141
}
142
143
/**
144
* @return {number} Total number of calls.
145
*/
146
recordedFunction.getCallCount = function() {
147
'use strict';
148
return calls.length;
149
};
150
151
/**
152
* Asserts that the function was called a certain number of times.
153
* @param {number|string} a The expected number of calls (1 arg) or debug
154
* message (2 args).
155
* @param {number=} opt_b The expected number of calls (2 args only).
156
*/
157
recordedFunction.assertCallCount = function(a, opt_b) {
158
'use strict';
159
var actual = calls.length;
160
var expected = arguments.length == 1 ? a : opt_b;
161
var message = arguments.length == 1 ? '' : ' ' + a;
162
assertEquals(
163
'Expected ' + expected + ' call(s), but was ' + actual + '.' + message,
164
expected, actual);
165
};
166
167
/**
168
* @return {!Array<!goog.testing.FunctionCall>} All calls of the recorded
169
* function.
170
*/
171
recordedFunction.getCalls = function() {
172
'use strict';
173
return calls;
174
};
175
176
177
/**
178
* @return {goog.testing.FunctionCall} Last call of the recorded function or
179
* null if it hasn't been called.
180
*/
181
recordedFunction.getLastCall = function() {
182
'use strict';
183
return calls[calls.length - 1] || null;
184
};
185
186
/**
187
* Returns and removes the last call of the recorded function.
188
* @return {goog.testing.FunctionCall} Last call of the recorded function or
189
* null if it hasn't been called.
190
*/
191
recordedFunction.popLastCall = function() {
192
'use strict';
193
return calls.pop() || null;
194
};
195
196
/**
197
* Returns a goog.Promise that resolves when the recorded function has equal
198
* to or greater than the number of calls.
199
* @param {number} num
200
* @return {!goog.Promise<undefined>}
201
*/
202
recordedFunction.waitForCalls = function(num) {
203
'use strict';
204
waitForCallsCount = num;
205
waitForCallsResolver = goog.Promise.withResolver();
206
var promise = waitForCallsResolver.promise;
207
maybeResolveWaitForCalls();
208
return promise;
209
};
210
211
/**
212
* Resets the recorded function and removes all calls.
213
*/
214
recordedFunction.reset = function() {
215
'use strict';
216
calls.length = 0;
217
waitForCallsResolver = null;
218
waitForCallsCount = 0;
219
};
220
221
return recordedFunction;
222
};
223
224
/** @typedef {typeof goog.testing.recordedFunction_} */
225
goog.testing.recordFunction.Type;
226
227
228
/**
229
* Same as {@link goog.testing.recordFunction} but the recorded function will
230
* have the same prototype and static fields as the original one. It can be
231
* used with constructors.
232
*
233
* @param {!Function} ctor The function to wrap and record.
234
* @return {!Function} The wrapped function.
235
*/
236
goog.testing.recordConstructor = function(ctor) {
237
'use strict';
238
var recordedConstructor = goog.testing.recordFunction(ctor);
239
recordedConstructor.prototype = ctor.prototype;
240
241
// NOTE: This does not handle non-enumerable properties, should it?
242
for (var x in ctor) {
243
recordedConstructor[x] = ctor[x];
244
}
245
return recordedConstructor;
246
};
247
248
249
250
/**
251
* Struct for a single function call.
252
* @param {!Function} func The called function.
253
* @param {!Object} thisContext `this` context of called function.
254
* @param {!Arguments} args Arguments of the called function.
255
* @param {*} ret Return value of the function or undefined in case of error.
256
* @param {*} error The error thrown by the function or null if none.
257
* @constructor
258
*/
259
goog.testing.FunctionCall = function(func, thisContext, args, ret, error) {
260
'use strict';
261
this.function_ = func;
262
this.thisContext_ = thisContext;
263
this.arguments_ = Array.prototype.slice.call(args);
264
this.returnValue_ = ret;
265
this.error_ = error;
266
};
267
268
269
/**
270
* @return {!Function} The called function.
271
*/
272
goog.testing.FunctionCall.prototype.getFunction = function() {
273
'use strict';
274
return this.function_;
275
};
276
277
278
/**
279
* @return {!Object} `this` context of called function. It is the same as
280
* the created object if the function is a constructor.
281
*/
282
goog.testing.FunctionCall.prototype.getThis = function() {
283
'use strict';
284
return this.thisContext_;
285
};
286
287
288
/**
289
* @return {!Array<?>} Arguments of the called function.
290
*/
291
goog.testing.FunctionCall.prototype.getArguments = function() {
292
'use strict';
293
return this.arguments_;
294
};
295
296
297
/**
298
* Returns the nth argument of the called function.
299
* @param {number} index 0-based index of the argument.
300
* @return {*} The argument value or undefined if there is no such argument.
301
*/
302
goog.testing.FunctionCall.prototype.getArgument = function(index) {
303
'use strict';
304
return this.arguments_[index];
305
};
306
307
308
/**
309
* @return {*} Return value of the function or undefined in case of error.
310
*/
311
goog.testing.FunctionCall.prototype.getReturnValue = function() {
312
'use strict';
313
return this.returnValue_;
314
};
315
316
317
/**
318
* @return {*} The error thrown by the function or null if none.
319
*/
320
goog.testing.FunctionCall.prototype.getError = function() {
321
'use strict';
322
return this.error_;
323
};
324
325