2013-12-18 03:15:48 +00:00
|
|
|
var path = require('path');
|
|
|
|
var SIMPLE_APP = path.join(__dirname, 'fixtures', 'simple-app');
|
|
|
|
|
2013-06-07 19:57:51 +00:00
|
|
|
describe('app', function() {
|
2013-06-06 00:11:21 +00:00
|
|
|
|
2013-06-07 19:57:51 +00:00
|
|
|
describe('app.model(Model)', function() {
|
2014-01-22 10:22:23 +00:00
|
|
|
var app, db;
|
|
|
|
beforeEach(function() {
|
|
|
|
app = loopback();
|
|
|
|
db = loopback.createDataSource({connector: loopback.Memory});
|
|
|
|
});
|
|
|
|
|
2013-07-16 20:46:33 +00:00
|
|
|
it("Expose a `Model` to remote clients", function() {
|
2014-01-22 10:22:23 +00:00
|
|
|
var Color = db.createModel('color', {name: String});
|
2013-06-07 19:57:51 +00:00
|
|
|
app.model(Color);
|
2014-01-22 10:22:23 +00:00
|
|
|
|
|
|
|
expect(app.models()).to.eql([Color]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('uses singlar name as app.remoteObjects() key', function() {
|
|
|
|
var Color = db.createModel('color', {name: String});
|
|
|
|
app.model(Color);
|
|
|
|
expect(app.remoteObjects()).to.eql({ color: Color });
|
|
|
|
});
|
|
|
|
|
|
|
|
it('uses singular name as shared class name', function() {
|
|
|
|
var Color = db.createModel('color', {name: String});
|
|
|
|
app.model(Color);
|
|
|
|
expect(app.remotes().exports).to.eql({ color: Color });
|
|
|
|
});
|
|
|
|
|
2014-02-19 19:40:05 +00:00
|
|
|
it('updates REST API when a new model is added', function(done) {
|
|
|
|
app.use(loopback.rest());
|
|
|
|
request(app).get('/colors').expect(404, function(err, res) {
|
|
|
|
if (err) return done(err);
|
|
|
|
var Color = db.createModel('color', {name: String});
|
|
|
|
app.model(Color);
|
|
|
|
request(app).get('/colors').expect(200, done);
|
|
|
|
});
|
2014-02-18 20:40:35 +00:00
|
|
|
});
|
|
|
|
|
2014-01-22 10:22:23 +00:00
|
|
|
describe('in compat mode', function() {
|
|
|
|
before(function() {
|
|
|
|
loopback.compat.usePluralNamesForRemoting = true;
|
|
|
|
});
|
|
|
|
after(function() {
|
|
|
|
loopback.compat.usePluralNamesForRemoting = false;
|
|
|
|
});
|
|
|
|
|
|
|
|
it('uses plural name as shared class name', function() {
|
|
|
|
var Color = db.createModel('color', {name: String});
|
|
|
|
app.model(Color);
|
|
|
|
expect(app.remotes().exports).to.eql({ colors: Color });
|
|
|
|
});
|
|
|
|
|
|
|
|
it('uses plural name as app.remoteObjects() key', function() {
|
|
|
|
var Color = db.createModel('color', {name: String});
|
|
|
|
app.model(Color);
|
|
|
|
expect(app.remoteObjects()).to.eql({ colors: Color });
|
|
|
|
});
|
2013-06-07 19:57:51 +00:00
|
|
|
});
|
2013-06-06 00:11:21 +00:00
|
|
|
});
|
2013-06-07 19:57:51 +00:00
|
|
|
|
2013-10-29 21:12:23 +00:00
|
|
|
describe('app.model(name, properties, options)', function () {
|
|
|
|
it('Sugar for defining a fully built model', function () {
|
|
|
|
var app = loopback();
|
|
|
|
app.boot({
|
|
|
|
app: {port: 3000, host: '127.0.0.1'},
|
|
|
|
dataSources: {
|
|
|
|
db: {
|
|
|
|
connector: 'memory'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
app.model('foo', {
|
|
|
|
dataSource: 'db'
|
|
|
|
});
|
|
|
|
|
|
|
|
var Foo = app.models.foo;
|
|
|
|
var f = new Foo;
|
|
|
|
|
|
|
|
assert(f instanceof loopback.Model);
|
|
|
|
});
|
2013-12-12 03:31:16 +00:00
|
|
|
});
|
2013-10-29 21:12:23 +00:00
|
|
|
|
2014-02-04 19:28:19 +00:00
|
|
|
describe('app.models', function() {
|
|
|
|
it('is unique per app instance', function() {
|
|
|
|
var Color = app.model('Color', { dataSource: 'db' });
|
|
|
|
expect(app.models.Color).to.equal(Color);
|
|
|
|
var anotherApp = loopback();
|
|
|
|
expect(anotherApp.models.Color).to.equal(undefined);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2013-10-29 21:12:23 +00:00
|
|
|
describe('app.boot([options])', function () {
|
|
|
|
beforeEach(function () {
|
|
|
|
app.boot({
|
|
|
|
app: {
|
2014-02-18 20:40:35 +00:00
|
|
|
port: 3000,
|
2013-12-12 03:31:16 +00:00
|
|
|
host: '127.0.0.1',
|
2014-01-07 15:05:48 +00:00
|
|
|
restApiRoot: '/rest-api',
|
2013-12-12 03:31:16 +00:00
|
|
|
foo: {bar: 'bat'},
|
|
|
|
baz: true
|
2013-10-29 21:12:23 +00:00
|
|
|
},
|
|
|
|
models: {
|
|
|
|
'foo-bar-bat-baz': {
|
|
|
|
options: {
|
|
|
|
plural: 'foo-bar-bat-bazzies'
|
|
|
|
},
|
|
|
|
dataSource: 'the-db'
|
|
|
|
}
|
|
|
|
},
|
|
|
|
dataSources: {
|
|
|
|
'the-db': {
|
|
|
|
connector: 'memory'
|
2014-02-18 20:40:35 +00:00
|
|
|
}
|
2013-10-29 21:12:23 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2013-12-12 03:31:16 +00:00
|
|
|
it('should have port setting', function () {
|
2013-10-29 21:12:23 +00:00
|
|
|
assert.equal(this.app.get('port'), 3000);
|
2013-12-12 03:31:16 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should have host setting', function() {
|
2013-10-29 21:12:23 +00:00
|
|
|
assert.equal(this.app.get('host'), '127.0.0.1');
|
|
|
|
});
|
|
|
|
|
2014-01-07 15:05:48 +00:00
|
|
|
it('should have restApiRoot setting', function() {
|
|
|
|
assert.equal(this.app.get('restApiRoot'), '/rest-api');
|
|
|
|
});
|
|
|
|
|
2013-12-12 03:31:16 +00:00
|
|
|
it('should have other settings', function () {
|
|
|
|
expect(this.app.get('foo')).to.eql({
|
|
|
|
bar: 'bat'
|
|
|
|
});
|
|
|
|
expect(this.app.get('baz')).to.eql(true);
|
|
|
|
});
|
|
|
|
|
2013-12-18 03:15:48 +00:00
|
|
|
describe('boot and models directories', function() {
|
|
|
|
beforeEach(function() {
|
|
|
|
var app = this.app = loopback();
|
|
|
|
app.boot(SIMPLE_APP);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should run all modules in the boot directory', function () {
|
|
|
|
assert(process.loadedFooJS);
|
|
|
|
delete process.loadedFooJS;
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should run all modules in the models directory', function () {
|
|
|
|
assert(process.loadedBarJS);
|
|
|
|
delete process.loadedBarJS;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2013-12-06 01:42:06 +00:00
|
|
|
describe('PaaS and npm env variables', function() {
|
|
|
|
beforeEach(function() {
|
|
|
|
this.boot = function () {
|
|
|
|
var app = loopback();
|
|
|
|
app.boot({
|
|
|
|
app: {
|
2014-02-18 20:40:35 +00:00
|
|
|
port: undefined,
|
2013-12-06 01:42:06 +00:00
|
|
|
host: undefined
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return app;
|
|
|
|
}
|
|
|
|
});
|
2014-02-18 20:40:35 +00:00
|
|
|
|
2013-12-06 01:42:06 +00:00
|
|
|
it('should be honored', function() {
|
|
|
|
var assertHonored = function (portKey, hostKey) {
|
|
|
|
process.env[hostKey] = randomPort();
|
|
|
|
process.env[portKey] = randomHost();
|
|
|
|
var app = this.boot();
|
|
|
|
assert.equal(app.get('port'), process.env[portKey]);
|
|
|
|
assert.equal(app.get('host'), process.env[hostKey]);
|
|
|
|
delete process.env[portKey];
|
|
|
|
delete process.env[hostKey];
|
|
|
|
}.bind(this);
|
|
|
|
|
|
|
|
assertHonored('OPENSHIFT_SLS_PORT', 'OPENSHIFT_NODEJS_IP');
|
|
|
|
assertHonored('npm_config_port', 'npm_config_host');
|
|
|
|
assertHonored('npm_package_config_port', 'npm_package_config_host');
|
|
|
|
assertHonored('OPENSHIFT_SLS_PORT', 'OPENSHIFT_SLS_IP');
|
|
|
|
assertHonored('PORT', 'HOST');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should be honored in order', function() {
|
|
|
|
process.env.npm_config_host = randomHost();
|
|
|
|
process.env.OPENSHIFT_SLS_IP = randomHost();
|
|
|
|
process.env.OPENSHIFT_NODEJS_IP = randomHost();
|
|
|
|
process.env.HOST = randomHost();
|
|
|
|
process.env.npm_package_config_host = randomHost();
|
|
|
|
|
|
|
|
var app = this.boot();
|
|
|
|
assert.equal(app.get('host'), process.env.npm_config_host);
|
|
|
|
|
2014-02-18 19:20:23 +00:00
|
|
|
delete process.env.npm_config_host;
|
|
|
|
delete process.env.OPENSHIFT_SLS_IP;
|
|
|
|
delete process.env.OPENSHIFT_NODEJS_IP;
|
|
|
|
delete process.env.HOST;
|
|
|
|
delete process.env.npm_package_config_host;
|
|
|
|
|
2013-12-06 01:42:06 +00:00
|
|
|
process.env.npm_config_port = randomPort();
|
|
|
|
process.env.OPENSHIFT_SLS_PORT = randomPort();
|
|
|
|
process.env.OPENSHIFT_NODEJS_PORT = randomPort();
|
|
|
|
process.env.PORT = randomPort();
|
|
|
|
process.env.npm_package_config_port = randomPort();
|
|
|
|
|
|
|
|
var app = this.boot();
|
|
|
|
assert.equal(app.get('host'), process.env.npm_config_host);
|
|
|
|
assert.equal(app.get('port'), process.env.npm_config_port);
|
2014-02-18 19:20:23 +00:00
|
|
|
|
|
|
|
delete process.env.npm_config_port;
|
|
|
|
delete process.env.OPENSHIFT_SLS_PORT;
|
|
|
|
delete process.env.OPENSHIFT_NODEJS_PORT;
|
|
|
|
delete process.env.PORT;
|
|
|
|
delete process.env.npm_package_config_port;
|
2013-12-06 01:42:06 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
function randomHost() {
|
|
|
|
return Math.random().toString().split('.')[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
function randomPort() {
|
|
|
|
return Math.floor(Math.random() * 10000);
|
|
|
|
}
|
2014-02-18 19:20:23 +00:00
|
|
|
|
|
|
|
it('should honor 0 for free port', function () {
|
|
|
|
var app = loopback();
|
|
|
|
app.boot({app: {port: 0}});
|
|
|
|
assert.equal(app.get('port'), 0);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should default to port 3000', function () {
|
|
|
|
var app = loopback();
|
|
|
|
app.boot({app: {port: undefined}});
|
|
|
|
assert.equal(app.get('port'), 3000);
|
|
|
|
});
|
2013-12-06 01:42:06 +00:00
|
|
|
});
|
|
|
|
|
2013-10-29 21:12:23 +00:00
|
|
|
it('Instantiate models', function () {
|
|
|
|
assert(app.models);
|
|
|
|
assert(app.models.FooBarBatBaz);
|
|
|
|
assert(app.models.fooBarBatBaz);
|
|
|
|
assertValidDataSource(app.models.FooBarBatBaz.dataSource);
|
|
|
|
assert.isFunc(app.models.FooBarBatBaz, 'find');
|
|
|
|
assert.isFunc(app.models.FooBarBatBaz, 'create');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('Attach models to data sources', function () {
|
|
|
|
assert.equal(app.models.FooBarBatBaz.dataSource, app.dataSources.theDb);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('Instantiate data sources', function () {
|
|
|
|
assert(app.dataSources);
|
|
|
|
assert(app.dataSources.theDb);
|
|
|
|
assertValidDataSource(app.dataSources.theDb);
|
|
|
|
assert(app.dataSources.TheDb);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2013-11-04 22:07:26 +00:00
|
|
|
describe('app.boot(appRootDir)', function () {
|
2013-10-29 21:12:23 +00:00
|
|
|
it('Load config files', function () {
|
|
|
|
var app = loopback();
|
|
|
|
|
2013-12-18 03:15:48 +00:00
|
|
|
app.boot(SIMPLE_APP);
|
2013-10-29 21:12:23 +00:00
|
|
|
|
|
|
|
assert(app.models.foo);
|
|
|
|
assert(app.models.Foo);
|
|
|
|
assert(app.models.Foo.dataSource);
|
|
|
|
assert.isFunc(app.models.Foo, 'find');
|
|
|
|
assert.isFunc(app.models.Foo, 'create');
|
|
|
|
});
|
|
|
|
});
|
2013-11-19 20:35:29 +00:00
|
|
|
|
2014-01-13 14:24:52 +00:00
|
|
|
describe('installMiddleware()', function() {
|
|
|
|
var app;
|
|
|
|
beforeEach(function() { app = loopback(); });
|
|
|
|
|
|
|
|
it('installs loopback.token', function(done) {
|
|
|
|
app.models.accessToken = loopback.AccessToken;
|
|
|
|
|
|
|
|
app.installMiddleware();
|
|
|
|
|
|
|
|
app.get('/', function(req, res) {
|
|
|
|
res.send({ accessTokenId: req.accessToken && req.accessToken.id });
|
|
|
|
});
|
|
|
|
|
|
|
|
app.models.accessToken.create({}, function(err, token) {
|
|
|
|
if (err) done(err);
|
|
|
|
request(app).get('/')
|
|
|
|
.set('Authorization', token.id)
|
|
|
|
.expect(200, { accessTokenId: token.id })
|
|
|
|
.end(done);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('emits "middleware:preprocessors" before handlers are installed',
|
|
|
|
function(done) {
|
|
|
|
app.on('middleware:preprocessors', function() {
|
|
|
|
this.use(function(req, res, next) {
|
|
|
|
req.preprocessed = true;
|
|
|
|
next();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
app.installMiddleware();
|
|
|
|
|
|
|
|
app.get('/', function(req, res) {
|
|
|
|
res.send({ preprocessed: req.preprocessed });
|
|
|
|
});
|
|
|
|
|
|
|
|
request(app).get('/')
|
|
|
|
.expect(200, { preprocessed: true})
|
|
|
|
.end(done);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
it('emits "middleware:handlers before installing express router',
|
|
|
|
function(done) {
|
|
|
|
app.on('middleware:handlers', function() {
|
|
|
|
this.use(function(req, res, next) {
|
|
|
|
res.send({ handler: 'middleware' });
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
app.installMiddleware();
|
|
|
|
|
|
|
|
app.get('/', function(req, res) {
|
|
|
|
res.send({ handler: 'router' });
|
|
|
|
});
|
|
|
|
|
|
|
|
request(app).get('/')
|
|
|
|
.expect(200, { handler: 'middleware' })
|
|
|
|
.end(done);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
it('emits "middleware:error-handlers" after all request handlers',
|
|
|
|
function(done) {
|
|
|
|
var logs = [];
|
|
|
|
app.on('middleware:error-handlers', function() {
|
|
|
|
app.use(function(err, req, res, next) {
|
|
|
|
logs.push(req.url);
|
|
|
|
next(err);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
app.installMiddleware();
|
|
|
|
|
|
|
|
request(app).get('/not-found')
|
|
|
|
.expect(404)
|
|
|
|
.end(function(err, res) {
|
|
|
|
if (err) done(err);
|
|
|
|
expect(logs).to.eql(['/not-found']);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
it('installs REST transport', function(done) {
|
|
|
|
app.model(loopback.Application);
|
|
|
|
app.set('restApiRoot', '/api');
|
|
|
|
app.installMiddleware();
|
|
|
|
|
|
|
|
request(app).get('/api/applications')
|
|
|
|
.expect(200, [])
|
|
|
|
.end(done);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2014-01-08 14:20:17 +00:00
|
|
|
describe('listen()', function() {
|
|
|
|
it('starts http server', function(done) {
|
|
|
|
var app = loopback();
|
|
|
|
app.set('port', 0);
|
|
|
|
app.get('/', function(req, res) { res.send(200, 'OK'); });
|
|
|
|
|
|
|
|
var server = app.listen();
|
|
|
|
|
|
|
|
expect(server).to.be.an.instanceOf(require('http').Server);
|
|
|
|
|
|
|
|
request(server)
|
|
|
|
.get('/')
|
|
|
|
.expect(200, done);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('updates port on "listening" event', function(done) {
|
|
|
|
var app = loopback();
|
|
|
|
app.set('port', 0);
|
|
|
|
|
|
|
|
app.listen(function() {
|
|
|
|
expect(app.get('port'), 'port').to.not.equal(0);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('forwards to http.Server.listen on more than one arg', function(done) {
|
|
|
|
var app = loopback();
|
|
|
|
app.set('port', 1);
|
|
|
|
app.listen(0, '127.0.0.1', function() {
|
|
|
|
expect(app.get('port'), 'port').to.not.equal(0).and.not.equal(1);
|
|
|
|
expect(this.address().address).to.equal('127.0.0.1');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('forwards to http.Server.listen when the single arg is not a function',
|
|
|
|
function(done) {
|
|
|
|
var app = loopback();
|
|
|
|
app.set('port', 1);
|
|
|
|
app.listen(0).on('listening', function() {
|
|
|
|
expect(app.get('port'), 'port') .to.not.equal(0).and.not.equal(1);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
it('uses app config when no parameter is supplied', function(done) {
|
|
|
|
var app = loopback();
|
|
|
|
// Http listens on all interfaces by default
|
|
|
|
// Custom host serves as an indicator whether
|
|
|
|
// the value was used by app.listen
|
|
|
|
app.set('host', '127.0.0.1');
|
|
|
|
app.listen()
|
|
|
|
.on('listening', function() {
|
|
|
|
expect(this.address().address).to.equal('127.0.0.1');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2014-02-05 17:46:22 +00:00
|
|
|
describe('enableAuth', function() {
|
|
|
|
it('should set app.isAuthEnabled to true', function() {
|
|
|
|
expect(app.isAuthEnabled).to.not.equal(true);
|
|
|
|
app.enableAuth();
|
|
|
|
expect(app.isAuthEnabled).to.equal(true);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2013-11-19 20:35:29 +00:00
|
|
|
describe('app.get("/", loopback.status())', function () {
|
|
|
|
it('should return the status of the application', function (done) {
|
|
|
|
var app = loopback();
|
|
|
|
app.get('/', loopback.status());
|
|
|
|
request(app)
|
|
|
|
.get('/')
|
|
|
|
.expect(200)
|
|
|
|
.end(function(err, res) {
|
|
|
|
if(err) return done(err);
|
|
|
|
|
|
|
|
assert.equal(typeof res.body, 'object');
|
|
|
|
assert(res.body.started);
|
2014-02-19 23:14:31 +00:00
|
|
|
// The number can be 0
|
|
|
|
assert(res.body.uptime !== undefined);
|
2013-11-19 20:35:29 +00:00
|
|
|
|
|
|
|
var elapsed = Date.now() - Number(new Date(res.body.started));
|
|
|
|
|
|
|
|
// elapsed should be a positive number...
|
|
|
|
assert(elapsed > 0);
|
|
|
|
|
|
|
|
// less than 100 milliseconds
|
|
|
|
assert(elapsed < 100);
|
|
|
|
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2013-10-29 21:12:23 +00:00
|
|
|
});
|