Using es6 transpiled classes in Nodejs - node.js

So I have my example classes in my file ContrivedExampleA.es6
export class Person {
constructor(name, age) {
this._name = name;
this._age = age;
}
get name() {
return this._name;
}
get age() {
return this._age;
}
}
export class Greeter {
constructor(person) {
this._person = person;
}
greet() {
return `Hello ${this._person.name}, I believe you are ${this._person.age} years old!`;
}
}
which I compile (successfully), using the following Gulp task:
var gulp = require('gulp');
var browserify = require('browserify');
var babelify = require('babelify');
var source = require('vinyl-source-stream');
gulp.task('build', function () {
return browserify({entries: './src/ContrivedExampleA.es6', extensions: ['.es6'], debug: true})
.transform(babelify)
.bundle()
.pipe(source('example.js'))
.pipe(gulp.dest('build'));
});
So I want to use this code in regular Nodejs land, so I do the following:
"use strict";
var Person = require('./example').Person;
var Greeter = require('./example').Greeter;
var person = new Person("Test Person", 25);
var greeter = new Greeter(person);
console.log(greeter.greet());
However, both Person and Greeter are undefined. I've even tried including transform-es2015-modules-commonjs in my .babelrc file which hasn't helped anything.
What am I doing wrong? and how can I get these transpiled ES6 classes imported into a regular Nodejs file?
EDIT
I also have a .babelrc file which looks like:
{
"presets": ["es2015"],
"plugins": ["transform-es2015-modules-commonjs"]
}

Ignore my previous answer, I was focusing on the wrong thing.
If you want to get the regular ES6 classes imported into a Nodejs file, you could skip the browserify and babelify steps all together, and just use the gulp-babel plugin directly. I would recommend using gulp-rename too.
Your ContrivedExampleA.es6 file would stay the same, but your gulpfile.js would become:
var gulp = require('gulp');
var babel = require('gulp-babel');
var rename = require('gulp-rename');
gulp.task('build', function () {
return gulp.src('./src/ContrivedExampleA.es6')
.pipe(babel({presets: ["es2015"], plugins: ["transform-es2015-modules-commonjs"]}))
.pipe(rename('example.js'))
.pipe(gulp.dest('build'));
});
Note: since you have a .babelrc you could probably skip passing the options to babel.
Then in your node file, you could simply do
"use strict";
var Person = require('./example').Person;
var Greeter = require('./example').Greeter;
var person = new Person("Test Person", 25);
var greeter = new Greeter(person);
console.log(greeter.greet());

Related

Is it possible to collect coverage on code loaded with vm.runInContext with Jest?

I'm working on a legacy JS project which is not using any require/import. When deploying, the files are just concatenated and the result is sent to a server.
In order to write tests with jest, I created a custom environment to load all the JS files in the global context so that I can call the functions in the test file.
For example:
src/index.js
function sum(x, y) {
return x + y;
}
src/index.spec.js
it('should sum two numbers', () => {
expect(sum(1, 2)).toBe(3);
});
jest.config.js
module.exports = {
clearMocks: true,
collectCoverage: true,
collectCoverageFrom: [
"src/**/*.js",
],
coverageDirectory: "coverage",
coverageProvider: "v8",
testEnvironment: "./jest.env.js",
};
jest.env.js
const NodeEnvironment = require('jest-environment-node').TestEnvironment;
const fs = require('fs');
const vm = require("vm");
const path = require("path");
class CustomEnv extends NodeEnvironment {
constructor(config, context) {
super(config, context);
this.loadContext();
}
loadContext() {
const js = fs.readFileSync('./src/index.js', 'utf8');
const context = vm.createContext(this.global);
vm.runInContext(js, context, {
filename: path.resolve('./src/index.js'),
displayErrors: true,
});
Object.assign(this.global, context);
}
}
module.exports = CustomEnv;
When I run npx jest, the test is executed but the coverage is empty...
Any idea on how to fix the coverage?
I've created a minimal reproducible repo here: https://github.com/GP4cK/jest-coverage-run-in-context/tree/main. You can just clone it, run npm i and npm t.
Note: I'm happy to change v8 to babel or load the context differently if it makes it easier.

RequireJS + Mocha + JSDom + Node -> Shim config not supported in Node

I'm trying to setup a Mocha testing framework using JSDom with RequireJS. Because I'm running the test on node instead of using a browser (since I'm using JSDom), all the non AMD modules doesn't seem to be imported and is throwing Shim config not supported in Node. Does anyone know how I can export those modules to AMD or what the right approach is? (aka what I'm doing wrong)
Example of my set-up
Component.js
define(["jquery", "non_AMD_Module", ... ], function($, NonAMDModule, ...) {
let component = {
...
foo = () => {
NonAMDModule.bar();
};
};
return component;
});
Component.test.js
const requirejs = require('requirejs');
const { JSDOM } = require('jsdom');
requirejs.config({
baseUrl: "dist/app",
paths: {
jquery: "lib/jquery",
component: "path_to_component",
non_AMD_Module: "path_to_module"
},
shim: {
non_AMD_Module: { exports: "non_AMD_Module" } // This doesn't work
}
});
const { window } = new JSDOM("<html></html>");
global.window = window;
global.document = window.document;
global.$ = requirejs('jquery');
const Component = requireJS('component');
describe('test', () => {
it('is a simple test', () => {
const testComponent = new Component();
testComponent.foo();
}
});
When I run the test suite, I get:
Mocha Exploded!
TypeError: Cannot read property 'bar' of undefined
running r.js -convert "path_to_module" did not work for this module
Looking at the source code for jQuery, I found that there's this boiler-plate coded that exports it to AMD.
This can be added at the bottom of the non-AMD-module in order to export it to an AMD module accessible by RequireJS
if ( typeof define === "function" && define.amd ) {
define([], function {
return non_AMD_Module;
});
}
Other Resources:
Shim a module in Require.js that uses module.exports possible?
https://github.com/requirejs/requirejs/wiki/Updating-existing-libraries#anon

Mocking a function in a jest environment file

I want to share a server between all my tests, to do this I create the file server-environment.js
const NodeEnvironment = require('jest-environment-node')
const supertest = require('supertest')
//A koa server
const { app, init } = require('../src/server')
class ServerEnvironment extends NodeEnvironment {
constructor(config, context) {
super(config, context)
this.testPath = context.testPath
}
async setup() {
await init
this.server = app.listen()
this.api = supertest(this.server)
this.global.api = this.api
}
async teardown() {
this.server.close()
}
}
module.exports = ServerEnvironment
The thing is that I want to mock some middleware that the servers routes use but I can't really find a way to do that. If I try to declare jest.mock anywhere in the file I get the error that jest isn't defined. If I mock the function in the actual test file the global wouldn't make use of it. Not sure if something like this would be possible to do with Jest?
I had a same issue and solved it by adding setupFilesAfterEnv.
jest.config.js:
module.exports = {
...
setupFilesAfterEnv: [
'./test/setupMocks.js'
]
...
};
test/setupMocks.js
jest.mock('path/to/api', () => global.api);

How do I make "export default" compile to "module.exports"

I'm writing in typescript with it set to compile to commonjs. Whenever I put export default, it compiles into exports.default instead of module.exports. I am making an NPM package, so I want this to be fixed. How do I solve it? If needed, I can add my tsconfig.json file.
const test = ()=> 'text';
export = test;
compiled
"use strict";
const test = () => 'text';
module.exports = test;
click demo
typescript doc: https://www.typescriptlang.org/docs/handbook/modules.html#export--and-import--require
You can simply write it with module.exports in your TS file
const myExportedObj = {
};
module.exports = {
foo: myExportedObj,
};
Output:
var myExportedObj = {};
module.exports = {
foo: myExportedObj,
};
Or, as far as I can see from your question, you could don't export default but export instead
TS
export const myExportedObj = {
};
JS
exports.myExportedObj = {};
Another good approach is to make an index.ts file and export modules from there
TS
export * as Context from './context';
JS
exports.Context = require("./context");

Loading CreateJS with RequrieJS “shim” dosen't work

I have made requirejs work for my own modules (with define), but I'm not able to use shim for createjs. I've gone through countless examples and ended up using this: https://github.com/CreateJS/EaselJS/wiki/Using-easeljs-and-tweenjs-with-requirejs, but I'm getting net::ERR_ABORTED error
My module:
define(function (require) {
var createjs = require('createjs');
var start = function () {
var canvas = document.getElementById('canvas');
var stage = new createjs.Stage(canvas);
}
return {
start: start
};
});
My configuration:
require.config({
shim: {
easel: {
exports: 'createjs'
}
},
paths: {
easel: 'libs/easeljs.min'
}
});
I finally found the answer somewhere else; it should be:
require('libs/createjs');
not:
var createjs=require('libs/createjs');
As c

Resources