diff --git a/config.coffee b/config.coffee index 1c67481..36e4e3f 100644 --- a/config.coffee +++ b/config.coffee @@ -15,7 +15,6 @@ module.exports = (rbDir, options) -> config = require("#{config.req.config}/config-app") config, options config = require("#{config.req.config}/config-build") config, options config = require("#{config.req.config}/config-ports") config, options - config = require("#{config.req.config}/config-server") config config = require("#{config.req.config}/config-browser") config, options config = require("#{config.req.config}/config-minify") config, options config = require("#{config.req.config}/config-file-names") config diff --git a/config/config-dist-and-src.coffee b/config/config-dist-and-src.coffee index d9f2e69..aea15f6 100644 --- a/config/config-dist-and-src.coffee +++ b/config/config-dist-and-src.coffee @@ -19,7 +19,7 @@ module.exports = (config, options) -> file = appServer: 'routes.js' # app server dist entry file - rbServer: 'server.js' # rb server dist bootstrap file + rbServerInit: 'init-server.js' # rb server dist bootstrap file # dirs # ==== @@ -149,7 +149,7 @@ module.exports = (config, options) -> config[v1][v2].server.scripts.dir = config[v1][v2].server.dir addToServerRbDist = -> - config.dist.rb.server.scripts.file = file.rbServer # rb server dist bootstrap file + config.dist.rb.server.scripts.file = file.rbServerInit # rb server dist bootstrap file config.dist.rb.server.scripts.path = path.join( config.app.dir config.dist.rb.server.scripts.dir diff --git a/config/config-node_modules.coffee b/config/config-node_modules.coffee index bba084e..1738ad3 100644 --- a/config/config-node_modules.coffee +++ b/config/config-node_modules.coffee @@ -5,7 +5,7 @@ module.exports = (config, options) -> # modules # ======= - rbModules = ['express', 'body-parser'] + rbModules = ['body-parser', 'express', 'q'] appModules = options.server.node_modules or [] # http proxy @@ -18,25 +18,29 @@ module.exports = (config, options) -> rb: modules: rbModules dist: dir: null, modules: {} - src: dir: null, modules: {} + src: dir: null, relPath: null, modules: {} app: modules: appModules dist: dir: null, modules: {} - src: dir: null, modules: {} + src: dir: null, relPath: null, modules: {} # dist and src # ============ addDistAndSrc = -> + nmDir = 'node_modules' for appOrRb, v1 of node_modules for k2, v2 of v1 continue unless k2 is 'dist' or k2 is 'src' switch k2 when 'dist' - dir = config.dist[appOrRb].server.scripts.dir - v2.dir = path.join dir, 'node_modules' + dir = config.dist[appOrRb].server.scripts.dir + v2.dir = path.join dir, nmDir when 'src' - dir = config[appOrRb].dir - v2.dir = path.join dir, 'node_modules' + dir = config[appOrRb].dir + v2.dir = path.join dir, nmDir + v2.relPath = nmDir + continue if appOrRb is 'app' + v2.relPath = path.join nmDir, config.rb.name, nmDir addDistAndSrc() diff --git a/config/config-server.coffee b/config/config-server.coffee deleted file mode 100644 index 1865978..0000000 --- a/config/config-server.coffee +++ /dev/null @@ -1,31 +0,0 @@ -module.exports = (config) -> - log = require "#{config.req.helpers}/log" - test = require("#{config.req.helpers}/test")() - - # init server - # =========== - server = {} - - # messages - # ======== - server.msg = - start: 'Server started on' - noScripts: 'No application server scripts to load.' - - # add server to config - # ==================== - config.server = server - - # logs - # ==== - # log.json server, 'server =' - - # tests - # ===== - test.log 'true', config.server, 'add server to config' - - # return - # ====== - config - - diff --git a/helpers/jasmine.coffee b/helpers/jasmine.coffee new file mode 100644 index 0000000..823e418 --- /dev/null +++ b/helpers/jasmine.coffee @@ -0,0 +1,63 @@ +module.exports = (config) -> + q = require 'q' + path = require 'path' + Jasmine = require 'jasmine' + Reporter = require 'jasmine-terminal-reporter' + jasmineExpect = path.join config.node_modules.rb.src.relPath, 'jasmine-expect', 'index.js' + + jasmine = + # properties + # ========== + defer: q.defer() + jasmine: null + results: status: null, total: 0, passed: 0, failed: 0, failedSpecs: [] + + # public + # ====== + init: (files) -> + @_setJasmine() + ._setConfig files + ._setOnComplete() + ._addReporter() + @ + + execute: -> # 5 seconds is the default spec timeout + @jasmine.execute() + @defer.promise + + getResults: -> + @results + + # private + # ======= + _setJasmine: -> + @jasmine = new Jasmine() + @ + + _setConfig: (files) -> + @jasmine.loadConfig + spec_dir: '' + spec_files: files + helpers: [ jasmineExpect ] + @ + + _setOnComplete: (defer) -> + @jasmine.onComplete (passed) => + @results.status = if passed then 'passed' else 'failed' + @defer.resolve() + @ + + _addReporter: -> + @jasmine.addReporter new Reporter + isVerbose: false + showColors: true + includeStackTrace: false + + @jasmine.addReporter + specDone: (result) => + @results.total++ + return @results.passed++ if result.status is 'passed' + @results.failed++ + @results.failedSpecs.push result.fullName + @ + diff --git a/init/rapid.coffee b/init/rapid.coffee index e677e2a..c33a9b0 100644 --- a/init/rapid.coffee +++ b/init/rapid.coffee @@ -79,6 +79,7 @@ module.exports = (gulp, config) -> "#{config.rb.prefix.task}common-server" "#{config.rb.prefix.task}start-server" "#{config.rb.prefix.task}common-test-server" + "#{config.rb.prefix.task}stop-server" cb ) -> defer.resolve() unless task.wasCalledFrom config.rb.tasks['test'] @@ -111,6 +112,7 @@ module.exports = (gulp, config) -> "#{config.rb.prefix.task}start-server" "#{config.rb.prefix.task}common-test-server" "#{config.rb.prefix.task}clean-server-test-dist" + "#{config.rb.prefix.task}stop-server" cb ) -> defer.resolve() unless task.wasCalledFrom config.rb.tasks['prod:test'] diff --git a/init/tasks.coffee b/init/tasks.coffee index bd122cc..0e66b16 100644 --- a/init/tasks.coffee +++ b/init/tasks.coffee @@ -91,9 +91,10 @@ module.exports = (gulp, config) -> # server # ====== require("#{config.req.tasks}/server/find-open-port") gulp, config - require("#{config.req.tasks}/server/start-server") gulp, config - require("#{config.req.tasks}/server/spawn-server") gulp, config require("#{config.req.tasks}/server/nodemon") gulp, config, bs + require("#{config.req.tasks}/server/spawn-server") gulp, config + require("#{config.req.tasks}/server/start-server") gulp, config + require("#{config.req.tasks}/server/stop-server") gulp, config # client test # =========== diff --git a/package.json b/package.json index a51f188..8f907c8 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "dependencies": { "body-parser": "1.14.1", "bower": "1.5.3", - "browser-sync": "2.9.6", + "browser-sync": "2.9.7", "coffee-script": "1.10.0", "colors": "1.1.2", "copy-paste": "1.1.3", @@ -47,8 +47,7 @@ "gulp-cachebust": "0.0.6", "gulp-coffee": "2.3.1", "gulp-concat": "2.6.0", - "gulp-if": "1.2.5", - "gulp-jasmine": "2.1.0", + "gulp-if": "2.0.0", "gulp-jsonminify": "1.0.0", "gulp-less": "3.0.3", "gulp-minify-css": "1.2.1", @@ -64,7 +63,10 @@ "gulp-util": "3.0.6", "gulp-watch": "4.3.5", "http-proxy-middleware": "0.9.0", + "jasmine": "2.3.2", "jasmine-core": "2.3.4", + "jasmine-expect": "2.0.0-beta2", + "jasmine-terminal-reporter": "1.0.0", "karma": "0.13.10", "karma-jasmine": "0.3.6", "karma-jasmine-matchers": "2.0.0-beta2", @@ -75,6 +77,7 @@ "karma-safari-launcher": "0.1.1", "lodash": "3.10.1", "open": "0.0.5", + "phantomjs": "1.9.18", "postcss": "5.0.8", "postcss-import": "7.0.0", "q": "1.4.1", diff --git a/src/server/app-defaults.coffee b/src/server/app-defaults.coffee new file mode 100644 index 0000000..07c28b8 --- /dev/null +++ b/src/server/app-defaults.coffee @@ -0,0 +1,15 @@ +# default app configuration +# ========================= +module.exports = (server, config) -> + app = server.app + spa = config.spa.dist.file # ex: spa.html + + app.set 'x-powered-by', false # removes this http header + app.use server.express.static server.paths.client + app.use server.middleware.bodyParser.json() # parse application/json + + app.get '/', (req, res) -> + msg = 'Hello Server!' + return res.send msg unless config.build.client + return res.send msg if config.exclude.spa + res.sendFile spa, root: server.paths.client \ No newline at end of file diff --git a/src/server/http-proxy.coffee b/src/server/http-proxy.coffee index d3d83a0..df3050a 100644 --- a/src/server/http-proxy.coffee +++ b/src/server/http-proxy.coffee @@ -1,5 +1,4 @@ -module.exports = (app, config, opts) -> - return if not config.httpProxy.length +module.exports = (app, config) -> proxyMidware = require 'http-proxy-middleware' # express middleware proxies = [] @@ -11,4 +10,8 @@ module.exports = (app, config, opts) -> # add middleware to express app # ============================= - app.use proxies \ No newline at end of file + app.use proxies + + # return middleware + # ================= + proxyMidware \ No newline at end of file diff --git a/src/server/init-server.coffee b/src/server/init-server.coffee new file mode 100644 index 0000000..ac3675f --- /dev/null +++ b/src/server/init-server.coffee @@ -0,0 +1,36 @@ +dir = __dirname # all paths are relative to this file +path = require 'path' +express = require 'express' +bodyParser = require 'body-parser' # middleware for parsing the req.body +config = require path.join dir, 'config.json' +appFilePath = path.resolve dir, '..', config.dist.app.server.scripts.file +clientDirPath = path.resolve dir, '..', '..', config.dist.app.client.dirName # creates absolute path to the client folder +serverDirPath = path.resolve dir, '..', '..', config.dist.app.server.dirName + +# create the server object +# ======================== +server = require './server' +server.express = express +server.app = server.express() +server.middleware = { bodyParser } +server.paths = client: clientDirPath, server: serverDirPath +server.server = require('./start-server') server.app, config +require('./app-defaults') server, config + +# load optional http proxy +# ======================== +proxyFilePath = path.join dir, 'http-proxy.js' +require(proxyFilePath) server.app, config if config.httpProxy.length + +# load optional app server dist entry script +# ========================================== +try require(appFilePath) server +catch e + if e.code and + e.code.toLowerCase() is 'module_not_found' and + e.message.indexOf(appFilePath) isnt -1 + console.log 'No application server scripts to load.' + else + console.log e # log e if there is an actual error + + diff --git a/src/server/server.coffee b/src/server/server.coffee index 48ef464..2513583 100644 --- a/src/server/server.coffee +++ b/src/server/server.coffee @@ -1,48 +1,3 @@ -dir = __dirname # all paths are relative to this file -path = require 'path' -express = require 'express' -bodyParser = require 'body-parser' -config = require path.join dir, 'config.json' -app = express() -port = process.env.PORT or config.ports.server -spa = config.spa.dist.file # ex: spa.html -clientDirPath = path.resolve dir, '..', '..', config.dist.app.client.dirName # creates absolute path to the client folder -appFilePath = path.resolve dir, '..', config.dist.app.server.scripts.file -serverDirPath = path.resolve dir, '..', '..', config.dist.app.server.dirName -proxyFilePath = path.join dir, 'http-proxy.js' - -# configure -# ========= -app.use express.static clientDirPath -app.use bodyParser.json() # parse application/json - -app.listen port, -> - console.log "#{config.server.msg.start} #{config.ports.server}" - -app.get '/', (req, res) -> - msg = 'Hello Server!' - return res.send msg unless config.build.client - return res.send msg if config.exclude.spa - res.sendFile spa, root: clientDirPath - -# options to pass -# =============== -opts = - path: - client: clientDirPath - server: serverDirPath - -# load optional http proxy -# ======================== -require(proxyFilePath) app, config, opts if config.httpProxy.length - -# load optional app server dist entry script -# ========================================== -try require(appFilePath) app, opts -catch e - if e.code and - e.code.toLowerCase() is 'module_not_found' and - e.message.indexOf(appFilePath) isnt -1 - console.log config.server.msg.noScripts - else - console.log e # log e if there is an actual error +# Dynamically populated in init-server.js +# ======================================= +module.exports = {} \ No newline at end of file diff --git a/src/server/start-server.coffee b/src/server/start-server.coffee new file mode 100644 index 0000000..b96ded3 --- /dev/null +++ b/src/server/start-server.coffee @@ -0,0 +1,7 @@ +module.exports = (app, config) -> + port = process.env.PORT or config.ports.server + + # must return server + # ================== + server = app.listen port, -> + console.log "Server started on port #{port}" \ No newline at end of file diff --git a/src/server/stop-server.coffee b/src/server/stop-server.coffee new file mode 100644 index 0000000..ac97168 --- /dev/null +++ b/src/server/stop-server.coffee @@ -0,0 +1,11 @@ +module.exports = -> + q = require 'q' + server = require('./server').server + port = server.address().port + + defer = q.defer() + server.close -> + console.log "Server stopped on port #{port}" + defer.resolve() + + defer.promise diff --git a/tasks/server/find-open-port.coffee b/tasks/server/find-open-port.coffee index 94eea23..59f5726 100644 --- a/tasks/server/find-open-port.coffee +++ b/tasks/server/find-open-port.coffee @@ -2,7 +2,6 @@ # ========================================= module.exports = (gulp, config) -> q = require 'q' - fse = require 'fs-extra' findPort = require 'find-port' configHelp = require("#{config.req.helpers}/config") config diff --git a/tasks/server/nodemon.coffee b/tasks/server/nodemon.coffee index f2deaff..b98ba7b 100644 --- a/tasks/server/nodemon.coffee +++ b/tasks/server/nodemon.coffee @@ -1,7 +1,6 @@ module.exports = (gulp, config, browserSync) -> - q = require 'q' - path = require 'path' - nodemon = require 'gulp-nodemon' + q = require 'q' + nodemon = require 'gulp-nodemon' # globals # ======= diff --git a/tasks/server/stop-server.coffee b/tasks/server/stop-server.coffee new file mode 100644 index 0000000..b6d4560 --- /dev/null +++ b/tasks/server/stop-server.coffee @@ -0,0 +1,14 @@ +module.exports = (gulp, config) -> + q = require 'q' + path = require 'path' + promiseHelp = require "#{config.req.helpers}/promise" + stopServerFile = path.join config.dist.rb.server.scripts.path, 'stop-server.js' + + # register task + # ============= + gulp.task "#{config.rb.prefix.task}stop-server", -> + return promiseHelp.get() unless config.build.server + defer = q.defer() + stopServer = require stopServerFile + stopServer().done -> defer.resolve() + defer.promise \ No newline at end of file diff --git a/tasks/test/client/run-client-tests.coffee b/tasks/test/client/run-client-tests.coffee index a366213..4027145 100644 --- a/tasks/test/client/run-client-tests.coffee +++ b/tasks/test/client/run-client-tests.coffee @@ -7,6 +7,7 @@ module.exports = (gulp, config) -> moduleHelp = require "#{config.req.helpers}/module" promiseHelp = require "#{config.req.helpers}/promise" format = require("#{config.req.helpers}/format")() + resultsFile = path.join config.dist.app.client.dir, 'test-results.json' # Global # ====== @@ -31,10 +32,9 @@ module.exports = (gulp, config) -> # tasks # ===== - cleanResultsFile = (src, file) -> + cleanResultsFile = (src) -> defer = q.defer() del(src, force:true).then (paths) -> - # console.log "removed #{file}".yellow defer.resolve() defer.promise @@ -50,7 +50,7 @@ module.exports = (gulp, config) -> karmaConfig.files = tests.scripts server = new Server karmaConfig, (exitCode) -> - console.log "karma has exited with #{exitCode}".yellow + # console.log "karma has exited with #{exitCode}".yellow TestResults.status = if not exitCode then 'passed' else 'failed' TestResults.exitCode = exitCode defer.resolve() @@ -63,14 +63,20 @@ module.exports = (gulp, config) -> fs.writeFileSync file, format.json TestResults promiseHelp.get() + failureCheck = -> + return promiseHelp.get() if TestResults.status is 'passed' + process.on 'exit', -> + msg = "Client test failed - created #{resultsFile}" + console.error msg.error + .exit 1 + runTask = -> # synchronously defer = q.defer() - resultsFileName = 'test-results.json' - resultsFilePath = path.join config.dist.app.client.dir, resultsFileName tasks = [ - -> cleanResultsFile resultsFilePath, resultsFileName + -> cleanResultsFile resultsFile -> runTests() - -> writeResultsFile resultsFilePath + -> writeResultsFile resultsFile + -> failureCheck() ] tasks.reduce(q.when, q()).done -> defer.resolve() defer.promise diff --git a/tasks/test/server/run-server-tests.coffee b/tasks/test/server/run-server-tests.coffee index b46437d..b168acf 100644 --- a/tasks/test/server/run-server-tests.coffee +++ b/tasks/test/server/run-server-tests.coffee @@ -1,23 +1,51 @@ module.exports = (gulp, config) -> - q = require 'q' - jasmine = require 'gulp-jasmine' + q = require 'q' + del = require 'del' + path = require 'path' + fse = require 'fs-extra' + promiseHelp = require "#{config.req.helpers}/promise" + jasmine = require("#{config.req.helpers}/jasmine") config + resultsFile = path.join config.dist.app.server.dir, 'test-results.json' - runTask = (src) -> + # tasks + # ===== + cleanResultsFile = (src) -> defer = q.defer() - gulp.src src - .pipe jasmine() - .on 'finish', -> - defer.resolve() + del(src, force:true).then (paths) -> + defer.resolve() defer.promise - runMulti = -> - src = [].concat( - config.glob.dist.rb.server.test.js - config.glob.dist.app.server.test.js - ) - runTask src + runTests = (files) -> + jasmine.init(files).execute() # returns promise + + writeResultsFile = (src) -> + results = jasmine.getResults() + return promiseHelp.get() unless results.status is 'failed' + fse.writeJSONSync src, results, spaces: '\t' + promiseHelp.get() + + failureCheck = -> + results = jasmine.getResults() + return promiseHelp.get() if results.status is 'passed' + process.on 'exit', -> + msg = "Server test failed - created #{resultsFile}" + console.error msg.error + .exit 1 + + runMulti = -> # synchronously + defer = q.defer() + tasks = [ + -> cleanResultsFile resultsFile + -> runTests config.glob.dist.app.server.test.js + -> writeResultsFile resultsFile + -> failureCheck() + ] + tasks.reduce(q.when, q()).done -> defer.resolve() + defer.promise # register task # ============= gulp.task "#{config.rb.prefix.task}run-server-tests", -> - runMulti() \ No newline at end of file + runMulti() + +