Reputation: 15032
is there a way to make PhantomJS natively support ES6, I have a bunch of ES6 code which is converted to ES5 via Babel, what I need to accomplish is accurate measurement of code coverage which is done for ES6 code rather than ES5. It's a requirement from client, so I can't just tell him to stop requesting such thing...
Afaik NodeJS already has native support for ES6, is there a way to do that with PhantomJS?
Upvotes: 4
Views: 2241
Reputation: 15032
I've ended up using raw NodeJS (without PhantomJs) + Express + JSDom (https://github.com/tmpvar/jsdom), the POC looks like this:
"use strict"
const $module = require('module');
const path = require('path');
const babel = require("babel-core");
const Jasmine = require('jasmine');
const reporters = require('jasmine-reporters');
const express = require('express');
const jsdom = require("jsdom");
const app = express();
const vm = require('vm');
const fs = require("fs");
app.get('/', function (req, res) {
res.sendFile('index.html', { root: __dirname });
});
app.use('/bower_components', express.static('bower_components'));
const load = function (filename) {
return fs.readFileSync(`./bower_components/${filename}`, "utf-8");
};
const packages = [
fs.readFileSync('./bower_components/jquery/dist/jquery.js', "utf-8"),
fs.readFileSync('./bower_components/angular/angular.js', "utf-8"),
fs.readFileSync('./bower_components/angular-mocks/angular-mocks.js', "utf-8")
];
const sut = {
'./js/code.js': fs.readFileSync('./js/code.js', "utf-8")
};
const tests = {
'./tests/test.js': fs.readFileSync('./tests/test.js', "utf-8")
};
function navigate(FakeFileSystem, root, cwd, filename) {
// Normalize path according to root
let relative = path.relative(root, path.resolve(root, cwd, filename));
let parts = relative.split(path.sep);
let iterator = FakeFileSystem;
for (let part of parts) {
iterator = iterator[part] || (iterator[part] = { });
}
return iterator;
}
const server = app.listen(3333, function () {
const host = server.address().address;
const port = server.address().port;
const url = `http://${host === '::' ? 'localhost' : host}:${port}`;
console.log(`Server launched at ${ url }`);
console.log(`Running tests...`)
jsdom.env({
url: url,
src: packages,
done: function (err, window) {
let jasmine = new Jasmine();
let FakeFileSystem = {};
let descriptors = [];
jasmine.configureDefaultReporter({ showColors: true });
let env = jasmine.env;
for (let propertyName in env) {
if (env.hasOwnProperty(propertyName)) {
window[propertyName] = env[propertyName];
}
}
let context = vm.createContext(window);
let collections = [sut, tests];
for (let collection of collections) {
for (let filename in collection) {
let descriptor = navigate(FakeFileSystem, __dirname, '.', filename);
let source = collection[filename];
let transpiled = babel.transform(source, { "plugins": ["transform-es2015-modules-commonjs"] });
let code = $module.wrap(transpiled.code);
let _exports = {};
let _module = { exports: _exports };
descriptor.code = vm.runInContext(code, context);
descriptor.module = _module;
descriptor.exports = _exports;
descriptor.filename = filename;
descriptors.push(descriptor);
}
}
for (let descriptor of descriptors) {
let cwd = path.dirname(path.relative(__dirname, descriptor.filename));
descriptor.code.call(
undefined,
descriptor.exports,
// Closure is used to capture cwd
(function (cwd) {
return function (filename) { // Fake require function
return navigate(FakeFileSystem, __dirname, cwd, filename).exports;
}
})(cwd),
descriptor.module,
descriptor.filename
);
}
jasmine.execute();
server.close();
}
});
});
The beauty of this approach is that there is no need in transpiling code with babel, it allows frontend packages such as Angular to get loaded from bower, while all the config stuff comes from npm...
I've stumbled upon the fact that NodeJS doesn't support all ES6 features yet, and such feature as ES6 modules is a real pain, they aren't supported anywhere, so I've ended up with doing partial transpilation of code with babel, with the expectation that as NodeJS will start providing richer and richer support for ES6 I will eventually turn-off babel features step by step and switch to native support when it will become available...
Upvotes: 4