我正在尝试在使用 Yeoman 搭建的 AngularJS 应用程序中运行单元测试。我尝试运行的唯一测试只是检查数组是否具有正确的长度但由于与 CanvasJS 相关的某些原因而失败
这里的日志
LOG: 'CanvasJS Error: Chart Container with id "chartContainer" was not found'
PhantomJS 1.9.7 (Windows 7) Controller: MainCtrl should attach a list of inputs to the scope FAILED
TypeError: 'undefined' is not an object (evaluating 'this._toolBar.appendChild')
at /path/to/Chart/app/scripts/vendor/canvasjs-1.5.0-beta/source/canvasjs.js:1799
at /path/to/Chart/app/scripts/vendor/canvasjs-1.5.0-beta/source/canvasjs.js:1919
at /path/to/Chart/app/scripts/vendor/canvasjs-1.5.0-beta/source/canvasjs.js:2093
at /path/to/Chart/app/scripts/vendor/canvasjs-1.5.0-beta/source/canvasjs.js:12551
at /path/to/Chart/app/scripts/controllers/main.js:101
at invoke (/path/to/Chart/app/bower_components/angular/angular.js:3869)
at instantiate (/path/to/Chart/app/bower_components/angular/angular.js:3880)
at /path/to/Chart/app/bower_components/angular/angular.js:7134
at /path/to/Chart/test/spec/controllers/main.js:15
at invoke (/path/to/Chart/app/bower_components/angular/angular.js:3869)
at workFn (/path/to/Chart/app/bower_components/angular-mocks/angular-mocks.js:2147)
undefined
Expected 0 to be 3.
PhantomJS 1.9.7 (Windows 7): Executed 1 of 1 (1 FAILED) ERROR (0.025 secs / 0.021 secs)
Warning: Task "karma:unit" failed. Use --force to continue.
该应用程序可以在这里找到https://github.com/kaiohken1982/Chart
我不确定我是否在 AngularJS 应用程序中正确实现了这个库,我们将不胜感激。
谢谢
------------------- 编辑 #1 --------------------
下面的一些代码可以更好地理解场景,正如您所看到的,CanvasJS 被用作全局而不是作为服务注入,所以问题之一是如果没有凉亭回购,以这种方式使用第三方库是否正确.
我认为这条线导致了这个问题
...
$scope.chart = new CanvasJS.Chart('chartContainer', {
...
控制器视图包含“chartContainer” id
<div id="chartContainer"></div>
app/scripts/controllers/main.js '使用严格';
/*global CanvasJS:false */
/**
* @ngdoc function
* @name ngprojectApp.controller:MainCtrl
* @description
* # MainCtrl
* Controller of the ngprojectApp
*/
angular.module('ChartApp')
.controller('MainCtrl', function ($scope) {
// Regexp to ensure that input dates are in the required format
$scope.dateRegexp = /^(January|February|March|April|June|July|August|Semptember|October|November|December)[ ](0[1-9]|1[0-9]|2[0-9]|3[0-1])[ ](19|20)\d{2}$/i;
// Called to remove an entry
$scope.removeInput = function (index) {
$scope.inputs.splice(index, 1);
};
// Called to add an entry
$scope.addRow = function () {
$scope.inputs.push($scope.value);
$scope.value = '';
};
$scope.predicate = '';
$scope.reverse = false;
$scope.inputs = [];
$scope.updateMyText = function() {};
// Chart below
var datapoints = [];
var chartPoint = null;
$scope.canEdit = true;
$scope.editMode = false;
$scope.units = 1; // increase or decrease bar value by this unit
$scope.chart = new CanvasJS.Chart('chartContainer', {
theme: 'theme1',
interactivityEnabled: true,
title:{
text: 'Website response time'
},
axisY: {
title: 'ms',
labelFontSize: 16,
},
axisX: {
title: 'timeline',
labelFontSize: 16,
gridThickness: 1
},
data: [
{
click: function() {
$scope.$apply(function() {
if($scope.canEdit) {
$scope.editMode = !$scope.editMode;
}
});
if($scope.editMode) {
console.log('EditMode is now TRUE');
}
if(!$scope.editMode) {
console.log('EditMode is now FALSE');
}
},
mousemove: function(e) {
if(!$scope.editMode) {
chartPoint = null;
return false;
}
// First point? Assign it and return
if(null === chartPoint) {
chartPoint = e;
return false;
}
// Update inputs at the correct index will re-render graph and table data
$scope.$apply(function() {
var diffY = e.y - chartPoint.y; // if it is > 0 means that the mouse pointer went UP
var time = diffY < 0 ? e.dataPoint.y+$scope.units : e.dataPoint.y-$scope.units;
$scope.inputs[e.dataPointIndex].time = time;
// Update chartPoint
chartPoint = e;
});
},
type: 'column',
dataPoints: []
}
]
});
$scope.chart.render(); //render the chart for the first time
$scope.changeChartType = function(chartType) {
$scope.canEdit = 'column' === chartType;
$scope.editMode = false; // disable EditMode whatever the type is
$scope.chart.options.data[0].dataPoints = datapoints;
$scope.chart.options.data[0].type = chartType;
$scope.chart.render(); //re-render the chart to display the new layout
};
// DEEP watch for any changes in the array
$scope.$watch('inputs', function() {
datapoints = [];
for(var i in $scope.inputs) {
var e = $scope.inputs[i];
// update the timestamp for the value
var d = new Date(e.date);
e.timestamp = d.valueOf() / 1000;
datapoints.push({
'label': e.url,
x: new Date(e.date),
y: e.time
});
}
// Reassign data to chart
$scope.chart.options.data[0].dataPoints = datapoints;
$scope.chart.render();
}, true);
$scope.inputs.push({
date: 'January 02 2014',
url: 'http://uno.it',
time: 111
});
$scope.inputs.push({
date: 'January 12 2014',
url: 'http://due.it',
time: 292
});
$scope.inputs.push({
date: 'January 22 2014',
url: 'http://tre.it',
time: 333
});
});
test/spec/controllers/main.js '使用严格';
describe('Controller: MainCtrl', function () {
// load the controller's module
beforeEach(module('ChartApp'));
var MainCtrl,
scope;
// Initialize the controller and a mock scope
beforeEach(inject(function ($controller, $rootScope) {
scope = $rootScope.$new();
MainCtrl = $controller('MainCtrl', {
$scope: scope
});
}));
it('should attach a list of inputs to the scope ', function () {
expect(scope.inputs.length).toBe(3);
});
});
Karma.conf.js 有所有必需的文件,我想......
....
files: [
'app/bower_components/angular/angular.js',
'app/bower_components/angular-mocks/angular-mocks.js',
'app/bower_components/angular-animate/angular-animate.js',
'app/bower_components/angular-cookies/angular-cookies.js',
'app/bower_components/angular-resource/angular-resource.js',
'app/bower_components/angular-route/angular-route.js',
'app/bower_components/angular-sanitize/angular-sanitize.js',
'app/bower_components/angular-touch/angular-touch.js',
'app/bower_components/jquery/dist/jquery.js',
'app/bower_components/angular-ui/build/angular-ui.js',
'app/bower_components/jquery-ui/jquery-ui.js',
'app/scripts/vendor/canvasjs-1.5.0-beta/canvasjs.min.js',
'app/scripts/directives/directive.js',
'app/scripts/**/*.js',
'test/mock/**/*.js',
'test/spec/**/*.js'
],
...
------------------- 编辑 #2 --------------------
这就是我在收到建议后编辑 main.js 测试的方式
beforeEach(inject(function ($controller, $rootScope, $compile) {
var htmlString = '' +
'<div ng-controller="MainCtrl">' +
' <div id="chartContainer">' +
'</div>'
;
var element = angular.element(htmlString)
scope = $rootScope.$new();
$compile(element)(scope);
scope.$digest();
MainCtrl = $controller('MainCtrl', {
$scope: scope
});
}));
错误几乎一样
LOG: 'CanvasJS Error: Chart Container with id "chartContainer" was not found'
PhantomJS 1.9.7 (Windows 7) Controller: MainCtrl should attach a list of inputs to the scope FAILED
TypeError: 'undefined' is not an object (evaluating 'this._toolBar.appendChild')
at /path/to/workspace/Chart/app/scripts/vendor/canvasjs-1.5.0-beta/source/canvasjs.js:1799
at /path/to/workspace/Chart/app/scripts/vendor/canvasjs-1.5.0-beta/source/canvasjs.js:1919
at /path/to/workspace/Chart/app/scripts/vendor/canvasjs-1.5.0-beta/source/canvasjs.js:2093
at /path/to/workspace/Chart/app/scripts/vendor/canvasjs-1.5.0-beta/source/canvasjs.js:12551
at /path/to/workspace/Chart/app/scripts/controllers/main.js:101
at invoke (/path/to/workspace/Chart/app/bower_components/angular/angular.js:3869)
at instantiate (/path/to/workspace/Chart/app/bower_components/angular/angular.js:3880)
at /path/to/workspace/Chart/app/bower_components/angular/angular.js:7134
at /path/to/workspace/Chart/app/bower_components/angular/angular.js:6538
at forEach (/path/to/workspace/Chart/app/bower_components/angular/angular.js:330)
at nodeLinkFn (/path/to/workspace/Chart/app/bower_components/angular/angular.js:6552)
at compositeLinkFn (/path/to/workspace/Chart/app/bower_components/angular/angular.js:5986)
at publicLinkFn (/path/to/workspace/Chart/app/bower_components/angular/angular.js:5891)
at /path/to/workspace/Chart/test/spec/controllers/main.js:20
at invoke (/path/to/workspace/Chart/app/bower_components/angular/angular.js:3869)
at workFn (/path/to/workspace/Chart/app/bower_components/angular-mocks/angular-mocks.js:2147)
undefined
TypeError: 'undefined' is not an object (evaluating 'scope.inputs.length')
at /path/to/workspace/Chart/test/spec/controllers/main.js:28
PhantomJS 1.9.7 (Windows 7): Executed 1 of 1 (1 FAILED) ERROR (0.029 secs / 0.028 secs)
Warning: Task "karma:unit" failed. Use --force to continue.
更新测试控制器时我是否弄错了什么?
------------------- 编辑#3 --------------------
在 Ivarni 的宝贵帮助下,我最终得到了这个解决方案:
在应用程序控制器中
...
$scope.chart = new $window.CanvasJS.Chart('chartContainer', {
...
在控制器测试中
...
beforeEach(inject(function ($controller, $rootScope, $compile, $window) {
$window.CanvasJS = { Chart: function(){
this.render = function() {};
} };
...
现在可以模拟 CanvasJS 并且可以运行 UnitTest :)