From 186e3e8f924bbb324b66f46ed8ea4e10f2647319 Mon Sep 17 00:00:00 2001 From: Simon Ho Date: Thu, 31 Dec 2015 15:41:18 -0800 Subject: [PATCH] Remove dependency on loopback-testing - Copy depedent source from loopback-testing into test/helpers - Removed loopback-testing from package.json --- package.json | 1 - test/access-control.integration.js | 2 +- test/helpers/loopback-testing-helper.js | 408 ++++++++++++++++++++++++ test/relations.integration.js | 2 +- test/remoting.integration.js | 2 +- test/user.integration.js | 2 +- 6 files changed, 412 insertions(+), 5 deletions(-) create mode 100644 test/helpers/loopback-testing-helper.js diff --git a/package.json b/package.json index b093c9ec..9fa18d8a 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,6 @@ "karma-script-launcher": "^0.1.0", "loopback-boot": "^2.7.0", "loopback-datasource-juggler": "^3.0.0-alpha.1", - "loopback-testing": "~1.1.0", "mocha": "^2.1.0", "sinon": "^1.13.0", "strong-task-emitter": "^0.0.6", diff --git a/test/access-control.integration.js b/test/access-control.integration.js index 3125a653..66f10d60 100644 --- a/test/access-control.integration.js +++ b/test/access-control.integration.js @@ -1,7 +1,7 @@ /*jshint -W030 */ var loopback = require('../'); -var lt = require('loopback-testing'); +var lt = require('./helpers/loopback-testing-helper'); var path = require('path'); var ACCESS_CONTROL_APP = path.join(__dirname, 'fixtures', 'access-control'); var app = require(path.join(ACCESS_CONTROL_APP, 'server/server.js')); diff --git a/test/helpers/loopback-testing-helper.js b/test/helpers/loopback-testing-helper.js new file mode 100644 index 00000000..3d37954a --- /dev/null +++ b/test/helpers/loopback-testing-helper.js @@ -0,0 +1,408 @@ +var _describe = {}; +var _it = {}; +var _beforeEach = {}; +var helpers = { + describe: _describe, + it: _it, + beforeEach: _beforeEach +}; +module.exports = helpers; + +var assert = require('assert'); +var request = require('supertest'); +var expect = require('chai').expect; + +_beforeEach.withApp = function(app) { + if (app.models.User) { + // Speed up the password hashing algorithm + app.models.User.settings.saltWorkFactor = 4; + } + + beforeEach(function() { + this.app = app; + var _request = this.request = request(app); + this.post = _request.post; + this.get = _request.get; + this.put = _request.put; + this.del = _request.del; + }); +}; + +_beforeEach.cleanDatasource = function(dsName) { + beforeEach(function(done) { + if (!dsName) dsName = 'db'; + + if (typeof this.app === 'function' && + typeof this.app.datasources === 'object' && + typeof this.app.datasources[dsName] === 'object') { + this.app.datasources[dsName].automigrate(); + this.app.datasources[dsName].connector.ids = {}; + } + + done(); + }); +}; + +function mixin(obj, into) { + Object.keys(obj).forEach(function(key) { + if (typeof obj[key] === 'function') { + into[key] = obj[key]; + } + }); +} + +_describe.staticMethod = function(methodName, cb) { + describe('.' + methodName, function() { + beforeEach(function() { + this.method = methodName; + this.isStaticMethod = true; + }); + cb(); + }); +}; + +_describe.instanceMethod = function(methodName, cb) { + describe('.prototype.' + methodName, function() { + beforeEach(function() { + this.method = methodName; + this.isInstanceMethod = true; + }); + cb(); + }); +}; + +_beforeEach.withArgs = function() { + var args = Array.prototype.slice.call(arguments, 0); + beforeEach(function() { + this.args = args; + }); +}; + +_beforeEach.givenModel = function(modelName, attrs, optionalHandler) { + var modelKey = modelName; + + if (typeof attrs === 'function') { + optionalHandler = attrs; + attrs = undefined; + } + + if (typeof optionalHandler === 'string') { + modelKey = optionalHandler; + } + + attrs = attrs || {}; + + beforeEach(function(done) { + var test = this; + var app = this.app; + var model = app.models[modelName]; + assert(model, 'cannot get model of name ' + modelName + ' from app.models'); + assert(model.dataSource, 'cannot test model ' + modelName + + ' without attached dataSource'); + assert( + typeof model.create === 'function', + modelName + ' does not have a create method' + ); + + model.create(attrs, function(err, result) { + if (err) { + console.error(err.message); + if (err.details) console.error(err.details); + done(err); + } else { + test[modelKey] = result; + done(); + } + }); + }); + + if (typeof optionalHandler === 'function') { + beforeEach(optionalHandler); + } + + afterEach(function(done) { + this[modelKey].destroy(done); + }); +}; + +_beforeEach.givenUser = function(attrs, optionalHandler) { + _beforeEach.givenModel('user', attrs, optionalHandler); +}; + +_beforeEach.givenUserWithRole = function(attrs, role, optionalHandler) { + _beforeEach.givenUser(attrs, function(done) { + var test = this; + test.app.models.Role.create({name: role}, function(err, result) { + if (err) { + console.error(err.message); + if (err.details) console.error(err.details); + return done(err); + } + + test.userRole = result; + test.app.models.roleMapping.create( + {principalId: test.user.id, + principalType: test.app.models.roleMapping.USER, + roleId: result.id}, + function(err, result) { + if (err) { + console.error(err.message); + if (err.details) console.error(err.details); + return done(err); + } + + test.userRoleMapping = result; + done(); + } + ); + }); + }); + + if (typeof optionalHandler === 'function') { + beforeEach(optionalHandler); + } + + afterEach(function(done) { + var test = this; + this.userRole.destroy(function(err) { + if (err) return done(err); + test.userRole = undefined; + + test.userRoleMapping.destroy(function(err) { + if (err) return done(err); + test.userRoleMapping = undefined; + done(); + }); + }); + }); +}; + +_beforeEach.givenLoggedInUser = function(credentials, optionalHandler) { + _beforeEach.givenUser(credentials, function(done) { + var test = this; + this.user.constructor.login(credentials, function(err, token) { + if (err) { + done(err); + } else { + test.loggedInAccessToken = token; + done(); + } + }); + }); + + afterEach(function(done) { + var test = this; + this.loggedInAccessToken.destroy(function(err) { + if (err) return done(err); + test.loggedInAccessToken = undefined; + done(); + }); + }); +}; + +_beforeEach.givenLoggedInUserWithRole = function(credentials, role, optionalHandler) { + _beforeEach.givenUserWithRole(credentials, role, function(done) { + var test = this; + this.user.constructor.login(credentials, function(err, token) { + if (err) { + done(err); + } else { + test.loggedInAccessToken = token; + done(); + } + }); + }); + + afterEach(function(done) { + var test = this; + this.loggedInAccessToken.destroy(function(err) { + if (err) return done(err); + test.loggedInAccessToken = undefined; + done(); + }); + }); +}; + +_beforeEach.givenAnUnauthenticatedToken = function(attrs, optionalHandler) { + _beforeEach.givenModel('accessToken', attrs, optionalHandler); +}; + +_beforeEach.givenAnAnonymousToken = function(attrs, optionalHandler) { + _beforeEach.givenModel('accessToken', {id: '$anonymous'}, optionalHandler); +}; + +_describe.whenCalledRemotely = function(verb, url, data, cb) { + if (cb === undefined) { + cb = data; + data = null; + } + + var urlStr = url; + if (typeof url === 'function') { + urlStr = '/'; + } + + describe(verb.toUpperCase() + ' ' + urlStr, function() { + beforeEach(function(cb) { + if (typeof url === 'function') { + this.url = url.call(this); + } + this.remotely = true; + this.verb = verb.toUpperCase(); + this.url = this.url || url; + var methodForVerb = verb.toLowerCase(); + if (methodForVerb === 'delete') methodForVerb = 'del'; + + if (this.request === undefined) { + throw new Error('App is not specified. Please use lt.beforeEach.withApp to specify the app.'); + } + + this.http = this.request[methodForVerb](this.url); + delete this.url; + this.http.set('Accept', 'application/json'); + if (this.loggedInAccessToken) { + this.http.set('authorization', this.loggedInAccessToken.id); + } + if (data) { + var payload = data; + if (typeof data === 'function') + payload = data.call(this); + this.http.send(payload); + } + this.req = this.http.req; + var test = this; + this.http.end(function(err) { + test.req = test.http.req; + test.res = test.http.res; + delete test.url; + cb(); + }); + }); + + cb(); + }); +}; + +_describe.whenLoggedInAsUser = function(credentials, cb) { + describe('when logged in as user', function() { + _beforeEach.givenLoggedInUser(credentials); + cb(); + }); +}; + +_describe.whenLoggedInAsUserWithRole = function(credentials, role, cb) { + describe('when logged in as user', function() { + _beforeEach.givenLoggedInUser(credentials, role); + cb(); + }); +}; + +_describe.whenCalledByUser = function(credentials, verb, url, data, cb) { + describe('when called by logged in user', function() { + _beforeEach.givenLoggedInUser(credentials); + _describe.whenCalledRemotely(verb, url, data, cb); + }); +}; + +_describe.whenCalledByUserWithRole = function(credentials, role, verb, url, data, cb) { + describe('when called by logged in user with role ' + role, function() { + _beforeEach.givenLoggedInUserWithRole(credentials, role); + _describe.whenCalledRemotely(verb, url, data, cb); + }); +}; + +_describe.whenCalledAnonymously = function(verb, url, data, cb) { + describe('when called anonymously', function() { + _beforeEach.givenAnAnonymousToken(); + _describe.whenCalledRemotely(verb, url, data, cb); + }); +}; + +_describe.whenCalledUnauthenticated = function(verb, url, data, cb) { + describe('when called with unauthenticated token', function() { + _beforeEach.givenAnAnonymousToken(); + _describe.whenCalledRemotely(verb, url, data, cb); + }); +}; + +_it.shouldBeAllowed = function() { + it('should be allowed', function() { + assert(this.req); + assert(this.res); + // expect success - status 2xx or 3xx + expect(this.res.statusCode).to.be.within(100, 399); + }); +}; + +_it.shouldBeDenied = function() { + it('should not be allowed', function() { + assert(this.res); + var expectedStatus = this.aclErrorStatus || + this.app && this.app.get('aclErrorStatus') || + 401; + expect(this.res.statusCode).to.equal(expectedStatus); + }); +}; + +_it.shouldNotBeFound = function() { + it('should not be found', function() { + assert(this.res); + assert.equal(this.res.statusCode, 404); + }); +}; + +_it.shouldBeAllowedWhenCalledAnonymously = +function(verb, url, data) { + _describe.whenCalledAnonymously(verb, url, data, function() { + _it.shouldBeAllowed(); + }); +}; + +_it.shouldBeDeniedWhenCalledAnonymously = +function(verb, url) { + _describe.whenCalledAnonymously(verb, url, function() { + _it.shouldBeDenied(); + }); +}; + +_it.shouldBeAllowedWhenCalledUnauthenticated = +function(verb, url, data) { + _describe.whenCalledUnauthenticated(verb, url, data, function() { + _it.shouldBeAllowed(); + }); +}; + +_it.shouldBeDeniedWhenCalledUnauthenticated = +function(verb, url) { + _describe.whenCalledUnauthenticated(verb, url, function() { + _it.shouldBeDenied(); + }); +}; + +_it.shouldBeAllowedWhenCalledByUser = +function(credentials, verb, url, data) { + _describe.whenCalledByUser(credentials, verb, url, data, function() { + _it.shouldBeAllowed(); + }); +}; + +_it.shouldBeDeniedWhenCalledByUser = +function(credentials, verb, url) { + _describe.whenCalledByUser(credentials, verb, url, function() { + _it.shouldBeDenied(); + }); +}; + +_it.shouldBeAllowedWhenCalledByUserWithRole = +function(credentials, role, verb, url, data) { + _describe.whenCalledByUserWithRole(credentials, role, verb, url, data, function() { + _it.shouldBeAllowed(); + }); +}; + +_it.shouldBeDeniedWhenCalledByUserWithRole = +function(credentials, role, verb, url) { + _describe.whenCalledByUserWithRole(credentials, role, verb, url, function() { + _it.shouldBeDenied(); + }); +}; diff --git a/test/relations.integration.js b/test/relations.integration.js index 70f1ae12..e47bfafa 100644 --- a/test/relations.integration.js +++ b/test/relations.integration.js @@ -1,7 +1,7 @@ /*jshint -W030 */ var loopback = require('../'); -var lt = require('loopback-testing'); +var lt = require('./helpers/loopback-testing-helper'); var path = require('path'); var SIMPLE_APP = path.join(__dirname, 'fixtures', 'simple-integration-app'); var app = require(path.join(SIMPLE_APP, 'server/server.js')); diff --git a/test/remoting.integration.js b/test/remoting.integration.js index c3288d79..198c378c 100644 --- a/test/remoting.integration.js +++ b/test/remoting.integration.js @@ -1,5 +1,5 @@ var loopback = require('../'); -var lt = require('loopback-testing'); +var lt = require('./helpers/loopback-testing-helper'); var path = require('path'); var SIMPLE_APP = path.join(__dirname, 'fixtures', 'simple-integration-app'); var app = require(path.join(SIMPLE_APP, 'server/server.js')); diff --git a/test/user.integration.js b/test/user.integration.js index b2a92537..9cada628 100644 --- a/test/user.integration.js +++ b/test/user.integration.js @@ -1,6 +1,6 @@ /*jshint -W030 */ var loopback = require('../'); -var lt = require('loopback-testing'); +var lt = require('./helpers/loopback-testing-helper'); var path = require('path'); var SIMPLE_APP = path.join(__dirname, 'fixtures', 'user-integration-app'); var app = require(path.join(SIMPLE_APP, 'server/server.js'));