Testing AMD modules with tape/ES6 unit tests? - javascript

I have a web app using:
ES5
RequireJS
Underscore
Backbone
jQuery
I have tried setting up a new unit test suite using:
ES6
Tape
Babel6
My AMD module app/util/stringUtil.js:
define([], function() {
'use strict';
return {
isBlank: function(str) {
return _.isUndefined(str) || _.isNull(str) || _.isString(str) && str.trim().length === 0;
}
};
});
My unit test in tapeTest.js:
import test from 'tape';
import sortUtil from 'app/util/stringUtil';
test('Testing stringUtil', (assert) => {
assert.ok(stringUtil.isBlank(' ')),
'Should be blank');
assert.end();
});
My .babelrc:
{
"presets": ["es2015"]
}
I run the test with tape:
tape -r babel-register tapeTest.js
I get the following error:
app/util/stringUtil.js:1
(function (exports, require, module, __filename, __dirname) { define([], function () {
^
ReferenceError: define is not defined
at Object.<anonymous> (stringUtil.js:1:23)
at Module._compile (module.js:434:26)
at loader (node_modules/babel-register/lib/node.js:126:5)
at Object.require.extensions.(anonymous function) [as .js] (node_modules/babel-register/lib/node.js:136:7)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Module.require (module.js:365:17)
at require (module.js:384:17)
at Object.<anonymous> (tapeTest.js:7:17)
at Module._compile (module.js:434:26)
I'm guessing tape doesn't recognize AMD modules? Can I fix this somehow? Maybe transpile AMD modules to CommonJS modules or something?

You can load AMD modules inside node with requirejs :_)
Read here: http://requirejs.org/docs/node.html
You have to import require and do a little config, something like this:
'use strict';
const test = require('tape');
const requirejs = require('requirejs');
requirejs.config({
baseUrl: __dirname,
nodeRequire: require
});
test('Test something', function (assert) {
requirejs(['app/util/stringUtil'], function (stringUtil) {
assert.ok(stringUtil.isBlank(' '), 'Should be blank');
assert.end();
});
});

I solved it by using karma, webpack and phantomjs launcher:
karma
karma-webpack
karma-phantomjs-launcher
karma-tap
tape
Webpack transpiles the ES6 unit tests to ES5 modules and karma launches and runs the tests in a phantomjs browser.

Related

How to provide test ESModule implementation in mocha test?

I have a mocha test which tests my code. My code uses another "core" npm package (which uses CommonJS modules). One of "core" the files ("synchronizer.js" file) requires "prefs" modules which is assumed to be provided at some point:
const {Prefs} = require("prefs");
In the mocha test i'd like to implement this "prefs" module, so i've created "prefs.mjs" file (with exports that "synchronizer.js" expects). However during the test i have the following error:
Error: Cannot find module 'prefs'
Require stack:
- /Users/developer/Documents/dev/src/project/node_modules/core/lib/synchronizer.js
- /Users/developer/Documents/dev/src/project/node_modules/core/lib/index.js
at Module._resolveFilename (node:internal/modules/cjs/loader:1026:15)
at Module._load (node:internal/modules/cjs/loader:872:27)
at Module.require (node:internal/modules/cjs/loader:1092:19)
at require (node:internal/modules/cjs/helpers:103:18)
at Object.<anonymous> (/Users/developer/Documents/dev/src/project/node_modules/core/lib/synchronizer.js:26:17)
at Module._compile (node:internal/modules/cjs/loader:1205:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1259:10)
at Module.load (node:internal/modules/cjs/loader:1068:32)
at Module._load (node:internal/modules/cjs/loader:909:12)
at Module.require (node:internal/modules/cjs/loader:1092:19)
at require (node:internal/modules/cjs/helpers:103:18)
at Object.<anonymous> (/Users/developer/Documents/dev/src/project/node_modules/core/lib/index.js:33:24)
at Module._compile (node:internal/modules/cjs/loader:1205:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1259:10)
at Module.load (node:internal/modules/cjs/loader:1068:32)
at Module._load (node:internal/modules/cjs/loader:909:12)
at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:169:29)
at ModuleJob.run (node:internal/modules/esm/module_job:194:25)
My project structure:
\sdk
\test
\unit
\ prefs
\prefs.mjs
\test.js
I run the tests (package.json):
"dependencies": {
...
"core": "^0.10.1",
...
},
"scripts": {
...
"unittest": "mocha --recursive ./test/unit/*.js",
...
}
}
test.js looks as follows:
describe("Section1", function() {
beforeEach(async function() {
await configureTestEnv();
// TODO: set "prefs" module
// TODO: set "io" module
// TODO: set "info" module
});
describe("subscriptions", function() {
it("throws if no condition is achieved", async function() {
...
I can run the tests (which does not include "core") successfully, so the testing works in general.
I suspect i have to use smth like webpack or babel, but i'd like to keep it clean and not using any deps or intermediate build steps if possible.
Should i pass modules directories paths to mocha to let node.js somehow find it?
Ended up using webpack and generating a module with aliased modules including prefs.

Unexpected Identifier {classname} when importing JavaScript Class into another Class

I'm using Node v10.11.0 and am running this script from Ubuntu 18.04.
My file setup looks like this:
main.js
import Login from './Login.mjs';
class Main {
constructor() {
const login = new Login();
login.login();
}
}
new Main();
Login.mjs
import readline from 'readline';
class Login {
constructor() {
this.username = '';
this.password = '';
this.readline = readline.createInterface({
input: process.stdin,
output: process.stdout
});
}
login() {
this.readline.question('What is your username?', answer => {
this.username = answer;
});
this.readline.question('What is your password?', answer => {
this.password = answer;
});
}
}
export default Login;
I'm calling the main.js with the following command:
node --experimental-modules main.js
This leads to the following error:
(node:7280) ExperimentalWarning: The ESM module loader is experimental.
/home/jrenk/Workspace/bitefight/main.js:1
(function (exports, require, module, __filename, __dirname) { import Login from './Login.mjs';
^^^^^
SyntaxError: Unexpected identifier
at new Script (vm.js:79:7)
at createScript (vm.js:251:10)
at Proxy.runInThisContext (vm.js:303:10)
at Module._compile (internal/modules/cjs/loader.js:657:28)
at Object.Module._extensions..js
(internal/modules/cjs/loader.js:700:10)
at Module.load (internal/modules/cjs/loader.js:599:32)
at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
at Function.Module._load (internal/modules/cjs/loader.js:530:3)
at createDynamicModule (internal/modules/esm/translators.js:56:15)
at setExecutor
(internal/modules/esm/create_dynamic_module.js:50:23)
The ^^^^^ belongs under the Login but I can't seem to get it formatted right here in the question.
I also tried to save the Login.mjs as Login.js and calling the main.js without the --experimental-modules but this leads to the exact same error.
This question is similar to this question. As I said above I already tried what is described there but no luck.
Native ES modules (import and export statements) can only be used in .mjs files in Node. In order to use them, entry point should be named main.mjs.
In order to use ES modules in .js files, ES modules should either be transpiled to fall back to require, or used natively with custom ES module loader. Since the latter isn't native Node.js behaviour, it cannot be recommended as a rule of thumb.

Importing AMD module in to Mocha test

I am using Mocha to test code exported as AMD module. Running mocha test gives me following error.
ReferenceError: define is not defined
at Object.<anonymous> (/home/malintha/projects/...../xxx.js:1:63)
at Module._compile (module.js:571:32)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:488:32)
at tryModuleLoad (module.js:447:12)
at Function.Module._load (module.js:439:3)
at Module.require (module.js:498:17)
at require (internal/module.js:20:19)
The source which is tested as floows
define(['lodash', 'log', './yyy'], function(_, log, YYY) {
var xxxy = function() {
};
..............
});
And the mocha test
var expect = require("chai").expect;
var sourceGenVisitor = require("../../xxx")
describe("", function() {
describe("", function() {
it("Checks generated source", function() {
...................
});
});
});
How can I fix this issue ?
You can use amd-loader. I used it for years in a project of mine that was structured as a collection of AMD modules. Install with:
`npm install amd-loader`
It then needs to be loaded before any AMD module. In general:
require("amd-loader");
For Mocha you can use the argument --require amd-loader. You can put it in your test/mocha.opts file if you don't want to have to remember typing it over and over.
If you run mocha test with the typescript. Maybe you do this:
Install amd-loader:
npm install amd-loader --save
Run mocha test:
mocha src/**/*test.ts --require ts-node/register -r amd-loader

Gulp Node.js Istanbul Isparta

I'm trying to get unit tests coverage with Istanbul and Isparta, and I'm having some trouble.
Actually, here's my gulp file tasks:
gulp.task('pre-test', ['default'], function() {
return gulp.src('src/app/**/*.js')
.pipe(plumber())
.pipe(istanbul({
instrumenter: isparta.Instrumenter,
includeUntested: true
}))
.pipe(istanbul.hookRequire());
});
gulp.task('test', ['pre-test'], function() {
return gulp.src('src/test/**/*.js')
.pipe(mocha({reporter: 'spec'}))
.pipe(istanbul.writeReports({}));
});
When I start the gulp "test" task, I have the following errors:
[08:34:17] Plumber found unhandled error:
Error in plugin 'gulp-istanbul'
Message:
Unable to parse C:\projects\nodejs\mon-notaire\src\app\core\logger\concrete\ConsoleLogger.js
Line 1: Unexpected token
[08:34:17] Finished 'pre-test' after 2.11 s
[08:34:17] Starting 'test'...
stream.js:94
throw er; // Unhandled stream error in pipe.
^
C:\projects\nodejs\mon-notaire\src\test\core\TestConfReader.js:1
(function (exports, require, module, __filename, __dirname) { import ConfReade
^^^^^^
SyntaxError: Unexpected reserved word
at exports.runInThisContext (vm.js:73:16)
at Module._compile (module.js:443:25)
at Object.Module._extensions..js (module.js:478:10)
at Object.Module._extensions.(anonymous function) [as .js] (C:\projects\nodejs\mon-notaire\node_modules\gulp-istanbul\node_modules\istanbul\lib\hook.js:109:37)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Module.require (module.js:365:17)
at require (module.js:384:17)
at C:\projects\nodejs\mon-notaire\node_modules\mocha\lib\mocha.js:192:27
at Array.forEach (native)
npm ERR! Test failed. See above for more details.
How can I prevent these errors from occurring?
Have you set up .babelrc?
If you're using the latest version of isparta, which depends on babel v6, then you need to set up .babelrc like the following. ( You also need to do npm install --save-dev babel-preset-es2015 )
{
"presets": [
"es2015"
]
}
From gulp-istanbul github page.
var isparta = require('isparta');
var istanbul = require('gulp-istanbul');
gulp.src('lib/**.js')
.pipe(istanbul({
// supports es6
instrumenter: isparta.Instrumenter
}));
This line :
Message:
Unable to parse C:\projects\nodejs\mon-notaire\src\app\core\logger\concrete\ConsoleLogger.js
Means that there is a problem in your code in ConsoleLogger.js , so you might want to check that file out.
This Line :
C:\projects\nodejs\mon-notaire\src\test\core\TestConfReader.js:1
(function (exports, require, module, __filename, __dirname) { import ConfReade
^^^^^^
SyntaxError: Unexpected reserved word
Suggests that you are using ES6, but your gulp task is not transpiling it to ES5 before running it, which is why you are getting the error.
I have made a yeoman generator which creates a project for exactly this purpose (writing nodeJs projects in ES6) and includes code coverage using istanbul with source code mapping. You might want to take a look at that.
Otherwise, here is my working gulpfile from that generator.
I use istanbul, along with a module called remap-istanbul.
The error message indicates that you are using ES6, but the gulp-istanbul doesn't support it by default.
Of course, you can write your functions to compile the ES6 codes, but considering you are using gulp in this case, IMHO the simplest way you can do is to use gulp-babel-istanbul instead of gulp-istanbul, no need to change your code attached above at all.
import istanbul from 'gulp-babel-istanbul'
And the rest of the code remains the same.

Gulp concat and require path

I have a problem with gulp-concat. I'm trying to concate all my js files in a single file, let's say, dist/app.js.
But there is something that I don't understand. In that file, my required files path are still the same than before...
Here is my gulpfile.js :
var gulp = require("gulp");
var sourcemaps = require("gulp-sourcemaps");
var babel = require("gulp-babel");
var concat = require("gulp-concat");
var resolveDependencies = require("gulp-resolve-dependencies");
gulp.task("default", function () {
return gulp.src("client/**/*.js")
.pipe(sourcemaps.init())
.pipe(babel())
.pipe(concat("app.js"))
.pipe(sourcemaps.write("."))
.pipe(gulp.dest("dist/js"));
});
As you can see, I want to concat nested folders.
Take a look for example at the top of my /client/components/app.js :
import React, {PropTypes} from 'react';
import AppLeftNav from './AppLeftNav';
import {AppCanvas, AppBar, Styles} from 'material-ui';
//Code here
So in my app app.js generated by gulp, i can see :
var _AppLeftNav = require('./AppLeftNav');
It's a relative path and it can't work.
So, what's the tricks to handle theses required files with relative path ?
Thanks a lot.
EDIT : See the error I get :
Error: Cannot find module './components/App.js'
at Function.Module._resolveFilename (module.js:336:15)
at Function.Module._load (module.js:278:25)
at Module.require (module.js:365:17)
at require (module.js:384:17)
at Object.<anonymous> (MyFolder\dist\js\app.js:34:24)
at Module._compile (module.js:460:26)
at Object.Module._extensions..js (module.js:478:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Module.require (module.js:365:17)
To anyone who might have the same problem. Babel currently doesn't support imports inlining #1681, neither do gulp-concat, as it's just concatenating files.
I opted to use Rollup to propertly resolve dependencies and only then transpile output:
var gulp = require('gulp');
var gutil = require('gulp-util');
var babel = require('gulp-babel');
var concat = require('gulp-concat');
var rollup = require('gulp-rollup');
gulp.task('build', function () {
return gulp.src('src/parser-factory.js', { read: false })
.pipe(rollup({ external: ['request', 'cheerio'] }))
.on('error', gutil.log)
.pipe(babel({ stage: 0 }))
.pipe(concat('realty-parser.js'))
.pipe(gulp.dest('lib'));
});
If you want to get it all in a single file then you will have to write .pipe(gulp.dest("dist/js/jsfile.js")); where jsfile is the name of your file.

Categories

Resources