var boot = require('../'); var fs = require('fs'); var path = require('path'); var expect = require('must'); var browserify = require('browserify'); var sandbox = require('./helpers/sandbox'); var vm = require('vm'); describe('browser support', function() { this.timeout(60000); // 60s to give browserify enough time to finish beforeEach(sandbox.reset); it('has API for bundling and executing boot instructions', function(done) { var appDir = path.resolve(__dirname, './fixtures/browser-app'); browserifyTestApp(appDir, function(err, bundlePath) { if (err) return done(err); var app = executeBundledApp(bundlePath); // configured in fixtures/browser-app/boot/configure.js expect(app.settings).to.have.property('custom-key', 'custom-value'); expect(Object.keys(app.models)).to.include('Customer'); expect(app.models.Customer.settings) .to.have.property('_customized', 'Customer'); done(); }); }); }); function browserifyTestApp(appDir, next) { var b = browserify({ basedir: appDir, debug: true }); b.require('./app.js', { expose: 'browser-app' }); boot.compileToBrowserify(appDir, b); var bundlePath = sandbox.resolve('browser-app-bundle.js'); var out = fs.createWriteStream(bundlePath); b.bundle().pipe(out); out.on('error', function(err) { return next(err); }); out.on('close', function() { next(null, bundlePath); }); } function executeBundledApp(bundlePath) { var code = fs.readFileSync(bundlePath); var context = createBrowserLikeContext(); vm.runInContext(code, context, bundlePath); var app = vm.runInContext('require("browser-app")', context); printContextLogs(context); return app; } function createBrowserLikeContext() { var context = { // required by browserify XMLHttpRequest: function() { throw new Error('not implemented'); }, localStorage: { // used by `debug` module debug: process.env.DEBUG }, // used by DataSource.prototype.ready setTimeout: setTimeout, // used by `debug` module document: { documentElement: { style: {} } }, // used by `debug` module navigator: { userAgent: 'sandbox' }, // used by crypto-browserify & friends Int32Array: Int32Array, DataView: DataView, // allow the browserified code to log messages // call `printContextLogs(context)` to print the accumulated messages console: { log: function() { this._logs.log.push(Array.prototype.slice.call(arguments)); }, warn: function() { this._logs.warn.push(Array.prototype.slice.call(arguments)); }, error: function() { this._logs.error.push(Array.prototype.slice.call(arguments)); }, _logs: { log: [], warn: [], error: [] }, } }; // `window` is used by loopback to detect browser runtime context.window = context; return vm.createContext(context); } function printContextLogs(context) { for (var k in context.console._logs) { var items = context.console._logs[k]; for (var ix in items) { console[k].apply(console, items[ix]); } } }