配置Karma以使用requirejs加载pegjs

Luk*_*ker 12 javascript node.js requirejs pegjs karma-runner

尝试使用PegJS和requirejs测试项目.我有几个源文件,实现为AMD模块(定义),通过require API加载.目录结构下面:

js/
   somefile.js
   main.js
   parser.js
test/
   parser.spec.js
Run Code Online (Sandbox Code Playgroud)

我编写了一个parser.js模块来加载PegJS语法文件并使用PegJS创建一个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 });
    [...]
Run Code Online (Sandbox Code Playgroud)

这与在节点的命令行上执行的main.js一起工作正常.现在我想用karma,jasmine和PhantomJS来测试我的项目.我有一个像这样的karma.conf.js:

frameworks: ['jasmine', 'requirejs'],
files: [
  { pattern: './test/**/*.spec.js', included: false },
  { pattern: './js/**/*.js', included: false},
  './test/test-main.js',
],
Run Code Online (Sandbox Code Playgroud)

还有一个名为test-main.js的require bootstrap文件,它以这种方式配置:

'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
});
Run Code Online (Sandbox Code Playgroud)

现在,当我启动我的test(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([])
Run Code Online (Sandbox Code Playgroud)

所以我尝试将这些方式中的pegjs包含在Karma加载的文件中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'
],
Run Code Online (Sandbox Code Playgroud)

当我这样做时,我仍然会收到错误:

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

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

compiler/
compiler.js
grammar-error.js
parser.js
peg.js
utils/
  arrays.js
  classes.js
  objects.js
Run Code Online (Sandbox Code Playgroud)

所以试图也包括数组:

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'
],
Run Code Online (Sandbox Code Playgroud)

我明白了:

ReferenceError: Can't find variable: module
at /blabla/node_modules/pegjs/lib/utils/arrays.js:108
Run Code Online (Sandbox Code Playgroud)

因为:

108 module.exports = arrays;
Run Code Online (Sandbox Code Playgroud)

因此,在加载npm模块的过程中,我尝试以这种方式加载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'
],
Run Code Online (Sandbox Code Playgroud)

在这里你再去一次:

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

还尝试不在业力生成的网页中包含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'
],
Run Code Online (Sandbox Code Playgroud)

但它失败了:

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

试图将bower_component文件夹放在js文件夹中,但没有运气.

所以我不知道从这里开始......在谷歌或这里找不到任何相关内容.这似乎是一个特殊的问题,要求js/pegjs与业力...任何想法是受欢迎的.

在dan的回答后更新:

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

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 });
    [...]
Run Code Online (Sandbox Code Playgroud)

试图以包括pegjs凉亭组件karma.conf.js:

{ pattern: 'bower_components/pegjs/peg-0.9.0.js', included: false },
Run Code Online (Sandbox Code Playgroud)

或不包括它:

{ pattern: 'bower_components/pegjs/peg-0.9.0.js', included: true },
Run Code Online (Sandbox Code Playgroud)

但总是得到同样的错误:

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
Run Code Online (Sandbox Code Playgroud)

是的文件存在:

$ 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
Run Code Online (Sandbox Code Playgroud)

更新2:最后了解并找到了可接受的解决方案.

Luk*_*ker 0

因此,在 dan 和pieceOpiland 的各种答案和评论的帮助下,我终于找到了一种做我想做的事情的方法。

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

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

我的第一个误解是“require”在节点和浏览器中的工作方式不明确。这是错误的。似乎需要一个模块才能在浏览器中工作的唯一方法是通过异步调用,例如:

require(['module'], function(module) {
  ...
});
Run Code Online (Sandbox Code Playgroud)

另一个误解是我可以在浏览器中加载 npm 模块。某种魔法可以让我的页面加载各种 npm 文件。这可能是可能的,但只能使用一些特殊的工具,例如browserify。无需特殊改造,浏览器中只能加载bower版本。此外,pegjs Bower 模块的制作方式使得全局变量的定义如下:

var PEG = {
 ...
}

module.exports = PEG;
Run Code Online (Sandbox Code Playgroud)

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

因此,我实际上不是让我的客户端代码(在浏览器和节点中运行的代码)加载模块,而是在以下任一位置加载模块:

  1. main.js 通过同步 require 到 npm 模块,如下所示:var PEG = require('pegjs');
  2. main-browser.js 通过全局变量,当您加载 Bower pegjs 脚本(通过标签<script>)时该变量变得可用

然后,这两个“电源”都将 PEG 变量注入到我的解析器函数中。

为了让 karma 工作,我只需要在生成的页面中包含 pegjs Bower 模块(karma.conf.js摘录):

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',
],
Run Code Online (Sandbox Code Playgroud)