mirror of
https://github.com/chartjs/Chart.js.git
synced 2024-10-06 04:09:08 +02:00
Cleanup and reorganize core and canvas helpers
Move some of the "core" and "canvas" utils in `helpers.core.js` and `helpers.canvas.js` and introduce the new `isNullOrUndef` and `isObject` helpers. Deprecate `indexOf` and rename `drawRoundedRectangle` to `roundedRect` which now creates a simple `rect` path if radius is 0. Write missing unit tests for the moved helpers.
This commit is contained in:
parent
6c82c93853
commit
5196e05062
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,6 +4,7 @@
|
||||
/dist
|
||||
/docs/index.md
|
||||
/gh-pages
|
||||
/jsdoc
|
||||
/node_modules
|
||||
.DS_Store
|
||||
.idea
|
||||
|
@ -3,11 +3,12 @@
|
||||
*/
|
||||
var Chart = require('./core/core.js')();
|
||||
|
||||
require('./helpers/helpers.core')(Chart);
|
||||
require('./core/core.helpers')(Chart);
|
||||
require('./helpers/helpers.time')(Chart);
|
||||
require('./helpers/helpers.canvas')(Chart);
|
||||
|
||||
require('./platforms/platform.js')(Chart);
|
||||
require('./core/core.canvasHelpers')(Chart);
|
||||
require('./core/core.element')(Chart);
|
||||
require('./core/core.plugin.js')(Chart);
|
||||
require('./core/core.animation')(Chart);
|
||||
|
@ -285,13 +285,13 @@ module.exports = function(Chart) {
|
||||
var ilen = points.length;
|
||||
var i = 0;
|
||||
|
||||
Chart.canvasHelpers.clipArea(chart.ctx, area);
|
||||
Chart.helpers.canvas.clipArea(chart.ctx, area);
|
||||
|
||||
if (lineEnabled(me.getDataset(), chart.options)) {
|
||||
meta.dataset.draw();
|
||||
}
|
||||
|
||||
Chart.canvasHelpers.unclipArea(chart.ctx);
|
||||
Chart.helpers.canvas.unclipArea(chart.ctx);
|
||||
|
||||
// Draw the points
|
||||
for (; i<ilen; ++i) {
|
||||
|
@ -151,7 +151,7 @@ module.exports = function(Chart) {
|
||||
},
|
||||
|
||||
clear: function() {
|
||||
helpers.clear(this);
|
||||
helpers.canvas.clear(this);
|
||||
return this;
|
||||
},
|
||||
|
||||
@ -511,7 +511,7 @@ module.exports = function(Chart) {
|
||||
|
||||
me.clear();
|
||||
|
||||
if (easingValue === undefined || easingValue === null) {
|
||||
if (helpers.isNullOrUndef(easingValue)) {
|
||||
easingValue = 1;
|
||||
}
|
||||
|
||||
@ -688,7 +688,7 @@ module.exports = function(Chart) {
|
||||
|
||||
if (canvas) {
|
||||
me.unbindEvents();
|
||||
helpers.clear(me);
|
||||
helpers.canvas.clear(me);
|
||||
platform.releaseContext(me.ctx);
|
||||
me.canvas = null;
|
||||
me.ctx = null;
|
||||
|
@ -5,32 +5,9 @@
|
||||
var color = require('chartjs-color');
|
||||
|
||||
module.exports = function(Chart) {
|
||||
// Global Chart helpers object for utility methods and classes
|
||||
var helpers = Chart.helpers = {};
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
// -- Basic js utility methods
|
||||
helpers.each = function(loopable, callback, self, reverse) {
|
||||
// Check to see if null or undefined firstly.
|
||||
var i, len;
|
||||
if (helpers.isArray(loopable)) {
|
||||
len = loopable.length;
|
||||
if (reverse) {
|
||||
for (i = len - 1; i >= 0; i--) {
|
||||
callback.call(self, loopable[i], i);
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < len; i++) {
|
||||
callback.call(self, loopable[i], i);
|
||||
}
|
||||
}
|
||||
} else if (typeof loopable === 'object') {
|
||||
var keys = Object.keys(loopable);
|
||||
len = keys.length;
|
||||
for (i = 0; i < len; i++) {
|
||||
callback.call(self, loopable[keys[i]], keys[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
helpers.clone = function(obj) {
|
||||
var objClone = {};
|
||||
helpers.each(obj, function(value, key) {
|
||||
@ -123,32 +100,7 @@ module.exports = function(Chart) {
|
||||
|
||||
return base;
|
||||
};
|
||||
helpers.getValueAtIndexOrDefault = function(value, index, defaultValue) {
|
||||
if (value === undefined || value === null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
if (helpers.isArray(value)) {
|
||||
return index < value.length ? value[index] : defaultValue;
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
helpers.getValueOrDefault = function(value, defaultValue) {
|
||||
return value === undefined ? defaultValue : value;
|
||||
};
|
||||
helpers.indexOf = Array.prototype.indexOf?
|
||||
function(array, item) {
|
||||
return array.indexOf(item);
|
||||
}:
|
||||
function(array, item) {
|
||||
for (var i = 0, ilen = array.length; i < ilen; ++i) {
|
||||
if (array[i] === item) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
helpers.where = function(collection, filterCallback) {
|
||||
if (helpers.isArray(collection) && Array.prototype.filter) {
|
||||
return collection.filter(filterCallback);
|
||||
@ -178,7 +130,7 @@ module.exports = function(Chart) {
|
||||
};
|
||||
helpers.findNextWhere = function(arrayToSearch, filterCallback, startIndex) {
|
||||
// Default to start of the array
|
||||
if (startIndex === undefined || startIndex === null) {
|
||||
if (helpers.isNullOrUndef(startIndex)) {
|
||||
startIndex = -1;
|
||||
}
|
||||
for (var i = startIndex + 1; i < arrayToSearch.length; i++) {
|
||||
@ -190,7 +142,7 @@ module.exports = function(Chart) {
|
||||
};
|
||||
helpers.findPreviousWhere = function(arrayToSearch, filterCallback, startIndex) {
|
||||
// Default to end of the array
|
||||
if (startIndex === undefined || startIndex === null) {
|
||||
if (helpers.isNullOrUndef(startIndex)) {
|
||||
startIndex = arrayToSearch.length;
|
||||
}
|
||||
for (var i = startIndex - 1; i >= 0; i--) {
|
||||
@ -223,13 +175,6 @@ module.exports = function(Chart) {
|
||||
|
||||
return ChartElement;
|
||||
};
|
||||
helpers.noop = function() {};
|
||||
helpers.uid = (function() {
|
||||
var id = 0;
|
||||
return function() {
|
||||
return id++;
|
||||
};
|
||||
}());
|
||||
// -- Math methods
|
||||
helpers.isNumber = function(n) {
|
||||
return !isNaN(parseFloat(n)) && isFinite(n);
|
||||
@ -837,9 +782,6 @@ module.exports = function(Chart) {
|
||||
canvas.style.width = width + 'px';
|
||||
};
|
||||
// -- Canvas methods
|
||||
helpers.clear = function(chart) {
|
||||
chart.ctx.clearRect(0, 0, chart.width, chart.height);
|
||||
};
|
||||
helpers.fontString = function(pixelSize, fontStyle, fontFamily) {
|
||||
return fontStyle + ' ' + pixelSize + 'px ' + fontFamily;
|
||||
};
|
||||
@ -903,19 +845,6 @@ module.exports = function(Chart) {
|
||||
});
|
||||
return numberOfLines;
|
||||
};
|
||||
helpers.drawRoundedRectangle = function(ctx, x, y, width, height, radius) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x + radius, y);
|
||||
ctx.lineTo(x + width - radius, y);
|
||||
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
|
||||
ctx.lineTo(x + width, y + height - radius);
|
||||
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
|
||||
ctx.lineTo(x + radius, y + height);
|
||||
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
|
||||
ctx.lineTo(x, y + radius);
|
||||
ctx.quadraticCurveTo(x, y, x + radius, y);
|
||||
ctx.closePath();
|
||||
};
|
||||
|
||||
helpers.color = !color?
|
||||
function(value) {
|
||||
@ -931,54 +860,10 @@ module.exports = function(Chart) {
|
||||
return color(value);
|
||||
};
|
||||
|
||||
helpers.isArray = Array.isArray?
|
||||
function(obj) {
|
||||
return Array.isArray(obj);
|
||||
} :
|
||||
function(obj) {
|
||||
return Object.prototype.toString.call(obj) === '[object Array]';
|
||||
};
|
||||
// ! @see http://stackoverflow.com/a/14853974
|
||||
helpers.arrayEquals = function(a0, a1) {
|
||||
var i, ilen, v0, v1;
|
||||
|
||||
if (!a0 || !a1 || a0.length !== a1.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0, ilen=a0.length; i < ilen; ++i) {
|
||||
v0 = a0[i];
|
||||
v1 = a1[i];
|
||||
|
||||
if (v0 instanceof Array && v1 instanceof Array) {
|
||||
if (!helpers.arrayEquals(v0, v1)) {
|
||||
return false;
|
||||
}
|
||||
} else if (v0 !== v1) {
|
||||
// NOTE: two different object instances will never be equal: {x:20} != {x:20}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
helpers.callback = function(fn, args, thisArg) {
|
||||
if (fn && typeof fn.call === 'function') {
|
||||
return fn.apply(thisArg, args);
|
||||
}
|
||||
};
|
||||
helpers.getHoverColor = function(colorValue) {
|
||||
/* global CanvasPattern */
|
||||
return (colorValue instanceof CanvasPattern) ?
|
||||
colorValue :
|
||||
helpers.color(colorValue).saturate(0.5).darken(0.1).rgbString();
|
||||
};
|
||||
|
||||
/**
|
||||
* Provided for backward compatibility, use Chart.helpers#callback instead.
|
||||
* @function Chart.helpers#callCallback
|
||||
* @deprecated since version 2.6.0
|
||||
* @todo remove at version 3
|
||||
*/
|
||||
helpers.callCallback = helpers.callback;
|
||||
};
|
||||
|
@ -422,7 +422,7 @@ module.exports = function(Chart) {
|
||||
// Get the correct value. NaN bad inputs, If the value type is object get the x or y based on whether we are horizontal or not
|
||||
getRightValue: function(rawValue) {
|
||||
// Null and undefined values first
|
||||
if (rawValue === null || typeof(rawValue) === 'undefined') {
|
||||
if (helpers.isNullOrUndef(rawValue)) {
|
||||
return NaN;
|
||||
}
|
||||
// isNaN(object) returns true, so make sure NaN is checking for a number; Discard Infinite values
|
||||
@ -575,7 +575,7 @@ module.exports = function(Chart) {
|
||||
helpers.each(me.ticks, function(tick, index) {
|
||||
var label = (tick && tick.value) || tick;
|
||||
// If the callback returned a null or undefined value, do not draw this line
|
||||
if (label === undefined || label === null) {
|
||||
if (helpers.isNullOrUndef(label)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -583,7 +583,7 @@ module.exports = function(Chart) {
|
||||
|
||||
// Since we always show the last tick,we need may need to hide the last shown one before
|
||||
var shouldSkip = (skipRatio > 1 && index % skipRatio > 0) || (index % skipRatio === 0 && index + skipRatio >= me.ticks.length);
|
||||
if (shouldSkip && !isLastTick || (label === undefined || label === null)) {
|
||||
if (shouldSkip && !isLastTick || helpers.isNullOrUndef(label)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -94,7 +94,7 @@ module.exports = function(Chart) {
|
||||
ctx.fillStyle = color(ctx.fillStyle).alpha(ratio).rgbString();
|
||||
}
|
||||
|
||||
Chart.canvasHelpers.drawPoint(ctx, pointStyle, radius, x, y);
|
||||
Chart.helpers.canvas.drawPoint(ctx, pointStyle, radius, x, y);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -1,10 +1,50 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = function(Chart) {
|
||||
// Global Chart canvas helpers object for drawing items to canvas
|
||||
var helpers = Chart.canvasHelpers = {};
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
helpers.drawPoint = function(ctx, pointStyle, radius, x, y) {
|
||||
/**
|
||||
* @namespace Chart.helpers.canvas
|
||||
*/
|
||||
helpers.canvas = {
|
||||
/**
|
||||
* Clears the entire canvas associated to the given `chart`.
|
||||
* @param {Chart} chart - The chart for which to clear the canvas.
|
||||
*/
|
||||
clear: function(chart) {
|
||||
chart.ctx.clearRect(0, 0, chart.width, chart.height);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a "path" for a rectangle with rounded corners at position (x, y) with a
|
||||
* given size (width, height) and the same `radius` for all corners.
|
||||
* @param {CanvasRenderingContext2D} ctx - The canvas 2D Context.
|
||||
* @param {Number} x - The x axis of the coordinate for the rectangle starting point.
|
||||
* @param {Number} y - The y axis of the coordinate for the rectangle starting point.
|
||||
* @param {Number} width - The rectangle's width.
|
||||
* @param {Number} height - The rectangle's height.
|
||||
* @param {Number} radius - The rounded amount (in pixels) for the four corners.
|
||||
* @todo handler `radius` as top-left, top-right, bottom-right, bottom-left array/object?
|
||||
* @todo clamp `radius` to the maximum "correct" value.
|
||||
*/
|
||||
roundedRect: function(ctx, x, y, width, height, radius) {
|
||||
if (radius) {
|
||||
ctx.moveTo(x + radius, y);
|
||||
ctx.lineTo(x + width - radius, y);
|
||||
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
|
||||
ctx.lineTo(x + width, y + height - radius);
|
||||
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
|
||||
ctx.lineTo(x + radius, y + height);
|
||||
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
|
||||
ctx.lineTo(x, y + radius);
|
||||
ctx.quadraticCurveTo(x, y, x + radius, y);
|
||||
} else {
|
||||
ctx.rect(x, y, width, height);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
helpers.canvas.drawPoint = function(ctx, pointStyle, radius, x, y) {
|
||||
var type, edgeLength, xOffset, yOffset, height, size;
|
||||
|
||||
if (typeof pointStyle === 'object') {
|
||||
@ -48,7 +88,9 @@ module.exports = function(Chart) {
|
||||
var leftX = x - offset;
|
||||
var topY = y - offset;
|
||||
var sideSize = Math.SQRT2 * radius;
|
||||
Chart.helpers.drawRoundedRectangle(ctx, leftX, topY, sideSize, sideSize, radius / 2);
|
||||
ctx.beginPath();
|
||||
this.roundedRect(ctx, leftX, topY, sideSize, sideSize, radius / 2);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
break;
|
||||
case 'rectRot':
|
||||
@ -110,18 +152,18 @@ module.exports = function(Chart) {
|
||||
ctx.stroke();
|
||||
};
|
||||
|
||||
helpers.clipArea = function(ctx, clipArea) {
|
||||
helpers.canvas.clipArea = function(ctx, clipArea) {
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
ctx.rect(clipArea.left, clipArea.top, clipArea.right - clipArea.left, clipArea.bottom - clipArea.top);
|
||||
ctx.clip();
|
||||
};
|
||||
|
||||
helpers.unclipArea = function(ctx) {
|
||||
helpers.canvas.unclipArea = function(ctx) {
|
||||
ctx.restore();
|
||||
};
|
||||
|
||||
helpers.lineTo = function(ctx, previous, target, flip) {
|
||||
helpers.canvas.lineTo = function(ctx, previous, target, flip) {
|
||||
if (target.steppedLine) {
|
||||
if (target.steppedLine === 'after') {
|
||||
ctx.lineTo(previous.x, target.y);
|
||||
@ -146,5 +188,34 @@ module.exports = function(Chart) {
|
||||
target.y);
|
||||
};
|
||||
|
||||
Chart.helpers.canvas = helpers;
|
||||
/**
|
||||
* Provided for backward compatibility, use Chart.helpers.canvas instead.
|
||||
* @namespace Chart.canvasHelpers
|
||||
* @deprecated since version 2.6.0
|
||||
* @todo remove at version 3
|
||||
* @private
|
||||
*/
|
||||
Chart.canvasHelpers = helpers.canvas;
|
||||
|
||||
/**
|
||||
* Provided for backward compatibility, use Chart.helpers.canvas.clear instead.
|
||||
* @namespace Chart.helpers.clear
|
||||
* @deprecated since version 2.7.0
|
||||
* @todo remove at version 3
|
||||
* @private
|
||||
*/
|
||||
helpers.clear = helpers.canvas.clear;
|
||||
|
||||
/**
|
||||
* Provided for backward compatibility, use Chart.helpers.canvas.roundedRect instead.
|
||||
* @namespace Chart.helpers.drawRoundedRectangle
|
||||
* @deprecated since version 2.7.0
|
||||
* @todo remove at version 3
|
||||
* @private
|
||||
*/
|
||||
helpers.drawRoundedRectangle = function(ctx) {
|
||||
ctx.beginPath();
|
||||
helpers.canvas.roundedRect.apply(this, arguments);
|
||||
ctx.closePath();
|
||||
};
|
||||
};
|
182
src/helpers/helpers.core.js
Normal file
182
src/helpers/helpers.core.js
Normal file
@ -0,0 +1,182 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = function(Chart) {
|
||||
/**
|
||||
* @namespace Chart.helpers
|
||||
*/
|
||||
var helpers = Chart.helpers = {
|
||||
/**
|
||||
* An empty function that can be used, for example, for optional callback.
|
||||
*/
|
||||
noop: function() {},
|
||||
|
||||
/**
|
||||
* Returns a unique id, sequentially generated from a global variable.
|
||||
* @returns {Number}
|
||||
* @function
|
||||
*/
|
||||
uid: (function() {
|
||||
var id = 0;
|
||||
return function() {
|
||||
return id++;
|
||||
};
|
||||
}()),
|
||||
|
||||
/**
|
||||
* Returns true if `value` is neither null nor undefined, else returns false.
|
||||
* @param {*} value - The value to test.
|
||||
* @returns {Boolean}
|
||||
* @since 2.7.0
|
||||
*/
|
||||
isNullOrUndef: function(value) {
|
||||
return value === null || typeof value === 'undefined';
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if `value` is an array, else returns false.
|
||||
* @param {*} value - The value to test.
|
||||
* @returns {Boolean}
|
||||
* @function
|
||||
*/
|
||||
isArray: Array.isArray? Array.isArray : function(value) {
|
||||
return Object.prototype.toString.call(value) === '[object Array]';
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if `value` is an object (excluding null), else returns false.
|
||||
* @param {*} value - The value to test.
|
||||
* @returns {Boolean}
|
||||
* @since 2.7.0
|
||||
*/
|
||||
isObject: function(value) {
|
||||
return value !== null && Object.prototype.toString.call(value) === '[object Object]';
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns `value` if defined, else returns `defaultValue`.
|
||||
* @param {*} value - The value to return if defined.
|
||||
* @param {*} defaultValue - The value to return if `value` is undefined.
|
||||
* @returns {*}
|
||||
*/
|
||||
getValueOrDefault: function(value, defaultValue) {
|
||||
return typeof value === 'undefined'? defaultValue : value;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns value at the given `index` in array if defined, else returns `defaultValue`.
|
||||
* @param {Array} value - The array to lookup for value at `index`.
|
||||
* @param {Number} index - The index in `value` to lookup for value.
|
||||
* @param {*} defaultValue - The value to return if `value[index]` is undefined.
|
||||
* @returns {*}
|
||||
*/
|
||||
getValueAtIndexOrDefault: function(value, index, defaultValue) {
|
||||
if (helpers.isNullOrUndef(value)) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
if (helpers.isArray(value)) {
|
||||
value = value[index];
|
||||
return typeof value === 'undefined'? defaultValue : value;
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
|
||||
/**
|
||||
* Calls `fn` with the given `args` in the scope defined by `thisArg` and returns the
|
||||
* value returned by `fn`. If `fn` is not a function, this method returns undefined.
|
||||
* @param {Function} fn - The function to call.
|
||||
* @param {Array|undefined|null} args - The arguments with which `fn` should be called.
|
||||
* @param {Object} [thisArg] - The value of `this` provided for the call to `fn`.
|
||||
* @returns {*}
|
||||
*/
|
||||
callback: function(fn, args, thisArg) {
|
||||
if (fn && typeof fn.call === 'function') {
|
||||
return fn.apply(thisArg, args);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Note(SB) for performance sake, this method should only be used when loopable type
|
||||
* is unknown or in none intensive code (not called often and small loopable). Else
|
||||
* it's preferable to use a regular for() loop and save extra function calls.
|
||||
* @param {Object|Array} loopable - The object or array to be iterated.
|
||||
* @param {Function} fn - The function to call for each item.
|
||||
* @param {Object} [thisArg] - The value of `this` provided for the call to `fn`.
|
||||
* @param {Boolean} [reverse] - If true, iterates backward on the loopable.
|
||||
*/
|
||||
each: function(loopable, fn, thisArg, reverse) {
|
||||
var i, len, keys;
|
||||
if (helpers.isArray(loopable)) {
|
||||
len = loopable.length;
|
||||
if (reverse) {
|
||||
for (i = len - 1; i >= 0; i--) {
|
||||
fn.call(thisArg, loopable[i], i);
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < len; i++) {
|
||||
fn.call(thisArg, loopable[i], i);
|
||||
}
|
||||
}
|
||||
} else if (helpers.isObject(loopable)) {
|
||||
keys = Object.keys(loopable);
|
||||
len = keys.length;
|
||||
for (i = 0; i < len; i++) {
|
||||
fn.call(thisArg, loopable[keys[i]], keys[i]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if the `a0` and `a1` arrays have the same content, else returns false.
|
||||
* @see http://stackoverflow.com/a/14853974
|
||||
* @param {Array} a0 - The array to compare
|
||||
* @param {Array} a1 - The array to compare
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
arrayEquals: function(a0, a1) {
|
||||
var i, ilen, v0, v1;
|
||||
|
||||
if (!a0 || !a1 || a0.length !== a1.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0, ilen=a0.length; i < ilen; ++i) {
|
||||
v0 = a0[i];
|
||||
v1 = a1[i];
|
||||
|
||||
if (v0 instanceof Array && v1 instanceof Array) {
|
||||
if (!helpers.arrayEquals(v0, v1)) {
|
||||
return false;
|
||||
}
|
||||
} else if (v0 !== v1) {
|
||||
// NOTE: two different object instances will never be equal: {x:20} != {x:20}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Provided for backward compatibility, use Chart.helpers.callback instead.
|
||||
* @function Chart.helpers.callCallback
|
||||
* @deprecated since version 2.6.0
|
||||
* @todo remove at version 3
|
||||
* @private
|
||||
*/
|
||||
helpers.callCallback = helpers.callback;
|
||||
|
||||
/**
|
||||
* Provided for backward compatibility, use Array.prototype.indexOf instead.
|
||||
* Array.prototype.indexOf compatibility: Chrome, Opera, Safari, FF1.5+, IE9+
|
||||
* @function Chart.helpers.indexOf
|
||||
* @deprecated since version 2.7.0
|
||||
* @todo remove at version 3
|
||||
* @private
|
||||
*/
|
||||
helpers.indexOf = function(array, item, fromIndex) {
|
||||
return Array.prototype.indexOf.call(array, item, fromIndex);
|
||||
};
|
||||
};
|
@ -229,7 +229,7 @@ module.exports = function(Chart) {
|
||||
var initial = canvas._chartjs.initial;
|
||||
['height', 'width'].forEach(function(prop) {
|
||||
var value = initial[prop];
|
||||
if (value === undefined || value === null) {
|
||||
if (helpers.isNullOrUndef(value)) {
|
||||
canvas.removeAttribute(prop);
|
||||
} else {
|
||||
canvas.setAttribute(prop, value);
|
||||
|
@ -360,7 +360,7 @@ module.exports = function(Chart) {
|
||||
var centerY = y + offSet;
|
||||
|
||||
// Draw pointStyle as legend symbol
|
||||
Chart.canvasHelpers.drawPoint(ctx, legendItem.pointStyle, radius, centerX, centerY);
|
||||
Chart.helpers.canvas.drawPoint(ctx, legendItem.pointStyle, radius, centerX, centerY);
|
||||
} else {
|
||||
// Draw box as legend symbol
|
||||
if (!isLineWidthZero) {
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
module.exports = function(Chart) {
|
||||
|
||||
var helpers = Chart.helpers;
|
||||
// Default config for a category scale
|
||||
var defaultConfig = {
|
||||
position: 'bottom'
|
||||
@ -28,13 +27,13 @@ module.exports = function(Chart) {
|
||||
|
||||
if (me.options.ticks.min !== undefined) {
|
||||
// user specified min value
|
||||
findIndex = helpers.indexOf(labels, me.options.ticks.min);
|
||||
findIndex = labels.indexOf(me.options.ticks.min);
|
||||
me.minIndex = findIndex !== -1 ? findIndex : me.minIndex;
|
||||
}
|
||||
|
||||
if (me.options.ticks.max !== undefined) {
|
||||
// user specified max value
|
||||
findIndex = helpers.indexOf(labels, me.options.ticks.max);
|
||||
findIndex = labels.indexOf(me.options.ticks.max);
|
||||
me.maxIndex = findIndex !== -1 ? findIndex : me.maxIndex;
|
||||
}
|
||||
|
||||
|
@ -89,6 +89,7 @@ Context.prototype._initMethods = function() {
|
||||
},
|
||||
moveTo: function() {},
|
||||
quadraticCurveTo: function() {},
|
||||
rect: function() {},
|
||||
restore: function() {},
|
||||
rotate: function() {},
|
||||
save: function() {},
|
||||
|
@ -6,59 +6,6 @@ describe('Core helper tests', function() {
|
||||
helpers = window.Chart.helpers;
|
||||
});
|
||||
|
||||
it('should iterate over an array and pass the extra data to that function', function() {
|
||||
var testData = [0, 9, 'abc'];
|
||||
var scope = {}; // fake out the scope and ensure that 'this' is the correct thing
|
||||
|
||||
helpers.each(testData, function(item, index) {
|
||||
expect(item).not.toBe(undefined);
|
||||
expect(index).not.toBe(undefined);
|
||||
|
||||
expect(testData[index]).toBe(item);
|
||||
expect(this).toBe(scope);
|
||||
}, scope);
|
||||
|
||||
// Reverse iteration
|
||||
var iterated = [];
|
||||
helpers.each(testData, function(item, index) {
|
||||
expect(item).not.toBe(undefined);
|
||||
expect(index).not.toBe(undefined);
|
||||
|
||||
expect(testData[index]).toBe(item);
|
||||
expect(this).toBe(scope);
|
||||
|
||||
iterated.push(item);
|
||||
}, scope, true);
|
||||
|
||||
expect(iterated.slice().reverse()).toEqual(testData);
|
||||
});
|
||||
|
||||
it('should iterate over properties in an object', function() {
|
||||
var testData = {
|
||||
myProp1: 'abc',
|
||||
myProp2: 276,
|
||||
myProp3: ['a', 'b']
|
||||
};
|
||||
|
||||
helpers.each(testData, function(value, key) {
|
||||
if (key === 'myProp1') {
|
||||
expect(value).toBe('abc');
|
||||
} else if (key === 'myProp2') {
|
||||
expect(value).toBe(276);
|
||||
} else if (key === 'myProp3') {
|
||||
expect(value).toEqual(['a', 'b']);
|
||||
} else {
|
||||
expect(false).toBe(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should not error when iterating over a null object', function() {
|
||||
expect(function() {
|
||||
helpers.each(undefined);
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it('should clone an object', function() {
|
||||
var testData = {
|
||||
myProp1: 'abc',
|
||||
@ -268,14 +215,6 @@ describe('Core helper tests', function() {
|
||||
expect(merged.scales.yAxes[2].ticks.callback).toEqual(jasmine.any(Function));
|
||||
});
|
||||
|
||||
it('should get value or default', function() {
|
||||
expect(helpers.getValueAtIndexOrDefault(98, 0, 56)).toBe(98);
|
||||
expect(helpers.getValueAtIndexOrDefault(0, 0, 56)).toBe(0);
|
||||
expect(helpers.getValueAtIndexOrDefault(undefined, undefined, 56)).toBe(56);
|
||||
expect(helpers.getValueAtIndexOrDefault([1, 2, 3], 1, 100)).toBe(2);
|
||||
expect(helpers.getValueAtIndexOrDefault([1, 2, 3], 3, 100)).toBe(100);
|
||||
});
|
||||
|
||||
it('should filter an array', function() {
|
||||
var data = [-10, 0, 6, 0, 7];
|
||||
var callback = function(item) {
|
||||
@ -588,20 +527,6 @@ describe('Core helper tests', function() {
|
||||
expect(helpers.previousItem(testData, 1, true)).toEqual(0);
|
||||
});
|
||||
|
||||
it('should clear a canvas', function() {
|
||||
var context = window.createMockContext();
|
||||
helpers.clear({
|
||||
width: 100,
|
||||
height: 150,
|
||||
ctx: context
|
||||
});
|
||||
|
||||
expect(context.getCalls()).toEqual([{
|
||||
name: 'clearRect',
|
||||
args: [0, 0, 100, 150]
|
||||
}]);
|
||||
});
|
||||
|
||||
it('should return the width of the longest text in an Array and 2D Array', function() {
|
||||
var context = window.createMockContext();
|
||||
var font = "normal 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif";
|
||||
@ -664,46 +589,6 @@ describe('Core helper tests', function() {
|
||||
expect(helpers.numberOfLabelLines(arrayOfThings3)).toEqual(3);
|
||||
});
|
||||
|
||||
it('should draw a rounded rectangle', function() {
|
||||
var context = window.createMockContext();
|
||||
helpers.drawRoundedRectangle(context, 10, 20, 30, 40, 5);
|
||||
|
||||
expect(context.getCalls()).toEqual([{
|
||||
name: 'beginPath',
|
||||
args: []
|
||||
}, {
|
||||
name: 'moveTo',
|
||||
args: [15, 20]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [35, 20]
|
||||
}, {
|
||||
name: 'quadraticCurveTo',
|
||||
args: [40, 20, 40, 25]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [40, 55]
|
||||
}, {
|
||||
name: 'quadraticCurveTo',
|
||||
args: [40, 60, 35, 60]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [15, 60]
|
||||
}, {
|
||||
name: 'quadraticCurveTo',
|
||||
args: [10, 60, 10, 55]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [10, 25]
|
||||
}, {
|
||||
name: 'quadraticCurveTo',
|
||||
args: [10, 20, 15, 20]
|
||||
}, {
|
||||
name: 'closePath',
|
||||
args: []
|
||||
}]);
|
||||
});
|
||||
|
||||
it ('should get the maximum width and height for a node', function() {
|
||||
// Create div with fixed size as a test bed
|
||||
var div = document.createElement('div');
|
||||
|
@ -209,9 +209,9 @@ describe('Point element tests', function() {
|
||||
}]);
|
||||
|
||||
var drawRoundedRectangleSpy = jasmine.createSpy('drawRoundedRectangle');
|
||||
var drawRoundedRectangle = Chart.helpers.drawRoundedRectangle;
|
||||
var drawRoundedRectangle = Chart.helpers.canvas.roundedRect;
|
||||
var offset = point._view.radius / Math.SQRT2;
|
||||
Chart.helpers.drawRoundedRectangle = drawRoundedRectangleSpy;
|
||||
Chart.helpers.canvas.roundedRect = drawRoundedRectangleSpy;
|
||||
mockContext.resetCalls();
|
||||
point._view.pointStyle = 'rectRounded';
|
||||
point.draw();
|
||||
@ -231,7 +231,7 @@ describe('Point element tests', function() {
|
||||
})
|
||||
);
|
||||
|
||||
Chart.helpers.drawRoundedRectangle = drawRoundedRectangle;
|
||||
Chart.helpers.canvas.roundedRect = drawRoundedRectangle;
|
||||
mockContext.resetCalls();
|
||||
point._view.pointStyle = 'rectRot';
|
||||
point.draw();
|
||||
|
@ -1,8 +1,8 @@
|
||||
describe('Deprecations', function() {
|
||||
describe('Version 2.7.0', function() {
|
||||
describe('Chart.Controller.update(duration, lazy)', function() {
|
||||
beforeEach(function() {
|
||||
this.chart = acquireChart({
|
||||
it('should add an animation with the provided options', function() {
|
||||
var chart = acquireChart({
|
||||
type: 'doughnut',
|
||||
options: {
|
||||
animation: {
|
||||
@ -12,14 +12,12 @@ describe('Deprecations', function() {
|
||||
}
|
||||
});
|
||||
|
||||
this.addAnimationSpy = spyOn(Chart.animationService, 'addAnimation');
|
||||
});
|
||||
spyOn(Chart.animationService, 'addAnimation');
|
||||
|
||||
it('should add an animation with the provided options', function() {
|
||||
this.chart.update(800, false);
|
||||
chart.update(800, false);
|
||||
|
||||
expect(this.addAnimationSpy).toHaveBeenCalledWith(
|
||||
this.chart,
|
||||
expect(Chart.animationService.addAnimation).toHaveBeenCalledWith(
|
||||
chart,
|
||||
jasmine.objectContaining({easing: 'linear'}),
|
||||
800,
|
||||
false
|
||||
@ -28,8 +26,8 @@ describe('Deprecations', function() {
|
||||
});
|
||||
|
||||
describe('Chart.Controller.render(duration, lazy)', function() {
|
||||
beforeEach(function() {
|
||||
this.chart = acquireChart({
|
||||
it('should add an animation with the provided options', function() {
|
||||
var chart = acquireChart({
|
||||
type: 'doughnut',
|
||||
options: {
|
||||
animation: {
|
||||
@ -39,20 +37,56 @@ describe('Deprecations', function() {
|
||||
}
|
||||
});
|
||||
|
||||
this.addAnimationSpy = spyOn(Chart.animationService, 'addAnimation');
|
||||
});
|
||||
spyOn(Chart.animationService, 'addAnimation');
|
||||
|
||||
it('should add an animation with the provided options', function() {
|
||||
this.chart.render(800, true);
|
||||
chart.render(800, true);
|
||||
|
||||
expect(this.addAnimationSpy).toHaveBeenCalledWith(
|
||||
this.chart,
|
||||
expect(Chart.animationService.addAnimation).toHaveBeenCalledWith(
|
||||
chart,
|
||||
jasmine.objectContaining({easing: 'linear'}),
|
||||
800,
|
||||
true
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Chart.helpers.indexOf', function() {
|
||||
it('should be defined and a function', function() {
|
||||
expect(Chart.helpers.indexOf).toBeDefined();
|
||||
expect(typeof Chart.helpers.indexOf).toBe('function');
|
||||
});
|
||||
it('should returns the correct index', function() {
|
||||
expect(Chart.helpers.indexOf([1, 2, 42], 42)).toBe(2);
|
||||
expect(Chart.helpers.indexOf([1, 2, 42], 3)).toBe(-1);
|
||||
expect(Chart.helpers.indexOf([1, 42, 2, 42], 42, 2)).toBe(3);
|
||||
expect(Chart.helpers.indexOf([1, 42, 2, 42], 3, 2)).toBe(-1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Chart.helpers.clear', function() {
|
||||
it('should be defined and an alias of Chart.helpers.canvas.clear', function() {
|
||||
expect(Chart.helpers.clear).toBeDefined();
|
||||
expect(Chart.helpers.clear).toBe(Chart.helpers.canvas.clear);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Chart.helpers.drawRoundedRectangle', function() {
|
||||
it('should be defined and a function', function() {
|
||||
expect(Chart.helpers.drawRoundedRectangle).toBeDefined();
|
||||
expect(typeof Chart.helpers.drawRoundedRectangle).toBe('function');
|
||||
});
|
||||
it('should call Chart.helpers.canvas.roundedRect', function() {
|
||||
var ctx = window.createMockContext();
|
||||
spyOn(Chart.helpers.canvas, 'roundedRect');
|
||||
|
||||
Chart.helpers.drawRoundedRectangle(ctx, 10, 20, 30, 40, 5);
|
||||
|
||||
var calls = ctx.getCalls();
|
||||
expect(calls[0]).toEqual({name: 'beginPath', args: []});
|
||||
expect(calls[calls.length-1]).toEqual({name: 'closePath', args: []});
|
||||
expect(Chart.helpers.canvas.roundedRect).toHaveBeenCalledWith(ctx, 10, 20, 30, 40, 5);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Version 2.6.0', function() {
|
||||
@ -163,6 +197,13 @@ describe('Deprecations', function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Chart.helpers.callCallback', function() {
|
||||
it('should be defined and an alias of Chart.helpers.callback', function() {
|
||||
expect(Chart.helpers.callCallback).toBeDefined();
|
||||
expect(Chart.helpers.callCallback).toBe(Chart.helpers.callback);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Version 2.5.0', function() {
|
||||
|
50
test/specs/helpers.canvas.tests.js
Normal file
50
test/specs/helpers.canvas.tests.js
Normal file
@ -0,0 +1,50 @@
|
||||
'use strict';
|
||||
|
||||
describe('Chart.helpers.canvas', function() {
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
describe('clear', function() {
|
||||
it('should clear the chart canvas', function() {
|
||||
var chart = acquireChart({}, {
|
||||
canvas: {
|
||||
style: 'width: 150px; height: 245px'
|
||||
}
|
||||
});
|
||||
|
||||
spyOn(chart.ctx, 'clearRect');
|
||||
|
||||
helpers.canvas.clear(chart);
|
||||
|
||||
expect(chart.ctx.clearRect.calls.count()).toBe(1);
|
||||
expect(chart.ctx.clearRect.calls.first().object).toBe(chart.ctx);
|
||||
expect(chart.ctx.clearRect.calls.first().args).toEqual([0, 0, 150, 245]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('roundedRect', function() {
|
||||
it('should create a rounded rectangle path', function() {
|
||||
var context = window.createMockContext();
|
||||
|
||||
helpers.canvas.roundedRect(context, 10, 20, 30, 40, 5);
|
||||
|
||||
expect(context.getCalls()).toEqual([
|
||||
{name: 'moveTo', args: [15, 20]},
|
||||
{name: 'lineTo', args: [35, 20]},
|
||||
{name: 'quadraticCurveTo', args: [40, 20, 40, 25]},
|
||||
{name: 'lineTo', args: [40, 55]},
|
||||
{name: 'quadraticCurveTo', args: [40, 60, 35, 60]},
|
||||
{name: 'lineTo', args: [15, 60]},
|
||||
{name: 'quadraticCurveTo', args: [10, 60, 10, 55]},
|
||||
{name: 'lineTo', args: [10, 25]},
|
||||
{name: 'quadraticCurveTo', args: [10, 20, 15, 20]}
|
||||
]);
|
||||
});
|
||||
it('should optimize path if radius is 0', function() {
|
||||
var context = window.createMockContext();
|
||||
|
||||
helpers.canvas.roundedRect(context, 10, 20, 30, 40, 0);
|
||||
|
||||
expect(context.getCalls()).toEqual([{name: 'rect', args: [10, 20, 30, 40]}]);
|
||||
});
|
||||
});
|
||||
});
|
239
test/specs/helpers.core.tests.js
Normal file
239
test/specs/helpers.core.tests.js
Normal file
@ -0,0 +1,239 @@
|
||||
'use strict';
|
||||
|
||||
describe('Chart.helpers.core', function() {
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
describe('noop', function() {
|
||||
it('should be callable', function() {
|
||||
expect(helpers.noop).toBeDefined();
|
||||
expect(typeof helpers.noop).toBe('function');
|
||||
expect(typeof helpers.noop.call).toBe('function');
|
||||
});
|
||||
it('should returns "undefined"', function() {
|
||||
expect(helpers.noop(42)).not.toBeDefined();
|
||||
expect(helpers.noop.call(this, 42)).not.toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('isArray', function() {
|
||||
it('should return true if value is an array', function() {
|
||||
expect(helpers.isArray([])).toBeTruthy();
|
||||
expect(helpers.isArray([42])).toBeTruthy();
|
||||
expect(helpers.isArray(new Array())).toBeTruthy();
|
||||
expect(helpers.isArray(Array.prototype)).toBeTruthy();
|
||||
});
|
||||
it('should return false if value is not an array', function() {
|
||||
expect(helpers.isArray()).toBeFalsy();
|
||||
expect(helpers.isArray({})).toBeFalsy();
|
||||
expect(helpers.isArray(undefined)).toBeFalsy();
|
||||
expect(helpers.isArray(null)).toBeFalsy();
|
||||
expect(helpers.isArray(true)).toBeFalsy();
|
||||
expect(helpers.isArray(false)).toBeFalsy();
|
||||
expect(helpers.isArray(42)).toBeFalsy();
|
||||
expect(helpers.isArray('Array')).toBeFalsy();
|
||||
expect(helpers.isArray({__proto__: Array.prototype})).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('isObject', function() {
|
||||
it('should return true if value is an object', function() {
|
||||
expect(helpers.isObject({})).toBeTruthy();
|
||||
expect(helpers.isObject({a: 42})).toBeTruthy();
|
||||
expect(helpers.isObject(new Object())).toBeTruthy();
|
||||
});
|
||||
it('should return false if value is not an object', function() {
|
||||
expect(helpers.isObject()).toBeFalsy();
|
||||
expect(helpers.isObject(undefined)).toBeFalsy();
|
||||
expect(helpers.isObject(null)).toBeFalsy();
|
||||
expect(helpers.isObject(true)).toBeFalsy();
|
||||
expect(helpers.isObject(false)).toBeFalsy();
|
||||
expect(helpers.isObject(42)).toBeFalsy();
|
||||
expect(helpers.isObject('Object')).toBeFalsy();
|
||||
expect(helpers.isObject([])).toBeFalsy();
|
||||
expect(helpers.isObject([42])).toBeFalsy();
|
||||
expect(helpers.isObject(new Array())).toBeFalsy();
|
||||
expect(helpers.isObject(new Date())).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('isNullOrUndef', function() {
|
||||
it('should return true if value is null/undefined', function() {
|
||||
expect(helpers.isNullOrUndef(null)).toBeTruthy();
|
||||
expect(helpers.isNullOrUndef(undefined)).toBeTruthy();
|
||||
});
|
||||
it('should return false if value is not null/undefined', function() {
|
||||
expect(helpers.isNullOrUndef(true)).toBeFalsy();
|
||||
expect(helpers.isNullOrUndef(false)).toBeFalsy();
|
||||
expect(helpers.isNullOrUndef('')).toBeFalsy();
|
||||
expect(helpers.isNullOrUndef('String')).toBeFalsy();
|
||||
expect(helpers.isNullOrUndef(0)).toBeFalsy();
|
||||
expect(helpers.isNullOrUndef([])).toBeFalsy();
|
||||
expect(helpers.isNullOrUndef({})).toBeFalsy();
|
||||
expect(helpers.isNullOrUndef([42])).toBeFalsy();
|
||||
expect(helpers.isNullOrUndef(new Date())).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getValueOrDefault', function() {
|
||||
it('should return value if defined', function() {
|
||||
var object = {};
|
||||
var array = [];
|
||||
|
||||
expect(helpers.getValueOrDefault(null, 42)).toBe(null);
|
||||
expect(helpers.getValueOrDefault(false, 42)).toBe(false);
|
||||
expect(helpers.getValueOrDefault(object, 42)).toBe(object);
|
||||
expect(helpers.getValueOrDefault(array, 42)).toBe(array);
|
||||
expect(helpers.getValueOrDefault('', 42)).toBe('');
|
||||
expect(helpers.getValueOrDefault(0, 42)).toBe(0);
|
||||
});
|
||||
it('should return default if undefined', function() {
|
||||
expect(helpers.getValueOrDefault(undefined, 42)).toBe(42);
|
||||
expect(helpers.getValueOrDefault({}.foo, 42)).toBe(42);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getValueAtIndexOrDefault', function() {
|
||||
it('should return the passed value if not an array', function() {
|
||||
expect(helpers.getValueAtIndexOrDefault(0, 0, 42)).toBe(0);
|
||||
expect(helpers.getValueAtIndexOrDefault('', 0, 42)).toBe('');
|
||||
expect(helpers.getValueAtIndexOrDefault(false, 0, 42)).toBe(false);
|
||||
expect(helpers.getValueAtIndexOrDefault(98, 0, 42)).toBe(98);
|
||||
});
|
||||
it('should return the default value if the passed value is null or undefined', function() {
|
||||
expect(helpers.getValueAtIndexOrDefault(null, 0, 42)).toBe(42);
|
||||
expect(helpers.getValueAtIndexOrDefault(undefined, 0, 42)).toBe(42);
|
||||
});
|
||||
it('should return the value at index if defined', function() {
|
||||
expect(helpers.getValueAtIndexOrDefault([1, false, 'foo'], 1, 42)).toBe(false);
|
||||
expect(helpers.getValueAtIndexOrDefault([1, false, 'foo'], 2, 42)).toBe('foo');
|
||||
});
|
||||
it('should return the default value if value at index is undefined', function() {
|
||||
expect(helpers.getValueAtIndexOrDefault([1, false, 'foo'], 3, 42)).toBe(42);
|
||||
expect(helpers.getValueAtIndexOrDefault([1, undefined, 'foo'], 1, 42)).toBe(42);
|
||||
});
|
||||
});
|
||||
|
||||
describe('callback', function() {
|
||||
it('should return undefined if fn is not a function', function() {
|
||||
expect(helpers.callback()).not.toBeDefined();
|
||||
expect(helpers.callback(null)).not.toBeDefined();
|
||||
expect(helpers.callback(42)).not.toBeDefined();
|
||||
expect(helpers.callback([])).not.toBeDefined();
|
||||
expect(helpers.callback({})).not.toBeDefined();
|
||||
});
|
||||
it('should call fn with the given args', function() {
|
||||
var spy = jasmine.createSpy('spy');
|
||||
helpers.callback(spy);
|
||||
helpers.callback(spy, []);
|
||||
helpers.callback(spy, ['foo']);
|
||||
helpers.callback(spy, [42, 'bar']);
|
||||
|
||||
expect(spy.calls.argsFor(0)).toEqual([]);
|
||||
expect(spy.calls.argsFor(1)).toEqual([]);
|
||||
expect(spy.calls.argsFor(2)).toEqual(['foo']);
|
||||
expect(spy.calls.argsFor(3)).toEqual([42, 'bar']);
|
||||
});
|
||||
it('should call fn with the given scope', function() {
|
||||
var spy = jasmine.createSpy('spy');
|
||||
var scope = {};
|
||||
|
||||
helpers.callback(spy);
|
||||
helpers.callback(spy, [], null);
|
||||
helpers.callback(spy, [], undefined);
|
||||
helpers.callback(spy, [], scope);
|
||||
|
||||
expect(spy.calls.all()[0].object).toBe(window);
|
||||
expect(spy.calls.all()[1].object).toBe(window);
|
||||
expect(spy.calls.all()[2].object).toBe(window);
|
||||
expect(spy.calls.all()[3].object).toBe(scope);
|
||||
});
|
||||
it('should return the value returned by fn', function() {
|
||||
expect(helpers.callback(helpers.noop, [41])).toBe(undefined);
|
||||
expect(helpers.callback(function(i) {
|
||||
return i+1;
|
||||
}, [41])).toBe(42);
|
||||
});
|
||||
});
|
||||
|
||||
describe('each', function() {
|
||||
it('should iterate over an array forward if reverse === false', function() {
|
||||
var scope = {};
|
||||
var scopes = [];
|
||||
var items = [];
|
||||
var keys = [];
|
||||
|
||||
helpers.each(['foo', 'bar', 42], function(item, key) {
|
||||
scopes.push(this);
|
||||
items.push(item);
|
||||
keys.push(key);
|
||||
}, scope);
|
||||
|
||||
expect(scopes).toEqual([scope, scope, scope]);
|
||||
expect(items).toEqual(['foo', 'bar', 42]);
|
||||
expect(keys).toEqual([0, 1, 2]);
|
||||
});
|
||||
it('should iterate over an array backward if reverse === true', function() {
|
||||
var scope = {};
|
||||
var scopes = [];
|
||||
var items = [];
|
||||
var keys = [];
|
||||
|
||||
helpers.each(['foo', 'bar', 42], function(item, key) {
|
||||
scopes.push(this);
|
||||
items.push(item);
|
||||
keys.push(key);
|
||||
}, scope, true);
|
||||
|
||||
expect(scopes).toEqual([scope, scope, scope]);
|
||||
expect(items).toEqual([42, 'bar', 'foo']);
|
||||
expect(keys).toEqual([2, 1, 0]);
|
||||
});
|
||||
it('should iterate over object properties', function() {
|
||||
var scope = {};
|
||||
var scopes = [];
|
||||
var items = [];
|
||||
|
||||
helpers.each({a: 'foo', b: 'bar', c: 42}, function(item, key) {
|
||||
scopes.push(this);
|
||||
items[key] = item;
|
||||
}, scope);
|
||||
|
||||
expect(scopes).toEqual([scope, scope, scope]);
|
||||
expect(items).toEqual(jasmine.objectContaining({a: 'foo', b: 'bar', c: 42}));
|
||||
});
|
||||
it('should not throw when called with a non iterable object', function() {
|
||||
expect(function() {
|
||||
helpers.each(undefined);
|
||||
}).not.toThrow();
|
||||
expect(function() {
|
||||
helpers.each(null);
|
||||
}).not.toThrow();
|
||||
expect(function() {
|
||||
helpers.each(42);
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('arrayEquals', function() {
|
||||
it('should return false if arrays are not the same', function() {
|
||||
expect(helpers.arrayEquals([], [42])).toBeFalsy();
|
||||
expect(helpers.arrayEquals([42], ['42'])).toBeFalsy();
|
||||
expect(helpers.arrayEquals([1, 2, 3], [1, 2, 3, 4])).toBeFalsy();
|
||||
expect(helpers.arrayEquals(['foo', 'bar'], ['bar', 'foo'])).toBeFalsy();
|
||||
expect(helpers.arrayEquals([1, 2, 3], [1, 2, 'foo'])).toBeFalsy();
|
||||
expect(helpers.arrayEquals([1, 2, [3, 4]], [1, 2, [3, 'foo']])).toBeFalsy();
|
||||
expect(helpers.arrayEquals([{a: 42}], [{a: 42}])).toBeFalsy();
|
||||
});
|
||||
it('should return false if arrays are not the same', function() {
|
||||
var o0 = {};
|
||||
var o1 = {};
|
||||
var o2 = {};
|
||||
|
||||
expect(helpers.arrayEquals([], [])).toBeTruthy();
|
||||
expect(helpers.arrayEquals([1, 2, 3], [1, 2, 3])).toBeTruthy();
|
||||
expect(helpers.arrayEquals(['foo', 'bar'], ['foo', 'bar'])).toBeTruthy();
|
||||
expect(helpers.arrayEquals([true, false, true], [true, false, true])).toBeTruthy();
|
||||
expect(helpers.arrayEquals([o0, o1, o2], [o0, o1, o2])).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user