configurationKarma使用requirejs加载pegjs

尝试使用PegJS和requirejs来testing一个项目。 我有几个源文件,作为通过require API加载的AMD模块(define)实现。 在目录结构下面:

js/ somefile.js main.js parser.js test/ parser.spec.js 

我写了一个parser.js模块来加载一个PegJS语法文件,并使用PegJS创build一个peg分析器:

 define(function() { 'use strict'; var PEG = require('pegjs'); var grammarFile = 'grammar.peg' return { parse: function(fs, content, debug) { var grammar = fs.readFileSync(grammarFile, 'utf8').toString(); // Build parser from grammar var parser = PEG.buildParser(grammar, { trace: debug }); [...] 

这与一个main.js在节点的命令行上执行正常工作。 现在我想用业力,茉莉花和PhantomJS来testing我的项目。 我有这样一个karma.conf.js

 frameworks: ['jasmine', 'requirejs'], files: [ { pattern: './test/**/*.spec.js', included: false }, { pattern: './js/**/*.js', included: false}, './test/test-main.js', ], 

还有一个名为test-main.js的需要引导文件,这个文件是这样configuration的:

 'use strict'; var allTestFiles = []; var TEST_REGEXP = /(spec|test)\.js$/i; // Get a list of all the test files to include Object.keys(window.__karma__.files).forEach(function(file) { console.log(file); if (TEST_REGEXP.test(file)) { // Normalize paths to RequireJS module names. // If you require sub-dependencies of test files to be loaded as-is (requiring file extension) // then do not normalize the paths var normalizedTestModule = file.replace(/^\/base\/|\.js$/g, ''); allTestFiles.push(file); } }); require.config({ // Karma serves files under /base, which is the basePath from your config file baseUrl: '/base/js', // dynamically load all test files deps: allTestFiles, // we have to kickoff jasmine, as it is asynchronous callback: window.__karma__.start }); 

现在,当我启动我的testing( grunt karma )时,我得到这个错误:

 PhantomJS 1.9.8 (Linux 0.0.0) ERROR: Error{message: 'Module name "pegjs" has not been loaded yet for context: _. Use require([]) 

所以我尝试在Karma加载的文件中包含pegjs karma.conf.js

 files: [ { pattern: 'node_modules/pegjs/lib/**/*.js', included: true }, { pattern: './test/**/*.spec.js', included: false }, { pattern: './js/**/*.js', included: false}, './test/test-main.js' ], 

当我这样做,我仍然得到一个错误:

 Error: Module name "utils/arrays" has not been loaded yet for context: _. Use require([]) 

查看pegjs模块,确实有一个arrays.js文件:

 compiler/ compiler.js grammar-error.js parser.js peg.js utils/ arrays.js classes.js objects.js 

所以试图包括数组:

 files: [ { pattern: 'node_modules/pegjs/lib/utils/arrays.js', included: true }, { pattern: 'node_modules/pegjs/lib/**/*.js', included: true }, { pattern: './test/**/*.spec.js', included: false }, { pattern: './js/**/*.js', included: false}, './test/test-main.js' ], 

我得到:

 ReferenceError: Can't find variable: module at /blabla/node_modules/pegjs/lib/utils/arrays.js:108 

因为:

 108 module.exports = arrays; 

所以,加载npm模块的intead,我试图用这种方式加载bower模块:

 files: [ { pattern: 'bower_components/pegjs/peg-0.9.0.js', included: true }, { pattern: './test/**/*.spec.js', included: false }, { pattern: './js/**/*.js', included: false}, './test/test-main.js' ], 

你又来了

 PhantomJS 1.9.8 (Linux 0.0.0) ERROR: Error{message: 'Module name "pegjs" has not been loaded yet for context: _. Use require([]) 

还试图不包括pegjs在业力生成的网页:

 files: [ { pattern: 'bower_components/pegjs/peg-0.9.0.js', included: false }, { pattern: './test/**/*.spec.js', included: false }, { pattern: './js/**/*.js', included: false}, './test/test-main.js' ], 

但是它失败了:

 PhantomJS 1.9.8 (Linux 0.0.0) ERROR: 'There is no timestamp for /base/bower_components/pegjs/peg-0.9.0!' 

试图把bower_component文件夹里面的js文件夹,但没有运气。

所以我不知道要从这里出发…在Google或这里找不到任何相关的东西。 这似乎是一个具体的问题,要求与业力要求/ pegjs …任何想法是值得欢迎的。

更新以下dan的答案:

所以我从parser.js中的同步需求切换到asynchronous需求:

 define(['../bower_components/pegjs/peg-0.9.0'], function(PEG) { 'use strict'; var grammarFile = 'grammar.peg' return { parse: function(fs, content, debug) { var grammar = fs.readFileSync(grammarFile, 'utf8').toString(); // Build parser from grammar var parser = PEG.buildParser(grammar, { trace: debug }); [...] 

试图在karma.conf.js中包含pegjs bower组件:

 { pattern: 'bower_components/pegjs/peg-0.9.0.js', included: false }, 

或不包括它:

 { pattern: 'bower_components/pegjs/peg-0.9.0.js', included: true }, 

但总是得到同样的错误:

 Error: Script error for "/blabla/bower_components/pegjs/peg-0.9.0", needed by: /blabla/js/parser.js http://requirejs.org/docs/errors.html#scripterror at /blabla/node_modules/requirejs/require.js:140 

是的,文件存在:

 $ file /home/aa024149/share/logofrjs/bower_components/pegjs/peg-0.9.0.js /blabla/bower_components/pegjs/peg-0.9.0.js: ASCII text, with very long lines 

UPDATE2 :最后了解并find了一个可接受的解决scheme。

这听起来像你正在通过requirejs加载pegjs。 如果是这样的话,pegjs不应该是包含的文件。 在你的karma.conf.js中,你是否尝试过以下方法:

 files: [ { pattern: 'bower_components/pegjs/peg-0.9.0.js', included: false }, { pattern: './test/**/*.spec.js', included: false }, { pattern: './js/**/*.js', included: false}, './test/test-main.js' ], 

包含的值指示karma服务器生成的网页是否应该具有该文件的脚本标记(请参阅http://karma-runner.github.io/0.13/config/files.html )。 所以你的karma.config:

 files: [ { pattern: 'bower_components/pegjs/peg-0.9.0.js', included: true }, { pattern: './test/**/*.spec.js', included: false }, { pattern: './js/**/*.js', included: false}, './test/test-main.js' ], 

会导致业力产生一个类似于头标签的网页:

 <head> <script src="/base/bower_components/pegjs/peg-0.9.0.js"></script> <script src="/base/require.js"></script> <script src="/base/test/test-main.js"></script> </head> 

根据我的经验,我已经看到了很多类似这样的行为,这是由于我的文件被标记为included: true 。 如果有一个文件正在尝试加载requirejs,请确保它被标记为included: false

我相信这标志着它的前处理工作,但我不完全确定这是为什么这样做的差异。

据我所知,Karma是一个testing框架,它将在浏览器中运行你的testing。

这不适用于testing许多节点模块。

浏览器不具备同步执行此操作的function: var PEG = require('pegjs') 。 这就是为什么它要求您在pegjs加载完成时使用传递callback的require([])来执行。

使用pegjs的bower版本并确保它在require('pegjs')被调用之前加载可能require('pegjs')有所帮助。 这将确保pegjs已经加载上下文_(默认的requirejs上下文,我假设)。

它也无法使用fs.readFileSync(grammarFile, 'utf8')从文件系统加载文件,因此您必须以另一种方式进行操作。 你可以让Karma把你的peg语法放在文件数组中,然后使用requirejs文本插件加载它。

如果您正在testing的模块旨在运行在node.js而不是浏览器上,那么它可能更适合使用不在浏览器中运行代码的testing框架,而是在节点中运行它,节点模块可供您使用。 如果你正在瞄准浏览器,我会重写它更具体的目标浏览器。

所以在dan和pieceOpiland的各种答案和评论的帮助下,我终于find了一个我想做的事情。

首先,pegjs和许多javascript库一样有两种格式:npm模块和bower模块。

Npm模块用于为节点创build的脚本,并从命令行调用。 Bower模块用于在浏览器中加载的脚本。

首先,我的误解是,'require'在模糊的节点和浏览器中是不起作用的。 这是错误的。 这似乎是要求一个模块,以便它在浏览器中工作的唯一方法是通过asynchronous调用,如:

 require(['module'], function(module) { ... }); 

另一个误解是我可以在浏览器中加载npm模块。 这种神奇的function将用于加载我的网页的各种npm文件。 这可能是可能的,但只使用像browserify一些特殊的工具。 如果没有特殊的转换,只能在浏览器中加载凉亭版本。 另外,pegjs bower模块的制作方式使得全局variables的定义如下:

 var PEG = { ... } module.exports = PEG; 

基本上,bower模块将一个全局variables(实际上是几个全局variables)插入顶层作用域。

因此,我不是让我的客户端代码(在浏览器中运行,并在节点中)加载模块,我实际上加载模块:

  1. main.js通过一个同步需求到npm模块,如下所示: var PEG = require('pegjs');
  2. main-browser.js通过全局variables,在加载bower pegjs脚本(通过<script>标记)时变得可用。

然后这两个“干线”都将PEGvariables注入到parsing器函数中。

对于业力工作,我只需要在生成的页面( karma.conf.js提取)中包含pegjs bower模块:

 files: [ { pattern: 'bower_components/pegjs/peg-0.9.0.js', included: true }, { pattern: './test/**/*.spec.js', included: false }, { pattern: './js/**/*.js', included: false}, './test/test-main.js', ],