hyper-spec 0.1.2 → 0.99.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,156 @@
1
- require 'timecop'
1
+ if RUBY_ENGINE == 'opal'
2
+ # Wrap the Lolex js package
3
+ class Lolex
4
+ class << self
2
5
 
3
- module HyperSpec
6
+ # to avoid forcing us to require time we make our own Time.parse method
7
+ # copied from opal.rb master branch
8
+
9
+ def parse_time(str)
10
+ `new Date(Date.parse(str))`
11
+ end
12
+
13
+ def stack
14
+ @stack ||= []
15
+ end
16
+
17
+ def push(time, scale = 1, resolution = 10)
18
+ time = parse_time(time) if time.is_a? String
19
+ stack << [Time.now, @scale, @resolution]
20
+ update_lolex(time, scale, resolution)
21
+ end
22
+
23
+ def pop
24
+ update_lolex(*stack.pop) unless stack.empty?
25
+ end
26
+
27
+ def unmock(time, resolution)
28
+ push(time, 1, resolution)
29
+ @backup_stack = stack
30
+ @stack = []
31
+ end
32
+
33
+ def restore
34
+ @stack = @backup_stack
35
+ pop
36
+ end
37
+
38
+ def tick
39
+ real_clock = `(new #{@lolex}['_Date']).getTime()`
40
+ mock_clock = Time.now.to_f * 1000
41
+ real_elapsed_time = real_clock - @real_start_time
42
+ mock_elapsed_time = mock_clock - @mock_start_time
43
+
44
+ ticks = real_elapsed_time * @scale - mock_elapsed_time
45
+
46
+ `#{@lolex}.tick(#{ticks.to_i})`
47
+ nil
48
+ end
49
+
50
+ def create_ticker
51
+ return unless @scale && @scale > 0
52
+ ticker = %x{
53
+ #{@lolex}['_setInterval'].call(
54
+ window,
55
+ function() { #{tick} },
56
+ #{@resolution}
57
+ )
58
+ }
59
+ ticker
60
+ end
61
+
62
+ def update_lolex(time, scale, resolution)
63
+ `#{@lolex}.uninstall()` && return if scale.nil?
64
+ @mock_start_time = time.to_f * 1000
65
+
66
+ if @lolex
67
+ `#{@lolex}['_clearInterval'].call(window, #{@ticker})` if @ticker
68
+ @real_start_time = `(new #{@lolex}['_Date']).getTime()`
69
+ `#{@lolex}.tick(#{@mock_start_time - Time.now.to_f * 1000})`
70
+ else
71
+ @real_start_time = Time.now.to_f * 1000
72
+ @lolex = `lolex.install({ now: #{@mock_start_time} })`
73
+ end
74
+
75
+ @scale = scale
76
+ @resolution = resolution
77
+ @ticker = create_ticker
78
+ nil # must return nil otherwise we try to return a timer to server!
79
+ end
80
+ end
81
+ end
82
+
83
+ else
84
+ require 'timecop'
85
+
86
+ # Interface to the Lolex package running on the client side
87
+ # Below we will monkey patch Timecop to call these methods
88
+ class Lolex
89
+ class << self
90
+ def init(page, client_time_zone, resolution)
91
+ @capybara_page = page
92
+ @resolution = resolution || 10
93
+ @client_time_zone = client_time_zone
94
+ run_pending_evaluations
95
+ @initialized = true
96
+ end
97
+
98
+ def initialized?
99
+ @initialized
100
+ end
101
+
102
+ def push(mock_type, *args)
103
+ scale = if mock_type == :freeze
104
+ 0
105
+ elsif mock_type == :scale
106
+ args[0]
107
+ else
108
+ 1
109
+ end
110
+ evaluate_ruby do
111
+ "Lolex.push('#{time_string_in_zone}', #{scale}, #{@resolution})"
112
+ end
113
+ end
114
+
115
+ def pop
116
+ evaluate_ruby { 'Lolex.pop' }
117
+ end
118
+
119
+ def unmock
120
+ evaluate_ruby { "Lolex.unmock('#{time_string_in_zone}', #{@resolution})" }
121
+ end
122
+
123
+ def restore
124
+ evaluate_ruby { 'Lolex.restore' }
125
+ end
126
+
127
+ private
128
+
129
+ def time_string_in_zone
130
+ Time.now.in_time_zone(@client_time_zone).strftime('%Y/%m/%d %H:%M:%S %z')
131
+ end
132
+
133
+ def pending_evaluations
134
+ @pending_evaluations ||= []
135
+ end
136
+
137
+ def evaluate_ruby(&block)
138
+ if @capybara_page
139
+ @capybara_page.evaluate_ruby(yield)
140
+ else
141
+ pending_evaluations << block
142
+ end
143
+ end
144
+
145
+ def run_pending_evaluations
146
+ return if pending_evaluations.empty?
147
+ @capybara_page.evaluate_ruby(pending_evaluations.collect(&:call).join("\n"))
148
+ @pending_evaluations ||= []
149
+ end
150
+ end
151
+ end
152
+
153
+ # Monkey patches to call our Lolex interface
4
154
  class Timecop
5
155
  private
6
156
 
@@ -1,3 +1,3 @@
1
1
  module HyperSpec
2
- VERSION = '0.1.2'
2
+ VERSION = '0.99.0'
3
3
  end
@@ -10,21 +10,36 @@ module HyperSpec
10
10
  end
11
11
 
12
12
  def running?
13
- result = page.evaluate_script('(function(active) { return active; })(jQuery.active)')
14
- result && !result.zero?
13
+ jscode = <<-CODE
14
+ (function() {
15
+ if (typeof Opal !== "undefined" && Opal.Hyperloop !== undefined) {
16
+ try {
17
+ return Opal.Hyperloop.$const_get("HTTP")["$active?"]();
18
+ } catch(err) {
19
+ if (typeof jQuery !== "undefined" && jQuery.active !== undefined) {
20
+ return (jQuery.active > 0);
21
+ } else {
22
+ return false;
23
+ }
24
+ }
25
+ } else if (typeof jQuery !== "undefined" && jQuery.active !== undefined) {
26
+ return (jQuery.active > 0);
27
+ } else {
28
+ return false;
29
+ }
30
+ })();
31
+ CODE
32
+ page.evaluate_script(jscode)
15
33
  rescue Exception => e
16
- puts "wait_for_ajax failed while testing state of jQuery.active: #{e}"
34
+ puts "wait_for_ajax failed while testing state of ajax requests: #{e}"
17
35
  end
18
36
 
19
37
  def finished_all_ajax_requests?
20
- unless running?
21
- sleep 0.25 # this was 1 second, not sure if its necessary to be so long...
22
- !running?
23
- end
38
+ !running?
24
39
  rescue Capybara::NotSupportedByDriverError
25
40
  true
26
41
  rescue Exception => e
27
- e.message == 'jQuery is not defined'
42
+ e.message == 'either jQuery or Hyperloop::HTTP is not defined'
28
43
  end
29
44
  end
30
45
  end
@@ -31,57 +31,47 @@ module React
31
31
  def component
32
32
  return @component if @component
33
33
  paths_searched = []
34
-
34
+ component = nil
35
35
  if params.component_name.start_with?('::')
36
- paths_searched << params.component_name.gsub(/^\:\:/, '')
37
-
38
- @component =
39
- begin
40
- params.component_name.gsub(/^\:\:/, '').split('::')
41
- .inject(Module) { |scope, next_const| scope.const_get(next_const, false) }
42
- rescue
43
- nil
44
- end
45
-
46
- return @component if @component && @component.method_defined?(:render)
36
+ # if absolute path of component is given, look it up and fail if not found
37
+ paths_searched << params.component_name
38
+ component = begin
39
+ Object.const_get(params.component_name)
40
+ rescue NameError
41
+ nil
42
+ end
47
43
  else
48
- self.class.search_path.each do |path|
49
- # try each path + params.controller + params.component_name
50
- paths_searched << "#{path.name + '::' unless path == Module}"\
51
- "#{params.controller}::#{params.component_name}"
52
-
53
- @component =
54
- begin
55
- [params.controller, params.component_name]
56
- .join('::').split('::')
57
- .inject(path) { |scope, next_const| scope.const_get(next_const, false) }
58
- rescue
59
- nil
60
- end
61
-
62
- return @component if @component && @component.method_defined?(:render)
44
+ # if relative path is given, look it up like this
45
+ # 1) we check each path + controller-name + component-name
46
+ # 2) if we can't find it there we check each path + component-name
47
+ # if we can't find it we just try const_get
48
+ # so (assuming controller name is Home)
49
+ # ::Foo::Bar will only resolve to some component named ::Foo::Bar
50
+ # but Foo::Bar will check (in this order) ::Home::Foo::Bar, ::Components::Home::Foo::Bar, ::Foo::Bar, ::Components::Foo::Bar
51
+ self.class.search_path.each do |scope|
52
+ paths_searched << "#{scope.name}::#{params.controller}::#{params.component_name}"
53
+ component = begin
54
+ scope.const_get(params.controller, false).const_get(params.component_name, false)
55
+ rescue NameError
56
+ nil
57
+ end
58
+ break if component != nil
63
59
  end
64
-
65
- self.class.search_path.each do |path|
66
- # then try each path + params.component_name
67
- paths_searched << "#{path.name + '::' unless path == Module}#{params.component_name}"
68
- @component =
69
- begin
70
- params.component_name.to_s.split('::')
71
- .inject(path) { |scope, next_const| scope.const_get(next_const, false) }
72
- rescue
73
- nil
74
- end
75
-
76
- return @component if @component && @component.method_defined?(:render)
60
+ unless component
61
+ self.class.search_path.each do |scope|
62
+ paths_searched << "#{scope.name}::#{params.component_name}"
63
+ component = begin
64
+ scope.const_get(params.component_name, false)
65
+ rescue NameError
66
+ nil
67
+ end
68
+ break if component != nil
69
+ end
77
70
  end
78
71
  end
79
-
80
- @component = nil
81
-
82
- raise "Could not find component class '#{params.component_name}' "\
83
- "for params.controller '#{params.controller}' in any component directory. "\
84
- "Tried [#{paths_searched.join(', ')}]"
72
+ @component = component
73
+ return @component if @component && @component.method_defined?(:render)
74
+ raise "Could not find component class '#{params.component_name}' for params.controller '#{params.controller}' in any component directory. Tried [#{paths_searched.join(", ")}]"
85
75
  end
86
76
 
87
77
  before_mount do
@@ -98,7 +88,7 @@ module React
98
88
  end
99
89
 
100
90
  def render
101
- present component, @render_params
91
+ React::RenderingContext.render(component, @render_params)
102
92
  end
103
93
  end
104
94
  end
@@ -6,7 +6,7 @@ module Selenium
6
6
  attr_accessor :firebug_version
7
7
 
8
8
  def firebug_version
9
- @firebug_version ||= '2.0.13-fx'
9
+ @firebug_version ||= '2.0.19-fx'
10
10
  end
11
11
  end
12
12
 
@@ -15,7 +15,7 @@ module Selenium
15
15
  end
16
16
 
17
17
  def frame_position=(position)
18
- @frame_position = %w(left right top detached).detect do |side|
18
+ @frame_position = %w[left right top detached].detect do |side|
19
19
  position && position[0].downcase == side[0]
20
20
  end || 'detached'
21
21
  end
@@ -36,7 +36,7 @@ module Selenium
36
36
  self['extensions.firebug.allPagesActivation'] = 'on'
37
37
 
38
38
  # Enable all features.
39
- %w(console net script).each do |feature|
39
+ %w[console net script].each do |feature|
40
40
  self["extensions.firebug.#{feature}.enableSites"] = true
41
41
  end
42
42
 
@@ -0,0 +1,733 @@
1
+ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.lolex = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
2
+ (function (global){
3
+ "use strict";
4
+
5
+ var userAgent = global.navigator && global.navigator.userAgent;
6
+ var isRunningInIE = userAgent && userAgent.indexOf("MSIE ") > -1;
7
+ var maxTimeout = Math.pow(2, 31) - 1; //see https://heycam.github.io/webidl/#abstract-opdef-converttoint
8
+
9
+ // Make properties writable in IE, as per
10
+ // http://www.adequatelygood.com/Replacing-setTimeout-Globally.html
11
+ if (isRunningInIE) {
12
+ global.setTimeout = global.setTimeout;
13
+ global.clearTimeout = global.clearTimeout;
14
+ global.setInterval = global.setInterval;
15
+ global.clearInterval = global.clearInterval;
16
+ global.Date = global.Date;
17
+ }
18
+
19
+ // setImmediate is not a standard function
20
+ // avoid adding the prop to the window object if not present
21
+ if (global.setImmediate !== undefined) {
22
+ global.setImmediate = global.setImmediate;
23
+ global.clearImmediate = global.clearImmediate;
24
+ }
25
+
26
+ // node expects setTimeout/setInterval to return a fn object w/ .ref()/.unref()
27
+ // browsers, a number.
28
+ // see https://github.com/cjohansen/Sinon.JS/pull/436
29
+
30
+ var NOOP = function () { return undefined; };
31
+ var timeoutResult = setTimeout(NOOP, 0);
32
+ var addTimerReturnsObject = typeof timeoutResult === "object";
33
+ var hrtimePresent = (global.process && typeof global.process.hrtime === "function");
34
+ var nextTickPresent = (global.process && typeof global.process.nextTick === "function");
35
+ var performancePresent = (global.performance && typeof global.performance.now === "function");
36
+
37
+ clearTimeout(timeoutResult);
38
+
39
+ var NativeDate = Date;
40
+ var uniqueTimerId = 1;
41
+
42
+ /**
43
+ * Parse strings like "01:10:00" (meaning 1 hour, 10 minutes, 0 seconds) into
44
+ * number of milliseconds. This is used to support human-readable strings passed
45
+ * to clock.tick()
46
+ */
47
+ function parseTime(str) {
48
+ if (!str) {
49
+ return 0;
50
+ }
51
+
52
+ var strings = str.split(":");
53
+ var l = strings.length;
54
+ var i = l;
55
+ var ms = 0;
56
+ var parsed;
57
+
58
+ if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
59
+ throw new Error("tick only understands numbers, 'm:s' and 'h:m:s'. Each part must be two digits");
60
+ }
61
+
62
+ while (i--) {
63
+ parsed = parseInt(strings[i], 10);
64
+
65
+ if (parsed >= 60) {
66
+ throw new Error("Invalid time " + str);
67
+ }
68
+
69
+ ms += parsed * Math.pow(60, (l - i - 1));
70
+ }
71
+
72
+ return ms * 1000;
73
+ }
74
+
75
+ /**
76
+ * Floor function that also works for negative numbers
77
+ */
78
+ function fixedFloor(n) {
79
+ return (n >= 0 ? Math.floor(n) : Math.ceil(n));
80
+ }
81
+
82
+ /**
83
+ * % operator that also works for negative numbers
84
+ */
85
+ function fixedModulo(n, m) {
86
+ return ((n % m) + m) % m;
87
+ }
88
+
89
+ /**
90
+ * Used to grok the `now` parameter to createClock.
91
+ * @param epoch {Date|number} the system time
92
+ */
93
+ function getEpoch(epoch) {
94
+ if (!epoch) { return 0; }
95
+ if (typeof epoch.getTime === "function") { return epoch.getTime(); }
96
+ if (typeof epoch === "number") { return epoch; }
97
+ throw new TypeError("now should be milliseconds since UNIX epoch");
98
+ }
99
+
100
+ function inRange(from, to, timer) {
101
+ return timer && timer.callAt >= from && timer.callAt <= to;
102
+ }
103
+
104
+ function mirrorDateProperties(target, source) {
105
+ var prop;
106
+ for (prop in source) {
107
+ if (source.hasOwnProperty(prop)) {
108
+ target[prop] = source[prop];
109
+ }
110
+ }
111
+
112
+ // set special now implementation
113
+ if (source.now) {
114
+ target.now = function now() {
115
+ return target.clock.now;
116
+ };
117
+ } else {
118
+ delete target.now;
119
+ }
120
+
121
+ // set special toSource implementation
122
+ if (source.toSource) {
123
+ target.toSource = function toSource() {
124
+ return source.toSource();
125
+ };
126
+ } else {
127
+ delete target.toSource;
128
+ }
129
+
130
+ // set special toString implementation
131
+ target.toString = function toString() {
132
+ return source.toString();
133
+ };
134
+
135
+ target.prototype = source.prototype;
136
+ target.parse = source.parse;
137
+ target.UTC = source.UTC;
138
+ target.prototype.toUTCString = source.prototype.toUTCString;
139
+
140
+ return target;
141
+ }
142
+
143
+ function createDate() {
144
+ function ClockDate(year, month, date, hour, minute, second, ms) {
145
+ // Defensive and verbose to avoid potential harm in passing
146
+ // explicit undefined when user does not pass argument
147
+ switch (arguments.length) {
148
+ case 0:
149
+ return new NativeDate(ClockDate.clock.now);
150
+ case 1:
151
+ return new NativeDate(year);
152
+ case 2:
153
+ return new NativeDate(year, month);
154
+ case 3:
155
+ return new NativeDate(year, month, date);
156
+ case 4:
157
+ return new NativeDate(year, month, date, hour);
158
+ case 5:
159
+ return new NativeDate(year, month, date, hour, minute);
160
+ case 6:
161
+ return new NativeDate(year, month, date, hour, minute, second);
162
+ default:
163
+ return new NativeDate(year, month, date, hour, minute, second, ms);
164
+ }
165
+ }
166
+
167
+ return mirrorDateProperties(ClockDate, NativeDate);
168
+ }
169
+
170
+
171
+ function enqueueJob(clock, job) {
172
+ // enqueues a microtick-deferred task - ecma262/#sec-enqueuejob
173
+ if (!clock.jobs) {
174
+ clock.jobs = [];
175
+ }
176
+ clock.jobs.push(job);
177
+ }
178
+
179
+ function runJobs(clock) {
180
+ // runs all microtick-deferred tasks - ecma262/#sec-runjobs
181
+ if (!clock.jobs) {
182
+ return;
183
+ }
184
+ for (var i = 0; i < clock.jobs.length; i++) {
185
+ var job = clock.jobs[i];
186
+ job.func.apply(null, job.args);
187
+ }
188
+ clock.jobs = [];
189
+ }
190
+
191
+ function addTimer(clock, timer) {
192
+ if (timer.func === undefined) {
193
+ throw new Error("Callback must be provided to timer calls");
194
+ }
195
+
196
+ if (timer.hasOwnProperty("delay")) {
197
+ timer.delay = timer.delay > maxTimeout ? 1 : timer.delay;
198
+ }
199
+
200
+ if (timer.hasOwnProperty("interval")) {
201
+ timer.interval = timer.interval > maxTimeout ? 1 : timer.interval;
202
+ }
203
+
204
+ if (!clock.timers) {
205
+ clock.timers = {};
206
+ }
207
+
208
+ timer.id = uniqueTimerId++;
209
+ timer.createdAt = clock.now;
210
+ timer.callAt = clock.now + (parseInt(timer.delay) || (clock.duringTick ? 1 : 0));
211
+
212
+ clock.timers[timer.id] = timer;
213
+
214
+ if (addTimerReturnsObject) {
215
+ return {
216
+ id: timer.id,
217
+ ref: NOOP,
218
+ unref: NOOP
219
+ };
220
+ }
221
+
222
+ return timer.id;
223
+ }
224
+
225
+
226
+ /* eslint consistent-return: "off" */
227
+ function compareTimers(a, b) {
228
+ // Sort first by absolute timing
229
+ if (a.callAt < b.callAt) {
230
+ return -1;
231
+ }
232
+ if (a.callAt > b.callAt) {
233
+ return 1;
234
+ }
235
+
236
+ // Sort next by immediate, immediate timers take precedence
237
+ if (a.immediate && !b.immediate) {
238
+ return -1;
239
+ }
240
+ if (!a.immediate && b.immediate) {
241
+ return 1;
242
+ }
243
+
244
+ // Sort next by creation time, earlier-created timers take precedence
245
+ if (a.createdAt < b.createdAt) {
246
+ return -1;
247
+ }
248
+ if (a.createdAt > b.createdAt) {
249
+ return 1;
250
+ }
251
+
252
+ // Sort next by id, lower-id timers take precedence
253
+ if (a.id < b.id) {
254
+ return -1;
255
+ }
256
+ if (a.id > b.id) {
257
+ return 1;
258
+ }
259
+
260
+ // As timer ids are unique, no fallback `0` is necessary
261
+ }
262
+
263
+ function firstTimerInRange(clock, from, to) {
264
+ var timers = clock.timers;
265
+ var timer = null;
266
+ var id, isInRange;
267
+
268
+ for (id in timers) {
269
+ if (timers.hasOwnProperty(id)) {
270
+ isInRange = inRange(from, to, timers[id]);
271
+
272
+ if (isInRange && (!timer || compareTimers(timer, timers[id]) === 1)) {
273
+ timer = timers[id];
274
+ }
275
+ }
276
+ }
277
+
278
+ return timer;
279
+ }
280
+
281
+ function firstTimer(clock) {
282
+ var timers = clock.timers;
283
+ var timer = null;
284
+ var id;
285
+
286
+ for (id in timers) {
287
+ if (timers.hasOwnProperty(id)) {
288
+ if (!timer || compareTimers(timer, timers[id]) === 1) {
289
+ timer = timers[id];
290
+ }
291
+ }
292
+ }
293
+
294
+ return timer;
295
+ }
296
+
297
+ function lastTimer(clock) {
298
+ var timers = clock.timers;
299
+ var timer = null;
300
+ var id;
301
+
302
+ for (id in timers) {
303
+ if (timers.hasOwnProperty(id)) {
304
+ if (!timer || compareTimers(timer, timers[id]) === -1) {
305
+ timer = timers[id];
306
+ }
307
+ }
308
+ }
309
+
310
+ return timer;
311
+ }
312
+
313
+ function callTimer(clock, timer) {
314
+ if (typeof timer.interval === "number") {
315
+ clock.timers[timer.id].callAt += timer.interval;
316
+ } else {
317
+ delete clock.timers[timer.id];
318
+ }
319
+
320
+ if (typeof timer.func === "function") {
321
+ timer.func.apply(null, timer.args);
322
+ } else {
323
+ /* eslint no-eval: "off" */
324
+ eval(timer.func);
325
+ }
326
+ }
327
+
328
+ function timerType(timer) {
329
+ if (timer.immediate) {
330
+ return "Immediate";
331
+ }
332
+ if (timer.interval !== undefined) {
333
+ return "Interval";
334
+ }
335
+ return "Timeout";
336
+ }
337
+
338
+ function clearTimer(clock, timerId, ttype) {
339
+ if (!timerId) {
340
+ // null appears to be allowed in most browsers, and appears to be
341
+ // relied upon by some libraries, like Bootstrap carousel
342
+ return;
343
+ }
344
+
345
+ if (!clock.timers) {
346
+ clock.timers = [];
347
+ }
348
+
349
+ // in Node, timerId is an object with .ref()/.unref(), and
350
+ // its .id field is the actual timer id.
351
+ if (typeof timerId === "object") {
352
+ timerId = timerId.id;
353
+ }
354
+
355
+ if (clock.timers.hasOwnProperty(timerId)) {
356
+ // check that the ID matches a timer of the correct type
357
+ var timer = clock.timers[timerId];
358
+ if (timerType(timer) === ttype) {
359
+ delete clock.timers[timerId];
360
+ } else {
361
+ throw new Error("Cannot clear timer: timer created with set" + timerType(timer)
362
+ + "() but cleared with clear" + ttype + "()");
363
+ }
364
+ }
365
+ }
366
+
367
+ function uninstall(clock, target, config) {
368
+ var method,
369
+ i,
370
+ l;
371
+ var installedHrTime = "_hrtime";
372
+ var installedNextTick = "_nextTick";
373
+
374
+ for (i = 0, l = clock.methods.length; i < l; i++) {
375
+ method = clock.methods[i];
376
+ if (method === "hrtime" && target.process) {
377
+ target.process.hrtime = clock[installedHrTime];
378
+ } else if (method === "nextTick" && target.process) {
379
+ target.process.nextTick = clock[installedNextTick];
380
+ } else {
381
+ if (target[method] && target[method].hadOwnProperty) {
382
+ target[method] = clock["_" + method];
383
+ if (method === "clearInterval" && config.shouldAdvanceTime === true) {
384
+ target[method](clock.attachedInterval);
385
+ }
386
+ } else {
387
+ try {
388
+ delete target[method];
389
+ } catch (ignore) { /* eslint empty-block: "off" */ }
390
+ }
391
+ }
392
+ }
393
+
394
+ // Prevent multiple executions which will completely remove these props
395
+ clock.methods = [];
396
+ }
397
+
398
+ function hijackMethod(target, method, clock) {
399
+ var prop;
400
+ clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(target, method);
401
+ clock["_" + method] = target[method];
402
+
403
+ if (method === "Date") {
404
+ var date = mirrorDateProperties(clock[method], target[method]);
405
+ target[method] = date;
406
+ } else {
407
+ target[method] = function () {
408
+ return clock[method].apply(clock, arguments);
409
+ };
410
+
411
+ for (prop in clock[method]) {
412
+ if (clock[method].hasOwnProperty(prop)) {
413
+ target[method][prop] = clock[method][prop];
414
+ }
415
+ }
416
+ }
417
+
418
+ target[method].clock = clock;
419
+ }
420
+
421
+ function doIntervalTick(clock, advanceTimeDelta) {
422
+ clock.tick(advanceTimeDelta);
423
+ }
424
+
425
+ var timers = {
426
+ setTimeout: setTimeout,
427
+ clearTimeout: clearTimeout,
428
+ setImmediate: global.setImmediate,
429
+ clearImmediate: global.clearImmediate,
430
+ setInterval: setInterval,
431
+ clearInterval: clearInterval,
432
+ Date: Date
433
+ };
434
+
435
+ if (hrtimePresent) {
436
+ timers.hrtime = global.process.hrtime;
437
+ }
438
+
439
+ if (nextTickPresent) {
440
+ timers.nextTick = global.process.nextTick;
441
+ }
442
+
443
+ if (performancePresent) {
444
+ timers.performance = global.performance;
445
+ }
446
+
447
+ var keys = Object.keys || function (obj) {
448
+ var ks = [];
449
+ var key;
450
+
451
+ for (key in obj) {
452
+ if (obj.hasOwnProperty(key)) {
453
+ ks.push(key);
454
+ }
455
+ }
456
+
457
+ return ks;
458
+ };
459
+
460
+ exports.timers = timers;
461
+
462
+ /**
463
+ * @param now {Date|number} the system time
464
+ * @param loopLimit {number} maximum number of timers that will be run when calling runAll()
465
+ */
466
+ function createClock(now, loopLimit) {
467
+ loopLimit = loopLimit || 1000;
468
+
469
+ var clock = {
470
+ now: getEpoch(now),
471
+ hrNow: 0,
472
+ timeouts: {},
473
+ Date: createDate(),
474
+ loopLimit: loopLimit
475
+ };
476
+
477
+ clock.Date.clock = clock;
478
+
479
+ clock.setTimeout = function setTimeout(func, timeout) {
480
+ return addTimer(clock, {
481
+ func: func,
482
+ args: Array.prototype.slice.call(arguments, 2),
483
+ delay: timeout
484
+ });
485
+ };
486
+
487
+ clock.clearTimeout = function clearTimeout(timerId) {
488
+ return clearTimer(clock, timerId, "Timeout");
489
+ };
490
+ clock.nextTick = function nextTick(func) {
491
+ return enqueueJob(clock, {
492
+ func: func,
493
+ args: Array.prototype.slice.call(arguments, 1)
494
+ });
495
+ };
496
+ clock.setInterval = function setInterval(func, timeout) {
497
+ return addTimer(clock, {
498
+ func: func,
499
+ args: Array.prototype.slice.call(arguments, 2),
500
+ delay: timeout,
501
+ interval: timeout
502
+ });
503
+ };
504
+
505
+ clock.clearInterval = function clearInterval(timerId) {
506
+ return clearTimer(clock, timerId, "Interval");
507
+ };
508
+
509
+ clock.setImmediate = function setImmediate(func) {
510
+ return addTimer(clock, {
511
+ func: func,
512
+ args: Array.prototype.slice.call(arguments, 1),
513
+ immediate: true
514
+ });
515
+ };
516
+
517
+ clock.clearImmediate = function clearImmediate(timerId) {
518
+ return clearTimer(clock, timerId, "Immediate");
519
+ };
520
+
521
+ function updateHrTime(newNow) {
522
+ clock.hrNow += (newNow - clock.now);
523
+ }
524
+
525
+ clock.tick = function tick(ms) {
526
+ ms = typeof ms === "number" ? ms : parseTime(ms);
527
+ var tickFrom = clock.now;
528
+ var tickTo = clock.now + ms;
529
+ var previous = clock.now;
530
+ var timer = firstTimerInRange(clock, tickFrom, tickTo);
531
+ var oldNow, firstException;
532
+
533
+ clock.duringTick = true;
534
+ runJobs(clock);
535
+
536
+ while (timer && tickFrom <= tickTo) {
537
+ if (clock.timers[timer.id]) {
538
+ updateHrTime(timer.callAt);
539
+ tickFrom = timer.callAt;
540
+ clock.now = timer.callAt;
541
+ try {
542
+ runJobs(clock);
543
+ oldNow = clock.now;
544
+ callTimer(clock, timer);
545
+ } catch (e) {
546
+ firstException = firstException || e;
547
+ }
548
+
549
+ // compensate for any setSystemTime() call during timer callback
550
+ if (oldNow !== clock.now) {
551
+ tickFrom += clock.now - oldNow;
552
+ tickTo += clock.now - oldNow;
553
+ previous += clock.now - oldNow;
554
+ }
555
+ }
556
+
557
+ timer = firstTimerInRange(clock, previous, tickTo);
558
+ previous = tickFrom;
559
+ }
560
+
561
+ runJobs(clock);
562
+ clock.duringTick = false;
563
+ updateHrTime(tickTo);
564
+ clock.now = tickTo;
565
+
566
+ if (firstException) {
567
+ throw firstException;
568
+ }
569
+
570
+ return clock.now;
571
+ };
572
+
573
+ clock.next = function next() {
574
+ runJobs(clock);
575
+ var timer = firstTimer(clock);
576
+ if (!timer) {
577
+ return clock.now;
578
+ }
579
+
580
+ clock.duringTick = true;
581
+ try {
582
+ updateHrTime(timer.callAt);
583
+ clock.now = timer.callAt;
584
+ callTimer(clock, timer);
585
+ runJobs(clock);
586
+ return clock.now;
587
+ } finally {
588
+ clock.duringTick = false;
589
+ }
590
+ };
591
+
592
+ clock.runAll = function runAll() {
593
+ var numTimers, i;
594
+ runJobs(clock);
595
+ for (i = 0; i < clock.loopLimit; i++) {
596
+ if (!clock.timers) {
597
+ return clock.now;
598
+ }
599
+
600
+ numTimers = keys(clock.timers).length;
601
+ if (numTimers === 0) {
602
+ return clock.now;
603
+ }
604
+
605
+ clock.next();
606
+ }
607
+
608
+ throw new Error("Aborting after running " + clock.loopLimit + " timers, assuming an infinite loop!");
609
+ };
610
+
611
+ clock.runToLast = function runToLast() {
612
+ var timer = lastTimer(clock);
613
+ if (!timer) {
614
+ runJobs(clock);
615
+ return clock.now;
616
+ }
617
+
618
+ return clock.tick(timer.callAt);
619
+ };
620
+
621
+ clock.reset = function reset() {
622
+ clock.timers = {};
623
+ };
624
+
625
+ clock.setSystemTime = function setSystemTime(systemTime) {
626
+ // determine time difference
627
+ var newNow = getEpoch(systemTime);
628
+ var difference = newNow - clock.now;
629
+ var id, timer;
630
+
631
+ // update 'system clock'
632
+ clock.now = newNow;
633
+
634
+ // update timers and intervals to keep them stable
635
+ for (id in clock.timers) {
636
+ if (clock.timers.hasOwnProperty(id)) {
637
+ timer = clock.timers[id];
638
+ timer.createdAt += difference;
639
+ timer.callAt += difference;
640
+ }
641
+ }
642
+ };
643
+
644
+ if (performancePresent) {
645
+ clock.performance = Object.create(global.performance);
646
+ clock.performance.now = function lolexNow() {
647
+ return clock.hrNow;
648
+ };
649
+ }
650
+ if (hrtimePresent) {
651
+ clock.hrtime = function (prev) {
652
+ if (Array.isArray(prev)) {
653
+ var oldSecs = (prev[0] + prev[1] / 1e9);
654
+ var newSecs = (clock.hrNow / 1000);
655
+ var difference = (newSecs - oldSecs);
656
+ var secs = fixedFloor(difference);
657
+ var nanosecs = fixedModulo(difference * 1e9, 1e9);
658
+ return [
659
+ secs,
660
+ nanosecs
661
+ ];
662
+ }
663
+ return [
664
+ fixedFloor(clock.hrNow / 1000),
665
+ fixedModulo(clock.hrNow * 1e6, 1e9)
666
+ ];
667
+ };
668
+ }
669
+
670
+ return clock;
671
+ }
672
+ exports.createClock = createClock;
673
+
674
+ /**
675
+ * @param config {Object} optional config
676
+ * @param config.target {Object} the target to install timers in (default `window`)
677
+ * @param config.now {number|Date} a number (in milliseconds) or a Date object (default epoch)
678
+ * @param config.toFake {string[]} names of the methods that should be faked.
679
+ * @param config.loopLimit {number} the maximum number of timers that will be run when calling runAll()
680
+ * @param config.shouldAdvanceTime {Boolean} tells lolex to increment mocked time automatically (default false)
681
+ * @param config.advanceTimeDelta {Number} increment mocked time every <<advanceTimeDelta>> ms (default: 20ms)
682
+ */
683
+ exports.install = function install(config) {
684
+ if ( arguments.length > 1 || config instanceof Date || Array.isArray(config) || typeof config === "number") {
685
+ throw new TypeError("lolex.install called with " + String(config) +
686
+ " lolex 2.0+ requires an object parameter - see https://github.com/sinonjs/lolex");
687
+ }
688
+ config = typeof config !== "undefined" ? config : {};
689
+ config.shouldAdvanceTime = config.shouldAdvanceTime || false;
690
+ config.advanceTimeDelta = config.advanceTimeDelta || 20;
691
+
692
+ var i, l;
693
+ var target = config.target || global;
694
+ var clock = createClock(config.now, config.loopLimit);
695
+
696
+ clock.uninstall = function () {
697
+ uninstall(clock, target, config);
698
+ };
699
+
700
+ clock.methods = config.toFake || ["setTimeout", "clearTimeout", "setImmediate", "clearImmediate","setInterval", "clearInterval", "Date"];
701
+
702
+ if (clock.methods.length === 0) {
703
+ // do not fake nextTick by default - GitHub#126
704
+ clock.methods = keys(timers).filter(function (key) {return key !== "nextTick";});
705
+ }
706
+
707
+ for (i = 0, l = clock.methods.length; i < l; i++) {
708
+ if (clock.methods[i] === "hrtime") {
709
+ if (target.process && typeof target.process.hrtime === "function") {
710
+ hijackMethod(target.process, clock.methods[i], clock);
711
+ }
712
+ } else if (clock.methods[i] === "nextTick") {
713
+ if (target.process && typeof target.process.nextTick === "function") {
714
+ hijackMethod(target.process, clock.methods[i], clock);
715
+ }
716
+ } else {
717
+ if (clock.methods[i] === "setInterval" && config.shouldAdvanceTime === true) {
718
+ var intervalTick = doIntervalTick.bind(null, clock, config.advanceTimeDelta);
719
+ var intervalId = target[clock.methods[i]](
720
+ intervalTick,
721
+ config.advanceTimeDelta);
722
+ clock.attachedInterval = intervalId;
723
+ }
724
+ hijackMethod(target, clock.methods[i], clock);
725
+ }
726
+ }
727
+
728
+ return clock;
729
+ };
730
+
731
+ }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
732
+ },{}]},{},[1])(1)
733
+ });