@cycle/time
Advanced tools
Comparing version 0.1.1 to 0.2.0
@@ -5,11 +5,18 @@ "use strict"; | ||
var equal = deepEqual(completeStore['actual'], completeStore['expected']); | ||
var pass = true; | ||
var failReasons = []; | ||
if (completeStore['actual'].length !== completeStore['expected'].length) { | ||
failReasons.push("Length of actual and expected differs"); | ||
} | ||
completeStore['actual'].forEach(function (actual, index) { | ||
var expected = completeStore['expected'][index]; | ||
if (!actual || !expected) { | ||
pass = false; | ||
if (actual === undefined) { | ||
failReasons.push("Actual at index " + index + " was undefined"); | ||
return; | ||
} | ||
if (expected === undefined) { | ||
failReasons.push("Expected at index " + index + " was undefined"); | ||
return; | ||
} | ||
if (actual.type !== expected.type) { | ||
pass = false; | ||
failReasons.push("Expected type " + expected.type + " at time " + actual.time + " but got " + actual.type); | ||
} | ||
@@ -19,4 +26,7 @@ if (actual.type === 'next') { | ||
var rightValue = deepEqual(actual.value, expected.value); | ||
if (rightValue && !rightTime) { | ||
failReasons.push("Right value at wrong time, expected at " + expected.time + " but happened at " + actual.time + " (" + JSON.stringify(actual.value) + ")"); | ||
} | ||
if (!rightTime || !rightValue) { | ||
pass = false; | ||
failReasons.push("Expected value " + JSON.stringify(expected.value) + " at time " + expected.time + " but got " + JSON.stringify(actual.value) + " at " + actual.time); | ||
} | ||
@@ -26,2 +36,3 @@ } | ||
var rightTime = diagramFrame(actual.time, interval) === diagramFrame(expected.time, interval); | ||
var pass = true; | ||
if (expected.type !== 'error') { | ||
@@ -34,2 +45,3 @@ pass = false; | ||
if (!pass) { | ||
failReasons.push("Unexpected error occurred"); | ||
assert.unexpectedErrors.push(actual.error); | ||
@@ -39,3 +51,3 @@ } | ||
}); | ||
if (pass) { | ||
if (failReasons.length === 0) { | ||
assert.state = 'passed'; | ||
@@ -45,3 +57,3 @@ } | ||
assert.state = 'failed'; | ||
assert.error = new Error(strip("\n Expected\n\n " + diagramString(completeStore['expected'], interval) + "\n\n Got\n\n " + diagramString(completeStore['actual'], interval) + "\n\n " + displayUnexpectedErrors(assert.unexpectedErrors) + "\n ")); | ||
assert.error = new Error(strip("\n Expected\n\n " + diagramString(completeStore['expected'], interval) + "\n\n Got\n\n " + diagramString(completeStore['actual'], interval) + "\n\n Failed because\n\n " + failReasons[0] + "\n\n " + displayUnexpectedErrors(assert.unexpectedErrors) + "\n ")); | ||
} | ||
@@ -102,2 +114,5 @@ } | ||
function diagramString(entries, interval) { | ||
if (entries.length === 0) { | ||
return '<empty stream>'; | ||
} | ||
var maxTime = Math.max.apply(Math, entries.map(function (entry) { return entry.time; })); | ||
@@ -104,0 +119,0 @@ var characterCount = Math.ceil(maxTime / interval); |
@@ -11,4 +11,10 @@ import xs from 'xstream'; | ||
throttle: (period: number) => <T>(stream: xs<T>) => xs<T>; | ||
animationFrames: () => xs<{ | ||
time: number; | ||
delta: number; | ||
normalizedDelta: number; | ||
}>; | ||
throttleAnimation: <T>(stream: xs<T>) => xs<T>; | ||
run(doneCallback?: (err: any) => void): void; | ||
}; | ||
export { mockTimeSource }; |
@@ -11,2 +11,3 @@ "use strict"; | ||
var assert_equal_1 = require("./assert-equal"); | ||
var throttle_animation_1 = require("./throttle-animation"); | ||
function raiseError(err) { | ||
@@ -66,3 +67,3 @@ if (err) { | ||
} | ||
return { | ||
var timeSource = { | ||
diagram: diagram_1.makeDiagram(scheduler.add, currentTime, interval), | ||
@@ -74,2 +75,4 @@ assertEqual: assert_equal_1.makeAssertEqual(scheduler.add, currentTime, interval, addAssert), | ||
throttle: throttle_1.makeThrottle(scheduler.add, currentTime), | ||
animationFrames: function () { return timeSource.periodic(16).map(frame); }, | ||
throttleAnimation: throttle_animation_1.makeThrottleAnimation(function () { return timeSource; }, scheduler.add, currentTime), | ||
run: function (doneCallback) { | ||
@@ -81,3 +84,11 @@ if (doneCallback === void 0) { doneCallback = raiseError; } | ||
}; | ||
return timeSource; | ||
} | ||
exports.mockTimeSource = mockTimeSource; | ||
function frame(i) { | ||
return { | ||
time: i * 16, | ||
delta: 16, | ||
normalizedDelta: 1 | ||
}; | ||
} |
import xs from 'xstream'; | ||
declare function timeDriver(_: any, streamAdapter: any): { | ||
animationFrames: () => xs<{ | ||
delta: number; | ||
normalizedDelta: number; | ||
time: number; | ||
}>; | ||
delay: (delayTime: number) => <T>(stream: xs<T>) => xs<T>; | ||
@@ -7,3 +12,4 @@ debounce: (debounceInterval: number) => <T>(stream: xs<T>) => xs<T>; | ||
throttle: (period: number) => <T>(stream: xs<T>) => xs<T>; | ||
throttleAnimation: <T>(stream: xs<T>) => xs<T>; | ||
}; | ||
export { timeDriver }; |
@@ -8,4 +8,14 @@ "use strict"; | ||
var throttle_1 = require("./throttle"); | ||
var animation_frames_1 = require("./animation-frames"); | ||
var throttle_animation_1 = require("./throttle-animation"); | ||
function popAll(array) { | ||
var poppedItems = []; | ||
while (array.length > 0) { | ||
poppedItems.push(array.pop()); | ||
} | ||
return poppedItems; | ||
} | ||
function timeDriver(_, streamAdapter) { | ||
var time = 0; | ||
var frameCallbacks = []; | ||
var scheduler = scheduler_1.makeScheduler(); | ||
@@ -15,4 +25,9 @@ function currentTime() { | ||
} | ||
function addFrameCallback(callback) { | ||
frameCallbacks.push(callback); | ||
} | ||
function processEvent(eventTime) { | ||
time = eventTime; | ||
var currentCallbacks = popAll(frameCallbacks); | ||
currentCallbacks.forEach(function (callback) { return callback(time); }); | ||
if (scheduler.isEmpty()) { | ||
@@ -42,3 +57,4 @@ requestAnimationFrame(processEvent); | ||
requestAnimationFrame(processEvent); | ||
return { | ||
var timeSource = { | ||
animationFrames: animation_frames_1.makeAnimationFrames(addFrameCallback, currentTime), | ||
delay: delay_1.makeDelay(scheduler.add, currentTime), | ||
@@ -48,4 +64,6 @@ debounce: debounce_1.makeDebounce(scheduler.add, currentTime), | ||
throttle: throttle_1.makeThrottle(scheduler.add, currentTime), | ||
throttleAnimation: throttle_animation_1.makeThrottleAnimation(function () { return timeSource; }, scheduler.add, currentTime) | ||
}; | ||
return timeSource; | ||
} | ||
exports.timeDriver = timeDriver; |
{ | ||
"name": "@cycle/time", | ||
"version": "0.1.1", | ||
"version": "0.2.0", | ||
"description": "A time driver designed to enable awesome testing and dev tooling", | ||
@@ -17,3 +17,3 @@ "main": "dist/index.js", | ||
"scripts": { | ||
"start": "budo example/index.ts:index.js --live -- -p tsify", | ||
"start": "budo -d example example/index.ts:index.js --live -- -p tsify", | ||
"test": "mocha 'test/**/*.ts' --compilers ts:ts-node/register && npm run test/docs", | ||
@@ -20,0 +20,0 @@ "test/auto": "mocha 'test/**/*.ts' --compilers ts:ts-node/register --watch -R min", |
@@ -23,2 +23,3 @@ # @cycle/time | ||
* No more intermittent failures and timing errors. Runs in virtual time so ordering is guaranteed. | ||
* No more tests timing out when they fail, assertions works even with streams that don't complete | ||
@@ -69,2 +70,4 @@ Installation | ||
Additionally, the `timeDriver` provides support for animations. `animationFrames` can be used to build games or animations. `throttleAnimation` can be used to throttle a stream so that only one event passes through each frame. | ||
Usage (Testing) | ||
@@ -333,3 +336,3 @@ --- | ||
#### `periodic(period)` | ||
Returns a stream that emits every `period` msec. Starts with 0, and increases by 1 every time. | ||
Returns a stream that emits every `period` msec. Starts with zero and increases by one every time. | ||
@@ -349,3 +352,3 @@ ```js | ||
#### `throttle(period)` | ||
An operator that can be used with `.compose` that will prevent more than 1 event emitting in the given period. | ||
An operator that can be used with `.compose` that will prevent more than one event emitting in the given period. | ||
@@ -365,2 +368,28 @@ ```js | ||
#### `throttleAnimation` | ||
An operator that can be used with `.compose` that will only allow one event in each animation frame. Uses `requestAnimationFrame`. | ||
Useful for throttling noisy streams like scroll events or mousemose events. | ||
The period between frames should be around `16ms` if the application is focused and running smoothly, but may greatly increase if the application is in the background. | ||
```js | ||
const scroll$ = DOM.select('body').events('scroll'); | ||
const throttledScroll$ = scroll$.compose(Time.throttleAnimation) | ||
``` | ||
#### `animationFrames` | ||
A factory that returns a stream of frames. Each frame is an object with three values: | ||
* `time` - the elapsed time in millseconds since application start | ||
* `delta` - the time in milliseconds since the last frame | ||
* `normalizedDelta` - the delta divided by the expected frame length (16ms). Useful for game development | ||
```js | ||
const frames$ = Time.animationFrames(); | ||
``` | ||
For more information on `requestAnimationFrame`, see the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame). | ||
### `mockTimeSource({interval = 20})` | ||
@@ -367,0 +396,0 @@ |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
43474
27
685
468
0