使用 RequireJS 运行 Karma + Jasmine 测试——起步
帮助! . . . _ _ _ 。 . .求救!
目前,我有一个练习项目来熟悉 KarmaJS —— 以及整个单元测试。广泛的问题是,我真的对 Karma 在幕后所做的事情没有透明的看法,而且我似乎无法在相关领域找到足够的文档。事不宜迟……
这是我的文件夹结构 :
root
|-/lib
|-/[dependencies] (/angular, /angular-mocks, /bootstrap, /etc) # from bower
|-/src
|-/[unreferenced directories] (/js, /css, /views) # not referenced anywhere
|-app.js # sets up angular.module('app', ...)
|-globals.js # may be referenced in RequireJS main file; not used.
|-index.html # loads bootstrap.css and RequireJS main file
|-main.js # .config + require(['app', 'etc'])
|-routeMap.js # sets up a single route
|-test-file.js # *** simple define(function(){ return {...}; })
|-/test
|-/spec
|-test-test-file.js # *** require || define(['test-file'])
|-.bowerrc # { "directory": "lib" }
|-bower.json # standard format
|-karma.conf.js # *** HELP!
|-test-main.js # *** Save Our Souls!!!
karma .conf.js
// Karma configuration
// Generated on Wed Nov 19 2014 15:16:56 GMT-0700 (Mountain Standard Time)
module.exports = function(config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['jasmine', 'requirejs'],
// list of files / patterns to load in the browser
files: [
//'test/spec/test-test-file.js',
//'lib/**/*.js',
//'src/**/*.js',
//'test/spec/**/*.js',
'test-main.js',
{pattern: 'lib/**/*.js', included: false},
{pattern: 'src/**/*.js', included: false},
{pattern: 'test/spec/*.js', included: true}
],
// list of files to exclude
exclude: [
'lib/**/!(angular|angular-mocks|angular-resource|angular-route|require|text).js',
'lib/**/**/!(jquery|bootstrap).js',
'src/app.js'
],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['progress'],
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ['Chrome'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: false
});
};
test-main.js var allTestFiles = [];
var TEST_REGEXP = /(spec|test)\.js$/i;
var pathToModule = function(path) {
return path.replace(/^\/base\//, '').replace(/\.js$/, '');
};
Object.keys(window.__karma__.files).forEach(function(file) {
if (TEST_REGEXP.test(file)) {
// Normalize paths to RequireJS module names.
allTestFiles.push(pathToModule(file));
}
});
require.config({
// Karma serves files under /base, which is the basePath from your config file
baseUrl: '/base/src',
paths: {
angular: '../lib/angular/angular',
ngRoute: '../lib/angular-route/angular-route',
jquery: '../lib/jQuery/dist/jquery',
bootstrap: '../lib/bootstrap/dist/js/bootstrap',
models: 'models',
controllers: 'controllers',
globals: 'globals',
routeMap: 'routeMap'
},
shim: {
angular: {
exports: 'angular'
},
ngRoute: {
deps: ['angular']
},
jquery: {
exports: '$'
},
bootstrap: {
deps: ['jquery']
}
},
// dynamically load all test files
deps: allTestFiles,
// we have to kickoff jasmine, as it is asynchronous
callback: window.__karma__.start
});
测试测试文件.js console.log('....................');
define(function(){
//console.log('testing test-file', testFile);
describe('Testing testing', function(){
it('should work', function(){
expect(true).toEqual(true);
});
});
});
测试文件.js define('testFile', [], function(){
return function init(sandbox){
var app, application = app = sandbox.app
, globals = sandbox.globals;
return {
some: 'module'
};
};
});
问题和说明
我很想听到答案的关键点是
我收到错误和问题的时间是在我将规范包装在
define(...)
中时call -- 当我给模块一个 ID 时的事件 -- define('someId', function(){ ... })
-- 我需要从这个模块中返回一些东西吗,因为它是 define
称呼?其他时候,我会收到“ol ERROR: 'There is no timestamp for/base/src/app.js!”。 “当然是时间戳!我真是太傻了……”——这到底是什么意思?!有时我会得到臭名昭著的“Executed 0 of 0 ERROR”——我也可以在这里澄清一下。真的,我收到很多 ERROR: '...no timestamp...' 错误——甚至是
404
s 似乎我应该使用 karma.conf.js files
拉入该库配置...???甚至似乎通常当我明确告诉 karma 排除
src/app.js
我仍然得到 404
s 和错误。tl;博士
显然,我对 Karma 和 *DD 大体上有点困惑......
我可以运行
test-test-file.js
很好,当我的 karma.conf.js files
数组看起来像 [ 'test-main.js', 'test/spec/test-test-file.js' ]
-- 但是,如果我将测试包装在 RequireJS 定义调用中,我会得到上面提到的“不匹配匿名定义()”错误。似乎当我添加 { pattern: '...', include: 假 } 那么 karma 就不会为给定的模式添加我的任何文件(???)。
如果有人甚至可以简单地指导我如何将 RequireJS 与 Karma 一起使用——也就是说,我可以将我的测试包装在一个 define/require 调用中并拉入我想要测试的模块......那将不胜感激。
由于保持这些类型的问题简短并仍然提供足够的信息有点困难,我希望我没有把它弄得太长。
编辑
在阅读了 glepretre 的答案和我自己的一些摆弄之后,我重新配置了我的项目,如下所示:
test-main.js
至test/test-main.js
, test/spec
移出至test/
, karma.conf.js:
...
// list of files / patterns to load in the browser
files: [
{pattern: 'lib/**/*.js', included: false},
{pattern: 'src/**/*.js', included: false},
{pattern: 'test/**/*Spec.js', included: false},
'test/test-main.js'
],
....
测试/test-main.js: /* **************** HOW COME THE DEFAULT (Karma-generated) CONFIGURATION DOES ***NOT WORK???
var allTestFiles = [];
var TEST_REGEXP = /(spec|test)\.js$/i;
var pathToModule = function(path) {
return path.replace(/^\/base\//, '').replace(/\.js$/, '');
};
Object.keys(window.__karma__.files).forEach(function(file) {
if (TEST_REGEXP.test(file)) {
// Normalize paths to RequireJS module names.
allTestFiles.push(pathToModule(file));
}
});
*/
var tests = [];
for (var file in window.__karma__.files) {
if (/Spec\.js$/.test(file)) {
tests.push(file);
}
}
require.config({
// Karma serves files under /base, which is the basePath from your config file
baseUrl: '/base/src',
paths: {},
shim: {},
// dynamically load all test files
//deps: allTestFiles,
//
deps: tests,
// we have to kickoff jasmine, as it is asynchronous
callback: window.__karma__.start
});
我现在正在成功运行单元测试!特别感谢 glepretre 和所有其他贡献者。 感谢您的任何见解:)
最佳答案
好的,我将尝试一次解决每个问题:
问题1
- what does { pattern: '...', included: true|false } do?
Karma 的默认行为是:
pattern
(强制属性) watched
选项),以便在编辑代码时重新启动单元测试以提供实时结果(只有将默认值 autoWatch
保留为 true
时才有效)。 served
选项) <script>
将它们包含在浏览器中( included
选项) 因此,在 karma 配置的
files
数组中,您可以通过仅添加字符串模式来使用默认行为:files: [
// this will match all your JS files
// in the src/ directory and subdirectories
'src/**/*.js'
]
或者使用完整的对象语法来自定义每个选项:files: [
{pattern: 'src/**/*.js', watched: true, served: true, included: false}
]
使用 requireJS,你不希望它们被包含,因为它会与 requireJS 的行为冲突!Included. Description: Should the files be included in the browser using
<script>
tag? Use false if you want to load them manually, eg. using Require.js.
从 karma/config/files docs
注意:注意在数组中添加文件/模式的顺序。很重要!如需更多了解,请在您的 karma 配置中设置
logLevel: config.LOG_DEBUG
。问题2
- what files do I need to include in the karma.conf.js file?
至少为单元测试的组件正常运行所需的所有文件。
基本上,您的
define([])
和 require()
block 中列出的所有文件。问题3
- best way to exclude all the extra stuff inside the bower directories.
你到底想做什么?
根据我之前写的内容,您可以看到您可以选择性地添加测试中需要的文件。
当我的凉亭包使用模板时,我使用添加模式
'/bower_components/**/*.js'
甚至 '/bower_components/**/*.html'
。如果这是您所担心的,我从未注意到任何重大的性能问题......由您来定义您需要的文件模式。问题 4 & 5
what does test-main.js actually do; what's it for?
what files do I need to include in the test-main.js file?
test-main.js
文件的目的是在启动 Karma 之前查找并加载您的测试文件。它连接了 Karma 和 requireJS 之间的点您必须选择一个约定来命名您的测试文件,然后定义
TEST_REGEXP
以匹配所有这些文件。“官方” angular style guide and best practices for app structure 建议使用后缀
*_test.js
。编辑:您的正则表达式不起作用,因为它被定义为在末尾捕获
"spec.js" || "test.js"
或您的规范文件名以 "file.js"
结尾;)请参阅 http://regex101.com/r/bE9tV9/1还有一件事
我希望我足够清楚。您可以使用 Angular + Require: angular-requirejs-ready 查看我们项目的入门应用程序结构。它已经使用 Karma 和 Protractor 进行了设置和测试。
关于unit-testing - KarmaJS、Jasmine、RequireJS 等 : How to Use Require for Testing Modules,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27050180/