`karma.conf.ci.js` has been merged into `karma.conf.js` for local testing consistency: `gulp unittestWatch` has been replaced by `gulp unittest --watch` and thus use exactly the same config file. Upgrade to latest jasmine and karma packages and remove deprecated `gulp-karma` dependency (directly use `karma.Server` in gulp).
Split `test/mockContext.js` into smaller `test/jasmine.*` modules to make easier unit tests maintenance and finally, move all `*.test.js` files under the `test/specs` folder.
var util = require('gulp-util');
var zip = require('gulp-zip');
var exec = require('child_process').exec;
-var karma = require('gulp-karma');
+var karma = require('karma');
var browserify = require('browserify');
var source = require('vinyl-source-stream');
var merge = require('merge-stream');
var collapse = require('bundle-collapser/plugin');
var argv = require('yargs').argv
+var path = require('path');
var package = require('./package.json');
var srcDir = './src/';
" * https://github.com/chartjs/Chart.js/blob/master/LICENSE.md\n" +
" */\n";
-var preTestFiles = [
- './node_modules/moment/min/moment.min.js'
-];
-
-var testFiles = [
- './test/*.js'
-];
-
gulp.task('bower', bowerTask);
gulp.task('build', buildTask);
gulp.task('package', packageTask);
gulp.task('server', serverTask);
gulp.task('validHTML', validHTMLTask);
gulp.task('unittest', unittestTask);
-gulp.task('unittestWatch', unittestWatchTask);
gulp.task('library-size', librarySizeTask);
gulp.task('module-sizes', moduleSizesTask);
gulp.task('_open', _openTask);
'beforeEach',
'describe',
'expect',
+ 'fail',
'it',
'jasmine',
'moment',
}
function startTest() {
- return [].concat(preTestFiles).concat([
- './src/**/*.js',
- './test/mockContext.js'
- ]).concat(
- argv.inputs?
- argv.inputs.split(';'):
- testFiles);
+ return [
+ './node_modules/moment/min/moment.min.js',
+ './test/jasmine.index.js',
+ './src/**/*.js',
+ ].concat(
+ argv.inputs?
+ argv.inputs.split(';'):
+ ['./test/specs/**/*.js']
+ );
}
-function unittestTask() {
- return gulp.src(startTest())
- .pipe(karma({
- configFile: 'karma.conf.ci.js',
- action: 'run'
- }));
+function unittestTask(done) {
+ new karma.Server({
+ configFile: path.join(__dirname, 'karma.conf.js'),
+ singleRun: !argv.watch,
+ files: startTest(),
+ }, done).start();
}
-function unittestWatchTask() {
- return gulp.src(startTest())
- .pipe(karma({
- configFile: 'karma.conf.js',
- action: 'watch'
- }));
-}
-
-function coverageTask() {
- return gulp.src(startTest())
- .pipe(karma({
- configFile: 'karma.coverage.conf.js',
- action: 'run'
- }));
+function coverageTask(done) {
+ new karma.Server({
+ configFile: path.join(__dirname, 'karma.coverage.conf.js'),
+ files: startTest(),
+ singleRun: true,
+ }, done).start();
}
function librarySizeTask() {
+++ /dev/null
-module.exports = function(config) {
- var configuration = {
- browsers: ['Firefox'],
- customLaunchers: {
- Chrome_travis_ci: {
- base: 'Chrome',
- flags: ['--no-sandbox']
- }
- },
- frameworks: ['browserify', 'jasmine'],
- reporters: ['progress', 'html'],
- preprocessors: {
- 'src/**/*.js': ['browserify']
- },
- browserify: {
- debug: true
- }
- };
-
- if (process.env.TRAVIS) {
- configuration.browsers.push('Chrome_travis_ci');
- }
-
- config.set(configuration);
-};
\ No newline at end of file
-module.exports = function(config) {
- config.set({
- browsers: ['Chrome', 'Firefox'],
+/* eslint camelcase: 0 */
+
+module.exports = function(karma) {
+ var config = {
+ browsers: ['Firefox'],
frameworks: ['browserify', 'jasmine'],
- reporters: ['progress', 'html'],
+ reporters: ['progress', 'kjhtml'],
preprocessors: {
- 'src/**/*.js': ['browserify']
+ './test/jasmine.index.js': ['browserify'],
+ './src/**/*.js': ['browserify']
},
+
browserify: {
debug: true
}
- });
-};
\ No newline at end of file
+ };
+
+ // https://swizec.com/blog/how-to-run-javascript-tests-in-chrome-on-travis/swizec/6647
+ if (process.env.TRAVIS) {
+ config.browsers.push('chrome_travis_ci');
+ config.customLaunchers = {
+ chrome_travis_ci: {
+ base: 'Chrome',
+ flags: ['--no-sandbox']
+ }
+ };
+ } else {
+ config.browsers.push('Chrome');
+ }
+
+ karma.set(config);
+};
module.exports = function(config) {
var configuration = {
browsers: ['Firefox'],
-
frameworks: ['browserify', 'jasmine'],
+ reporters: ['progress', 'coverage'],
preprocessors: {
- 'src/**/*.js': ['browserify']
+ './test/jasmine.index.js': ['browserify'],
+ './src/**/*.js': ['browserify']
},
+
browserify: {
debug: true,
transform: [['browserify-istanbul', {
}
}]]
},
-
- reporters: ['progress', 'coverage'],
+
coverageReporter: {
dir: 'coverage/',
reporters: [
"gulp-file": "^0.3.0",
"gulp-html-validator": "^0.0.2",
"gulp-insert": "~0.5.0",
- "gulp-karma": "0.0.4",
"gulp-replace": "^0.5.4",
"gulp-size": "~0.4.0",
"gulp-streamify": "^1.0.2",
"gulp-uglify": "~2.0.x",
"gulp-util": "~2.2.x",
"gulp-zip": "~3.2.0",
- "jasmine": "^2.3.2",
- "jasmine-core": "^2.3.4",
- "karma": "^0.12.37",
- "karma-browserify": "^5.0.1",
- "karma-chrome-launcher": "^0.2.0",
- "karma-coverage": "^0.5.1",
- "karma-firefox-launcher": "^0.1.6",
- "karma-jasmine": "^0.3.6",
- "karma-jasmine-html-reporter": "^0.1.8",
+ "jasmine": "^2.5.0",
+ "jasmine-core": "^2.5.0",
+ "karma": "^1.5.0",
+ "karma-browserify": "^5.1.0",
+ "karma-chrome-launcher": "^2.0.0",
+ "karma-coverage": "^1.1.0",
+ "karma-firefox-launcher": "^1.0.0",
+ "karma-jasmine": "^1.1.0",
+ "karma-jasmine-html-reporter": "^0.2.2",
"merge-stream": "^1.0.0",
"vinyl-source-stream": "^1.1.0",
"watchify": "^3.7.0",
--- /dev/null
+// Code from http://stackoverflow.com/questions/4406864/html-canvas-unit-testing
+var Context = function() {
+ this._calls = []; // names/args of recorded calls
+ this._initMethods();
+
+ this._fillStyle = null;
+ this._lineCap = null;
+ this._lineDashOffset = null;
+ this._lineJoin = null;
+ this._lineWidth = null;
+ this._strokeStyle = null;
+
+ // Define properties here so that we can record each time they are set
+ Object.defineProperties(this, {
+ fillStyle: {
+ get: function() {
+ return this._fillStyle;
+ },
+ set: function(style) {
+ this._fillStyle = style;
+ this.record('setFillStyle', [style]);
+ }
+ },
+ lineCap: {
+ get: function() {
+ return this._lineCap;
+ },
+ set: function(cap) {
+ this._lineCap = cap;
+ this.record('setLineCap', [cap]);
+ }
+ },
+ lineDashOffset: {
+ get: function() {
+ return this._lineDashOffset;
+ },
+ set: function(offset) {
+ this._lineDashOffset = offset;
+ this.record('setLineDashOffset', [offset]);
+ }
+ },
+ lineJoin: {
+ get: function() {
+ return this._lineJoin;
+ },
+ set: function(join) {
+ this._lineJoin = join;
+ this.record('setLineJoin', [join]);
+ }
+ },
+ lineWidth: {
+ get: function() {
+ return this._lineWidth;
+ },
+ set: function(width) {
+ this._lineWidth = width;
+ this.record('setLineWidth', [width]);
+ }
+ },
+ strokeStyle: {
+ get: function() {
+ return this._strokeStyle;
+ },
+ set: function(style) {
+ this._strokeStyle = style;
+ this.record('setStrokeStyle', [style]);
+ }
+ },
+ });
+};
+
+Context.prototype._initMethods = function() {
+ // define methods to test here
+ // no way to introspect so we have to do some extra work :(
+ var me = this;
+ var methods = {
+ arc: function() {},
+ beginPath: function() {},
+ bezierCurveTo: function() {},
+ clearRect: function() {},
+ closePath: function() {},
+ fill: function() {},
+ fillRect: function() {},
+ fillText: function() {},
+ lineTo: function() {},
+ measureText: function(text) {
+ // return the number of characters * fixed size
+ return text ? {width: text.length * 10} : {width: 0};
+ },
+ moveTo: function() {},
+ quadraticCurveTo: function() {},
+ restore: function() {},
+ rotate: function() {},
+ save: function() {},
+ setLineDash: function() {},
+ stroke: function() {},
+ strokeRect: function() {},
+ setTransform: function() {},
+ translate: function() {},
+ };
+
+ Object.keys(methods).forEach(function(name) {
+ me[name] = function() {
+ me.record(name, arguments);
+ return methods[name].apply(me, arguments);
+ };
+ });
+};
+
+Context.prototype.record = function(methodName, args) {
+ this._calls.push({
+ name: methodName,
+ args: Array.prototype.slice.call(args)
+ });
+};
+
+Context.prototype.getCalls = function() {
+ return this._calls;
+};
+
+Context.prototype.resetCalls = function() {
+ this._calls = [];
+};
+
+module.exports = Context;
--- /dev/null
+var Context = require('./jasmine.context');
+var matchers = require('./jasmine.matchers');
+var utils = require('./jasmine.utils');
+
+(function() {
+
+ // Keep track of all acquired charts to automatically release them after each specs
+ var charts = {};
+
+ function acquireChart() {
+ var chart = utils.acquireChart.apply(utils, arguments);
+ charts[chart.id] = chart;
+ return chart;
+ }
+
+ function releaseChart(chart) {
+ utils.releaseChart.apply(utils, arguments);
+ delete charts[chart.id];
+ }
+
+ function createMockContext() {
+ return new Context();
+ }
+
+ window.acquireChart = acquireChart;
+ window.releaseChart = releaseChart;
+ window.createMockContext = createMockContext;
+
+ // some style initialization to limit differences between browsers across different plateforms.
+ utils.injectCSS(
+ '.chartjs-wrapper, .chartjs-wrapper canvas {' +
+ 'border: 0;' +
+ 'margin: 0;' +
+ 'padding: 0;' +
+ '}' +
+ '.chartjs-wrapper {' +
+ 'position: absolute' +
+ '}');
+
+ beforeEach(function() {
+ jasmine.addMatchers(matchers);
+ });
+
+ afterEach(function() {
+ // Auto releasing acquired charts
+ Object.keys(charts).forEach(function(id) {
+ var chart = charts[id];
+ if (!(chart.$test || {}).persistent) {
+ releaseChart(chart);
+ }
+ });
+ });
+}());
--- /dev/null
+'use strict';
+
+function toBeCloseToPixel() {
+ return {
+ compare: function(actual, expected) {
+ var result = false;
+
+ if (!isNaN(actual) && !isNaN(expected)) {
+ var diff = Math.abs(actual - expected);
+ var A = Math.abs(actual);
+ var B = Math.abs(expected);
+ var percentDiff = 0.005; // 0.5% diff
+ result = (diff <= (A > B ? A : B) * percentDiff) || diff < 2; // 2 pixels is fine
+ }
+
+ return {pass: result};
+ }
+ };
+}
+
+function toEqualOneOf() {
+ return {
+ compare: function(actual, expecteds) {
+ var result = false;
+ for (var i = 0, l = expecteds.length; i < l; i++) {
+ if (actual === expecteds[i]) {
+ result = true;
+ break;
+ }
+ }
+ return {
+ pass: result
+ };
+ }
+ };
+}
+
+function toBeValidChart() {
+ return {
+ compare: function(actual) {
+ var message = null;
+
+ if (!(actual instanceof Chart)) {
+ message = 'Expected ' + actual + ' to be an instance of Chart';
+ } else if (!(actual.canvas instanceof HTMLCanvasElement)) {
+ message = 'Expected canvas to be an instance of HTMLCanvasElement';
+ } else if (!(actual.ctx instanceof CanvasRenderingContext2D)) {
+ message = 'Expected context to be an instance of CanvasRenderingContext2D';
+ } else if (typeof actual.height !== 'number' || !isFinite(actual.height)) {
+ message = 'Expected height to be a strict finite number';
+ } else if (typeof actual.width !== 'number' || !isFinite(actual.width)) {
+ message = 'Expected width to be a strict finite number';
+ }
+
+ return {
+ message: message? message : 'Expected ' + actual + ' to be valid chart',
+ pass: !message
+ };
+ }
+ };
+}
+
+function toBeChartOfSize() {
+ return {
+ compare: function(actual, expected) {
+ var res = toBeValidChart().compare(actual);
+ if (!res.pass) {
+ return res;
+ }
+
+ var message = null;
+ var canvas = actual.ctx.canvas;
+ var style = getComputedStyle(canvas);
+ var pixelRatio = window.devicePixelRatio;
+ var dh = parseInt(style.height, 10);
+ var dw = parseInt(style.width, 10);
+ var rh = canvas.height;
+ var rw = canvas.width;
+ var orh = rh / pixelRatio;
+ var orw = rw / pixelRatio;
+
+ // sanity checks
+ if (actual.height !== orh) {
+ message = 'Expected chart height ' + actual.height + ' to be equal to original render height ' + orh;
+ } else if (actual.width !== orw) {
+ message = 'Expected chart width ' + actual.width + ' to be equal to original render width ' + orw;
+ }
+
+ // validity checks
+ if (dh !== expected.dh) {
+ message = 'Expected display height ' + dh + ' to be equal to ' + expected.dh;
+ } else if (dw !== expected.dw) {
+ message = 'Expected display width ' + dw + ' to be equal to ' + expected.dw;
+ } else if (rh !== expected.rh) {
+ message = 'Expected render height ' + rh + ' to be equal to ' + expected.rh;
+ } else if (rw !== expected.rw) {
+ message = 'Expected render width ' + rw + ' to be equal to ' + expected.rw;
+ }
+
+ return {
+ message: message? message : 'Expected ' + actual + ' to be a chart of size ' + expected,
+ pass: !message
+ };
+ }
+ };
+}
+
+module.exports = {
+ toBeCloseToPixel: toBeCloseToPixel,
+ toEqualOneOf: toEqualOneOf,
+ toBeValidChart: toBeValidChart,
+ toBeChartOfSize: toBeChartOfSize
+};
--- /dev/null
+/**
+ * Injects a new canvas (and div wrapper) and creates teh associated Chart instance
+ * using the given config. Additional options allow tweaking elements generation.
+ * @param {object} config - Chart config.
+ * @param {object} options - Chart acquisition options.
+ * @param {object} options.canvas - Canvas attributes.
+ * @param {object} options.wrapper - Canvas wrapper attributes.
+ * @param {boolean} options.persistent - If true, the chart will not be released after the spec.
+ */
+function acquireChart(config, options) {
+ var wrapper = document.createElement('div');
+ var canvas = document.createElement('canvas');
+ var chart, key;
+
+ config = config || {};
+ options = options || {};
+ options.canvas = options.canvas || {height: 512, width: 512};
+ options.wrapper = options.wrapper || {class: 'chartjs-wrapper'};
+
+ for (key in options.canvas) {
+ if (options.canvas.hasOwnProperty(key)) {
+ canvas.setAttribute(key, options.canvas[key]);
+ }
+ }
+
+ for (key in options.wrapper) {
+ if (options.wrapper.hasOwnProperty(key)) {
+ wrapper.setAttribute(key, options.wrapper[key]);
+ }
+ }
+
+ // by default, remove chart animation and auto resize
+ config.options = config.options || {};
+ config.options.animation = config.options.animation === undefined? false : config.options.animation;
+ config.options.responsive = config.options.responsive === undefined? false : config.options.responsive;
+ config.options.defaultFontFamily = config.options.defaultFontFamily || 'Arial';
+
+ wrapper.appendChild(canvas);
+ window.document.body.appendChild(wrapper);
+
+ chart = new Chart(canvas.getContext('2d'), config);
+ chart.$test = {
+ persistent: options.persistent,
+ wrapper: wrapper
+ };
+
+ return chart;
+}
+
+function releaseChart(chart) {
+ chart.destroy();
+
+ var wrapper = (chart.$test || {}).wrapper;
+ if (wrapper && wrapper.parentNode) {
+ wrapper.parentNode.removeChild(wrapper);
+ }
+}
+
+function injectCSS(css) {
+ // http://stackoverflow.com/q/3922139
+ var head = document.getElementsByTagName('head')[0];
+ var style = document.createElement('style');
+ style.setAttribute('type', 'text/css');
+ if (style.styleSheet) { // IE
+ style.styleSheet.cssText = css;
+ } else {
+ style.appendChild(document.createTextNode(css));
+ }
+ head.appendChild(style);
+}
+
+module.exports = {
+ injectCSS: injectCSS,
+ acquireChart: acquireChart,
+ releaseChart: releaseChart
+};
+++ /dev/null
-/* eslint guard-for-in: 1 */
-/* eslint camelcase: 1 */
-(function() {
- // Code from http://stackoverflow.com/questions/4406864/html-canvas-unit-testing
- var Context = function() {
- this._calls = []; // names/args of recorded calls
- this._initMethods();
-
- this._fillStyle = null;
- this._lineCap = null;
- this._lineDashOffset = null;
- this._lineJoin = null;
- this._lineWidth = null;
- this._strokeStyle = null;
-
- // Define properties here so that we can record each time they are set
- Object.defineProperties(this, {
- fillStyle: {
- get: function() {
- return this._fillStyle;
- },
- set: function(style) {
- this._fillStyle = style;
- this.record('setFillStyle', [style]);
- }
- },
- lineCap: {
- get: function() {
- return this._lineCap;
- },
- set: function(cap) {
- this._lineCap = cap;
- this.record('setLineCap', [cap]);
- }
- },
- lineDashOffset: {
- get: function() {
- return this._lineDashOffset;
- },
- set: function(offset) {
- this._lineDashOffset = offset;
- this.record('setLineDashOffset', [offset]);
- }
- },
- lineJoin: {
- get: function() {
- return this._lineJoin;
- },
- set: function(join) {
- this._lineJoin = join;
- this.record('setLineJoin', [join]);
- }
- },
- lineWidth: {
- get: function() {
- return this._lineWidth;
- },
- set: function(width) {
- this._lineWidth = width;
- this.record('setLineWidth', [width]);
- }
- },
- strokeStyle: {
- get: function() {
- return this._strokeStyle;
- },
- set: function(style) {
- this._strokeStyle = style;
- this.record('setStrokeStyle', [style]);
- }
- },
- });
- };
-
- Context.prototype._initMethods = function() {
- // define methods to test here
- // no way to introspect so we have to do some extra work :(
- var methods = {
- arc: function() {},
- beginPath: function() {},
- bezierCurveTo: function() {},
- clearRect: function() {},
- closePath: function() {},
- fill: function() {},
- fillRect: function() {},
- fillText: function() {},
- lineTo: function() {},
- measureText: function(text) {
- // return the number of characters * fixed size
- return text ? {width: text.length * 10} : {width: 0};
- },
- moveTo: function() {},
- quadraticCurveTo: function() {},
- restore: function() {},
- rotate: function() {},
- save: function() {},
- setLineDash: function() {},
- stroke: function() {},
- strokeRect: function() {},
- setTransform: function() {},
- translate: function() {},
- };
-
- // attach methods to the class itself
- var me = this;
- var methodName;
-
- var addMethod = function(name, method) {
- me[methodName] = function() {
- me.record(name, arguments);
- return method.apply(me, arguments);
- };
- };
-
- for (methodName in methods) {
- var method = methods[methodName];
-
- addMethod(methodName, method);
- }
- };
-
- Context.prototype.record = function(methodName, args) {
- this._calls.push({
- name: methodName,
- args: Array.prototype.slice.call(args)
- });
- };
-
- Context.prototype.getCalls = function() {
- return this._calls;
- };
-
- Context.prototype.resetCalls = function() {
- this._calls = [];
- };
-
- window.createMockContext = function() {
- return new Context();
- };
-
- // Custom matcher
- function toBeCloseToPixel() {
- return {
- compare: function(actual, expected) {
- var result = false;
-
- if (!isNaN(actual) && !isNaN(expected)) {
- var diff = Math.abs(actual - expected);
- var A = Math.abs(actual);
- var B = Math.abs(expected);
- var percentDiff = 0.005; // 0.5% diff
- result = (diff <= (A > B ? A : B) * percentDiff) || diff < 2; // 2 pixels is fine
- }
-
- return {pass: result};
- }
- };
- }
-
- function toEqualOneOf() {
- return {
- compare: function(actual, expecteds) {
- var result = false;
- for (var i = 0, l = expecteds.length; i < l; i++) {
- if (actual === expecteds[i]) {
- result = true;
- break;
- }
- }
- return {
- pass: result
- };
- }
- };
- }
-
- function toBeValidChart() {
- return {
- compare: function(actual) {
- var message = null;
-
- if (!(actual instanceof Chart)) {
- message = 'Expected ' + actual + ' to be an instance of Chart';
- } else if (!(actual.canvas instanceof HTMLCanvasElement)) {
- message = 'Expected canvas to be an instance of HTMLCanvasElement';
- } else if (!(actual.ctx instanceof CanvasRenderingContext2D)) {
- message = 'Expected context to be an instance of CanvasRenderingContext2D';
- } else if (typeof actual.height !== 'number' || !isFinite(actual.height)) {
- message = 'Expected height to be a strict finite number';
- } else if (typeof actual.width !== 'number' || !isFinite(actual.width)) {
- message = 'Expected width to be a strict finite number';
- }
-
- return {
- message: message? message : 'Expected ' + actual + ' to be valid chart',
- pass: !message
- };
- }
- };
- }
-
- function toBeChartOfSize() {
- return {
- compare: function(actual, expected) {
- var res = toBeValidChart().compare(actual);
- if (!res.pass) {
- return res;
- }
-
- var message = null;
- var canvas = actual.ctx.canvas;
- var style = getComputedStyle(canvas);
- var pixelRatio = window.devicePixelRatio;
- var dh = parseInt(style.height, 10);
- var dw = parseInt(style.width, 10);
- var rh = canvas.height;
- var rw = canvas.width;
- var orh = rh / pixelRatio;
- var orw = rw / pixelRatio;
-
- // sanity checks
- if (actual.height !== orh) {
- message = 'Expected chart height ' + actual.height + ' to be equal to original render height ' + orh;
- } else if (actual.width !== orw) {
- message = 'Expected chart width ' + actual.width + ' to be equal to original render width ' + orw;
- }
-
- // validity checks
- if (dh !== expected.dh) {
- message = 'Expected display height ' + dh + ' to be equal to ' + expected.dh;
- } else if (dw !== expected.dw) {
- message = 'Expected display width ' + dw + ' to be equal to ' + expected.dw;
- } else if (rh !== expected.rh) {
- message = 'Expected render height ' + rh + ' to be equal to ' + expected.rh;
- } else if (rw !== expected.rw) {
- message = 'Expected render width ' + rw + ' to be equal to ' + expected.rw;
- }
-
- return {
- message: message? message : 'Expected ' + actual + ' to be a chart of size ' + expected,
- pass: !message
- };
- }
- };
- }
-
- beforeEach(function() {
- jasmine.addMatchers({
- toBeCloseToPixel: toBeCloseToPixel,
- toEqualOneOf: toEqualOneOf,
- toBeValidChart: toBeValidChart,
- toBeChartOfSize: toBeChartOfSize
- });
- });
-
- // Canvas injection helpers
- var charts = {};
-
- /**
- * Injects a new canvas (and div wrapper) and creates teh associated Chart instance
- * using the given config. Additional options allow tweaking elements generation.
- * @param {object} config - Chart config.
- * @param {object} options - Chart acquisition options.
- * @param {object} options.canvas - Canvas attributes.
- * @param {object} options.wrapper - Canvas wrapper attributes.
- * @param {boolean} options.persistent - If true, the chart will not be released after the spec.
- */
- function acquireChart(config, options) {
- var wrapper = document.createElement('div');
- var canvas = document.createElement('canvas');
- var chart, key;
-
- config = config || {};
- options = options || {};
- options.canvas = options.canvas || {height: 512, width: 512};
- options.wrapper = options.wrapper || {class: 'chartjs-wrapper'};
-
- for (key in options.canvas) {
- if (options.canvas.hasOwnProperty(key)) {
- canvas.setAttribute(key, options.canvas[key]);
- }
- }
-
- for (key in options.wrapper) {
- if (options.wrapper.hasOwnProperty(key)) {
- wrapper.setAttribute(key, options.wrapper[key]);
- }
- }
-
- // by default, remove chart animation and auto resize
- config.options = config.options || {};
- config.options.animation = config.options.animation === undefined? false : config.options.animation;
- config.options.responsive = config.options.responsive === undefined? false : config.options.responsive;
- config.options.defaultFontFamily = config.options.defaultFontFamily || 'Arial';
-
- wrapper.appendChild(canvas);
- window.document.body.appendChild(wrapper);
-
- chart = new Chart(canvas.getContext('2d'), config);
- chart._test_persistent = options.persistent;
- chart._test_wrapper = wrapper;
- charts[chart.id] = chart;
- return chart;
- }
-
- function releaseChart(chart) {
- chart.destroy();
- chart._test_wrapper.remove();
- delete charts[chart.id];
- }
-
- afterEach(function() {
- // Auto releasing acquired charts
- for (var id in charts) {
- var chart = charts[id];
- if (!chart._test_persistent) {
- releaseChart(chart);
- }
- }
- });
-
- function injectCSS(css) {
- // http://stackoverflow.com/q/3922139
- var head = document.getElementsByTagName('head')[0];
- var style = document.createElement('style');
- style.setAttribute('type', 'text/css');
- if (style.styleSheet) { // IE
- style.styleSheet.cssText = css;
- } else {
- style.appendChild(document.createTextNode(css));
- }
- head.appendChild(style);
- }
-
- window.acquireChart = acquireChart;
- window.releaseChart = releaseChart;
-
- // some style initialization to limit differences between browsers across different plateforms.
- injectCSS(
- '.chartjs-wrapper, .chartjs-wrapper canvas {' +
- 'border: 0;' +
- 'margin: 0;' +
- 'padding: 0;' +
- '}' +
- '.chartjs-wrapper {' +
- 'position: absolute' +
- '}');
-}());