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 がサービスとして注入されずにグローバルとして使用されていることがわかるため、質問の 1 つは、bower リポジトリがない場合にサードパーティ ライブラリをこのように使用することが正しいかどうかです。 .
この行が問題を引き起こしていると思います
...
$scope.chart = new CanvasJS.Chart('chartContainer', {
...
コントローラービューには「chartContainer」IDが含まれています
<div id="chartContainer"></div>
app/scripts/controllers/main.js 'use strict';
/*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 'use strict';
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 を実行できるようになりました:)