Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 18 additions & 11 deletions lib/executor.js
Original file line number Diff line number Diff line change
Expand Up @@ -305,17 +305,24 @@ function runScripts(app, list, callback) {

async.eachSeries(functions, function(f, done) {
debug('Running script %s', f.path);
if (f.func.length >= 2) {
debug('Starting async function %s', f.path);
f.func(app, function(err) {
debug('Async function finished %s', f.path);
done(err);
});
} else {
debug('Starting sync function %s', f.path);
f.func(app);
debug('Sync function finished %s', f.path);
done();
var cb = function(err) {
debug('Async function finished %s', f.path);
done(err);
// Make sure done() isn't called twice, e.g. if a script returns a
// thenable object and also calls the passed callback.
cb = null;
};
try {
var result = f.func(app, cb);
if (result && typeof result.then === 'function') {
result.then(function() { cb(); }, cb);
} else if (f.func.length < 2) {
debug('Sync function finished %s', f.path);
done();
}
} catch (err) {
debug('Sync function failed %s', f.path, err);
done(err);
}
}, callback);
}
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
},
"devDependencies": {
"browserify": "^4.1.8",
"bluebird": "^3.1.1",
"chai": "^1.10.0",
"coffee-script": "^1.8.0",
"coffeeify": "^0.7.0",
Expand Down
112 changes: 83 additions & 29 deletions test/executor.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,8 @@ describe('executor', function() {
'barLoaded',
'barSyncLoaded',
'fooLoaded',
'promiseLoaded',
'thenableLoaded',
'barStarted',
]);

Expand All @@ -275,9 +277,15 @@ describe('executor', function() {
'barLoaded',
'barSyncLoaded',
'fooLoaded',
'promiseLoaded',
'thenableLoaded',
'barStarted',
'barFinished',
'barSyncExecuted',
'promiseStarted',
'promiseFinished',
'thenableStarted',
'thenableFinished',
'umdLoaded',
]);
done();
Expand All @@ -292,9 +300,15 @@ describe('executor', function() {
'barLoaded',
'barSyncLoaded',
'fooLoaded',
'promiseLoaded',
'thenableLoaded',
'barStarted',
'barFinished',
'barSyncExecuted',
'promiseStarted',
'promiseFinished',
'thenableStarted',
'thenableFinished',
'umdLoaded',
]);
done();
Expand All @@ -305,7 +319,7 @@ describe('executor', function() {
function(done) {
var options = {
app: app,
appRootDir: path.join(__dirname, './fixtures/simple-app'),
appRootDir: SIMPLE_APP,
scriptExtensions: ['.customjs', '.customjs2'],
};
boot.execute(app, boot.compile(options), function(err) {
Expand All @@ -317,44 +331,84 @@ describe('executor', function() {
done();
});
});
});

describe('for mixins', function() {
var options;
beforeEach(function() {
appdir.writeFileSync('custom-mixins/example.js',
'module.exports = ' +
'function(Model, options) {}');

appdir.writeFileSync('custom-mixins/time-stamps.js',
'module.exports = ' +
'function(Model, options) {}');
describe('with boot script returning a rejected promise', function() {
before(function() {
// Tell simple-app/boot/reject.js to return a rejected promise
process.rejectPromise = true;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be probably simpler to create a different application (a set of instructions) for each of these error cases. Having said that, your approach with process flags is ok too.

});

appdir.writeConfigFileSync('custom-mixins/time-stamps.json', {
name: 'Timestamping',
});
after(function() {
delete process.rejectPromise;
});

options = {
appRootDir: appdir.PATH,
};
it('receives rejected promise as callback error',
function(done) {
boot.execute(app, simpleAppInstructions(), function(err) {
expect(err).to.exist.and.be.an.instanceOf(Error)
.with.property('message', 'reject');
done();
});
});
});

it('defines mixins from instructions - using `mixinDirs`', function() {
options.mixinDirs = ['./custom-mixins'];
boot(app, options);
describe('with boot script throwing an error', function() {
before(function() {
// Tell simple-app/boot/throw.js to throw an error
process.throwError = true;
});

var modelBuilder = app.registry.modelBuilder;
var registry = modelBuilder.mixins.mixins;
expect(Object.keys(registry)).to.eql(['Example', 'Timestamping']);
after(function() {
delete process.throwError;
});

it('receives thrown error as callback errors',
function(done) {
boot.execute(app, simpleAppInstructions(), function(err) {
expect(err).to.exist.and.be.an.instanceOf(Error)
.with.property('message', 'throw');
done();
});
});
});

it('defines mixins from instructions - using `mixinSources`', function() {
options.mixinSources = ['./custom-mixins'];
boot(app, options);
describe('for mixins', function() {
var options;
beforeEach(function() {
appdir.writeFileSync('custom-mixins/example.js',
'module.exports = ' +
'function(Model, options) {}');

appdir.writeFileSync('custom-mixins/time-stamps.js',
'module.exports = ' +
'function(Model, options) {}');

var modelBuilder = app.registry.modelBuilder;
var registry = modelBuilder.mixins.mixins;
expect(Object.keys(registry)).to.eql(['Example', 'Timestamping']);
appdir.writeConfigFileSync('custom-mixins/time-stamps.json', {
name: 'Timestamping',
});

options = {
appRootDir: appdir.PATH,
};
});

it('defines mixins from instructions - using `mixinDirs`', function() {
options.mixinDirs = ['./custom-mixins'];
boot(app, options);

var modelBuilder = app.registry.modelBuilder;
var registry = modelBuilder.mixins.mixins;
expect(Object.keys(registry)).to.eql(['Example', 'Timestamping']);
});

it('defines mixins from instructions - using `mixinSources`', function() {
options.mixinSources = ['./custom-mixins'];
boot(app, options);

var modelBuilder = app.registry.modelBuilder;
var registry = modelBuilder.mixins.mixins;
expect(Object.keys(registry)).to.eql(['Example', 'Timestamping']);
});
});

Expand Down
19 changes: 19 additions & 0 deletions test/fixtures/simple-app/boot/promise.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright IBM Corp. 2017. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

var Promise = require('bluebird');

process.bootFlags.push('promiseLoaded');
module.exports = function(app) {
process.bootFlags.push('promiseStarted');
return Promise.resolve({
then: function(onFulfill, onReject) {
process.nextTick(function() {
process.bootFlags.push('promiseFinished');
onFulfill();
});
},
});
};
12 changes: 12 additions & 0 deletions test/fixtures/simple-app/boot/reject.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright IBM Corp. 2017. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

var Promise = require('bluebird');

module.exports = function(app) {
if (process.rejectPromise) {
return Promise.reject(new Error('reject'));
}
};
17 changes: 17 additions & 0 deletions test/fixtures/simple-app/boot/thenable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright IBM Corp. 2017. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

process.bootFlags.push('thenableLoaded');
module.exports = function(app) {
process.bootFlags.push('thenableStarted');
return {
then: function(onFulfill, onReject) {
process.nextTick(function() {
process.bootFlags.push('thenableFinished');
onFulfill();
});
},
};
};
10 changes: 10 additions & 0 deletions test/fixtures/simple-app/boot/throw.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright IBM Corp. 2017. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

module.exports = function(app) {
if (process.throwError) {
throw new Error('throw');
}
};