diff --git a/.eslintrc b/.eslintrc
index e3578aadf..d6622030e 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -1,3 +1,4 @@
{
- "extends": "standard"
+ "extends": "standard",
+ "parser": "babel-eslint"
}
diff --git a/client/karma.js b/client/karma.js
index 9caf386b3..176538cd2 100644
--- a/client/karma.js
+++ b/client/karma.js
@@ -113,7 +113,13 @@ var Karma = function (socket, iframe, opener, navigator, location) {
// we are not going to execute at all
this.error = function (msg, url, line) {
hasError = true
- socket.emit('karma_error', url ? msg + '\nat ' + url + (line ? ':' + line : '') : msg)
+ var message = msg
+
+ if (url) {
+ message = msg + '\nat ' + url + (line ? ':' + line : '')
+ }
+
+ socket.emit('karma_error', message)
this.complete()
return false
}
diff --git a/gruntfile.js b/gruntfile.js
index 2285372d7..365be2df1 100644
--- a/gruntfile.js
+++ b/gruntfile.js
@@ -28,15 +28,18 @@ module.exports = function (grunt) {
},
mochaTest: {
options: {
- ui: 'bdd',
+ require: [
+ 'babel/register'
+ ],
reporter: 'dot',
- quite: false,
+ ui: 'bdd',
+ quiet: false,
colors: true
},
unit: {
src: [
- 'test/unit/mocha-globals.coffee',
- 'test/unit/**/*.coffee'
+ 'test/unit/mocha-globals.js',
+ 'test/unit/**/*.spec.js'
]
}
},
@@ -64,6 +67,9 @@ module.exports = function (grunt) {
}
},
eslint: {
+ options: {
+ quiet: true
+ },
target: [
'<%= files.server %>',
'<%= files.grunt %>',
@@ -72,23 +78,6 @@ module.exports = function (grunt) {
'test/**/*.js'
]
},
- coffeelint: {
- unittests: {
- files: {
- src: ['test/unit/**/*.coffee']
- }
- },
- taskstests: {
- files: {
- src: ['test/tasks/**/*.coffee']
- }
- },
- options: {
- max_line_length: {
- value: 100
- }
- }
- },
'npm-publish': {
options: {
requires: ['build'],
@@ -127,7 +116,7 @@ module.exports = function (grunt) {
grunt.registerTask('build', ['browserify:client'])
grunt.registerTask('default', ['build', 'test', 'lint'])
- grunt.registerTask('lint', ['eslint', 'coffeelint'])
+ grunt.registerTask('lint', ['eslint'])
grunt.registerTask('release', 'Build, bump and publish to NPM.', function (type) {
grunt.task.run([
diff --git a/package.json b/package.json
index e8490f3cd..8bf00a5bd 100644
--- a/package.json
+++ b/package.json
@@ -215,7 +215,7 @@
"chokidar": "^1.0.1",
"colors": "^1.1.0",
"connect": "^3.3.5",
- "core-js": "^0.9.17",
+ "core-js": "^1.0.1",
"di": "^0.0.1",
"dom-serialize": "^2.2.0",
"expand-braces": "^0.1.1",
@@ -235,24 +235,24 @@
},
"devDependencies": {
"LiveScript": "^1.3.0",
+ "babel": "^5.6.23",
+ "babel-eslint": "^4.0.5",
"chai": "^2.3.0",
"chai-as-promised": "^5.0.0",
"chai-subset": "^1.0.1",
- "coffee-errors": "^0.8.6",
"coffee-script": "^1.9.2",
"cucumber": "^0.5.2",
- "eslint": "^0.24.1",
- "eslint-config-standard": "^3.4.1",
- "eslint-plugin-react": "^2.5.0",
+ "eslint": "^1.0.0",
+ "eslint-config-standard": "^4.0.0",
+ "eslint-plugin-react": "^3.2.0",
"grunt": "^0.4",
"grunt-auto-release": "^0.0.6",
"grunt-browserify": "^3.8.0",
"grunt-bump": "^0.3.1",
- "grunt-coffeelint": "^0.0.13",
"grunt-contrib-watch": "^0.6.1",
"grunt-conventional-changelog": "^1.2.2",
"grunt-cucumberjs": "^0.7.0",
- "grunt-eslint": "^16.0.0",
+ "grunt-eslint": "^17.0.0",
"grunt-mocha-test": "^0.12.7",
"grunt-npm": "0.0.2",
"karma-browserify": "^4.1.2",
diff --git a/test/.eslintrc b/test/.eslintrc
index 3c8fcd734..32dfd9f91 100644
--- a/test/.eslintrc
+++ b/test/.eslintrc
@@ -3,6 +3,8 @@
"mocha": true
},
"globals": {
- "expect": true
+ "expect": true,
+ "sinon": true,
+ "scheduleNextTick": true
}
}
diff --git a/test/unit/browser.spec.coffee b/test/unit/browser.spec.coffee
deleted file mode 100644
index 73eaea72a..000000000
--- a/test/unit/browser.spec.coffee
+++ /dev/null
@@ -1,509 +0,0 @@
-#==============================================================================
-# lib/browser.js module
-#==============================================================================
-describe 'Browser', ->
- e = require '../../lib/events'
- Browser = require '../../lib/browser'
- Collection = require '../../lib/browser_collection'
- createMockTimer = require './mocks/timer'
-
- browser = collection = emitter = socket = null
- socketId = 0
-
- mkSocket = ->
- s = new e.EventEmitter
- s.id = socketId++
- return s
-
- beforeEach ->
- socket = mkSocket()
- emitter = new e.EventEmitter
- collection = new Collection emitter
-
-
- it 'should set fullName and name', ->
- fullName = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.7 ' +
- '(KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7'
- browser = new Browser 'id', fullName, collection, emitter, socket
- expect(browser.name).to.equal 'Chrome 16.0.912 (Mac OS X 10.6.8)'
- expect(browser.fullName).to.equal fullName
-
-
- #==========================================================================
- # Browser.init
- #==========================================================================
- describe 'init', ->
-
- it 'should emit "browser_register"', ->
- spyRegister = sinon.spy()
- emitter.on 'browser_register', spyRegister
- browser = new Browser 12345, '', collection, emitter, socket
- browser.init()
-
- expect(spyRegister).to.have.been.called
- expect(spyRegister.args[0][0]).to.equal browser
-
-
- it 'should ad itself into the collection', ->
- browser = new Browser 12345, '', collection, emitter, socket
- browser.init()
-
- expect(collection.length).to.equal 1
- collection.forEach (browserInCollection) ->
- expect(browserInCollection).to.equal browser
-
-
- #==========================================================================
- # Browser.toString
- #==========================================================================
- describe 'toString', ->
-
- it 'should return browser name', ->
- fullName = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.7 ' +
- '(KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7'
- browser = new Browser 'id', fullName, collection, emitter, socket
- expect(browser.toString()).to.equal 'Chrome 16.0.912 (Mac OS X 10.6.8)'
-
- it 'should return verbatim user agent string for unrecognized browser', ->
- fullName = 'NonexistentBot/1.2.3'
- browser = new Browser 'id', fullName, collection, emitter, socket
- expect(browser.toString()).to.equal 'NonexistentBot/1.2.3'
-
-
- #==========================================================================
- # Browser.onKarmaError
- #==========================================================================
- describe 'onKarmaError', ->
-
- beforeEach ->
- browser = new Browser 'fake-id', 'full name', collection, emitter, socket
-
-
- it 'should set lastResult.error and fire "browser_error"', ->
- spy = sinon.spy()
- emitter.on 'browser_error', spy
- browser.state = Browser.STATE_EXECUTING
-
- browser.onKarmaError()
- expect(browser.lastResult.error).to.equal true
- expect(spy).to.have.been.called
-
-
- it 'should ignore if browser not executing', ->
- spy = sinon.spy()
- emitter.on 'browser_error', spy
- browser.state = Browser.STATE_READY
-
- browser.onKarmaError()
- expect(browser.lastResult.error).to.equal false
- expect(spy).not.to.have.been.called
-
-
- #==========================================================================
- # Browser.onInfo
- #==========================================================================
- describe 'onInfo', ->
-
- beforeEach ->
- browser = new Browser 'fake-id', 'full name', collection, emitter, socket
-
-
- it 'should emit "browser_log"', ->
- spy = sinon.spy()
- emitter.on 'browser_log', spy
-
- browser.state = Browser.STATE_EXECUTING
- browser.onInfo {log: 'something', type: 'info'}
- expect(spy).to.have.been.calledWith browser, 'something', 'info'
-
-
- it 'should ignore if browser not executing', ->
- spy = sinon.spy()
- emitter.on 'browser_dump', spy
-
- browser.state = Browser.STATE_READY
- browser.onInfo {dump: 'something'}
- browser.onInfo {total: 20}
-
- expect(browser.lastResult.total).to.equal 0
- expect(spy).not.to.have.been.called
-
-
- #==========================================================================
- # Browser.onStart
- #==========================================================================
- describe 'onStart', ->
-
- beforeEach ->
- browser = new Browser 'fake-id', 'full name', collection, emitter, socket
-
-
- it 'should set total count of specs', ->
- browser.state = Browser.STATE_EXECUTING
- browser.onStart {total: 20}
- expect(browser.lastResult.total).to.equal 20
-
-
- it 'should emit "browser_start"', ->
- spy = sinon.spy()
- emitter.on 'browser_start', spy
-
- browser.state = Browser.STATE_EXECUTING
- browser.onStart {total: 20}
-
- expect(spy).to.have.been.calledWith browser, {total: 20}
-
-
- #==========================================================================
- # Browser.onComplete
- #==========================================================================
- describe 'onComplete', ->
-
- beforeEach ->
- sinon.stub Date, 'now'
- Date.now.returns 12345
- browser = new Browser 'fake-id', 'full name', collection, emitter, socket
-
- afterEach -> Date.now.restore()
-
-
- it 'should set isReady to true', ->
- browser.state = Browser.STATE_EXECUTING
- browser.onComplete()
- expect(browser.isReady()).to.equal true
-
-
- it 'should fire "browsers_change" event', ->
- spy = sinon.spy()
- emitter.on 'browsers_change', spy
-
- browser.state = Browser.STATE_EXECUTING
- browser.onComplete()
- expect(spy).to.have.been.calledWith collection
-
-
- it 'should ignore if browser not executing', ->
- spy = sinon.spy()
- emitter.on 'browsers_change', spy
- emitter.on 'browser_complete', spy
-
- browser.state = Browser.STATE_READY
- browser.onComplete()
- expect(spy).not.to.have.been.called
-
-
- it 'should set totalTime', ->
- Date.now.returns 12347 # the default spy return 12345
-
- browser.state = Browser.STATE_EXECUTING
- browser.onComplete()
-
- expect(browser.lastResult.totalTime).to.equal 2
-
-
- it 'should error the result if zero tests executed', ->
- browser.state = Browser.STATE_EXECUTING
- browser.onComplete()
-
- expect(browser.lastResult.error).to.equal true
-
-
- #==========================================================================
- # Browser.onDisconnect
- #==========================================================================
- describe 'onDisconnect', ->
- timer = null
-
- beforeEach ->
- timer = createMockTimer()
- browser = new Browser 'fake-id', 'full name', collection, emitter, socket, timer, 10
- browser.init()
-
-
- it 'should remove from parent collection', ->
- expect(collection.length).to.equal 1
-
- browser.onDisconnect 'socket.io-reason', socket
- expect(collection.length).to.equal 0
-
-
- it 'should complete if browser executing', ->
- spy = sinon.spy()
- emitter.on 'browser_complete', spy
- browser.state = Browser.STATE_EXECUTING
-
- browser.onDisconnect 'socket.io-reason', socket
- timer.wind 20
-
- expect(browser.lastResult.disconnected).to.equal true
- expect(spy).to.have.been.called
-
-
- it 'should not complete if browser not executing', ->
- spy = sinon.spy()
- emitter.on 'browser_complete', spy
- browser.state = Browser.STATE_READY
-
- browser.onDisconnect 'socket.io-reason', socket
- expect(spy).not.to.have.been.called
-
-
- #==========================================================================
- # Browser.reconnect
- #==========================================================================
- describe 'reconnect', ->
-
- it 'should cancel disconnecting', ->
- timer = createMockTimer()
-
- browser = new Browser 'id', 'Chrome 19.0', collection, emitter, socket, timer, 10
- browser.init()
- browser.state = Browser.STATE_EXECUTING
-
- browser.onDisconnect 'socket.io-reason', socket
- browser.reconnect mkSocket()
-
- timer.wind 10
- expect(browser.state).to.equal Browser.STATE_EXECUTING
-
-
- it 'should ignore disconnects on old sockets, but accept other messages', ->
- # IE on polling sometimes reconnect on another socket (before disconnecting)
-
- browser = new Browser 'id', 'Chrome 19.0', collection, emitter, socket, null, 0
- browser.init()
- browser.state = Browser.STATE_EXECUTING
-
- browser.reconnect mkSocket()
-
- # still accept results on the old socket
- socket.emit 'result', {success: true}
- expect(browser.lastResult.success).to.equal 1
-
- socket.emit 'karma_error', {}
- expect(browser.lastResult.error).to.equal true
-
- # should be ignored, keep executing
- socket.emit 'disconnect', 'socket.io reason'
- expect(browser.state).to.equal Browser.STATE_EXECUTING
-
-
- it 'should reconnect a disconnected browser', ->
- browser = new Browser 'id', 'Chrome 25.0', collection, emitter, socket, null, 10
- browser.state = Browser.STATE_DISCONNECTED
-
- browser.reconnect mkSocket()
-
- expect(browser.isReady()).to.equal true
-
-
- #==========================================================================
- # Browser.onResult
- #==========================================================================
- describe 'onResult', ->
-
- createSuccessResult = ->
- {success: true, suite: [], log: []}
-
- createFailedResult = ->
- {success: false, suite: [], log: []}
-
- createSkippedResult = ->
- {success: true, skipped: true, suite: [], log: []}
-
- beforeEach ->
- browser = new Browser 'fake-id', 'full name', collection, emitter, socket
-
-
- it 'should update lastResults', ->
- browser.state = Browser.STATE_EXECUTING
- browser.onResult createSuccessResult()
- browser.onResult createSuccessResult()
- browser.onResult createFailedResult()
- browser.onResult createSkippedResult()
-
- expect(browser.lastResult.success).to.equal 2
- expect(browser.lastResult.failed).to.equal 1
- expect(browser.lastResult.skipped).to.equal 1
-
-
- it 'should ignore if not running', ->
- browser.state = Browser.STATE_READY
- browser.onResult createSuccessResult()
- browser.onResult createSuccessResult()
- browser.onResult createFailedResult()
-
- expect(browser.lastResult.success).to.equal 0
- expect(browser.lastResult.failed).to.equal 0
-
-
- it 'should update netTime', ->
- browser.state = Browser.STATE_EXECUTING
- browser.onResult {time: 3, suite: [], log: []}
- browser.onResult {time: 1, suite: [], log: []}
- browser.onResult {time: 5, suite: [], log: []}
-
- expect(browser.lastResult.netTime).to.equal 9
-
-
- it 'should accept array of results', ->
- browser.state = Browser.STATE_EXECUTING
- browser.onResult [createSuccessResult(), createSuccessResult(),
- createFailedResult(), createSkippedResult()]
-
- expect(browser.lastResult.success).to.equal 2
- expect(browser.lastResult.failed).to.equal 1
- expect(browser.lastResult.skipped).to.equal 1
-
-
- #==========================================================================
- # Browser.serialize
- #==========================================================================
- describe 'serialize', ->
-
- it 'should return plain object with only name, id, isReady properties', ->
- browser = new Browser 'fake-id', 'full name', collection, emitter, socket
- browser.state = Browser.STATE_READY
- browser.name = 'Browser 1.0'
- browser.id = '12345'
-
- expect(browser.serialize()).to.deep.equal {id: '12345', name: 'Browser 1.0', isReady: true}
-
-
- #==========================================================================
- # Browser.serialize
- #==========================================================================
- describe 'execute', ->
- it 'should emit execute and change state to EXECUTING', ->
- spyExecute = sinon.spy()
- config = {}
- browser = new Browser 'fake-id', 'full name', collection, emitter, socket
- socket.on 'execute', spyExecute
- browser.execute config
-
- expect(browser.isReady()).to.equal false
- expect(spyExecute).to.have.been.calledWith config
-
-
- #==========================================================================
- # Browser higher level tests for reconnecting
- #==========================================================================
- describe 'scenario:', ->
-
- it 'reconnecting during the run', ->
- timer = createMockTimer()
- browser = new Browser 'fake-id', 'full name', collection, emitter, socket, timer, 10
- browser.init()
- browser.state = Browser.STATE_EXECUTING
- socket.emit 'result', {success: true, suite: [], log: []}
- socket.emit 'disconnect', 'socket.io reason'
- expect(browser.isReady()).to.equal false
-
- newSocket = mkSocket()
- browser.reconnect newSocket
- expect(browser.isReady()).to.equal false
-
- newSocket.emit 'result', {success: false, suite: [], log: []}
- newSocket.emit 'complete'
- expect(browser.isReady()).to.equal true
- expect(browser.lastResult.success).to.equal 1
- expect(browser.lastResult.failed).to.equal 1
-
-
- it 'disconecting during the run', ->
- spy = sinon.spy()
- emitter.on 'browser_complete', spy
- timer = createMockTimer()
- browser = new Browser 'fake-id', 'full name', collection, emitter, socket, timer, 10
- browser.init()
- browser.state = Browser.STATE_EXECUTING
- socket.emit 'result', {success: true, suite: [], log: []}
- socket.emit 'disconnect', 'socket.io reason'
-
- timer.wind 10
- expect(browser.lastResult.disconnected).to.equal true
- expect(spy).to.have.been.calledWith browser
-
-
- it 'restarting a disconnected browser', ->
- timer = createMockTimer()
- browser = new Browser 'fake-id', 'Chrome 31.0', collection, emitter, socket, timer, 10
- browser.init()
-
- browser.execute()
- socket.emit 'start', {total: 10}
- socket.emit 'result', {success: true, suite: [], log: []}
- socket.emit 'result', {success: false, suite: [], log: []}
- socket.emit 'result', {skipped: true, suite: [], log: []}
- socket.emit 'disconnect', 'socket.io reason'
- timer.wind 10 # wait-for reconnecting delay
- expect(browser.state).to.equal Browser.STATE_DISCONNECTED
- expect(browser.disconnectsCount).to.equal 1
-
- newSocket = mkSocket()
- emitter.on 'browser_register', -> browser.execute()
-
- # reconnect on a new socket (which triggers re-execution)
- browser.reconnect newSocket
- expect(browser.state).to.equal Browser.STATE_EXECUTING
- newSocket.emit 'start', {total: 11}
- socket.emit 'result', {success: true, suite: [], log: []}
-
- # expected cleared last result (should not include the results from previous run)
- expect(browser.lastResult.total).to.equal 11
- expect(browser.lastResult.success).to.equal 1
- expect(browser.lastResult.failed).to.equal 0
- expect(browser.lastResult.skipped).to.equal 0
-
-
- it 'keeping multiple active sockets', ->
- # If there is a new connection (socket) for an already connected browser,
- # we need to keep the old socket, in the case that the new socket will disconnect.
- browser = new Browser 'fake-id', 'Chrome 31.0', collection, emitter, socket, null, 10
- browser.init()
- browser.execute()
-
- # A second connection...
- newSocket = mkSocket()
- browser.reconnect newSocket
-
- # Disconnect the second connection...
- browser.onDisconnect 'socket.io-reason', newSocket
- expect(browser.state).to.equal Browser.STATE_EXECUTING
-
- # It should still be listening on the old socket.
- socket.emit 'result', {success: true, suite: [], log: []}
- expect(browser.lastResult.success).to.equal 1
-
- it 'complete only once after reconnect on the same socket', ->
- # If there is a new connection on the same socket,
- # we should emit complete message only once.
- browser = new Browser 'fake-id', 'Chrome 31.0', collection, emitter, socket, null, 10
- browser.onComplete = sinon.spy()
- browser.init()
- browser.execute()
-
- # A second connection...
- browser.reconnect socket
-
- socket.emit 'result', {success: true, suite: [], log: []}
- socket.emit 'complete'
-
- expect(browser.onComplete.callCount).to.equal 1
-
- it 'disconnect when no message during the run', ->
- timer = createMockTimer()
- browser = new Browser 'fake-id', 'Chrome 31.0', collection, emitter, socket, timer, 10, 20
- browser.init()
- browser.execute()
-
- spyBrowserComplete = sinon.spy()
- emitter.on 'browser_complete', spyBrowserComplete
-
- socket.emit 'start', {total: 11}
- socket.emit 'result', {success: true, suite: [], log: []}
-
- timer.wind 20
- expect(browser.state).to.equal Browser.STATE_DISCONNECTED
- expect(browser.disconnectsCount).to.equal 1
- expect(spyBrowserComplete).to.have.been.called
diff --git a/test/unit/browser.spec.js b/test/unit/browser.spec.js
new file mode 100644
index 000000000..6f7ef2762
--- /dev/null
+++ b/test/unit/browser.spec.js
@@ -0,0 +1,488 @@
+describe('Browser', () => {
+ var collection
+ var emitter
+ var socket
+ var e = require('../../lib/events')
+ var Browser = require('../../lib/browser')
+ var Collection = require('../../lib/browser_collection')
+ var createMockTimer = require('./mocks/timer')
+
+ var browser = collection = emitter = socket = null
+ var socketId = 0
+
+ var mkSocket = () => {
+ var s = new e.EventEmitter()
+ socketId = socketId + 1
+ s.id = socketId
+ return s
+ }
+
+ beforeEach(() => {
+ socket = mkSocket()
+ emitter = new e.EventEmitter()
+ collection = new Collection(emitter)
+ })
+
+ it('should set fullName and name', () => {
+ var fullName = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.7 ' + '(KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7'
+ browser = new Browser('id', fullName, collection, emitter, socket)
+ expect(browser.name).to.equal('Chrome 16.0.912 (Mac OS X 10.6.8)')
+ expect(browser.fullName).to.equal(fullName)
+ })
+
+ describe('init', () => {
+ it('should emit "browser_register"', () => {
+ var spyRegister = sinon.spy()
+ emitter.on('browser_register', spyRegister)
+ browser = new Browser(12345, '', collection, emitter, socket)
+ browser.init()
+
+ expect(spyRegister).to.have.been.called
+ expect(spyRegister.args[0][0]).to.equal(browser)
+ })
+
+ it('should ad itself into the collection', () => {
+ browser = new Browser(12345, '', collection, emitter, socket)
+ browser.init()
+
+ expect(collection.length).to.equal(1)
+ collection.forEach(browserInCollection => {
+ expect(browserInCollection).to.equal(browser)
+ })
+ })
+ })
+
+ describe('toString', () => {
+ it('should return browser name', () => {
+ var fullName = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.7 ' + '(KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7'
+ browser = new Browser('id', fullName, collection, emitter, socket)
+ expect(browser.toString()).to.equal('Chrome 16.0.912 (Mac OS X 10.6.8)')
+ })
+
+ it('should return verbatim user agent string for unrecognized browser', () => {
+ var fullName = 'NonexistentBot/1.2.3'
+ browser = new Browser('id', fullName, collection, emitter, socket)
+ expect(browser.toString()).to.equal('NonexistentBot/1.2.3')
+ })
+ })
+
+ describe('onKarmaError', () => {
+ beforeEach(() => {
+ browser = new Browser('fake-id', 'full name', collection, emitter, socket)
+ })
+
+ it('should set lastResult.error and fire "browser_error"', () => {
+ var spy = sinon.spy()
+ emitter.on('browser_error', spy)
+ browser.state = Browser.STATE_EXECUTING
+
+ browser.onKarmaError()
+ expect(browser.lastResult.error).to.equal(true)
+ expect(spy).to.have.been.called
+ })
+
+ it('should ignore if browser not executing', () => {
+ var spy = sinon.spy()
+ emitter.on('browser_error', spy)
+ browser.state = Browser.STATE_READY
+
+ browser.onKarmaError()
+ expect(browser.lastResult.error).to.equal(false)
+ expect(spy).not.to.have.been.called
+ })
+ })
+
+ describe('onInfo', () => {
+ beforeEach(() => {
+ browser = new Browser('fake-id', 'full name', collection, emitter, socket)
+ })
+
+ it('should emit "browser_log"', () => {
+ var spy = sinon.spy()
+ emitter.on('browser_log', spy)
+
+ browser.state = Browser.STATE_EXECUTING
+ browser.onInfo({log: 'something', type: 'info'})
+ expect(spy).to.have.been.calledWith(browser, 'something', 'info')
+ })
+
+ it('should ignore if browser not executing', () => {
+ var spy = sinon.spy()
+ emitter.on('browser_dump', spy)
+
+ browser.state = Browser.STATE_READY
+ browser.onInfo({dump: 'something'})
+ browser.onInfo({total: 20})
+
+ expect(browser.lastResult.total).to.equal(0)
+ expect(spy).not.to.have.been.called
+ })
+ })
+
+ describe('onStart', () => {
+ beforeEach(() => {
+ browser = new Browser('fake-id', 'full name', collection, emitter, socket)
+ })
+
+ it('should set total count of specs', () => {
+ browser.state = Browser.STATE_EXECUTING
+ browser.onStart({total: 20})
+ expect(browser.lastResult.total).to.equal(20)
+ })
+
+ it('should emit "browser_start"', () => {
+ var spy = sinon.spy()
+ emitter.on('browser_start', spy)
+
+ browser.state = Browser.STATE_EXECUTING
+ browser.onStart({total: 20})
+
+ expect(spy).to.have.been.calledWith(browser, {total: 20})
+ })
+ })
+
+ describe('onComplete', () => {
+ beforeEach(() => {
+ sinon.stub(Date, 'now')
+ Date.now.returns(12345)
+ browser = new Browser('fake-id', 'full name', collection, emitter, socket)
+ })
+
+ afterEach(() => {
+ Date.now.restore()
+ })
+
+ it('should set isReady to true', () => {
+ browser.state = Browser.STATE_EXECUTING
+ browser.onComplete()
+ expect(browser.isReady()).to.equal(true)
+ })
+
+ it('should fire "browsers_change" event', () => {
+ var spy = sinon.spy()
+ emitter.on('browsers_change', spy)
+
+ browser.state = Browser.STATE_EXECUTING
+ browser.onComplete()
+ expect(spy).to.have.been.calledWith(collection)
+ })
+
+ it('should ignore if browser not executing', () => {
+ var spy = sinon.spy()
+ emitter.on('browsers_change', spy)
+ emitter.on('browser_complete', spy)
+
+ browser.state = Browser.STATE_READY
+ browser.onComplete()
+ expect(spy).not.to.have.been.called
+ })
+
+ it('should set totalTime', () => {
+ Date.now.returns(12347) // the default spy return 12345
+
+ browser.state = Browser.STATE_EXECUTING
+ browser.onComplete()
+
+ expect(browser.lastResult.totalTime).to.equal(2)
+ })
+
+ it('should error the result if zero tests executed', () => {
+ browser.state = Browser.STATE_EXECUTING
+ browser.onComplete()
+
+ expect(browser.lastResult.error).to.equal(true)
+ })
+ })
+
+ describe('onDisconnect', () => {
+ var timer = null
+
+ beforeEach(() => {
+ timer = createMockTimer()
+ browser = new Browser('fake-id', 'full name', collection, emitter, socket, timer, 10)
+ browser.init()
+ })
+
+ it('should remove from parent collection', () => {
+ expect(collection.length).to.equal(1)
+
+ browser.onDisconnect('socket.io-reason', socket)
+ expect(collection.length).to.equal(0)
+ })
+
+ it('should complete if browser executing', () => {
+ var spy = sinon.spy()
+ emitter.on('browser_complete', spy)
+ browser.state = Browser.STATE_EXECUTING
+
+ browser.onDisconnect('socket.io-reason', socket)
+ timer.wind(20)
+
+ expect(browser.lastResult.disconnected).to.equal(true)
+ expect(spy).to.have.been.called
+ })
+
+ it('should not complete if browser not executing', () => {
+ var spy = sinon.spy()
+ emitter.on('browser_complete', spy)
+ browser.state = Browser.STATE_READY
+
+ browser.onDisconnect('socket.io-reason', socket)
+ expect(spy).not.to.have.been.called
+ })
+ })
+
+ describe('reconnect', () => {
+ it('should cancel disconnecting', () => {
+ var timer = createMockTimer()
+
+ browser = new Browser('id', 'Chrome 19.0', collection, emitter, socket, timer, 10)
+ browser.init()
+ browser.state = Browser.STATE_EXECUTING
+
+ browser.onDisconnect('socket.io-reason', socket)
+ browser.reconnect(mkSocket())
+
+ timer.wind(10)
+ expect(browser.state).to.equal(Browser.STATE_EXECUTING)
+ })
+
+ it('should ignore disconnects on old sockets, but accept other messages', () => {
+ // IE on polling sometimes reconnect on another socket (before disconnecting)
+
+ browser = new Browser('id', 'Chrome 19.0', collection, emitter, socket, null, 0)
+ browser.init()
+ browser.state = Browser.STATE_EXECUTING
+
+ browser.reconnect(mkSocket())
+
+ // still accept results on the old socket
+ socket.emit('result', {success: true})
+ expect(browser.lastResult.success).to.equal(1)
+
+ socket.emit('karma_error', {})
+ expect(browser.lastResult.error).to.equal(true)
+
+ // should be ignored, keep executing
+ socket.emit('disconnect', 'socket.io reason')
+ expect(browser.state).to.equal(Browser.STATE_EXECUTING)
+ })
+
+ it('should reconnect a disconnected browser', () => {
+ browser = new Browser('id', 'Chrome 25.0', collection, emitter, socket, null, 10)
+ browser.state = Browser.STATE_DISCONNECTED
+
+ browser.reconnect(mkSocket())
+
+ expect(browser.isReady()).to.equal(true)
+ })
+ })
+
+ describe('onResult', () => {
+ var createSuccessResult = () => {
+ return {success: true, suite: [], log: []}
+ }
+
+ var createFailedResult = () => {
+ return {success: false, suite: [], log: []}
+ }
+
+ var createSkippedResult = () => {
+ return {success: true, skipped: true, suite: [], log: []}
+ }
+
+ beforeEach(() => {
+ browser = new Browser('fake-id', 'full name', collection, emitter, socket)
+ })
+
+ it('should update lastResults', () => {
+ browser.state = Browser.STATE_EXECUTING
+ browser.onResult(createSuccessResult())
+ browser.onResult(createSuccessResult())
+ browser.onResult(createFailedResult())
+ browser.onResult(createSkippedResult())
+
+ expect(browser.lastResult.success).to.equal(2)
+ expect(browser.lastResult.failed).to.equal(1)
+ expect(browser.lastResult.skipped).to.equal(1)
+ })
+
+ it('should ignore if not running', () => {
+ browser.state = Browser.STATE_READY
+ browser.onResult(createSuccessResult())
+ browser.onResult(createSuccessResult())
+ browser.onResult(createFailedResult())
+
+ expect(browser.lastResult.success).to.equal(0)
+ expect(browser.lastResult.failed).to.equal(0)
+ })
+
+ it('should update netTime', () => {
+ browser.state = Browser.STATE_EXECUTING
+ browser.onResult({time: 3, suite: [], log: []})
+ browser.onResult({time: 1, suite: [], log: []})
+ browser.onResult({time: 5, suite: [], log: []})
+
+ expect(browser.lastResult.netTime).to.equal(9)
+ })
+
+ it('should accept array of results', () => {
+ browser.state = Browser.STATE_EXECUTING
+ browser.onResult([
+ createSuccessResult(), createSuccessResult(),
+ createFailedResult(), createSkippedResult()
+ ])
+
+ expect(browser.lastResult.success).to.equal(2)
+ expect(browser.lastResult.failed).to.equal(1)
+ expect(browser.lastResult.skipped).to.equal(1)
+ })
+ })
+
+ describe('serialize', () => {
+ it('should return plain object with only name, id, isReady properties', () => {
+ browser = new Browser('fake-id', 'full name', collection, emitter, socket)
+ browser.state = Browser.STATE_READY
+ browser.name = 'Browser 1.0'
+ browser.id = '12345'
+
+ expect(browser.serialize()).to.deep.equal({id: '12345', name: 'Browser 1.0', isReady: true})
+ })
+ })
+
+ describe('execute', () => {
+ it('should emit execute and change state to EXECUTING', () => {
+ var spyExecute = sinon.spy()
+ var config = {}
+ browser = new Browser('fake-id', 'full name', collection, emitter, socket)
+ socket.on('execute', spyExecute)
+ browser.execute(config)
+
+ expect(browser.isReady()).to.equal(false)
+ expect(spyExecute).to.have.been.calledWith(config)
+ })
+ })
+
+ describe('scenario:', () => {
+ it('reconnecting during the run', () => {
+ var timer = createMockTimer()
+ browser = new Browser('fake-id', 'full name', collection, emitter, socket, timer, 10)
+ browser.init()
+ browser.state = Browser.STATE_EXECUTING
+ socket.emit('result', {success: true, suite: [], log: []})
+ socket.emit('disconnect', 'socket.io reason')
+ expect(browser.isReady()).to.equal(false)
+
+ var newSocket = mkSocket()
+ browser.reconnect(newSocket)
+ expect(browser.isReady()).to.equal(false)
+
+ newSocket.emit('result', {success: false, suite: [], log: []})
+ newSocket.emit('complete')
+ expect(browser.isReady()).to.equal(true)
+ expect(browser.lastResult.success).to.equal(1)
+ expect(browser.lastResult.failed).to.equal(1)
+ })
+
+ it('disconecting during the run', () => {
+ var spy = sinon.spy()
+ emitter.on('browser_complete', spy)
+ var timer = createMockTimer()
+ browser = new Browser('fake-id', 'full name', collection, emitter, socket, timer, 10)
+ browser.init()
+ browser.state = Browser.STATE_EXECUTING
+ socket.emit('result', {success: true, suite: [], log: []})
+ socket.emit('disconnect', 'socket.io reason')
+
+ timer.wind(10)
+ expect(browser.lastResult.disconnected).to.equal(true)
+ expect(spy).to.have.been.calledWith(browser)
+ })
+
+ it('restarting a disconnected browser', () => {
+ var timer = createMockTimer()
+ browser = new Browser('fake-id', 'Chrome 31.0', collection, emitter, socket, timer, 10)
+ browser.init()
+
+ browser.execute()
+ socket.emit('start', {total: 10})
+ socket.emit('result', {success: true, suite: [], log: []})
+ socket.emit('result', {success: false, suite: [], log: []})
+ socket.emit('result', {skipped: true, suite: [], log: []})
+ socket.emit('disconnect', 'socket.io reason')
+ timer.wind(10) // wait-for reconnecting delay
+ expect(browser.state).to.equal(Browser.STATE_DISCONNECTED)
+ expect(browser.disconnectsCount).to.equal(1)
+
+ var newSocket = mkSocket()
+ emitter.on('browser_register', () => browser.execute())
+
+ // reconnect on a new socket (which triggers re-execution)
+ browser.reconnect(newSocket)
+ expect(browser.state).to.equal(Browser.STATE_EXECUTING)
+ newSocket.emit('start', {total: 11})
+ socket.emit('result', {success: true, suite: [], log: []})
+
+ // expected cleared last result (should not include the results from previous run)
+ expect(browser.lastResult.total).to.equal(11)
+ expect(browser.lastResult.success).to.equal(1)
+ expect(browser.lastResult.failed).to.equal(0)
+ expect(browser.lastResult.skipped).to.equal(0)
+ })
+
+ it('keeping multiple active sockets', () => {
+ // If there is a new connection (socket) for an already connected browser,
+ // we need to keep the old socket, in the case that the new socket will disconnect.
+ browser = new Browser('fake-id', 'Chrome 31.0', collection, emitter, socket, null, 10)
+ browser.init()
+ browser.execute()
+
+ // A second connection...
+ var newSocket = mkSocket()
+ browser.reconnect(newSocket)
+
+ // Disconnect the second connection...
+ browser.onDisconnect('socket.io-reason', newSocket)
+ expect(browser.state).to.equal(Browser.STATE_EXECUTING)
+
+ // It should still be listening on the old socket.
+ socket.emit('result', {success: true, suite: [], log: []})
+ expect(browser.lastResult.success).to.equal(1)
+ })
+
+ it('complete only once after reconnect on the same socket', () => {
+ // If there is a new connection on the same socket,
+ // we should emit complete message only once.
+ browser = new Browser('fake-id', 'Chrome 31.0', collection, emitter, socket, null, 10)
+ browser.onComplete = sinon.spy()
+ browser.init()
+ browser.execute()
+
+ // A second connection...
+ browser.reconnect(socket)
+
+ socket.emit('result', {success: true, suite: [], log: []})
+ socket.emit('complete')
+
+ expect(browser.onComplete.callCount).to.equal(1)
+ })
+
+ it('disconnect when no message during the run', () => {
+ var timer = createMockTimer()
+ browser = new Browser('fake-id', 'Chrome 31.0', collection, emitter, socket, timer, 10, 20)
+ browser.init()
+ browser.execute()
+
+ var spyBrowserComplete = sinon.spy()
+ emitter.on('browser_complete', spyBrowserComplete)
+
+ socket.emit('start', {total: 11})
+ socket.emit('result', {success: true, suite: [], log: []})
+
+ timer.wind(20)
+ expect(browser.state).to.equal(Browser.STATE_DISCONNECTED)
+ expect(browser.disconnectsCount).to.equal(1)
+ expect(spyBrowserComplete).to.have.been.called
+ })
+ })
+})
diff --git a/test/unit/browser_collection.spec.coffee b/test/unit/browser_collection.spec.coffee
deleted file mode 100644
index ff2f4be05..000000000
--- a/test/unit/browser_collection.spec.coffee
+++ /dev/null
@@ -1,310 +0,0 @@
-#============================================================================
-# lib/browser_collection.js module
-#============================================================================
-describe 'BrowserCollection', ->
- e = require '../../lib/events'
- Collection = require '../../lib/browser_collection'
- Browser = require '../../lib/browser'
- collection = emitter = null
-
- beforeEach ->
- emitter = new e.EventEmitter
- collection = new Collection emitter
-
- #==========================================================================
- # Collection.add
- #==========================================================================
- describe 'add', ->
-
- it 'should add browser', ->
- expect(collection.length).to.equal 0
- collection.add new Browser 'id'
- expect(collection.length).to.equal 1
-
-
- it 'should fire "browsers_change" event', ->
- spy = sinon.spy()
- emitter.on 'browsers_change', spy
- collection.add {}
- expect(spy).to.have.been.called
-
-
- #==========================================================================
- # Collection.remove
- #==========================================================================
- describe 'remove', ->
-
- it 'should remove given browser', ->
- browser = new Browser 'id'
- collection.add browser
-
- expect(collection.length).to.equal 1
- expect(collection.remove browser).to.equal true
- expect(collection.length).to.equal 0
-
-
- it 'should fire "browsers_change" event', ->
- spy = sinon.spy()
- browser = new Browser 'id'
- collection.add browser
-
- emitter.on 'browsers_change', spy
- collection.remove browser
- expect(spy).to.have.been.called
-
-
- it 'should return false if given browser does not exist within the collection', ->
- spy = sinon.spy()
- emitter.on 'browsers_change', spy
- expect(collection.remove {}).to.equal false
- expect(spy).not.to.have.been.called
-
-
- #==========================================================================
- # Collection.getById
- #==========================================================================
- describe 'getById', ->
-
- it 'should find the browser by id', ->
- browser = new Browser 123
- collection.add browser
-
- expect(collection.getById 123).to.equal browser
-
-
- it 'should return null if no browser with given id', ->
- expect(collection.getById 123).to.equal null
-
- collection.add new Browser 456
- expect(collection.getById 123).to.equal null
-
-
- #==========================================================================
- # Collection.setAllToExecuting
- #==========================================================================
- describe 'setAllToExecuting', ->
- browsers = null
-
- beforeEach ->
- browsers = [new Browser, new Browser, new Browser]
- browsers.forEach (browser) ->
- collection.add browser
-
-
- it 'should set all browsers state to executing', ->
- collection.setAllToExecuting()
- browsers.forEach (browser) ->
- expect(browser.isReady()).to.equal false
- expect(browser.state).to.equal Browser.STATE_EXECUTING
-
-
- it 'should fire "browsers_change" event', ->
- spy = sinon.spy()
- emitter.on 'browsers_change', spy
- collection.setAllToExecuting()
- expect(spy).to.have.been.called
-
-
- #==========================================================================
- # Collection.areAllReady
- #==========================================================================
- describe 'areAllReady', ->
- browsers = null
-
- beforeEach ->
- browsers = [new Browser, new Browser, new Browser]
- browsers.forEach (browser) ->
- browser.state = Browser.STATE_READY
- collection.add browser
-
-
- it 'should return true if all browsers are ready', ->
- expect(collection.areAllReady()).to.equal true
-
-
- it 'should return false if at least one browser is not ready', ->
- browsers[1].state = Browser.STATE_EXECUTING
- expect(collection.areAllReady()).to.equal false
-
-
- it 'should add all non-ready browsers into given array', ->
- browsers[0].state = Browser.STATE_EXECUTING
- browsers[1].state = Browser.STATE_EXECUTING_DISCONNECTED
- nonReady = []
- collection.areAllReady nonReady
- expect(nonReady).to.deep.equal [browsers[0], browsers[1]]
-
-
- #==========================================================================
- # Collection.serialize
- #==========================================================================
- describe 'serialize', ->
-
- it 'should return plain array with serialized browsers', ->
- browsers = [new Browser('1'), new Browser('2')]
- browsers[0].name = 'B 1.0'
- browsers[1].name = 'B 2.0'
- collection.add browsers[0]
- collection.add browsers[1]
-
- expect(collection.serialize()).to.deep.equal [{id: '1', name: 'B 1.0', isReady: true},
- {id: '2', name: 'B 2.0', isReady: true}]
-
-
- #==========================================================================
- # Collection.getResults
- #==========================================================================
- describe 'getResults', ->
-
- it 'should return sum of all browser results', ->
- browsers = [new Browser, new Browser]
- collection.add browsers[0]
- collection.add browsers[1]
- browsers[0].lastResult.success = 2
- browsers[0].lastResult.failed = 3
- browsers[1].lastResult.success = 4
- browsers[1].lastResult.failed = 5
-
- results = collection.getResults()
- expect(results.success).to.equal 6
- expect(results.failed).to.equal 8
-
-
- it 'should compute disconnected true if any browser got disconnected', ->
- browsers = [new Browser, new Browser]
- collection.add browsers[0]
- collection.add browsers[1]
-
- results = collection.getResults()
- expect(results.disconnected).to.equal false
-
- browsers[0].lastResult.disconnected = true
- results = collection.getResults()
- expect(results.disconnected).to.equal true
-
- browsers[1].lastResult.disconnected = true
- results = collection.getResults()
- expect(results.disconnected).to.equal true
-
- browsers[0].lastResult.disconnected = false
- results = collection.getResults()
- expect(results.disconnected).to.equal true
-
-
- it 'should compute error true if any browser had error', ->
- browsers = [new Browser, new Browser]
- collection.add browsers[0]
- collection.add browsers[1]
-
- results = collection.getResults()
- expect(results.error).to.equal false
-
- browsers[0].lastResult.error = true
- results = collection.getResults()
- expect(results.error).to.equal true
-
- browsers[1].lastResult.error = true
- results = collection.getResults()
- expect(results.error).to.equal true
-
- browsers[0].lastResult.error = false
- results = collection.getResults()
- expect(results.error).to.equal true
-
-
- it 'should compute exitCode', ->
- browsers = [new Browser, new Browser]
- collection.add browser for browser in browsers
-
- browsers[0].lastResult.success = 2
- results = collection.getResults()
- expect(results.exitCode).to.equal 0
-
- browsers[0].lastResult.failed = 2
- results = collection.getResults()
- expect(results.exitCode).to.equal 1
-
- browsers[0].lastResult.failed = 0
- browsers[1].lastResult.error = true
- results = collection.getResults()
- expect(results.exitCode).to.equal 1
-
- browsers[0].lastResult.disconnected = true
- browsers[1].lastResult.error = false
- results = collection.getResults()
- expect(results.exitCode).to.equal 1
-
- browsers[0].lastResult.disconnected = false
- results = collection.getResults()
- expect(results.exitCode).to.equal 0
-
-
- #==========================================================================
- # Collection.clearResults
- #==========================================================================
- describe 'clearResults', ->
-
- it 'should clear all results', ->
- # Date.now.returns 112233
- browsers = [new Browser, new Browser]
- collection.add browsers[0]
- collection.add browsers[1]
- browsers[0].lastResult.sucess++
- browsers[0].lastResult.error = true
- browsers[1].lastResult.failed++
- browsers[1].lastResult.skipped++
- browsers[1].lastResult.disconnected = true
-
- collection.clearResults()
- browsers.forEach (browser) ->
- expect(browser.lastResult.success).to.equal 0
- expect(browser.lastResult.failed).to.equal 0
- expect(browser.lastResult.skipped).to.equal 0
- expect(browser.lastResult.error).to.equal false
- expect(browser.lastResult.disconnected).to.equal false
-
-
- #==========================================================================
- # Collection.clone
- #==========================================================================
- describe 'clone', ->
-
- it 'should create a shallow copy of the collection', ->
- browsers = [new Browser, new Browser, new Browser]
- collection.add browser for browser in browsers
-
- clone = collection.clone()
- expect(clone.length).to.equal 3
-
- clone.remove browsers[0]
- expect(clone.length).to.equal 2
- expect(collection.length).to.equal 3
-
-
- #==========================================================================
- # Collection.map
- #==========================================================================
- describe 'map', ->
-
- it 'should have map()', ->
- browsers = [new Browser(1), new Browser(2), new Browser(3)]
- collection.add browser for browser in browsers
-
- mappedIds = collection.map (browser) ->
- browser.id
-
- expect(mappedIds).to.deep.equal [1, 2, 3]
-
-
- #==========================================================================
- # Collection.forEach
- #==========================================================================
- describe 'forEach', ->
-
- it 'should have forEach()', ->
- browsers = [new Browser(0), new Browser(1), new Browser(2)]
- collection.add browser for browser in browsers
-
- collection.forEach (browser, index) ->
- expect(browser.id).to.equal index
-
diff --git a/test/unit/browser_collection.spec.js b/test/unit/browser_collection.spec.js
new file mode 100644
index 000000000..1737e1132
--- /dev/null
+++ b/test/unit/browser_collection.spec.js
@@ -0,0 +1,285 @@
+describe('BrowserCollection', () => {
+ var emitter
+ var e = require('../../lib/events')
+ var Collection = require('../../lib/browser_collection')
+ var Browser = require('../../lib/browser')
+ var collection = emitter = null
+
+ beforeEach(() => {
+ emitter = new e.EventEmitter()
+ collection = new Collection(emitter)
+ })
+
+ describe('add', () => {
+ it('should add browser', () => {
+ expect(collection.length).to.equal(0)
+ collection.add(new Browser('id'))
+ expect(collection.length).to.equal(1)
+ })
+
+ it('should fire "browsers_change" event', () => {
+ var spy = sinon.spy()
+ emitter.on('browsers_change', spy)
+ collection.add({})
+ expect(spy).to.have.been.called
+ })
+ })
+
+ describe('remove', () => {
+ it('should remove given browser', () => {
+ var browser = new Browser('id')
+ collection.add(browser)
+
+ expect(collection.length).to.equal(1)
+ expect(collection.remove(browser)).to.equal(true)
+ expect(collection.length).to.equal(0)
+ })
+
+ it('should fire "browsers_change" event', () => {
+ var spy = sinon.spy()
+ var browser = new Browser('id')
+ collection.add(browser)
+
+ emitter.on('browsers_change', spy)
+ collection.remove(browser)
+ expect(spy).to.have.been.called
+ })
+
+ it('should return false if given browser does not exist within the collection', () => {
+ var spy = sinon.spy()
+ emitter.on('browsers_change', spy)
+ expect(collection.remove({})).to.equal(false)
+ expect(spy).not.to.have.been.called
+ })
+ })
+
+ describe('getById', () => {
+ it('should find the browser by id', () => {
+ var browser = new Browser(123)
+ collection.add(browser)
+
+ expect(collection.getById(123)).to.equal(browser)
+ })
+
+ it('should return null if no browser with given id', () => {
+ expect(collection.getById(123)).to.equal(null)
+
+ collection.add(new Browser(456))
+ expect(collection.getById(123)).to.equal(null)
+ })
+ })
+
+ describe('setAllToExecuting', () => {
+ var browsers = null
+
+ beforeEach(() => {
+ browsers = [new Browser(), new Browser(), new Browser()]
+ browsers.forEach(browser => {
+ collection.add(browser)
+ })
+ })
+
+ it('should set all browsers state to executing', () => {
+ collection.setAllToExecuting()
+ browsers.forEach(browser => {
+ expect(browser.isReady()).to.equal(false)
+ expect(browser.state).to.equal(Browser.STATE_EXECUTING)
+ })
+ })
+
+ it('should fire "browsers_change" event', () => {
+ var spy = sinon.spy()
+ emitter.on('browsers_change', spy)
+ collection.setAllToExecuting()
+ expect(spy).to.have.been.called
+ })
+ })
+
+ describe('areAllReady', () => {
+ var browsers = null
+
+ beforeEach(() => {
+ browsers = [new Browser(), new Browser(), new Browser()]
+ browsers.forEach(browser => {
+ browser.state = Browser.STATE_READY
+ collection.add(browser)
+ })
+ })
+
+ it('should return true if all browsers are ready', () => {
+ expect(collection.areAllReady()).to.equal(true)
+ })
+
+ it('should return false if at least one browser is not ready', () => {
+ browsers[1].state = Browser.STATE_EXECUTING
+ expect(collection.areAllReady()).to.equal(false)
+ })
+
+ it('should add all non-ready browsers into given array', () => {
+ browsers[0].state = Browser.STATE_EXECUTING
+ browsers[1].state = Browser.STATE_EXECUTING_DISCONNECTED
+ var nonReady = []
+ collection.areAllReady(nonReady)
+ expect(nonReady).to.deep.equal([browsers[0], browsers[1]])
+ })
+ })
+
+ describe('serialize', () => {
+ it('should return plain array with serialized browsers', () => {
+ var browsers = [new Browser('1'), new Browser('2')]
+ browsers[0].name = 'B 1.0'
+ browsers[1].name = 'B 2.0'
+ collection.add(browsers[0])
+ collection.add(browsers[1])
+
+ expect(collection.serialize()).to.deep.equal([
+ {id: '1', name: 'B 1.0', isReady: true},
+ {id: '2', name: 'B 2.0', isReady: true}
+ ])
+ })
+ })
+
+ describe('getResults', () => {
+ it('should return sum of all browser results', () => {
+ var browsers = [new Browser(), new Browser()]
+ collection.add(browsers[0])
+ collection.add(browsers[1])
+ browsers[0].lastResult.success = 2
+ browsers[0].lastResult.failed = 3
+ browsers[1].lastResult.success = 4
+ browsers[1].lastResult.failed = 5
+
+ var results = collection.getResults()
+ expect(results.success).to.equal(6)
+ expect(results.failed).to.equal(8)
+ })
+
+ it('should compute disconnected true if any browser got disconnected', () => {
+ var browsers = [new Browser(), new Browser()]
+ collection.add(browsers[0])
+ collection.add(browsers[1])
+
+ var results = collection.getResults()
+ expect(results.disconnected).to.equal(false)
+
+ browsers[0].lastResult.disconnected = true
+ results = collection.getResults()
+ expect(results.disconnected).to.equal(true)
+
+ browsers[1].lastResult.disconnected = true
+ results = collection.getResults()
+ expect(results.disconnected).to.equal(true)
+
+ browsers[0].lastResult.disconnected = false
+ results = collection.getResults()
+ expect(results.disconnected).to.equal(true)
+ })
+
+ it('should compute error true if any browser had error', () => {
+ var browsers = [new Browser(), new Browser()]
+ collection.add(browsers[0])
+ collection.add(browsers[1])
+
+ var results = collection.getResults()
+ expect(results.error).to.equal(false)
+
+ browsers[0].lastResult.error = true
+ results = collection.getResults()
+ expect(results.error).to.equal(true)
+
+ browsers[1].lastResult.error = true
+ results = collection.getResults()
+ expect(results.error).to.equal(true)
+
+ browsers[0].lastResult.error = false
+ results = collection.getResults()
+ expect(results.error).to.equal(true)
+ })
+
+ it('should compute exitCode', () => {
+ var browsers = [new Browser(), new Browser()]
+ browsers.forEach(collection.add)
+
+ browsers[0].lastResult.success = 2
+ var results = collection.getResults()
+ expect(results.exitCode).to.equal(0)
+
+ browsers[0].lastResult.failed = 2
+ results = collection.getResults()
+ expect(results.exitCode).to.equal(1)
+
+ browsers[0].lastResult.failed = 0
+ browsers[1].lastResult.error = true
+ results = collection.getResults()
+ expect(results.exitCode).to.equal(1)
+
+ browsers[0].lastResult.disconnected = true
+ browsers[1].lastResult.error = false
+ results = collection.getResults()
+ expect(results.exitCode).to.equal(1)
+
+ browsers[0].lastResult.disconnected = false
+ results = collection.getResults()
+ expect(results.exitCode).to.equal(0)
+ })
+ })
+
+ describe('clearResults', () => {
+ it('should clear all results', () => {
+ // Date.now.returns 112233
+ var browsers = [new Browser(), new Browser()]
+ collection.add(browsers[0])
+ collection.add(browsers[1])
+ browsers[0].lastResult.sucess++
+ browsers[0].lastResult.error = true
+ browsers[1].lastResult.failed++
+ browsers[1].lastResult.skipped++
+ browsers[1].lastResult.disconnected = true
+
+ collection.clearResults()
+ browsers.forEach(browser => {
+ expect(browser.lastResult.success).to.equal(0)
+ expect(browser.lastResult.failed).to.equal(0)
+ expect(browser.lastResult.skipped).to.equal(0)
+ expect(browser.lastResult.error).to.equal(false)
+ expect(browser.lastResult.disconnected).to.equal(false)
+ })
+ })
+ })
+
+ describe('clone', () => {
+ it('should create a shallow copy of the collection', () => {
+ var browsers = [new Browser(), new Browser(), new Browser()]
+ browsers.forEach(collection.add)
+
+ var clone = collection.clone()
+ expect(clone.length).to.equal(3)
+
+ clone.remove(browsers[0])
+ expect(clone.length).to.equal(2)
+ expect(collection.length).to.equal(3)
+ })
+ })
+
+ describe('map', () => {
+ it('should have map()', () => {
+ var browsers = [new Browser(1), new Browser(2), new Browser(3)]
+ browsers.forEach(collection.add)
+
+ var mappedIds = collection.map(browser => browser.id)
+
+ expect(mappedIds).to.deep.equal([1, 2, 3])
+ })
+ })
+
+ describe('forEach', () => {
+ it('should have forEach()', () => {
+ var browsers = [new Browser(0), new Browser(1), new Browser(2)]
+ browsers.forEach(collection.add)
+
+ collection.forEach(function (browser, index) {
+ expect(browser.id).to.equal(index)
+ })
+ })
+ })
+})
diff --git a/test/unit/browser_result.spec.coffee b/test/unit/browser_result.spec.coffee
deleted file mode 100644
index c30f4a1ab..000000000
--- a/test/unit/browser_result.spec.coffee
+++ /dev/null
@@ -1,64 +0,0 @@
-#============================================================================
-# lib/browser_result.js module
-#============================================================================
-describe 'BrowserResult', ->
- Result = require '../../lib/browser_result'
- result = null
-
- successResultFromBrowser =
- success: true
- skipped: false
- time: 100
- failedResultFromBrowser =
- success: false
- skipped: false
- time: 200
- skippedResultFromBrowser =
- success: false
- skipped: true
- time: 0
-
-
- beforeEach ->
- sinon.stub Date, 'now'
- Date.now.returns 123
- result = new Result
-
- afterEach -> Date.now.restore()
-
-
- it 'should compute totalTime', ->
- Date.now.returns 223
- result.totalTimeEnd()
- expect(result.totalTime).to.equal 223 - 123
-
-
- it 'should sum success/failed/skipped', ->
- result.add successResultFromBrowser
- expect(result.success).to.equal 1
- expect(result.failed).to.equal 0
- expect(result.skipped).to.equal 0
-
- result.add failedResultFromBrowser
- expect(result.success).to.equal 1
- expect(result.failed).to.equal 1
- expect(result.skipped).to.equal 0
-
- result.add successResultFromBrowser
- expect(result.success).to.equal 2
- expect(result.failed).to.equal 1
- expect(result.skipped).to.equal 0
-
- result.add skippedResultFromBrowser
- expect(result.success).to.equal 2
- expect(result.failed).to.equal 1
- expect(result.skipped).to.equal 1
-
-
- it 'should sum net time of all results', ->
- result.add successResultFromBrowser
- result.add failedResultFromBrowser
- expect(result.netTime).to.equal 300
-
- result.add successResultFromBrowser
- expect(result.netTime).to.equal 400
diff --git a/test/unit/browser_result.spec.js b/test/unit/browser_result.spec.js
new file mode 100644
index 000000000..9700ad113
--- /dev/null
+++ b/test/unit/browser_result.spec.js
@@ -0,0 +1,69 @@
+describe('BrowserResult', () => {
+ var Result = require('../../lib/browser_result')
+ var result = null
+
+ var successResultFromBrowser = {
+ success: true,
+ skipped: false,
+ time: 100
+ }
+
+ var failedResultFromBrowser = {
+ success: false,
+ skipped: false,
+ time: 200
+ }
+
+ var skippedResultFromBrowser = {
+ success: false,
+ skipped: true,
+ time: 0
+ }
+
+ beforeEach(() => {
+ sinon.stub(Date, 'now')
+ Date.now.returns(123)
+ result = new Result()
+ })
+
+ afterEach(() => {
+ Date.now.restore()
+ })
+
+ it('should compute totalTime', () => {
+ Date.now.returns(223)
+ result.totalTimeEnd()
+ expect(result.totalTime).to.equal(223 - 123)
+ })
+
+ it('should sum success/failed/skipped', () => {
+ result.add(successResultFromBrowser)
+ expect(result.success).to.equal(1)
+ expect(result.failed).to.equal(0)
+ expect(result.skipped).to.equal(0)
+
+ result.add(failedResultFromBrowser)
+ expect(result.success).to.equal(1)
+ expect(result.failed).to.equal(1)
+ expect(result.skipped).to.equal(0)
+
+ result.add(successResultFromBrowser)
+ expect(result.success).to.equal(2)
+ expect(result.failed).to.equal(1)
+ expect(result.skipped).to.equal(0)
+
+ result.add(skippedResultFromBrowser)
+ expect(result.success).to.equal(2)
+ expect(result.failed).to.equal(1)
+ expect(result.skipped).to.equal(1)
+ })
+
+ it('should sum net time of all results', () => {
+ result.add(successResultFromBrowser)
+ result.add(failedResultFromBrowser)
+ expect(result.netTime).to.equal(300)
+
+ result.add(successResultFromBrowser)
+ expect(result.netTime).to.equal(400)
+ })
+})
diff --git a/test/unit/cli.spec.coffee b/test/unit/cli.spec.coffee
deleted file mode 100644
index dc4413f76..000000000
--- a/test/unit/cli.spec.coffee
+++ /dev/null
@@ -1,177 +0,0 @@
-#==============================================================================
-# lib/cli.js module
-#==============================================================================
-describe 'cli', ->
- cli = require '../../lib/cli'
- optimist = require 'optimist'
- path = require 'path'
- constant = require '../../lib/constants'
- path = require 'path'
- mocks = require 'mocks'
- loadFile = mocks.loadFile
- mockery = m = e = null
-
- fsMock = mocks.fs.create
- cwd:
- 'karma.conf.js': true
- cwd2:
- 'karma.conf.coffee': true
-
- currentCwd = null
-
- pathMock =
- resolve: (p) -> path.resolve currentCwd, p
-
- setCWD = (cwd) ->
- currentCwd = cwd
- fsMock._setCWD cwd
-
- processArgs = (args, opts) ->
- argv = optimist.parse(args)
- e.processArgs argv, opts || {}, fsMock, pathMock
-
- beforeEach ->
- setCWD '/'
- mockery = {}
- mockery.process = exit: sinon.spy()
- mockery.console = error: sinon.spy()
-
- # load file under test
- m = loadFile __dirname + '/../../lib/cli.js', mockery, {
- global: {},
- console: mockery.console,
- process: mockery.process,
- require: (path) ->
- if path.indexOf('./') is 0
- require '../../lib/' + path
- else
- require path
- }
- e = m.exports
-
- describe 'processArgs', ->
-
- it 'should override if multiple options given', ->
- # optimist parses --port 123 --port 456 as port = [123, 456] which makes no sense
- options = processArgs ['some.conf', '--port', '12', '--log-level', 'info',
- '--port', '34', '--log-level', 'debug']
-
- expect(options.port).to.equal 34
- expect(options.logLevel).to.equal 'DEBUG'
-
-
- it 'should return camelCased options', ->
- options = processArgs ['some.conf', '--port', '12', '--single-run']
-
- expect(options.configFile).to.exist
- expect(options.port).to.equal 12
- expect(options.singleRun).to.equal true
-
-
- it 'should parse options without configFile and set default', ->
- setCWD '/cwd'
- options = processArgs ['--auto-watch', '--auto-watch-interval', '10']
- expect(path.resolve(options.configFile)).to.equal path.resolve('/cwd/karma.conf.js')
- expect(options.autoWatch).to.equal true
- expect(options.autoWatchInterval).to.equal 10
-
-
- it 'should set default karma.conf.coffee config file if exists', ->
- setCWD '/cwd2'
- options = processArgs ['--port', '10']
-
- expect(path.resolve(options.configFile)).to.equal path.resolve('/cwd2/karma.conf.coffee')
-
-
- it 'should not set default config if neither exists', ->
- setCWD '/'
- options = processArgs []
-
- expect(options.configFile).to.equal null
-
-
- it 'should parse auto-watch, colors, singleRun to boolean', ->
- options = processArgs ['--auto-watch', 'false', '--colors', 'false', '--single-run', 'false']
-
- expect(options.autoWatch).to.equal false
- expect(options.colors).to.equal false
- expect(options.singleRun).to.equal false
-
- options = processArgs ['--auto-watch', 'true', '--colors', 'true', '--single-run', 'true']
-
- expect(options.autoWatch).to.equal true
- expect(options.colors).to.equal true
- expect(options.singleRun).to.equal true
-
-
- it 'should replace log-level constants', ->
- options = processArgs ['--log-level', 'debug']
- expect(options.logLevel).to.equal constant.LOG_DEBUG
-
- options = processArgs ['--log-level', 'error']
- expect(options.logLevel).to.equal constant.LOG_ERROR
-
- options = processArgs ['--log-level', 'warn']
- expect(options.logLevel).to.equal constant.LOG_WARN
-
- options = processArgs ['--log-level', 'foo']
- expect(mockery.process.exit).to.have.been.calledWith 1
-
- options = processArgs ['--log-level']
- expect(mockery.process.exit).to.have.been.calledWith 1
-
-
- it 'should parse browsers into an array', ->
- options = processArgs ['--browsers', 'Chrome,ChromeCanary,Firefox']
- expect(options.browsers).to.deep.equal ['Chrome', 'ChromeCanary', 'Firefox']
-
-
- it 'should resolve configFile to absolute path', ->
- setCWD '/cwd'
- options = processArgs ['some/config.js']
- expect(path.resolve(options.configFile)).to.equal path.resolve('/cwd/some/config.js')
-
-
- it 'should parse report-slower-than to a number', ->
- options = processArgs ['--report-slower-than', '2000']
- expect(options.reportSlowerThan).to.equal 2000
-
- options = processArgs ['--no-report-slower-than']
- expect(options.reportSlowerThan).to.equal 0
-
-
- it 'should cast reporters to array', ->
- options = processArgs ['--reporters', 'dots,junit']
- expect(options.reporters).to.deep.equal ['dots', 'junit']
-
- options = processArgs ['--reporters', 'dots']
- expect(options.reporters).to.deep.equal ['dots']
-
-
- it 'should parse removed/added/changed files to array', ->
- options = processArgs [
- '--removed-files', 'r1.js,r2.js',
- '--changed-files', 'ch1.js,ch2.js',
- '--added-files', 'a1.js,a2.js'
- ]
-
- expect(options.removedFiles).to.deep.equal ['r1.js', 'r2.js']
- expect(options.addedFiles).to.deep.equal ['a1.js', 'a2.js']
- expect(options.changedFiles).to.deep.equal ['ch1.js', 'ch2.js']
-
-
- describe 'parseClientArgs', ->
- it 'should return arguments after --', ->
- args = cli.parseClientArgs ['node', 'karma.js', 'runArg', '--flag', '--', '--foo', '--bar',
- 'baz']
- expect(args).to.deep.equal ['--foo', '--bar', 'baz']
-
- it 'should return empty args if -- is not present', ->
- args = cli.parseClientArgs ['node', 'karma.js', 'runArg', '--flag', '--foo', '--bar', 'baz']
- expect(args).to.deep.equal []
-
-
- describe 'argsBeforeDoubleDash', ->
- it 'should return array of args that occur before --', ->
- args = cli.argsBeforeDoubleDash ['aa', '--bb', 'value', '--', 'some', '--no-more']
- expect(args).to.deep.equal ['aa', '--bb', 'value']
diff --git a/test/unit/cli.spec.js b/test/unit/cli.spec.js
new file mode 100644
index 000000000..93dbf23ed
--- /dev/null
+++ b/test/unit/cli.spec.js
@@ -0,0 +1,186 @@
+import cli from '../../lib/cli'
+import optimist from 'optimist'
+import path from 'path'
+import constant from '../../lib/constants'
+import mocks from 'mocks'
+var loadFile = mocks.loadFile
+
+describe('cli', () => {
+ var m
+ var e
+ var mockery
+
+ var fsMock = mocks.fs.create({
+ cwd: {'karma.conf.js': true},
+ cwd2: {'karma.conf.coffee': true}
+ })
+
+ var currentCwd = null
+
+ var pathMock = {
+ resolve (p) {
+ return path.resolve(currentCwd, p)
+ }
+ }
+
+ var setCWD = cwd => {
+ currentCwd = cwd
+ fsMock._setCWD(cwd)
+ }
+
+ var processArgs = (args, opts) => {
+ var argv = optimist.parse(args)
+ return e.processArgs(argv, opts || {}, fsMock, pathMock)
+ }
+
+ beforeEach(() => {
+ setCWD('/')
+ mockery = {}
+ mockery.process = {exit: sinon.spy()}
+ mockery.console = {error: sinon.spy()}
+
+ // load file under test
+ m = loadFile(__dirname + '/../../lib/cli.js', mockery, {
+ global: {},
+ console: mockery.console,
+ process: mockery.process,
+ require (path) {
+ if (path.indexOf('./') === 0) {
+ return require('../../lib/' + path)
+ } else {
+ return require(path)
+ }
+ }
+ })
+ e = m.exports
+ })
+
+ describe('processArgs', () => {
+ it('should override if multiple options given', () => {
+ // optimist parses --port 123 --port 456 as port = [123, 456] which makes no sense
+ var options = processArgs(['some.conf', '--port', '12', '--log-level', 'info', '--port', '34', '--log-level', 'debug'])
+
+ expect(options.port).to.equal(34)
+ expect(options.logLevel).to.equal('DEBUG')
+ })
+
+ it('should return camelCased options', () => {
+ var options = processArgs(['some.conf', '--port', '12', '--single-run'])
+
+ expect(options.configFile).to.exist
+ expect(options.port).to.equal(12)
+ expect(options.singleRun).to.equal(true)
+ })
+
+ it('should parse options without configFile and set default', () => {
+ setCWD('/cwd')
+ var options = processArgs(['--auto-watch', '--auto-watch-interval', '10'])
+ expect(path.resolve(options.configFile)).to.equal(path.resolve('/cwd/karma.conf.js'))
+ expect(options.autoWatch).to.equal(true)
+ expect(options.autoWatchInterval).to.equal(10)
+ })
+
+ it('should set default karma.conf.coffee config file if exists', () => {
+ setCWD('/cwd2')
+ var options = processArgs(['--port', '10'])
+
+ expect(path.resolve(options.configFile)).to.equal(path.resolve('/cwd2/karma.conf.coffee'))
+ })
+
+ it('should not set default config if neither exists', () => {
+ setCWD('/')
+ var options = processArgs([])
+
+ expect(options.configFile).to.equal(null)
+ })
+
+ it('should parse auto-watch, colors, singleRun to boolean', () => {
+ var options = processArgs(['--auto-watch', 'false', '--colors', 'false', '--single-run', 'false'])
+
+ expect(options.autoWatch).to.equal(false)
+ expect(options.colors).to.equal(false)
+ expect(options.singleRun).to.equal(false)
+
+ options = processArgs(['--auto-watch', 'true', '--colors', 'true', '--single-run', 'true'])
+
+ expect(options.autoWatch).to.equal(true)
+ expect(options.colors).to.equal(true)
+ expect(options.singleRun).to.equal(true)
+ })
+
+ it('should replace log-level constants', () => {
+ var options = processArgs(['--log-level', 'debug'])
+ expect(options.logLevel).to.equal(constant.LOG_DEBUG)
+
+ options = processArgs(['--log-level', 'error'])
+ expect(options.logLevel).to.equal(constant.LOG_ERROR)
+
+ options = processArgs(['--log-level', 'warn'])
+ expect(options.logLevel).to.equal(constant.LOG_WARN)
+
+ options = processArgs(['--log-level', 'foo'])
+ expect(mockery.process.exit).to.have.been.calledWith(1)
+
+ options = processArgs(['--log-level'])
+ expect(mockery.process.exit).to.have.been.calledWith(1)
+ })
+
+ it('should parse browsers into an array', () => {
+ var options = processArgs(['--browsers', 'Chrome,ChromeCanary,Firefox'])
+ expect(options.browsers).to.deep.equal(['Chrome', 'ChromeCanary', 'Firefox'])
+ })
+
+ it('should resolve configFile to absolute path', () => {
+ setCWD('/cwd')
+ var options = processArgs(['some/config.js'])
+ expect(path.resolve(options.configFile)).to.equal(path.resolve('/cwd/some/config.js'))
+ })
+
+ it('should parse report-slower-than to a number', () => {
+ var options = processArgs(['--report-slower-than', '2000'])
+ expect(options.reportSlowerThan).to.equal(2000)
+
+ options = processArgs(['--no-report-slower-than'])
+ expect(options.reportSlowerThan).to.equal(0)
+ })
+
+ it('should cast reporters to array', () => {
+ var options = processArgs(['--reporters', 'dots,junit'])
+ expect(options.reporters).to.deep.equal(['dots', 'junit'])
+
+ options = processArgs(['--reporters', 'dots'])
+ expect(options.reporters).to.deep.equal(['dots'])
+ })
+
+ it('should parse removed/added/changed files to array', () => {
+ var options = processArgs([
+ '--removed-files', 'r1.js,r2.js',
+ '--changed-files', 'ch1.js,ch2.js',
+ '--added-files', 'a1.js,a2.js'
+ ])
+
+ expect(options.removedFiles).to.deep.equal(['r1.js', 'r2.js'])
+ expect(options.addedFiles).to.deep.equal(['a1.js', 'a2.js'])
+ expect(options.changedFiles).to.deep.equal(['ch1.js', 'ch2.js'])
+ })
+ })
+
+ describe('parseClientArgs', () => {
+ it('should return arguments after --', () => {
+ var args = cli.parseClientArgs(['node', 'karma.js', 'runArg', '--flag', '--', '--foo', '--bar', 'baz'])
+ expect(args).to.deep.equal(['--foo', '--bar', 'baz'])
+ })
+
+ it('should return empty args if -- is not present', () => {
+ var args = cli.parseClientArgs(['node', 'karma.js', 'runArg', '--flag', '--foo', '--bar', 'baz'])
+ expect(args).to.deep.equal([])
+ })
+ })
+
+ describe('argsBeforeDoubleDash', () => {
+ it('should return array of args that occur before --', () => {
+ var args = cli.argsBeforeDoubleDash(['aa', '--bb', 'value', '--', 'some', '--no-more'])
+ expect(args).to.deep.equal(['aa', '--bb', 'value'])
+ })
+ })
+})
diff --git a/test/unit/completion.spec.coffee b/test/unit/completion.spec.coffee
deleted file mode 100644
index e5a822bcb..000000000
--- a/test/unit/completion.spec.coffee
+++ /dev/null
@@ -1,59 +0,0 @@
-#==============================================================================
-# lib/completion.js module
-#==============================================================================
-describe 'completion', ->
- c = require '../../lib/completion'
- completion = null
-
- mockEnv = (line) ->
- words = line.split ' '
-
- words: words
- count: words.length
- last: words[words.length - 1]
- prev: words[words.length - 2]
-
- beforeEach ->
- sinon.stub console, 'log', (msg) -> completion.push msg
- completion = []
-
- describe 'opositeWord', ->
-
- it 'should handle --no-x args', ->
- expect(c.opositeWord '--no-single-run').to.equal '--single-run'
-
-
- it 'should handle --x args', ->
- expect(c.opositeWord '--browsers').to.equal '--no-browsers'
-
-
- it 'should ignore args without --', ->
- expect(c.opositeWord 'start').to.equal null
-
-
- describe 'sendCompletion', ->
-
- it 'should filter only words matching last typed partial', ->
- c.sendCompletion ['start', 'init', 'run'], mockEnv 'in'
- expect(completion).to.deep.equal ['init']
-
-
- it 'should filter out already used words/args', ->
- c.sendCompletion ['--single-run', '--port', '--xxx'], mockEnv 'start --single-run '
- expect(completion).to.deep.equal ['--port', '--xxx']
-
-
- it 'should filter out already used oposite words', ->
- c.sendCompletion ['--auto-watch', '--port'], mockEnv 'start --no-auto-watch '
- expect(completion).to.deep.equal ['--port']
-
-
- describe 'complete', ->
-
- it 'should complete the basic commands', ->
- c.complete mockEnv ''
- expect(completion).to.deep.equal ['start', 'init', 'run']
-
- completion.length = 0 # reset
- c.complete mockEnv 's'
- expect(completion).to.deep.equal ['start']
diff --git a/test/unit/completion.spec.js b/test/unit/completion.spec.js
new file mode 100644
index 000000000..c6c04f70f
--- /dev/null
+++ b/test/unit/completion.spec.js
@@ -0,0 +1,63 @@
+var c = require('../../lib/completion')
+
+describe('completion', () => {
+ var completion
+
+ function mockEnv (line) {
+ var words = line.split(' ')
+
+ return {
+ words: words,
+ count: words.length,
+ last: words[words.length - 1],
+ prev: words[words.length - 2]
+ }
+ }
+
+ beforeEach(() => {
+ sinon.stub(console, 'log', msg => completion.push(msg))
+ completion = []
+ })
+
+ describe('opositeWord', () => {
+ it('should handle --no-x args', () => {
+ expect(c.opositeWord('--no-single-run')).to.equal('--single-run')
+ })
+
+ it('should handle --x args', () => {
+ expect(c.opositeWord('--browsers')).to.equal('--no-browsers')
+ })
+
+ it('should ignore args without --', () => {
+ expect(c.opositeWord('start')).to.equal(null)
+ })
+ })
+
+ describe('sendCompletion', () => {
+ it('should filter only words matching last typed partial', () => {
+ c.sendCompletion(['start', 'init', 'run'], mockEnv('in'))
+ expect(completion).to.deep.equal(['init'])
+ })
+
+ it('should filter out already used words/args', () => {
+ c.sendCompletion(['--single-run', '--port', '--xxx'], mockEnv('start --single-run '))
+ expect(completion).to.deep.equal(['--port', '--xxx'])
+ })
+
+ it('should filter out already used oposite words', () => {
+ c.sendCompletion(['--auto-watch', '--port'], mockEnv('start --no-auto-watch '))
+ expect(completion).to.deep.equal(['--port'])
+ })
+ })
+
+ describe('complete', () => {
+ it('should complete the basic commands', () => {
+ c.complete(mockEnv(''))
+ expect(completion).to.deep.equal(['start', 'init', 'run'])
+
+ completion.length = 0 // reset
+ c.complete(mockEnv('s'))
+ expect(completion).to.deep.equal(['start'])
+ })
+ })
+})
diff --git a/test/unit/config.spec.coffee b/test/unit/config.spec.coffee
deleted file mode 100644
index 182561293..000000000
--- a/test/unit/config.spec.coffee
+++ /dev/null
@@ -1,374 +0,0 @@
-#==============================================================================
-# lib/config.js module
-#==============================================================================
-describe 'config', ->
- loadFile = require('mocks').loadFile
- mocks = m = e = null
- path = require('path')
- helper = require('../../lib/helper')
-
- resolveWinPath = (p) -> helper.normalizeWinPath(path.resolve(p))
-
- normalizeConfigWithDefaults = (cfg) ->
- cfg.urlRoot = '' if not cfg.urlRoot
- cfg.files = [] if not cfg.files
- cfg.exclude = [] if not cfg.exclude
- cfg.junitReporter = {} if not cfg.junitReporter
- cfg.coverageReporter = {} if not cfg.coverageReporter
- cfg.plugins = [] if not cfg.plugins
- m.normalizeConfig cfg
-
- # extract only pattern properties from list of pattern objects
- patternsFrom = (list) ->
- list.map (pattern) -> pattern.pattern
-
- wrapCfg = (cfg) ->
- return (config) ->
- config.set cfg
-
- beforeEach ->
- mocks = {}
- mocks.process = exit: sinon.spy()
- mockConfigs = {
- '/home/config1.js': wrapCfg({basePath: 'base', reporters: ['dots']}),
- '/home/config2.js': wrapCfg({basePath: '/abs/base'}),
- '/home/config3.js': wrapCfg({files: ['one.js', 'sub/two.js']}),
- '/home/config4.js': wrapCfg({port: 123, autoWatch: true, basePath: '/abs/base'}),
- '/home/config6.js': wrapCfg({reporters: 'junit'}),
- '/home/config7.js': wrapCfg({browsers: ['Chrome', 'Firefox']}),
- '/conf/invalid.js': () -> throw new SyntaxError('Unexpected token =')
- '/conf/exclude.js': wrapCfg({exclude: ['one.js', 'sub/two.js']}),
- '/conf/absolute.js': wrapCfg({files: ['http://some.com', 'https://more.org/file.js']}),
- '/conf/both.js': wrapCfg({files: ['one.js', 'two.js'], exclude: ['third.js']}),
- '/conf/coffee.coffee': wrapCfg({files: [ 'one.js', 'two.js']}),
- }
-
- # load file under test
- m = loadFile __dirname + '/../../lib/config.js', mocks, {
- global: {},
- process: mocks.process,
- require: (path) ->
- if mockConfigs[path]
- return mockConfigs[path]
- if path.indexOf('./') is 0
- require '../../lib/' + path
- else
- require path
- }
- e = m.exports
-
-
- #============================================================================
- # config.parseConfig()
- # Should parse configuration file and do some basic processing as well
- #============================================================================
- describe 'parseConfig', ->
- logSpy = null
-
- beforeEach ->
- logSpy = sinon.spy()
- logger = require '../../lib/logger.js'
- logger.create('config').on 'log', logSpy
-
-
- it 'should resolve relative basePath to config directory', ->
- config = e.parseConfig '/home/config1.js', {}
- expect(config.basePath).to.equal resolveWinPath('/home/base')
-
-
- it 'should keep absolute basePath', ->
- config = e.parseConfig '/home/config2.js', {}
- expect(config.basePath).to.equal resolveWinPath('/abs/base')
-
-
- it 'should resolve all file patterns', ->
- config = e.parseConfig '/home/config3.js', {}
- actual = [resolveWinPath('/home/one.js'), resolveWinPath('/home/sub/two.js')]
- expect(patternsFrom config.files).to.deep.equal actual
-
-
- it 'should keep absolute url file patterns', ->
- config = e.parseConfig '/conf/absolute.js', {}
- expect(patternsFrom config.files).to.deep.equal [
- 'http://some.com'
- 'https://more.org/file.js'
- ]
-
-
- it 'should resolve all exclude patterns', ->
- config = e.parseConfig '/conf/exclude.js', {}
- actual = [
- resolveWinPath('/conf/one.js')
- resolveWinPath('/conf/sub/two.js')
- resolveWinPath('/conf/exclude.js')
- ]
-
- expect(config.exclude).to.deep.equal actual
-
-
- it 'should log error and exit if file does not exist', ->
- e.parseConfig '/conf/not-exist.js', {}
-
- expect(logSpy).to.have.been.called
- event = logSpy.lastCall.args[0]
- expect(event.level.toString()).to.be.equal 'ERROR'
- expect(event.data).to.be.deep.equal ['File %s does not exist!', '/conf/not-exist.js']
- expect(mocks.process.exit).to.have.been.calledWith 1
-
-
- it 'should throw and log error if invalid file', ->
- e.parseConfig '/conf/invalid.js', {}
-
- expect(logSpy).to.have.been.called
- event = logSpy.lastCall.args[0]
- expect(event.level.toString()).to.be.equal 'ERROR'
- expect(event.data).to.be.deep.equal ["Error in config file!\n",
- new SyntaxError('Unexpected token =')]
- expect(mocks.process.exit).to.have.been.calledWith 1
-
-
- it 'should override config with given cli options', ->
- config = e.parseConfig '/home/config4.js', {port: 456, autoWatch: false}
-
- expect(config.port).to.equal 456
- expect(config.autoWatch).to.equal false
- expect(config.basePath).to.equal resolveWinPath('/abs/base')
-
-
- it 'should override config with cli options, but not deep merge', ->
- # regression https://github.com/karma-runner/karma/issues/283
- config = e.parseConfig '/home/config7.js', {browsers: ['Safari']}
-
- expect(config.browsers).to.deep.equal ['Safari']
-
-
- it 'should resolve files and excludes to overriden basePath from cli', ->
- config = e.parseConfig '/conf/both.js', {port: 456, autoWatch: false, basePath: '/xxx'}
-
- expect(config.basePath).to.equal resolveWinPath('/xxx')
- actual = [resolveWinPath('/xxx/one.js'), resolveWinPath('/xxx/two.js')]
- expect(patternsFrom config.files).to.deep.equal actual
- expect(config.exclude).to.deep.equal [
- resolveWinPath('/xxx/third.js')
- resolveWinPath('/conf/both.js')
- ]
-
-
- it 'should normalize urlRoot config', ->
- config = normalizeConfigWithDefaults {urlRoot: ''}
- expect(config.urlRoot).to.equal '/'
-
- config = normalizeConfigWithDefaults {urlRoot: '/a/b'}
- expect(config.urlRoot).to.equal '/a/b/'
-
- config = normalizeConfigWithDefaults {urlRoot: 'a/'}
- expect(config.urlRoot).to.equal '/a/'
-
- config = normalizeConfigWithDefaults {urlRoot: 'some/thing'}
- expect(config.urlRoot).to.equal '/some/thing/'
-
-
- it 'should change autoWatch to false if singleRun', ->
- # config4.js has autoWatch = true
- config = m.parseConfig '/home/config4.js', {singleRun: true}
- expect(config.autoWatch).to.equal false
-
-
- it 'should normalize reporters to an array', ->
- config = m.parseConfig '/home/config6.js', {}
- expect(config.reporters).to.deep.equal ['junit']
-
-
- it 'should compile coffeescript config', ->
- config = e.parseConfig '/conf/coffee.coffee', {}
- expect(patternsFrom config.files).to.deep.equal [
- resolveWinPath('/conf/one.js')
- resolveWinPath('/conf/two.js')
- ]
-
-
- it 'should set defaults with coffeescript', ->
- config = e.parseConfig '/conf/coffee.coffee', {}
- expect(config.autoWatch).to.equal true
-
-
- it 'should not read config file, when null', ->
- config = e.parseConfig null, {basePath: '/some'}
-
- expect(logSpy).not.to.have.been.called
- expect(config.basePath).to.equal resolveWinPath('/some') # overriden by CLI
- expect(config.urlRoot).to.equal '/' # default value
-
-
- it 'should not read config file, when null but still resolve cli basePath', ->
- config = e.parseConfig null, {basePath: './some' }
-
- expect(logSpy).not.to.have.been.called
- expect(config.basePath).to.equal resolveWinPath('./some')
- expect(config.urlRoot).to.equal '/' # default value
-
- it 'should default unset options in client config', ->
- config = e.parseConfig null, {client: {args: ['--test']}}
-
- expect(config.client.useIframe).to.not.be.undefined
- expect(config.client.captureConsole).to.not.be.undefined
-
- config = e.parseConfig null, {client: {useIframe: true}}
-
- expect(config.client.args).to.not.be.undefined
- expect(config.client.captureConsole).to.not.be.undefined
-
- config = e.parseConfig null, {client: {captureConsole: true}}
-
- expect(config.client.useIframe).to.not.be.undefined
- expect(config.client.args).to.not.be.undefined
-
-
- describe 'normalizeConfig', ->
-
- it 'should convert patterns to objects and set defaults', ->
- config = normalizeConfigWithDefaults
- basePath: '/base'
- files: ['a/*.js', {pattern: 'b.js', watched: false, included: false}, {pattern: 'c.js'}]
-
- expect(config.files.length).to.equal 3
-
- file = config.files.shift()
- expect(file.pattern).to.equal resolveWinPath '/base/a/*.js'
- expect(file.included).to.equal true
- expect(file.served).to.equal true
- expect(file.watched).to.equal true
-
- file = config.files.shift()
- expect(file.pattern).to.equal resolveWinPath '/base/b.js'
- expect(file.included).to.equal false
- expect(file.served).to.equal true
- expect(file.watched).to.equal false
-
- file = config.files.shift()
- expect(file.pattern).to.equal resolveWinPath '/base/c.js'
- expect(file.included).to.equal true
- expect(file.served).to.equal true
- expect(file.watched).to.equal true
-
-
- it 'should normalize preprocessors to an array', ->
- config = normalizeConfigWithDefaults
- basePath: ''
- preprocessors:
- '/*.coffee': 'coffee'
- '/*.html': 'html2js'
-
- expect(config.preprocessors[resolveWinPath('/*.coffee')]).to.deep.equal ['coffee']
- expect(config.preprocessors[resolveWinPath('/*.html')]).to.deep.equal ['html2js']
-
-
- it 'should resolve relative preprocessor patterns', ->
- config = normalizeConfigWithDefaults
- basePath: '/some/base'
- preprocessors:
- '*.coffee': 'coffee'
- '/**/*.html': 'html2js'
-
- expect(config.preprocessors).to.have.property resolveWinPath('/some/base/*.coffee')
- expect(config.preprocessors).not.to.have.property resolveWinPath('*.coffee')
- expect(config.preprocessors).to.have.property resolveWinPath('/**/*.html')
-
-
- describe 'createPatternObject', ->
-
- it 'should parse string and set defaults', ->
- pattern = m.createPatternObject 'some/**/*.js'
-
- expect(typeof pattern).to.equal 'object'
- expect(pattern.pattern).to.equal 'some/**/*.js'
- expect(pattern.watched).to.equal true
- expect(pattern.included).to.equal true
- expect(pattern.served).to.equal true
-
-
- it 'should merge pattern object and set defaults', ->
- pattern = m.createPatternObject {pattern: 'a.js', included: false, watched: false}
-
- expect(typeof pattern).to.equal 'object'
- expect(pattern.pattern).to.equal 'a.js'
- expect(pattern.watched).to.equal false
- expect(pattern.included).to.equal false
- expect(pattern.served).to.equal true
-
-
- it 'should make urls not served neither watched', ->
- pattern = m.createPatternObject 'http://some.url.com'
-
- expect(pattern.pattern).to.equal 'http://some.url.com'
- expect(pattern.included).to.equal true
- expect(pattern.watched).to.equal false
- expect(pattern.served).to.equal false
-
- pattern = m.createPatternObject {pattern: 'https://some.other.com'}
-
- expect(pattern.pattern).to.equal 'https://some.other.com'
- expect(pattern.included).to.equal true
- expect(pattern.watched).to.equal false
- expect(pattern.served).to.equal false
-
-
- describe 'custom', ->
- di = require 'di'
-
- forwardArgsFactory = (args) ->
- args
-
- baseModule =
- 'preprocessor:base': ['type', forwardArgsFactory]
- 'launcher:base': ['type', forwardArgsFactory]
- 'reporter:base': ['type', forwardArgsFactory]
-
- it 'should define a custom launcher', ->
- config = normalizeConfigWithDefaults
- customLaunchers: custom:
- base: 'base'
- first: 123
- whatever: 'aaa'
-
- injector = new di.Injector([baseModule].concat config.plugins)
- injectedArgs = injector.get 'launcher:custom'
-
- expect(injectedArgs).to.be.defined
- expect(injectedArgs.first).to.equal 123
- expect(injectedArgs.whatever).to.equal 'aaa'
-
-
- it 'should define a custom preprocessor', ->
- config = normalizeConfigWithDefaults
- customPreprocessors: custom:
- base: 'base'
- second: 123
- whatever: 'bbb'
-
- injector = new di.Injector([baseModule].concat config.plugins)
- injectedArgs = injector.get 'preprocessor:custom'
-
- expect(injectedArgs).to.be.defined
- expect(injectedArgs.second).to.equal 123
- expect(injectedArgs.whatever).to.equal 'bbb'
-
-
- it 'should define a custom reporter', ->
- config = normalizeConfigWithDefaults
- customReporters: custom:
- base: 'base'
- third: 123
- whatever: 'ccc'
-
- injector = new di.Injector([baseModule].concat config.plugins)
- injectedArgs = injector.get 'reporter:custom'
-
- expect(injectedArgs).to.be.defined
- expect(injectedArgs.third).to.equal 123
- expect(injectedArgs.whatever).to.equal 'ccc'
-
-
- it 'should not create empty module', ->
- config = normalizeConfigWithDefaults {}
- expect(config.plugins).to.deep.equal []
diff --git a/test/unit/config.spec.js b/test/unit/config.spec.js
new file mode 100644
index 000000000..04fe920e8
--- /dev/null
+++ b/test/unit/config.spec.js
@@ -0,0 +1,394 @@
+var loadFile = require('mocks').loadFile
+import path from 'path'
+var helper = require('../../lib/helper')
+var logger = require('../../lib/logger.js')
+
+describe('config', () => {
+ var m
+ var e
+ var mocks
+
+ var resolveWinPath = p => helper.normalizeWinPath(path.resolve(p))
+
+ var normalizeConfigWithDefaults = cfg => {
+ if (!cfg.urlRoot) cfg.urlRoot = ''
+ if (!cfg.files) cfg.files = []
+ if (!cfg.exclude) cfg.exclude = []
+ if (!cfg.junitReporter) cfg.junitReporter = {}
+ if (!cfg.coverageReporter) cfg.coverageReporter = {}
+ if (!cfg.plugins) cfg.plugins = []
+
+ return m.normalizeConfig(cfg)
+ }
+
+ // extract only pattern properties from list of pattern objects
+ var patternsFrom = list => list.map(pattern => pattern.pattern)
+
+ var wrapCfg = function (cfg) {
+ return config => config.set(cfg)
+ }
+
+ beforeEach(() => {
+ mocks = {}
+ mocks.process = {exit: sinon.spy()}
+ var mockConfigs = {
+ '/home/config1.js': wrapCfg({basePath: 'base', reporters: ['dots']}),
+ '/home/config2.js': wrapCfg({basePath: '/abs/base'}),
+ '/home/config3.js': wrapCfg({files: ['one.js', 'sub/two.js']}),
+ '/home/config4.js': wrapCfg({port: 123, autoWatch: true, basePath: '/abs/base'}),
+ '/home/config6.js': wrapCfg({reporters: 'junit'}),
+ '/home/config7.js': wrapCfg({browsers: ['Chrome', 'Firefox']}),
+ '/conf/invalid.js': () => {throw new SyntaxError('Unexpected token =')},
+ '/conf/exclude.js': wrapCfg({exclude: ['one.js', 'sub/two.js']}),
+ '/conf/absolute.js': wrapCfg({files: ['http://some.com', 'https://more.org/file.js']}),
+ '/conf/both.js': wrapCfg({files: ['one.js', 'two.js'], exclude: ['third.js']}),
+ '/conf/coffee.coffee': wrapCfg({files: ['one.js', 'two.js']})
+ }
+
+ // load file under test
+ m = loadFile(__dirname + '/../../lib/config.js', mocks, {
+ global: {},
+ process: mocks.process,
+ require (path) {
+ if (mockConfigs[path]) {
+ return mockConfigs[path]
+ }
+ if (path.indexOf('./') === 0) {
+ return require('../../lib/' + path)
+ } else {
+ return require(path)
+ }
+ }
+ })
+ e = m.exports
+ })
+
+ describe('parseConfig', () => {
+ var logSpy
+
+ beforeEach(() => {
+ logSpy = sinon.spy()
+ logger.create('config').on('log', logSpy)
+ })
+
+ it('should resolve relative basePath to config directory', () => {
+ var config = e.parseConfig('/home/config1.js', {})
+ expect(config.basePath).to.equal(resolveWinPath('/home/base'))
+ })
+
+ it('should keep absolute basePath', () => {
+ var config = e.parseConfig('/home/config2.js', {})
+ expect(config.basePath).to.equal(resolveWinPath('/abs/base'))
+ })
+
+ it('should resolve all file patterns', () => {
+ var config = e.parseConfig('/home/config3.js', {})
+ var actual = [resolveWinPath('/home/one.js'), resolveWinPath('/home/sub/two.js')]
+ expect(patternsFrom(config.files)).to.deep.equal(actual)
+ })
+
+ it('should keep absolute url file patterns', () => {
+ var config = e.parseConfig('/conf/absolute.js', {})
+ expect(patternsFrom(config.files)).to.deep.equal([
+ 'http://some.com',
+ 'https://more.org/file.js'
+ ])
+ })
+
+ it('should resolve all exclude patterns', () => {
+ var config = e.parseConfig('/conf/exclude.js', {})
+ var actual = [
+ resolveWinPath('/conf/one.js'),
+ resolveWinPath('/conf/sub/two.js'),
+ resolveWinPath('/conf/exclude.js')
+ ]
+
+ expect(config.exclude).to.deep.equal(actual)
+ })
+
+ it('should log error and exit if file does not exist', () => {
+ e.parseConfig('/conf/not-exist.js', {})
+
+ expect(logSpy).to.have.been.called
+ var event = logSpy.lastCall.args[0]
+ expect(event.level.toString()).to.be.equal('ERROR')
+ expect(event.data).to.be.deep.equal(['File %s does not exist!', '/conf/not-exist.js'])
+ expect(mocks.process.exit).to.have.been.calledWith(1)
+ })
+
+ it('should throw and log error if invalid file', () => {
+ e.parseConfig('/conf/invalid.js', {})
+
+ expect(logSpy).to.have.been.called
+ var event = logSpy.lastCall.args[0]
+ expect(event.level.toString()).to.be.equal('ERROR')
+ expect(event.data).to.be.deep.equal([
+ 'Error in config file!\n',
+ new SyntaxError('Unexpected token =')
+ ])
+ expect(mocks.process.exit).to.have.been.calledWith(1)
+ })
+
+ it('should override config with given cli options', () => {
+ var config = e.parseConfig('/home/config4.js', {port: 456, autoWatch: false})
+
+ expect(config.port).to.equal(456)
+ expect(config.autoWatch).to.equal(false)
+ expect(config.basePath).to.equal(resolveWinPath('/abs/base'))
+ })
+
+ it('should override config with cli options, but not deep merge', () => {
+ // regression https://github.com/karma-runner/karma/issues/283
+ var config = e.parseConfig('/home/config7.js', {browsers: ['Safari']})
+
+ expect(config.browsers).to.deep.equal(['Safari'])
+ })
+
+ it('should resolve files and excludes to overriden basePath from cli', () => {
+ var config = e.parseConfig('/conf/both.js', {port: 456, autoWatch: false, basePath: '/xxx'})
+
+ expect(config.basePath).to.equal(resolveWinPath('/xxx'))
+ var actual = [resolveWinPath('/xxx/one.js'), resolveWinPath('/xxx/two.js')]
+ expect(patternsFrom(config.files)).to.deep.equal(actual)
+ expect(config.exclude).to.deep.equal([
+ resolveWinPath('/xxx/third.js'),
+ resolveWinPath('/conf/both.js')
+ ])
+ })
+
+ it('should normalize urlRoot config', () => {
+ var config = normalizeConfigWithDefaults({urlRoot: ''})
+ expect(config.urlRoot).to.equal('/')
+
+ config = normalizeConfigWithDefaults({urlRoot: '/a/b'})
+ expect(config.urlRoot).to.equal('/a/b/')
+
+ config = normalizeConfigWithDefaults({urlRoot: 'a/'})
+ expect(config.urlRoot).to.equal('/a/')
+
+ config = normalizeConfigWithDefaults({urlRoot: 'some/thing'})
+ expect(config.urlRoot).to.equal('/some/thing/')
+ })
+
+ it('should change autoWatch to false if singleRun', () => {
+ // config4.js has autoWatch = true
+ var config = m.parseConfig('/home/config4.js', {singleRun: true})
+ expect(config.autoWatch).to.equal(false)
+ })
+
+ it('should normalize reporters to an array', () => {
+ var config = m.parseConfig('/home/config6.js', {})
+ expect(config.reporters).to.deep.equal(['junit'])
+ })
+
+ it('should compile coffeescript config', () => {
+ var config = e.parseConfig('/conf/coffee.coffee', {})
+ expect(patternsFrom(config.files)).to.deep.equal([
+ resolveWinPath('/conf/one.js'),
+ resolveWinPath('/conf/two.js')
+ ])
+ })
+
+ it('should set defaults with coffeescript', () => {
+ var config = e.parseConfig('/conf/coffee.coffee', {})
+ expect(config.autoWatch).to.equal(true)
+ })
+
+ it('should not read config file, when null', () => {
+ var config = e.parseConfig(null, {basePath: '/some'})
+
+ expect(logSpy).not.to.have.been.called
+ expect(config.basePath).to.equal(resolveWinPath('/some')) // overriden by CLI
+ expect(config.urlRoot).to.equal('/')
+ }) // default value
+
+ it('should not read config file, when null but still resolve cli basePath', () => {
+ var config = e.parseConfig(null, {basePath: './some'})
+
+ expect(logSpy).not.to.have.been.called
+ expect(config.basePath).to.equal(resolveWinPath('./some'))
+ expect(config.urlRoot).to.equal('/')
+ }) // default value
+
+ it('should default unset options in client config', () => {
+ var config = e.parseConfig(null, {client: {args: ['--test']}})
+
+ expect(config.client.useIframe).to.not.be.undefined
+ expect(config.client.captureConsole).to.not.be.undefined
+
+ config = e.parseConfig(null, {client: {useIframe: true}})
+
+ expect(config.client.args).to.not.be.undefined
+ expect(config.client.captureConsole).to.not.be.undefined
+
+ config = e.parseConfig(null, {client: {captureConsole: true}})
+
+ expect(config.client.useIframe).to.not.be.undefined
+ expect(config.client.args).to.not.be.undefined
+ })
+ })
+
+ describe('normalizeConfig', () => {
+ it('should convert patterns to objects and set defaults', () => {
+ var config = normalizeConfigWithDefaults({
+ basePath: '/base',
+ files: ['a/*.js', {pattern: 'b.js', watched: false, included: false}, {pattern: 'c.js'}]
+ })
+
+ expect(config.files.length).to.equal(3)
+
+ var file = config.files.shift()
+ expect(file.pattern).to.equal(resolveWinPath('/base/a/*.js'))
+ expect(file.included).to.equal(true)
+ expect(file.served).to.equal(true)
+ expect(file.watched).to.equal(true)
+
+ file = config.files.shift()
+ expect(file.pattern).to.equal(resolveWinPath('/base/b.js'))
+ expect(file.included).to.equal(false)
+ expect(file.served).to.equal(true)
+ expect(file.watched).to.equal(false)
+
+ file = config.files.shift()
+ expect(file.pattern).to.equal(resolveWinPath('/base/c.js'))
+ expect(file.included).to.equal(true)
+ expect(file.served).to.equal(true)
+ expect(file.watched).to.equal(true)
+ })
+
+ it('should normalize preprocessors to an array', () => {
+ var config = normalizeConfigWithDefaults({
+ basePath: '',
+ preprocessors: {'/*.coffee': 'coffee',
+ '/*.html': 'html2js'}
+ })
+
+ expect(config.preprocessors[resolveWinPath('/*.coffee')]).to.deep.equal(['coffee'])
+ expect(config.preprocessors[resolveWinPath('/*.html')]).to.deep.equal(['html2js'])
+ })
+
+ it('should resolve relative preprocessor patterns', () => {
+ var config = normalizeConfigWithDefaults({
+ basePath: '/some/base',
+ preprocessors: {'*.coffee': 'coffee',
+ '/**/*.html': 'html2js'}
+ })
+
+ expect(config.preprocessors).to.have.property(resolveWinPath('/some/base/*.coffee'))
+ expect(config.preprocessors).not.to.have.property(resolveWinPath('*.coffee'))
+ expect(config.preprocessors).to.have.property(resolveWinPath('/**/*.html'))
+ })
+ })
+
+ describe('createPatternObject', () => {
+ it('should parse string and set defaults', () => {
+ var pattern = m.createPatternObject('some/**/*.js')
+
+ expect(typeof pattern).to.equal('object')
+ expect(pattern.pattern).to.equal('some/**/*.js')
+ expect(pattern.watched).to.equal(true)
+ expect(pattern.included).to.equal(true)
+ expect(pattern.served).to.equal(true)
+ })
+
+ it('should merge pattern object and set defaults', () => {
+ var pattern = m.createPatternObject({pattern: 'a.js', included: false, watched: false})
+
+ expect(typeof pattern).to.equal('object')
+ expect(pattern.pattern).to.equal('a.js')
+ expect(pattern.watched).to.equal(false)
+ expect(pattern.included).to.equal(false)
+ expect(pattern.served).to.equal(true)
+ })
+
+ it('should make urls not served neither watched', () => {
+ var pattern = m.createPatternObject('http://some.url.com')
+
+ expect(pattern.pattern).to.equal('http://some.url.com')
+ expect(pattern.included).to.equal(true)
+ expect(pattern.watched).to.equal(false)
+ expect(pattern.served).to.equal(false)
+
+ pattern = m.createPatternObject({pattern: 'https://some.other.com'})
+
+ expect(pattern.pattern).to.equal('https://some.other.com')
+ expect(pattern.included).to.equal(true)
+ expect(pattern.watched).to.equal(false)
+ expect(pattern.served).to.equal(false)
+ })
+ })
+
+ describe('custom', () => {
+ var di = require('di')
+
+ var forwardArgsFactory = args => args
+
+ var baseModule = {
+ 'preprocessor:base': ['type', forwardArgsFactory],
+ 'launcher:base': ['type', forwardArgsFactory],
+ 'reporter:base': ['type', forwardArgsFactory]
+ }
+
+ it('should define a custom launcher', () => {
+ var config = normalizeConfigWithDefaults({
+ customLaunchers: {
+ custom: {
+ base: 'base',
+ first: 123,
+ whatever: 'aaa'
+ }
+ }
+ })
+
+ var injector = new di.Injector([baseModule].concat(config.plugins))
+ var injectedArgs = injector.get('launcher:custom')
+
+ expect(injectedArgs).to.be.defined
+ expect(injectedArgs.first).to.equal(123)
+ expect(injectedArgs.whatever).to.equal('aaa')
+ })
+
+ it('should define a custom preprocessor', () => {
+ var config = normalizeConfigWithDefaults({
+ customPreprocessors: {
+ custom: {
+ base: 'base',
+ second: 123,
+ whatever: 'bbb'
+ }
+ }
+ })
+
+ var injector = new di.Injector([baseModule].concat(config.plugins))
+ var injectedArgs = injector.get('preprocessor:custom')
+
+ expect(injectedArgs).to.be.defined
+ expect(injectedArgs.second).to.equal(123)
+ expect(injectedArgs.whatever).to.equal('bbb')
+ })
+
+ it('should define a custom reporter', () => {
+ var config = normalizeConfigWithDefaults({
+ customReporters: {
+ custom: {
+ base: 'base',
+ third: 123,
+ whatever: 'ccc'
+ }
+ }
+ })
+
+ var injector = new di.Injector([baseModule].concat(config.plugins))
+ var injectedArgs = injector.get('reporter:custom')
+
+ expect(injectedArgs).to.be.defined
+ expect(injectedArgs.third).to.equal(123)
+ expect(injectedArgs.whatever).to.equal('ccc')
+ })
+
+ it('should not create empty module', () => {
+ var config = normalizeConfigWithDefaults({})
+ expect(config.plugins).to.deep.equal([])
+ })
+ })
+})
diff --git a/test/unit/emitter_wrapper.spec.coffee b/test/unit/emitter_wrapper.spec.coffee
deleted file mode 100644
index fa9ae9579..000000000
--- a/test/unit/emitter_wrapper.spec.coffee
+++ /dev/null
@@ -1,57 +0,0 @@
-#==============================================================================
-# lib/emitter_wrapper.js module
-#==============================================================================
-describe 'emitter_wrapper', ->
- EmitterWrapper = require '../../lib/emitter_wrapper'
- events = require 'events'
- EventEmitter = events.EventEmitter
-
- emitter = null
- wrapped = null
- called = false
-
- beforeEach ->
- emitter = new EventEmitter()
- emitter.aMethod = (e) -> called = true
- emitter.on 'anEvent', emitter.aMethod
- wrapped = new EmitterWrapper(emitter)
-
- #===========================================================================
- # wrapper.addListener
- #===========================================================================
- describe 'addListener', ->
- aListener = (e) -> true
-
- it 'should add a listener to the wrapped emitter', ->
- wrapped.addListener 'anEvent', aListener
- expect(emitter.listeners('anEvent')).to.contain aListener
-
- it 'returns the wrapped emitter', ->
- expect(wrapped.addListener 'anEvent', aListener).to.equal wrapped
-
- #===========================================================================
- # wrapper.removeAllListeners
- #===========================================================================
- describe 'removeAllListeners', ->
- aListener = (e) -> true
-
- beforeEach ->
- wrapped.addListener 'anEvent', aListener
-
- it 'should remove listeners that were attached via the wrapper', ->
- wrapped.removeAllListeners()
- expect(emitter.listeners('anEvent')).not.to.contain aListener
-
- it 'should not remove listeners that were attached to the original emitter', ->
- wrapped.removeAllListeners()
- expect(emitter.listeners('anEvent')).to.contain emitter.aMethod
-
- it 'should remove only matching listeners when called with an event name', ->
- anotherListener = (e) -> true
- wrapped.addListener 'anotherEvent', anotherListener
- wrapped.removeAllListeners('anEvent')
- expect(emitter.listeners('anEvent')).not.to.contain aListener
- expect(emitter.listeners('anotherEvent')).to.contain anotherListener
-
- it 'returns the wrapped emitter', ->
- expect(wrapped.addListener 'anEvent', aListener).to.equal wrapped
diff --git a/test/unit/emitter_wrapper.spec.js b/test/unit/emitter_wrapper.spec.js
new file mode 100644
index 000000000..b5caddbf9
--- /dev/null
+++ b/test/unit/emitter_wrapper.spec.js
@@ -0,0 +1,57 @@
+import EmitterWrapper from '../../lib/emitter_wrapper'
+import {EventEmitter} from 'events'
+
+describe('emitter_wrapper', () => {
+ var emitter
+ var wrapped
+
+ beforeEach(() => {
+ emitter = new EventEmitter()
+ emitter.aMethod = e => true
+ emitter.on('anEvent', emitter.aMethod)
+ wrapped = new EmitterWrapper(emitter)
+ })
+
+ describe('addListener', () => {
+ var aListener = e => true
+
+ it('should add a listener to the wrapped emitter', () => {
+ wrapped.addListener('anEvent', aListener)
+ expect(emitter.listeners('anEvent')).to.contain(aListener)
+ })
+
+ it('returns the wrapped emitter', () => {
+ expect(wrapped.addListener('anEvent', aListener)).to.equal(wrapped)
+ })
+ })
+
+ describe('removeAllListeners', () => {
+ var aListener = e => true
+
+ beforeEach(() => {
+ wrapped.addListener('anEvent', aListener)
+ })
+
+ it('should remove listeners that were attached via the wrapper', () => {
+ wrapped.removeAllListeners()
+ expect(emitter.listeners('anEvent')).not.to.contain(aListener)
+ })
+
+ it('should not remove listeners that were attached to the original emitter', () => {
+ wrapped.removeAllListeners()
+ expect(emitter.listeners('anEvent')).to.contain(emitter.aMethod)
+ })
+
+ it('should remove only matching listeners when called with an event name', () => {
+ var anotherListener = e => true
+ wrapped.addListener('anotherEvent', anotherListener)
+ wrapped.removeAllListeners('anEvent')
+ expect(emitter.listeners('anEvent')).not.to.contain(aListener)
+ expect(emitter.listeners('anotherEvent')).to.contain(anotherListener)
+ })
+
+ it('returns the wrapped emitter', () => {
+ expect(wrapped.addListener('anEvent', aListener)).to.equal(wrapped)
+ })
+ })
+})
diff --git a/test/unit/events.spec.coffee b/test/unit/events.spec.coffee
deleted file mode 100644
index d50005b7f..000000000
--- a/test/unit/events.spec.coffee
+++ /dev/null
@@ -1,180 +0,0 @@
-#==============================================================================
-# lib/events.js module
-#==============================================================================
-describe 'events', ->
- e = require '../../lib/events'
- emitter = null
-
- beforeEach ->
- emitter = new e.EventEmitter
-
- #============================================================================
- # events.EventEmitter
- #============================================================================
- describe 'EventEmitter', ->
-
- it 'should emit events', ->
- spy = sinon.spy()
-
- emitter.on 'abc', spy
- emitter.emit 'abc'
- expect(spy).to.have.been.called
-
-
- #==========================================================================
- # events.EventEmitter.bind()
- #==========================================================================
- describe 'bind', ->
- object = null
-
- beforeEach ->
- object = sinon.stub
- onFoo: ->
- onFooBar: ->
- foo: ->
- bar: ->
- emitter.bind object
-
-
- it 'should register all "on" methods to events', ->
- emitter.emit 'foo'
- expect(object.onFoo).to.have.been.called
-
- emitter.emit 'foo_bar'
- expect(object.onFooBar).to.have.been.called
-
- expect(object.foo).not.to.have.been.called
- expect(object.bar).not.to.have.been.called
-
-
- it 'should bind methods to the owner object', ->
- emitter.emit 'foo'
- emitter.emit 'foo_bar'
-
- expect(object.onFoo).to.have.always.been.calledOn object
- expect(object.onFooBar).to.have.always.been.calledOn object
- expect(object.foo).not.to.have.been.called
- expect(object.bar).not.to.have.been.called
-
-
- #==========================================================================
- # events.EventEmitter.emitAsync()
- #==========================================================================
- describe 'emitAsync', ->
- object = null
-
- beforeEach ->
- object = sinon.stub
- onFoo: ->
- onFooBar: ->
- foo: ->
- bar: ->
- emitter.bind object
-
-
- it 'should resolve the promise once all listeners are done', (done) ->
- callbacks = []
- eventDone = sinon.spy()
-
- emitter.on 'a', (d) -> d()
- emitter.on 'a', (d) -> callbacks.push d
- emitter.on 'a', (d) -> callbacks.push d
-
- promise = emitter.emitAsync('a')
-
- expect(eventDone).not.to.have.been.called
- callbacks.pop()()
- expect(eventDone).not.to.have.been.called
- callbacks.pop()()
-
- promise.then ->
- eventDone()
- expect(eventDone).to.have.been.called
- done()
-
-
- it 'should resolve asynchronously when no listener', (done) ->
- spyDone = sinon.spy done
- emitter.emitAsync('whatever').then spyDone
- expect(spyDone).to.not.have.been.called
-
-
- #============================================================================
- # events.bindAll
- #============================================================================
- describe 'bindAll', ->
-
- it 'should take emitter as second argument', ->
- object = sinon.stub onFoo: ->
-
- e.bindAll object, emitter
- emitter.emit 'foo'
- emitter.emit 'bar'
-
- expect(object.onFoo).to.have.been.called
-
-
- it 'should append "context" to event arguments', ->
- object = sinon.stub onFoo: ->
-
- e.bindAll object, emitter
- emitter.emit 'foo', 'event-argument'
-
- expect(object.onFoo).to.have.been.calledWith 'event-argument', emitter
-
-
- #============================================================================
- # events.bufferEvents
- #============================================================================
- describe 'bufferEvents', ->
-
- it 'should reply all events', ->
- spy = sinon.spy()
- replyEvents = e.bufferEvents emitter, ['foo', 'bar']
-
- emitter.emit 'foo', 'foo-1'
- emitter.emit 'bar', 'bar-2'
- emitter.emit 'foo', 'foo-3'
-
- emitter.on 'foo', spy
- emitter.on 'bar', spy
-
- replyEvents()
- expect(spy).to.have.been.calledThrice
- expect(spy.firstCall).to.have.been.calledWith 'foo-1'
- expect(spy.secondCall).to.have.been.calledWith 'bar-2'
- expect(spy.thirdCall).to.have.been.calledWith 'foo-3'
-
-
- it 'should not buffer after reply()', ->
- spy = sinon.spy()
- replyEvents = e.bufferEvents emitter, ['foo', 'bar']
- replyEvents()
-
- emitter.emit 'foo', 'foo-1'
- emitter.emit 'bar', 'bar-2'
- emitter.emit 'foo', 'foo-3'
-
- emitter.on 'foo', spy
- emitter.on 'bar', spy
-
- replyEvents()
- expect(spy).to.not.have.been.caleed
-
-
- it 'should work with overriden "emit" method', ->
- # This is to make sure it works with socket.io sockets,
- # which overrides the emit() method to send the event through the wire,
- # instead of local emit.
- originalEmit = emitter.emit
- emitter.emit = -> null
-
- spy = sinon.spy()
- replyEvents = e.bufferEvents emitter, ['foo']
-
- originalEmit.apply emitter, ['foo', 'whatever']
-
- emitter.on 'foo', spy
-
- replyEvents()
- expect(spy).to.have.been.calledWith 'whatever'
diff --git a/test/unit/events.spec.js b/test/unit/events.spec.js
new file mode 100644
index 000000000..6c254bdd0
--- /dev/null
+++ b/test/unit/events.spec.js
@@ -0,0 +1,171 @@
+var e = require('../../lib/events')
+
+describe('events', () => {
+ var emitter
+
+ beforeEach(() => {
+ emitter = new e.EventEmitter()
+ })
+
+ describe('EventEmitter', () => {
+ it('should emit events', () => {
+ var spy = sinon.spy()
+
+ emitter.on('abc', spy)
+ emitter.emit('abc')
+ expect(spy).to.have.been.called
+ })
+
+ describe('bind', () => {
+ var object = null
+
+ beforeEach(() => {
+ object = sinon.stub({
+ onFoo: () => {},
+ onFooBar: () => {},
+ foo: () => {},
+ bar: () => {}
+ })
+ emitter.bind(object)
+ })
+
+ it('should register all "on" methods to events', () => {
+ emitter.emit('foo')
+ expect(object.onFoo).to.have.been.called
+
+ emitter.emit('foo_bar')
+ expect(object.onFooBar).to.have.been.called
+
+ expect(object.foo).not.to.have.been.called
+ expect(object.bar).not.to.have.been.called
+ })
+
+ it('should bind methods to the owner object', () => {
+ emitter.emit('foo')
+ emitter.emit('foo_bar')
+
+ expect(object.onFoo).to.have.always.been.calledOn(object)
+ expect(object.onFooBar).to.have.always.been.calledOn(object)
+ expect(object.foo).not.to.have.been.called
+ expect(object.bar).not.to.have.been.called
+ })
+ })
+
+ describe('emitAsync', () => {
+ var object = null
+
+ beforeEach(() => {
+ object = sinon.stub({
+ onFoo: () => {},
+ onFooBar: () => {},
+ foo: () => {},
+ bar: () => {}
+ })
+ emitter.bind(object)
+ })
+
+ it('should resolve the promise once all listeners are done', done => {
+ var callbacks = []
+ var eventDone = sinon.spy()
+
+ emitter.on('a', d => d())
+ emitter.on('a', d => callbacks.push(d))
+ emitter.on('a', d => callbacks.push(d))
+
+ var promise = emitter.emitAsync('a')
+
+ expect(eventDone).not.to.have.been.called
+ callbacks.pop()()
+ expect(eventDone).not.to.have.been.called
+ callbacks.pop()()
+
+ promise.then(() => {
+ eventDone()
+ expect(eventDone).to.have.been.called
+ done()
+ })
+ })
+
+ it('should resolve asynchronously when no listener', done => {
+ var spyDone = sinon.spy(done)
+ emitter.emitAsync('whatever').then(spyDone)
+ expect(spyDone).to.not.have.been.called
+ })
+ })
+ })
+
+ describe('bindAll', () => {
+ it('should take emitter as second argument', () => {
+ var object = sinon.stub({onFoo: () => {}})
+
+ e.bindAll(object, emitter)
+ emitter.emit('foo')
+ emitter.emit('bar')
+
+ expect(object.onFoo).to.have.been.called
+ })
+
+ it('should append "context" to event arguments', () => {
+ var object = sinon.stub({onFoo: () => {}})
+
+ e.bindAll(object, emitter)
+ emitter.emit('foo', 'event-argument')
+
+ expect(object.onFoo).to.have.been.calledWith('event-argument', emitter)
+ })
+ })
+
+ describe('bufferEvents', () => {
+ it('should reply all events', () => {
+ var spy = sinon.spy()
+ var replyEvents = e.bufferEvents(emitter, ['foo', 'bar'])
+
+ emitter.emit('foo', 'foo-1')
+ emitter.emit('bar', 'bar-2')
+ emitter.emit('foo', 'foo-3')
+
+ emitter.on('foo', spy)
+ emitter.on('bar', spy)
+
+ replyEvents()
+ expect(spy).to.have.been.calledThrice
+ expect(spy.firstCall).to.have.been.calledWith('foo-1')
+ expect(spy.secondCall).to.have.been.calledWith('bar-2')
+ expect(spy.thirdCall).to.have.been.calledWith('foo-3')
+ })
+
+ it('should not buffer after reply()', () => {
+ var spy = sinon.spy()
+ var replyEvents = e.bufferEvents(emitter, ['foo', 'bar'])
+ replyEvents()
+
+ emitter.emit('foo', 'foo-1')
+ emitter.emit('bar', 'bar-2')
+ emitter.emit('foo', 'foo-3')
+
+ emitter.on('foo', spy)
+ emitter.on('bar', spy)
+
+ replyEvents()
+ expect(spy).to.not.have.been.caleed
+ })
+
+ it('should work with overriden "emit" method', () => {
+ // This is to make sure it works with socket.io sockets,
+ // which overrides the emit() method to send the event through the wire,
+ // instead of local emit.
+ var originalEmit = emitter.emit
+ emitter.emit = () => null
+
+ var spy = sinon.spy()
+ var replyEvents = e.bufferEvents(emitter, ['foo'])
+
+ originalEmit.apply(emitter, ['foo', 'whatever'])
+
+ emitter.on('foo', spy)
+
+ replyEvents()
+ expect(spy).to.have.been.calledWith('whatever')
+ })
+ })
+})
diff --git a/test/unit/executor.spec.coffee b/test/unit/executor.spec.coffee
deleted file mode 100644
index 564d244ad..000000000
--- a/test/unit/executor.spec.coffee
+++ /dev/null
@@ -1,47 +0,0 @@
-describe 'executor', ->
- Browser = require '../../lib/browser'
- BrowserCollection = require '../../lib/browser_collection'
- EventEmitter = require('../../lib/events').EventEmitter
- Executor = require '../../lib/executor'
-
- executor = emitter = capturedBrowsers = config = spy = null
-
- beforeEach ->
- config = {client: {}}
- emitter = new EventEmitter
- capturedBrowsers = new BrowserCollection emitter
- capturedBrowsers.add new Browser
- executor = new Executor capturedBrowsers, config, emitter
- executor.socketIoSockets = new EventEmitter
-
- spy =
- onRunStart: -> null
- onSocketsExecute: -> null
-
- sinon.spy spy, 'onRunStart'
- sinon.spy spy, 'onSocketsExecute'
-
- emitter.on 'run_start', spy.onRunStart
- executor.socketIoSockets.on 'execute', spy.onSocketsExecute
-
-
- it 'should start the run and pass client config', ->
- capturedBrowsers.areAllReady = -> true
-
- executor.schedule()
- expect(spy.onRunStart).to.have.been.called
- expect(spy.onSocketsExecute).to.have.been.calledWith config.client
-
-
- it 'should wait for all browsers to finish', ->
- capturedBrowsers.areAllReady = -> false
-
- # they are not ready yet
- executor.schedule()
- expect(spy.onRunStart).not.to.have.been.called
- expect(spy.onSocketsExecute).not.to.have.been.called
-
- capturedBrowsers.areAllReady = -> true
- emitter.emit 'run_complete'
- expect(spy.onRunStart).to.have.been.called
- expect(spy.onSocketsExecute).to.have.been.called
diff --git a/test/unit/executor.spec.js b/test/unit/executor.spec.js
new file mode 100644
index 000000000..21279aa18
--- /dev/null
+++ b/test/unit/executor.spec.js
@@ -0,0 +1,54 @@
+var Browser = require('../../lib/browser')
+var BrowserCollection = require('../../lib/browser_collection')
+var EventEmitter = require('../../lib/events').EventEmitter
+var Executor = require('../../lib/executor')
+
+describe('executor', () => {
+ var emitter
+ var capturedBrowsers
+ var config
+ var spy
+ var executor
+
+ beforeEach(() => {
+ config = {client: {}}
+ emitter = new EventEmitter()
+ capturedBrowsers = new BrowserCollection(emitter)
+ capturedBrowsers.add(new Browser())
+ executor = new Executor(capturedBrowsers, config, emitter)
+ executor.socketIoSockets = new EventEmitter()
+
+ spy = {
+ onRunStart: () => null,
+ onSocketsExecute: () => null
+ }
+
+ sinon.spy(spy, 'onRunStart')
+ sinon.spy(spy, 'onSocketsExecute')
+
+ emitter.on('run_start', spy.onRunStart)
+ executor.socketIoSockets.on('execute', spy.onSocketsExecute)
+ })
+
+ it('should start the run and pass client config', () => {
+ capturedBrowsers.areAllReady = () => true
+
+ executor.schedule()
+ expect(spy.onRunStart).to.have.been.called
+ expect(spy.onSocketsExecute).to.have.been.calledWith(config.client)
+ })
+
+ it('should wait for all browsers to finish', () => {
+ capturedBrowsers.areAllReady = () => false
+
+ // they are not ready yet
+ executor.schedule()
+ expect(spy.onRunStart).not.to.have.been.called
+ expect(spy.onSocketsExecute).not.to.have.been.called
+
+ capturedBrowsers.areAllReady = () => true
+ emitter.emit('run_complete')
+ expect(spy.onRunStart).to.have.been.called
+ expect(spy.onSocketsExecute).to.have.been.called
+ })
+})
diff --git a/test/unit/file-list.spec.coffee b/test/unit/file-list.spec.coffee
deleted file mode 100644
index 24322cf12..000000000
--- a/test/unit/file-list.spec.coffee
+++ /dev/null
@@ -1,639 +0,0 @@
-Promise = require 'bluebird'
-EventEmitter = require('events').EventEmitter
-mocks = require 'mocks'
-proxyquire = require 'proxyquire'
-helper = require '../../lib/helper'
-_ = helper._
-
-from = require 'core-js/library/fn/array/from'
-config = require '../../lib/config'
-
-# create an array of pattern objects from given strings
-patterns = (strings...) ->
- new config.Pattern(str) for str in strings
-
-pathsFrom = (files) ->
- _.pluck(from(files), 'path')
-
-findFile = (path, files) ->
- from(files).find (file) -> file.path is path
-
-PATTERN_LIST =
- '/some/*.js': ['/some/a.js', '/some/b.js']
- '*.txt': ['/c.txt', '/a.txt', '/b.txt']
- '/a.*': ['/a.txt']
-
-MG =
- statCache:
- '/some/a.js': {mtime: new Date()}
- '/some/b.js': {mtime: new Date()}
- '/a.txt': {mtime: new Date()}
- '/b.txt': {mtime: new Date()}
- '/c.txt': {mtime: new Date()}
-
-mockFs = mocks.fs.create
- some:
- '0.js': mocks.fs.file '2012-04-04'
- 'a.js': mocks.fs.file '2012-04-04'
- 'b.js': mocks.fs.file '2012-05-05'
- 'd.js': mocks.fs.file '2012-05-05'
- folder:
- 'x.js': mocks.fs.file 0
- 'a.txt': mocks.fs.file 0
- 'b.txt': mocks.fs.file 0
- 'c.txt': mocks.fs.file 0
- 'a.js': mocks.fs.file '2012-01-01'
-
-describe 'FileList', ->
- List = list = emitter = preprocess = patternList = mg = modified = glob = null
-
- beforeEach ->
-
- describe 'files', ->
- beforeEach ->
- patternList = PATTERN_LIST
- mg = MG
- preprocess = sinon.spy((file, done) -> process.nextTick done)
- emitter = new EventEmitter()
-
- glob = Glob: (pattern, opts) ->
- {found: patternList[pattern], statCache: mg.statCache}
-
- List = proxyquire('../../lib/file-list', {
- helper: helper
- glob: glob
- fs: mockFs
- })
-
- it 'returns a flat array of served files', ->
- list = new List(
- patterns('/some/*.js'),
- [],
- emitter,
- preprocess
- )
-
- list.refresh().then ->
- expect(list.files.served).to.have.length 2
-
- it 'returns a unique set', ->
- list = new List(
- patterns('/a.*', '*.txt'),
- [],
- emitter,
- preprocess
- )
-
- list.refresh().then ->
- expect(list.files.served).to.have.length 3
- expect(pathsFrom list.files.served).to.contain '/a.txt', '/b.txt', '/c.txt'
-
- it 'returns only served files', ->
- files = [
- new config.Pattern('/a.*', true) # served: true
- new config.Pattern('/some/*.js', false) # served: false
- ]
-
- list = new List(files, [], emitter, preprocess)
-
- list.refresh().then ->
- expect(pathsFrom list.files.served).to.eql ['/a.txt']
-
- it 'marks no cache files', ->
- files = [
- new config.Pattern('/a.*') # nocach: false
- new config.Pattern('/some/*.js', true, true, true, true) # nocache: true
- ]
-
- list = new List(files, [], emitter, preprocess)
-
- list.refresh().then ->
- expect(pathsFrom list.files.served).to.deep.equal [
- '/a.txt',
- '/some/a.js',
- '/some/b.js'
- ]
- expect(preprocess).to.have.been.calledOnce
- expect(list.files.served[0].doNotCache).to.be.false
- expect(list.files.served[1].doNotCache).to.be.true
- expect(list.files.served[2].doNotCache).to.be.true
-
- it 'returns a flat array of included files', ->
- files = [
- new config.Pattern('/a.*', true, false) # included: false
- new config.Pattern('/some/*.js') # included: true
- ]
-
- list = new List(files, [], emitter, preprocess)
-
- list.refresh().then ->
- expect(pathsFrom list.files.included).not.to.contain '/a.txt'
- expect(pathsFrom list.files.included).to.deep.equal [
- '/some/a.js'
- '/some/b.js'
- ]
-
-
-
- describe '_isExcluded', ->
- beforeEach ->
- preprocess = sinon.spy((file, done) -> process.nextTick done)
- emitter = new EventEmitter()
-
- it 'returns undefined when no match is found', ->
- list = new List([], ['hello.js', 'world.js'], emitter, preprocess)
- expect(list._isExcluded('hello.txt')).to.be.undefined
- expect(list._isExcluded('/hello/world/i.js')).to.be.undefined
-
- it 'returns the first match if it finds one', ->
- list = new List([], ['*.js', '**/*.js'], emitter, preprocess)
- expect(list._isExcluded('world.js')).to.be.eql '*.js'
- expect(list._isExcluded('/hello/world/i.js')).to.be.eql '**/*.js'
-
-
- describe '_isIncluded', ->
- beforeEach ->
- preprocess = sinon.spy((file, done) -> process.nextTick done)
- emitter = new EventEmitter()
-
- it 'returns undefined when no match is found', ->
- list = new List(patterns('*.js'), [], emitter, preprocess)
- expect(list._isIncluded('hello.txt')).to.be.undefined
- expect(list._isIncluded('/hello/world/i.js')).to.be.undefined
-
- it 'returns the first match if it finds one', ->
- list = new List(patterns('*.js', '**/*.js'), [], emitter, preprocess)
- expect(list._isIncluded('world.js').pattern).to.be.eql '*.js'
- expect(list._isIncluded('/hello/world/i.js').pattern).to.be.eql '**/*.js'
-
- describe '_exists', ->
- beforeEach ->
- preprocess = sinon.spy((file, done) -> process.nextTick done)
- emitter = new EventEmitter()
-
- glob = Glob: (pattern, opts) ->
- {found: patternList[pattern], statCache: mg.statCache}
-
- List = proxyquire('../../lib/file-list', {
- helper: helper
- glob: glob
- fs: mockFs
- })
-
- list = new List(
- patterns('/some/*.js', '*.txt'),
- [],
- emitter,
- preprocess
- )
-
- list.refresh()
-
- it 'returns false when no match is found', ->
- expect(list._exists('/some/s.js')).to.be.false
- expect(list._exists('/hello/world.ex')).to.be.false
-
- it 'returns true when a match is found', ->
- expect(list._exists('/some/a.js')).to.be.true
- expect(list._exists('/some/b.js')).to.be.true
-
- describe 'refresh', ->
- beforeEach ->
- patternList = _.cloneDeep(PATTERN_LIST)
- mg = _.cloneDeep(MG)
- preprocess = sinon.spy((file, done) -> process.nextTick done)
- emitter = new EventEmitter()
-
- glob = Glob: (pattern, opts) ->
- {found: patternList[pattern], statCache: mg.statCache}
-
- List = proxyquire('../../lib/file-list', {
- helper: helper
- glob: glob
- fs: mockFs
- })
-
- list = new List(
- patterns('/some/*.js', '*.txt'),
- [],
- emitter,
- preprocess
- )
-
- it 'resolves patterns', ->
- list.refresh().then (files) ->
- expect(list.buckets.size).to.equal 2
-
- first = pathsFrom list.buckets.get('/some/*.js')
- second = pathsFrom list.buckets.get('*.txt')
-
- expect(first).to.contain '/some/a.js', '/some/b.js'
- expect(second).to.contain '/a.txt', '/b.txt', '/c.txt'
-
- it 'cancels refreshs', ->
- checkResult = (files) ->
- expect(_.pluck(files.served, 'path')).to.contain '/some/a.js', '/some/b.js', '/some/c.js'
-
- p1 = list.refresh().then checkResult
- patternList['/some/*.js'].push '/some/c.js'
- mg.statCache['/some/c.js'] = {mtime: new Date()}
- p2 = list.refresh().then checkResult
-
- Promise.all([p1, p2])
-
- it 'sets the mtime for all files', ->
- list.refresh().then (files) ->
- bucket = list.buckets.get('/some/*.js')
-
- file1 = findFile '/some/a.js', bucket
- file2 = findFile '/some/b.js', bucket
-
- expect(file1.mtime).to.be.eql mg.statCache['/some/a.js'].mtime
- expect(file2.mtime).to.be.eql mg.statCache['/some/b.js'].mtime
-
- it 'sets the mtime for relative patterns', ->
- list = new List(
- patterns('/some/world/../*.js', '*.txt'),
- [],
- emitter,
- preprocess
- )
-
- list.refresh().then (files) ->
- bucket = list.buckets.get('/some/world/../*.js')
-
- file1 = findFile '/some/a.js', bucket
- file2 = findFile '/some/b.js', bucket
-
- expect(file1.mtime).to.be.eql mg.statCache['/some/a.js'].mtime
- expect(file2.mtime).to.be.eql mg.statCache['/some/b.js'].mtime
-
- it 'should sort files within buckets and keep order of patterns (buckets)', ->
- # /a.* => /a.txt [MATCH in *.txt as well]
- # /some/*.js => /some/a.js, /some/b.js [/some/b.js EXCLUDED]
- # *.txt => /c.txt, a.txt, b.txt [UNSORTED]
- list = new List(
- patterns('/a.*', '/some/*.js', '*.txt'),
- ['**/b.js'],
- emitter,
- preprocess
- )
-
- list.refresh().then (files) ->
- expect(pathsFrom files.served).to.deep.equal [
- '/a.txt',
- '/some/a.js',
- '/b.txt',
- '/c.txt'
- ]
-
- it 'ingores excluded files', ->
- list = new List(
- patterns('*.txt'),
- ['/a.*', '**/b.txt'],
- emitter,
- preprocess
- )
-
- list.refresh().then (files) ->
- bucket = pathsFrom list.buckets.get('*.txt')
-
- expect(bucket).to.contain '/c.txt'
- expect(bucket).not.to.contain '/a.txt'
- expect(bucket).not.to.contain '/b.txt'
-
- it 'does not glob urls and sets the isUrl flag', ->
- list = new List(
- patterns('http://some.com'),
- [],
- emitter,
- preprocess
- )
-
- list.refresh()
- .then (files) ->
- bucket = list.buckets.get('http://some.com')
- file = findFile('http://some.com', bucket)
-
- expect(file).to.have.property 'isUrl', true
-
- it 'preprocesses all files', ->
- list.refresh().then (files) ->
- expect(preprocess.callCount).to.be.eql 5
-
- it 'fails when a preprocessor fails', ->
- preprocess = sinon.spy (file, next) ->
- next new Error('failing'), null
-
- list = new List(
- patterns('/some/*.js'),
- [],
- emitter,
- preprocess
- )
-
- list.refresh().catch (err) ->
- expect(err.message).to.be.eql 'failing'
-
-
- describe 'reload', ->
- beforeEach ->
- preprocess = sinon.spy((file, done) -> process.nextTick done)
- emitter = new EventEmitter()
- list = new List(
- patterns('/some/*.js', '*.txt'),
- [],
- emitter,
- preprocess
- )
-
- it 'refreshes, even when a refresh is already happening', ->
- sinon.spy(list, '_refresh')
-
- Promise.all([
- list.refresh()
- list.reload(patterns('*.txt'), [])
- ])
- .then ->
- expect(list._refresh).to.have.been.calledTwice
-
-
- describe 'addFile', ->
- beforeEach ->
- patternList = PATTERN_LIST
- mg = MG
-
- preprocess = sinon.spy((file, done) -> process.nextTick done)
- emitter = new EventEmitter()
-
- glob = Glob: (pattern, opts) ->
- {found: patternList[pattern], statCache: mg.statCache}
-
- List = proxyquire('../../lib/file-list', {
- helper: helper
- glob: glob
- fs: mockFs
- })
-
- list = new List(
- patterns('/some/*.js', '*.txt'),
- ['/secret/*.txt'],
- emitter,
- preprocess
- )
-
- it 'does not add excluded files', ->
- list.refresh().then (before) ->
- list.addFile('/secret/hello.txt').then (files) ->
- expect(files.served).to.be.eql before.served
-
- it 'does not add already existing files', ->
- list.refresh().then (before) ->
- list.addFile('/some/a.js').then (files) ->
- expect(files.served).to.be.eql before.served
-
- it 'does not add unmatching files', ->
- list.refresh().then (before) ->
- list.addFile('/some/a.ex').then (files) ->
- expect(files.served).to.be.eql before.served
-
- it 'adds the file to the correct bucket', ->
- list.refresh().then (before) ->
- list.addFile('/some/d.js').then (files) ->
- expect(pathsFrom files.served).to.contain '/some/d.js'
- bucket = list.buckets.get('/some/*.js')
- expect(pathsFrom bucket).to.contain '/some/d.js'
-
- it 'fires "file_list_modified"', ->
- modified = sinon.stub()
- emitter.on 'file_list_modified', modified
-
- list.refresh().then ->
- expect(modified).to.have.been.calledOnce
- modified.reset()
-
- list.addFile('/some/d.js').then ->
- expect(modified).to.have.been.calledOnce
-
-
- it 'ignores quick double "add"', ->
- # On linux fs.watch (chokidar with usePolling: false) fires "add" event twice.
- # This checks that we only stat and preprocess the file once.
-
- modified = sinon.stub()
- emitter.on 'file_list_modified', modified
-
- list.refresh().then ->
- expect(modified).to.have.been.calledOnce
- modified.reset()
- preprocess.reset()
- sinon.spy mockFs, 'stat'
-
- Promise.all([
- list.addFile('/some/d.js')
- list.addFile('/some/d.js')
- ]).then ->
- expect(modified).to.have.been.calledOnce
- expect(preprocess).to.have.been.calledOnce
- expect(mockFs.stat).to.have.been.calledOnce
-
- it 'sets the proper mtime of the new file', ->
- list = new List(patterns('/a.*'), [], emitter, preprocess)
-
- list.refresh().then ->
- list.addFile('/a.js').then (files) ->
- expect(findFile('/a.js', files.served).mtime).to.eql new Date '2012-01-01'
-
- it 'preprocesses the added file', ->
- # MATCH: /a.txt
- list = new List(patterns('/a.*'), [], emitter, preprocess)
- list.refresh().then (files) ->
- preprocess.reset()
- list.addFile('/a.js').then ->
- expect(preprocess).to.have.been.calledOnce
- expect(preprocess.args[0][0].originalPath).to.eql '/a.js'
-
-
- describe 'changeFile', ->
- beforeEach ->
- patternList = PATTERN_LIST
- mg = MG
-
- preprocess = sinon.spy((file, done) -> process.nextTick done)
- emitter = new EventEmitter()
-
-
- glob = Glob: (pattern, opts) ->
- {found: patternList[pattern], statCache: mg.statCache}
-
- List = proxyquire('../../lib/file-list', {
- helper: helper
- glob: glob
- fs: mockFs
- })
-
- mockFs._touchFile '/some/a.js', '2012-04-04'
- mockFs._touchFile '/some/b.js', '2012-05-05'
-
- modified = sinon.stub()
- emitter.on 'file_list_modified', modified
-
- it 'updates mtime and fires "file_list_modified"', ->
- # MATCH: /some/a.js, /some/b.js
- list = new List(patterns('/some/*.js', '/a.*'), [], emitter, preprocess)
- list.refresh().then (files) ->
- mockFs._touchFile '/some/b.js', '2020-01-01'
- modified.reset()
-
- list.changeFile('/some/b.js').then (files) ->
- expect(modified).to.have.been.called
- expect(findFile('/some/b.js', files.served).mtime).to.be.eql new Date '2020-01-01'
-
- it 'does not fire "file_list_modified" if no matching file is found', ->
- # MATCH: /some/a.js
- list = new List(patterns('/some/*.js', '/a.*'), ['/some/b.js'], emitter, preprocess)
-
- list.refresh().then (files) ->
- mockFs._touchFile '/some/b.js', '2020-01-01'
- modified.reset()
-
- list.changeFile('/some/b.js').then ->
- expect(modified).to.not.have.been.called
-
- it 'does not fire "file_list_modified" if mtime has not changed', ->
- # chokidar on fucking windows sometimes fires event multiple times
- # MATCH: /some/a.js, /some/b.js, /a.txt
- list = new List(patterns('/some/*.js', '/a.*'), [], emitter, preprocess)
-
- list.refresh().then (files) ->
- # not touching the file, stat will return still the same
- modified.reset()
- list.changeFile('/some/b.js').then ->
- expect(modified).not.to.have.been.called
-
- it 'preprocesses the changed file', ->
- # MATCH: /some/a.js, /some/b.js
- list = new List(patterns('/some/*.js', '/a.*'), [], emitter, preprocess)
-
- list.refresh().then (files) ->
- preprocess.reset()
- mockFs._touchFile '/some/a.js', '2020-01-01'
- list.changeFile('/some/a.js').then ->
- expect(preprocess).to.have.been.called
- expect(preprocess.lastCall.args[0]).to.have.property 'path', '/some/a.js'
-
-
- describe 'removeFile', ->
- beforeEach ->
- patternList = PATTERN_LIST
- mg = MG
-
- preprocess = sinon.spy((file, done) -> process.nextTick done)
- emitter = new EventEmitter()
-
- glob = Glob: (pattern, opts) ->
- {found: patternList[pattern], statCache: mg.statCache}
-
- List = proxyquire('../../lib/file-list', {
- helper: helper
- glob: glob
- fs: mockFs
- })
-
- modified = sinon.stub()
- emitter.on 'file_list_modified', modified
-
- it 'removes the file from the list and fires "file_list_modified"', ->
- # MATCH: /some/a.js, /some/b.js, /a.txt
- list = new List(patterns('/some/*.js', '/a.*'), [], emitter, preprocess)
-
- list.refresh().then (files) ->
- modified.reset()
- list.removeFile('/some/a.js').then (files) ->
- expect(pathsFrom files.served).to.be.eql [
- '/some/b.js',
- '/a.txt'
- ]
- expect(modified).to.have.been.calledOnce
-
- it 'does not fire "file_list_modified" if the file is not in the list', ->
- # MATCH: /some/a.js, /some/b.js, /a.txt
- list = new List(patterns('/some/*.js', '/a.*'), [], emitter, preprocess)
-
- list.refresh().then (files) ->
- modified.reset()
- list.removeFile('/a.js').then ->
- expect(modified).to.not.have.been.called
-
- describe 'batch interval', ->
- clock = null
-
- beforeEach ->
- patternList = PATTERN_LIST
- mg = MG
-
- preprocess = sinon.spy((file, done) -> process.nextTick done)
- emitter = new EventEmitter()
-
- glob = Glob: (pattern, opts) ->
- {found: patternList[pattern], statCache: mg.statCache}
-
- modified = sinon.stub()
- emitter.on 'file_list_modified', modified
-
- clock = sinon.useFakeTimers()
- # This hack is needed to ensure lodash is using the fake timers
- # from sinon
- helper._ = _.runInContext()
- List = proxyquire('../../lib/file-list', {
- helper: helper
- glob: glob
- fs: mockFs
- })
-
- afterEach ->
- clock.restore()
-
- it 'batches multiple changes within an interval', (done) ->
-
- # MATCH: /some/a.js, /some/b.js, /a.txt
- list = new List(patterns('/some/*.js', '/a.*'), [], emitter, preprocess, 1000)
-
- list.refresh().then (files) ->
- modified.reset()
- mockFs._touchFile '/some/b.js', '2020-01-01'
- list.changeFile '/some/b.js'
- list.removeFile '/some/a.js' # /some/b.js, /a.txt
- list.removeFile '/a.txt' # /some/b.js
- list.addFile '/a.txt' # /some/b.js, /a.txt
- list.addFile '/some/0.js' # /some/0.js, /some/b.js, /a.txt
-
- clock.tick(999)
- expect(modified).to.not.have.been.called
- emitter.once 'file_list_modified', (files) ->
- expect(pathsFrom files.served).to.be.eql [
- '/some/0.js',
- '/some/b.js',
- '/a.txt'
- ]
- done()
-
- clock.tick(1001)
-
- it 'waits while file preprocessing, if the file was deleted and immediately added', (done) ->
- list = new List(patterns('/a.*'), [], emitter, preprocess, 1000)
-
- list.refresh().then (files) ->
- preprocess.reset()
-
- # Remove and then immediately add file to the bucket
- list.removeFile '/a.txt'
- list.addFile '/a.txt'
-
- clock.tick(1000)
-
- emitter.once 'file_list_modified', (files) ->
- expect(preprocess).to.have.been.calledOnce
- done()
-
- clock.tick(1001)
diff --git a/test/unit/file-list.spec.js b/test/unit/file-list.spec.js
new file mode 100644
index 000000000..172d744c2
--- /dev/null
+++ b/test/unit/file-list.spec.js
@@ -0,0 +1,723 @@
+import Promise from 'bluebird'
+import {EventEmitter} from 'events'
+import mocks from 'mocks'
+import proxyquire from 'proxyquire'
+var helper = require('../../lib/helper')
+var _ = helper._
+
+var from = require('core-js/library/fn/array/from')
+var config = require('../../lib/config')
+
+// create an array of pattern objects from given strings
+var patterns = (...strings) => strings.map(str => new config.Pattern(str))
+
+function pathsFrom (files) {
+ return _.pluck(from(files), 'path')
+}
+
+function findFile (path, files) {
+ return from(files).find(file => file.path === path)
+}
+
+var PATTERN_LIST = {
+ '/some/*.js': ['/some/a.js', '/some/b.js'],
+ '*.txt': ['/c.txt', '/a.txt', '/b.txt'],
+ '/a.*': ['/a.txt']
+}
+
+var MG = {
+ statCache: {
+ '/some/a.js': {mtime: new Date()},
+ '/some/b.js': {mtime: new Date()},
+ '/a.txt': {mtime: new Date()},
+ '/b.txt': {mtime: new Date()},
+ '/c.txt': {mtime: new Date()}
+ }
+}
+var mockFs = mocks.fs.create({
+ some: {'0.js': mocks.fs.file('2012-04-04'),
+ 'a.js': mocks.fs.file('2012-04-04'),
+ 'b.js': mocks.fs.file('2012-05-05'),
+ 'd.js': mocks.fs.file('2012-05-05')},
+ folder: {'x.js': mocks.fs.file(0)},
+ 'a.txt': mocks.fs.file(0),
+ 'b.txt': mocks.fs.file(0),
+ 'c.txt': mocks.fs.file(0),
+ 'a.js': mocks.fs.file('2012-01-01')
+})
+
+describe('FileList', () => {
+ var list
+ var emitter
+ var preprocess
+ var patternList
+ var mg
+ var modified
+ var glob
+ var List = list = emitter = preprocess = patternList = mg = modified = glob = null
+
+ beforeEach(() => {})
+
+ describe('files', () => {
+ beforeEach(() => {
+ patternList = PATTERN_LIST
+ mg = MG
+ preprocess = sinon.spy((file, done) => process.nextTick(done))
+ emitter = new EventEmitter()
+
+ glob = {
+ Glob: (pattern, opts) => ({
+ found: patternList[pattern],
+ statCache: mg.statCache
+ })
+ }
+
+ List = proxyquire('../../lib/file-list', {
+ helper: helper,
+ glob: glob,
+ fs: mockFs
+ })
+ })
+
+ it('returns a flat array of served files', () => {
+ list = new List(patterns('/some/*.js'), [], emitter, preprocess)
+
+ return list.refresh().then(() => {
+ expect(list.files.served).to.have.length(2)
+ })
+ })
+
+ it('returns a unique set', () => {
+ list = new List(patterns('/a.*', '*.txt'), [], emitter, preprocess)
+
+ return list.refresh().then(() => {
+ expect(list.files.served).to.have.length(3)
+ expect(pathsFrom(list.files.served)).to.contain('/a.txt', '/b.txt', '/c.txt')
+ })
+ })
+
+ it('returns only served files', () => {
+ var files = [
+ new config.Pattern('/a.*', true), // served: true
+ new config.Pattern('/some/*.js', false) // served: false
+ ]
+
+ list = new List(files, [], emitter, preprocess)
+
+ return list.refresh().then(() => {
+ expect(pathsFrom(list.files.served)).to.eql(['/a.txt'])
+ })
+ })
+
+ it('marks no cache files', () => {
+ var files = [
+ new config.Pattern('/a.*'), // nocach: false
+ new config.Pattern('/some/*.js', true, true, true, true) // nocache: true
+ ]
+
+ list = new List(files, [], emitter, preprocess)
+
+ return list.refresh().then(() => {
+ expect(pathsFrom(list.files.served)).to.deep.equal([
+ '/a.txt',
+ '/some/a.js',
+ '/some/b.js'
+ ])
+ expect(preprocess).to.have.been.calledOnce
+ expect(list.files.served[0].doNotCache).to.be.false
+ expect(list.files.served[1].doNotCache).to.be.true
+ expect(list.files.served[2].doNotCache).to.be.true
+ })
+ })
+
+ it('returns a flat array of included files', () => {
+ var files = [
+ new config.Pattern('/a.*', true, false), // included: false
+ new config.Pattern('/some/*.js') // included: true
+ ]
+
+ list = new List(files, [], emitter, preprocess)
+
+ return list.refresh().then(() => {
+ expect(pathsFrom(list.files.included)).not.to.contain('/a.txt')
+ expect(pathsFrom(list.files.included)).to.deep.equal([
+ '/some/a.js',
+ '/some/b.js'
+ ])
+ })
+ })
+ })
+
+ describe('_isExcluded', () => {
+ beforeEach(() => {
+ preprocess = sinon.spy((file, done) => process.nextTick(done))
+ emitter = new EventEmitter()
+ })
+
+ it('returns undefined when no match is found', () => {
+ list = new List([], ['hello.js', 'world.js'], emitter, preprocess)
+ expect(list._isExcluded('hello.txt')).to.be.undefined
+ expect(list._isExcluded('/hello/world/i.js')).to.be.undefined
+ })
+
+ it('returns the first match if it finds one', () => {
+ list = new List([], ['*.js', '**/*.js'], emitter, preprocess)
+ expect(list._isExcluded('world.js')).to.be.eql('*.js')
+ expect(list._isExcluded('/hello/world/i.js')).to.be.eql('**/*.js')
+ })
+ })
+
+ describe('_isIncluded', () => {
+ beforeEach(() => {
+ preprocess = sinon.spy((file, done) => process.nextTick(done))
+ emitter = new EventEmitter()
+ })
+
+ it('returns undefined when no match is found', () => {
+ list = new List(patterns('*.js'), [], emitter, preprocess)
+ expect(list._isIncluded('hello.txt')).to.be.undefined
+ expect(list._isIncluded('/hello/world/i.js')).to.be.undefined
+ })
+
+ it('returns the first match if it finds one', () => {
+ list = new List(patterns('*.js', '**/*.js'), [], emitter, preprocess)
+ expect(list._isIncluded('world.js').pattern).to.be.eql('*.js')
+ expect(list._isIncluded('/hello/world/i.js').pattern).to.be.eql('**/*.js')
+ })
+ })
+
+ describe('_exists', () => {
+ beforeEach(() => {
+ patternList = _.cloneDeep(PATTERN_LIST)
+ mg = _.cloneDeep(MG)
+
+ preprocess = sinon.spy((file, done) => process.nextTick(done))
+ emitter = new EventEmitter()
+
+ glob = {
+ Glob: (pattern, opts) => ({
+ found: patternList[pattern],
+ statCache: mg.statCache
+ })
+ }
+
+ List = proxyquire('../../lib/file-list', {
+ helper: helper,
+ glob: glob,
+ fs: mockFs
+ })
+
+ list = new List(patterns('/some/*.js', '*.txt'), [], emitter, preprocess)
+
+ return list.refresh()
+ })
+
+ it('returns false when no match is found', () => {
+ expect(list._exists('/some/s.js')).to.be.false
+ expect(list._exists('/hello/world.ex')).to.be.false
+ })
+
+ it('returns true when a match is found', () => {
+ expect(list._exists('/some/a.js')).to.be.true
+ expect(list._exists('/some/b.js')).to.be.true
+ })
+ })
+
+ describe('refresh', () => {
+ beforeEach(() => {
+ patternList = _.cloneDeep(PATTERN_LIST)
+ mg = _.cloneDeep(MG)
+ preprocess = sinon.spy((file, done) => process.nextTick(done))
+ emitter = new EventEmitter()
+
+ glob = {
+ Glob: (pattern, opts) => ({
+ found: patternList[pattern],
+ statCache: mg.statCache
+ })
+ }
+
+ List = proxyquire('../../lib/file-list', {
+ helper: helper,
+ glob: glob,
+ fs: mockFs
+ })
+
+ list = new List(patterns('/some/*.js', '*.txt'), [], emitter, preprocess)
+ })
+
+ it('resolves patterns', () => {
+ return list.refresh().then(files => {
+ expect(list.buckets.size).to.equal(2)
+
+ var first = pathsFrom(list.buckets.get('/some/*.js'))
+ var second = pathsFrom(list.buckets.get('*.txt'))
+
+ expect(first).to.contain('/some/a.js', '/some/b.js')
+ expect(second).to.contain('/a.txt', '/b.txt', '/c.txt')
+ })
+ })
+
+ it('cancels refreshs', () => {
+ var checkResult = files => {
+ expect(_.pluck(files.served, 'path')).to.contain('/some/a.js', '/some/b.js', '/some/c.js')
+ }
+
+ var p1 = list.refresh().then(checkResult)
+ patternList['/some/*.js'].push('/some/c.js')
+ mg.statCache['/some/c.js'] = {mtime: new Date()}
+ var p2 = list.refresh().then(checkResult)
+
+ return Promise.all([p1, p2])
+ })
+
+ it('sets the mtime for all files', () => {
+ return list.refresh().then(files => {
+ var bucket = list.buckets.get('/some/*.js')
+
+ var file1 = findFile('/some/a.js', bucket)
+ var file2 = findFile('/some/b.js', bucket)
+
+ expect(file1.mtime).to.be.eql(mg.statCache['/some/a.js'].mtime)
+ expect(file2.mtime).to.be.eql(mg.statCache['/some/b.js'].mtime)
+ })
+ })
+
+ it('sets the mtime for relative patterns', () => {
+ list = new List(patterns('/some/world/../*.js', '*.txt'), [], emitter, preprocess)
+
+ return list.refresh().then(files => {
+ var bucket = list.buckets.get('/some/world/../*.js')
+
+ var file1 = findFile('/some/a.js', bucket)
+ var file2 = findFile('/some/b.js', bucket)
+
+ expect(file1.mtime).to.be.eql(mg.statCache['/some/a.js'].mtime)
+ expect(file2.mtime).to.be.eql(mg.statCache['/some/b.js'].mtime)
+ })
+ })
+
+ it('should sort files within buckets and keep order of patterns (buckets)', () => {
+ // /a.* => /a.txt [MATCH in *.txt as well]
+ // /some/*.js => /some/a.js, /some/b.js [/some/b.js EXCLUDED]
+ // *.txt => /c.txt, a.txt, b.txt [UNSORTED]
+ list = new List(patterns('/a.*', '/some/*.js', '*.txt'), ['**/b.js'], emitter, preprocess)
+
+ return list.refresh().then(files => {
+ expect(pathsFrom(files.served)).to.deep.equal([
+ '/a.txt',
+ '/some/a.js',
+ '/b.txt',
+ '/c.txt'
+ ])
+ })
+ })
+
+ it('ingores excluded files', () => {
+ list = new List(patterns('*.txt'), ['/a.*', '**/b.txt'], emitter, preprocess)
+
+ return list.refresh().then(files => {
+ var bucket = pathsFrom(list.buckets.get('*.txt'))
+
+ expect(bucket).to.contain('/c.txt')
+ expect(bucket).not.to.contain('/a.txt')
+ expect(bucket).not.to.contain('/b.txt')
+ })
+ })
+
+ it('does not glob urls and sets the isUrl flag', () => {
+ list = new List(patterns('http://some.com'), [], emitter, preprocess)
+
+ return list.refresh()
+ .then(files => {
+ var bucket = list.buckets.get('http://some.com')
+ var file = findFile('http://some.com', bucket)
+
+ expect(file).to.have.property('isUrl', true)
+ }
+ )
+ })
+
+ it('preprocesses all files', () => {
+ return list.refresh().then(files => {
+ expect(preprocess.callCount).to.be.eql(5)
+ })
+ })
+
+ it('fails when a preprocessor fails', () => {
+ preprocess = sinon.spy((file, next) => {
+ next(new Error('failing'), null)
+ })
+
+ list = new List(patterns('/some/*.js'), [], emitter, preprocess)
+
+ return list.refresh().catch(err => {
+ expect(err.message).to.be.eql('failing')
+ })
+ })
+ })
+
+ describe('reload', () => {
+ beforeEach(() => {
+ preprocess = sinon.spy((file, done) => process.nextTick(done))
+ emitter = new EventEmitter()
+ list = new List(patterns('/some/*.js', '*.txt'), [], emitter, preprocess)
+ })
+
+ it('refreshes, even when a refresh is already happening', () => {
+ sinon.spy(list, '_refresh')
+
+ return Promise.all([
+ list.refresh(),
+ list.reload(patterns('*.txt'), [])
+ ])
+ .then(() => {
+ expect(list._refresh).to.have.been.calledTwice
+ }
+ )
+ })
+ })
+
+ describe('addFile', () => {
+ beforeEach(() => {
+ patternList = PATTERN_LIST
+ mg = MG
+
+ preprocess = sinon.spy((file, done) => process.nextTick(done))
+ emitter = new EventEmitter()
+
+ glob = {
+ Glob: (pattern, opts) => ({
+ found: patternList[pattern],
+ statCache: mg.statCache
+ })
+ }
+ List = proxyquire('../../lib/file-list', {
+ helper: helper,
+ glob: glob,
+ fs: mockFs
+ })
+
+ list = new List(patterns('/some/*.js', '*.txt'), ['/secret/*.txt'], emitter, preprocess)
+ })
+
+ it('does not add excluded files', () => {
+ return list.refresh().then(before => {
+ return list.addFile('/secret/hello.txt').then(files => {
+ expect(files.served).to.be.eql(before.served)
+ })
+ })
+ })
+
+ it('does not add already existing files', () => {
+ return list.refresh().then(before => {
+ return list.addFile('/some/a.js').then(files => {
+ expect(files.served).to.be.eql(before.served)
+ })
+ })
+ })
+
+ it('does not add unmatching files', () => {
+ return list.refresh().then(before => {
+ return list.addFile('/some/a.ex').then(files => {
+ expect(files.served).to.be.eql(before.served)
+ })
+ })
+ })
+
+ it('adds the file to the correct bucket', () => {
+ return list.refresh().then(before => {
+ return list.addFile('/some/d.js').then(files => {
+ expect(pathsFrom(files.served)).to.contain('/some/d.js')
+ var bucket = list.buckets.get('/some/*.js')
+ expect(pathsFrom(bucket)).to.contain('/some/d.js')
+ })
+ })
+ })
+
+ it('fires "file_list_modified"', () => {
+ modified = sinon.stub()
+ emitter.on('file_list_modified', modified)
+
+ return list.refresh().then(() => {
+ expect(modified).to.have.been.calledOnce
+ modified.reset()
+
+ return list.addFile('/some/d.js').then(() => {
+ expect(modified).to.have.been.calledOnce
+ })
+ })
+ })
+
+ it('ignores quick double "add"', () => {
+ // On linux fs.watch (chokidar with usePolling: false) fires "add" event twice.
+ // This checks that we only stat and preprocess the file once.
+
+ modified = sinon.stub()
+ emitter.on('file_list_modified', modified)
+
+ return list.refresh().then(() => {
+ expect(modified).to.have.been.calledOnce
+ modified.reset()
+ preprocess.reset()
+ sinon.spy(mockFs, 'stat')
+
+ return Promise.all([
+ list.addFile('/some/d.js'),
+ list.addFile('/some/d.js')
+ ]).then(() => {
+ expect(modified).to.have.been.calledOnce
+ expect(preprocess).to.have.been.calledOnce
+ expect(mockFs.stat).to.have.been.calledOnce
+ }
+ )
+ })
+ })
+
+ it('sets the proper mtime of the new file', () => {
+ list = new List(patterns('/a.*'), [], emitter, preprocess)
+
+ return list.refresh().then(() => {
+ return list.addFile('/a.js').then(files => {
+ expect(findFile('/a.js', files.served).mtime).to.eql(new Date('2012-01-01'))
+ })
+ })
+ })
+
+ it('preprocesses the added file', () => {
+ // MATCH: /a.txt
+ list = new List(patterns('/a.*'), [], emitter, preprocess)
+ return list.refresh().then(files => {
+ preprocess.reset()
+ return list.addFile('/a.js').then(() => {
+ expect(preprocess).to.have.been.calledOnce
+ expect(preprocess.args[0][0].originalPath).to.eql('/a.js')
+ })
+ })
+ })
+ })
+
+ describe('changeFile', () => {
+ beforeEach(() => {
+ patternList = PATTERN_LIST
+ mg = MG
+
+ preprocess = sinon.spy((file, done) => process.nextTick(done))
+ emitter = new EventEmitter()
+
+ glob = {
+ Glob: (pattern, opts) => ({
+ found: patternList[pattern],
+ statCache: mg.statCache
+ })
+ }
+
+ List = proxyquire('../../lib/file-list', {
+ helper: helper,
+ glob: glob,
+ fs: mockFs
+ })
+
+ mockFs._touchFile('/some/a.js', '2012-04-04')
+ mockFs._touchFile('/some/b.js', '2012-05-05')
+
+ modified = sinon.stub()
+ emitter.on('file_list_modified', modified)
+ })
+
+ it('updates mtime and fires "file_list_modified"', () => {
+ // MATCH: /some/a.js, /some/b.js
+ list = new List(patterns('/some/*.js', '/a.*'), [], emitter, preprocess)
+ return list.refresh().then(files => {
+ mockFs._touchFile('/some/b.js', '2020-01-01')
+ modified.reset()
+
+ return list.changeFile('/some/b.js').then(files => {
+ expect(modified).to.have.been.called
+ expect(findFile('/some/b.js', files.served).mtime).to.be.eql(new Date('2020-01-01'))
+ })
+ })
+ })
+
+ it('does not fire "file_list_modified" if no matching file is found', () => {
+ // MATCH: /some/a.js
+ list = new List(patterns('/some/*.js', '/a.*'), ['/some/b.js'], emitter, preprocess)
+
+ return list.refresh().then(files => {
+ mockFs._touchFile('/some/b.js', '2020-01-01')
+ modified.reset()
+
+ return list.changeFile('/some/b.js').then(() => {
+ expect(modified).to.not.have.been.called
+ })
+ })
+ })
+
+ it('does not fire "file_list_modified" if mtime has not changed', () => {
+ // chokidar on fucking windows sometimes fires event multiple times
+ // MATCH: /some/a.js, /some/b.js, /a.txt
+ list = new List(patterns('/some/*.js', '/a.*'), [], emitter, preprocess)
+
+ return list.refresh().then(files => {
+ // not touching the file, stat will return still the same
+ modified.reset()
+ return list.changeFile('/some/b.js').then(() => {
+ expect(modified).not.to.have.been.called
+ })
+ })
+ })
+
+ it('preprocesses the changed file', () => {
+ // MATCH: /some/a.js, /some/b.js
+ list = new List(patterns('/some/*.js', '/a.*'), [], emitter, preprocess)
+
+ return list.refresh().then(files => {
+ preprocess.reset()
+ mockFs._touchFile('/some/a.js', '2020-01-01')
+ return list.changeFile('/some/a.js').then(() => {
+ expect(preprocess).to.have.been.called
+ expect(preprocess.lastCall.args[0]).to.have.property('path', '/some/a.js')
+ })
+ })
+ })
+ })
+
+ describe('removeFile', () => {
+ beforeEach(() => {
+ patternList = PATTERN_LIST
+ mg = MG
+
+ preprocess = sinon.spy((file, done) => process.nextTick(done))
+ emitter = new EventEmitter()
+
+ glob = {
+ Glob: (pattern, opts) => ({
+ found: patternList[pattern],
+ statCache: mg.statCache
+ })
+ }
+
+ List = proxyquire('../../lib/file-list', {
+ helper: helper,
+ glob: glob,
+ fs: mockFs
+ })
+
+ modified = sinon.stub()
+ emitter.on('file_list_modified', modified)
+ })
+
+ it('removes the file from the list and fires "file_list_modified"', () => {
+ // MATCH: /some/a.js, /some/b.js, /a.txt
+ list = new List(patterns('/some/*.js', '/a.*'), [], emitter, preprocess)
+
+ return list.refresh().then(files => {
+ modified.reset()
+ return list.removeFile('/some/a.js').then(files => {
+ expect(pathsFrom(files.served)).to.be.eql([
+ '/some/b.js',
+ '/a.txt'
+ ])
+ expect(modified).to.have.been.calledOnce
+ })
+ })
+ })
+
+ it('does not fire "file_list_modified" if the file is not in the list', () => {
+ // MATCH: /some/a.js, /some/b.js, /a.txt
+ list = new List(patterns('/some/*.js', '/a.*'), [], emitter, preprocess)
+
+ return list.refresh().then(files => {
+ modified.reset()
+ return list.removeFile('/a.js').then(() => {
+ expect(modified).to.not.have.been.called
+ })
+ })
+ })
+ })
+
+ describe('batch interval', () => {
+ var clock = null
+
+ beforeEach(() => {
+ patternList = PATTERN_LIST
+ mg = MG
+
+ preprocess = sinon.spy((file, done) => process.nextTick(done))
+ emitter = new EventEmitter()
+
+ glob = {
+ Glob: (pattern, opts) => ({
+ found: patternList[pattern],
+ statCache: mg.statCache
+ })
+ }
+
+ modified = sinon.stub()
+ emitter.on('file_list_modified', modified)
+
+ clock = sinon.useFakeTimers()
+ // This hack is needed to ensure lodash is using the fake timers
+ // from sinon
+ helper._ = _.runInContext()
+ List = proxyquire('../../lib/file-list', {
+ helper: helper,
+ glob: glob,
+ fs: mockFs
+ })
+ })
+
+ afterEach(() => {
+ clock.restore()
+ })
+
+ it('batches multiple changes within an interval', done => {
+ // MATCH: /some/a.js, /some/b.js, /a.txt
+ list = new List(patterns('/some/*.js', '/a.*'), [], emitter, preprocess, 1000)
+
+ return list.refresh().then(files => {
+ modified.reset()
+ mockFs._touchFile('/some/b.js', '2020-01-01')
+ list.changeFile('/some/b.js')
+ list.removeFile('/some/a.js') // /some/b.js, /a.txt
+ list.removeFile('/a.txt') // /some/b.js
+ list.addFile('/a.txt') // /some/b.js, /a.txt
+ list.addFile('/some/0.js') // /some/0.js, /some/b.js, /a.txt
+
+ clock.tick(999)
+ expect(modified).to.not.have.been.called
+ emitter.once('file_list_modified', files => {
+ expect(pathsFrom(files.served)).to.be.eql([
+ '/some/0.js',
+ '/some/b.js',
+ '/a.txt'
+ ])
+ done()
+ })
+
+ clock.tick(1001)
+ })
+ })
+
+ it('waits while file preprocessing, if the file was deleted and immediately added', done => {
+ list = new List(patterns('/a.*'), [], emitter, preprocess, 1000)
+
+ return list.refresh().then(files => {
+ preprocess.reset()
+
+ // Remove and then immediately add file to the bucket
+ list.removeFile('/a.txt')
+ list.addFile('/a.txt')
+
+ clock.tick(1000)
+
+ emitter.once('file_list_modified', files => {
+ expect(preprocess).to.have.been.calledOnce
+ return done()
+ })
+
+ clock.tick(1001)
+ })
+ })
+ })
+})
diff --git a/test/unit/helper.spec.coffee b/test/unit/helper.spec.coffee
deleted file mode 100644
index 1230e021b..000000000
--- a/test/unit/helper.spec.coffee
+++ /dev/null
@@ -1,242 +0,0 @@
-#==============================================================================
-# lib/helper.js module
-#==============================================================================
-describe 'helper', ->
- helper = require '../../lib/helper'
-
- #==============================================================================
- # helper.browserFullNameToShort()
- #==============================================================================
- describe 'browserFullNameToShort', ->
-
- # helper function
- expecting = (name) ->
- expect helper.browserFullNameToShort name
-
- it 'should parse iOS', ->
- expecting('Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 ' +
- '(KHTML, like Gecko) Version/6.0 Mobile/10A403 Safari/8536.25').
- to.be.equal 'Mobile Safari 6.0.0 (iOS 6.0.0)'
-
-
- it 'should parse Linux', ->
- expecting('Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.19) Gecko/20081216 ' +
- 'Ubuntu/8.04 (hardy) Firefox/2.0.0.19').
- to.be.equal 'Firefox 2.0.0 (Ubuntu 8.04.0)'
-
-
- it 'should degrade gracefully when OS not recognized', ->
- expecting('Mozilla/5.0 (X11; U; FreeBSD; i386; en-US; rv:1.7) Gecko/20081216 ' +
- 'Firefox/2.0.0.19').
- to.be.equal 'Firefox 2.0.0 (FreeBSD 0.0.0)'
-
-
- it 'should parse Chrome', ->
- expecting('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.7 ' +
- '(KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7').
- to.be.equal 'Chrome 16.0.912 (Mac OS X 10.6.8)'
-
- expecting('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.15 ' +
- '(KHTML, like Gecko) Chrome/18.0.985.0 Safari/535.15').
- to.be.equal 'Chrome 18.0.985 (Mac OS X 10.6.8)'
-
-
- it 'should parse Firefox', ->
- expecting('Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 ' +
- 'Firefox/7.0.1').
- to.be.equal 'Firefox 7.0.1 (Mac OS X 10.6.0)'
-
-
- it 'should parse Opera', ->
- expecting('Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; en) Presto/2.9.168 ' +
- 'Version/11.52').
- to.be.equal 'Opera 11.52.0 (Mac OS X 10.6.8)'
-
-
- it 'should parse Safari', ->
- expecting('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.52.7 ' +
- '(KHTML, like Gecko) Version/5.1.2 Safari/534.52.7').
- to.be.equal 'Safari 5.1.2 (Mac OS X 10.6.8)'
-
-
- it 'should parse IE7', ->
- expecting('Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; WOW64; SLCC1; ' +
- '.NET CLR 2.0.50727; .NET4.0C; .NET4.0E)').
- to.be.equal 'IE 7.0.0 (Windows Vista 0.0.0)'
-
-
- it 'should parse IE8', ->
- expecting('Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; ' +
- 'SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; ' +
- '.NET4.0E; InfoPath.3)"').
- to.be.equal 'IE 8.0.0 (Windows 7 0.0.0)'
-
-
- it 'should parse IE9', ->
- expecting('Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; ' +
- '.NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; '+
- 'Media Center PC 6.0)').
- to.be.equal 'IE 9.0.0 (Windows 7 0.0.0)'
-
-
- it 'should parse IE10', ->
- expecting('Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0; ' +
- '.NET4.0E; .NET4.0C)').
- to.be.equal 'IE 10.0.0 (Windows 8 0.0.0)'
-
-
- it 'should parse PhantomJS', ->
- expecting('Mozilla/5.0 (Macintosh; Intel Mac OS X) AppleWebKit/534.34 (KHTML, like Gecko) ' +
- 'PhantomJS/1.6.0 Safari/534.34').
- to.be.equal 'PhantomJS 1.6.0 (Mac OS X 0.0.0)'
-
-
- # Fix for #318
- it 'should parse old Android Browser', ->
- expecting('Mozilla/5.0 (Linux; U; Android 4.2; en-us; sdk Build/JB_MR1) ' +
- 'AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30').
- to.be.equal 'Android 4.2.0 (Android 4.2.0)'
-
- #==============================================================================
- # helper.isDefined()
- #==============================================================================
- describe 'isDefined', ->
- isDefined = helper.isDefined
-
- it 'should return true if defined', ->
- expect(isDefined()).to.equal false
- expect(isDefined undefined).to.equal false
-
- expect(isDefined false).to.equal true
- expect(isDefined 0).to.equal true
- expect(isDefined null).to.equal true
- expect(isDefined '').to.equal true
-
-
- #==============================================================================
- # helper.camelToSnake()
- #==============================================================================
- describe 'camelToSnake', ->
- camelToSnake = helper.camelToSnake
-
- it 'should convert camelCase string to snake_case', ->
- expect(camelToSnake 'OneMoreThing' ).to.equal 'one_more_thing'
-
-
- #==============================================================================
- # helper.dashToCamel()
- #==============================================================================
- describe 'dashToCamel', ->
- dashToCamel = helper.dashToCamel
-
- it 'should convert dash-case to camelCase', ->
- expect(dashToCamel 'one-more-thing' ).to.equal 'oneMoreThing'
- expect(dashToCamel 'one' ).to.equal 'one'
-
-
- #==============================================================================
- # helper.arrayRemove()
- #==============================================================================
- describe 'arrayRemove', ->
- arrayRemove = helper.arrayRemove
-
- it 'should remove object from array', ->
- a = 'one'; b = []; c = {}; d = -> null
- collection = [a, b, c, d]
-
- expect(arrayRemove collection, b).to.equal true
- expect(collection).to.deep.equal [a, c, d]
-
- expect(arrayRemove collection, {}).to.equal false
- expect(collection).to.deep.equal [a, c, d]
-
- expect(arrayRemove collection, d).to.equal true
- expect(collection).to.deep.equal [a, c]
-
- expect(arrayRemove collection, a).to.equal true
- expect(collection).to.deep.equal [c]
-
-
- #==============================================================================
- # helper.merge()
- #==============================================================================
- describe 'merge', ->
-
- it 'should copy properties to first argument', ->
- destination = {a: 1, b: 2}
- result = helper.merge destination, {a: 4, c: 5}
-
- expect(destination.a).to.equal 1
- expect(result).to.deep.equal {a: 4, b: 2, c: 5}
-
-
- #==============================================================================
- # helper.isUrlAbsolute()
- #==============================================================================
- describe 'isUrlAbsolute', ->
-
- it 'should check http/https protocol', ->
- expect(helper.isUrlAbsolute 'some/path/http.html').to.equal false
- expect(helper.isUrlAbsolute '/some/more.py').to.equal false
- expect(helper.isUrlAbsolute 'http://some.com/path').to.equal true
- expect(helper.isUrlAbsolute 'https://more.org/some.js').to.equal true
-
-
- #==============================================================================
- # helper.formatTimeInterval()
- #==============================================================================
- describe 'formatTimeInterval', ->
-
- it 'should format into seconds', ->
- expect(helper.formatTimeInterval 23000).to.equal '23 secs'
-
-
- it 'should format into minutes', ->
- expect(helper.formatTimeInterval 142000).to.equal '2 mins 22 secs'
-
-
- it 'should handle singular minute or second', ->
- expect(helper.formatTimeInterval 61000).to.equal '1 min 1 sec'
-
-
- it 'should round to miliseconds', ->
- expect(helper.formatTimeInterval 163017).to.equal '2 mins 43.017 secs'
-
-
- #==============================================================================
- # helper.mkdirIfNotExists()
- #==============================================================================
- describe 'mkdirIfNotExists', ->
-
- fsMock = require('mocks').fs
- loadFile = require('mocks').loadFile
-
- done = null
-
- fs = fsMock.create
- home:
- 'some.js': fsMock.file()
-
- # load file under test
- m = loadFile __dirname + '/../../lib/helper.js', {fs: fs, lodash: require 'lodash'}
- mkdirIfNotExists = m.exports.mkdirIfNotExists
-
-
- it 'should not do anything, if dir already exists', (done) ->
- mkdirIfNotExists '/home', done
-
-
- it 'should create directory if it does not exist', (done) ->
- mkdirIfNotExists '/home/new', ->
- stat = fs.statSync '/home/new'
- expect(stat).to.exist
- expect(stat.isDirectory()).to.equal true
- done()
-
-
- it 'should create even parent directories if it does not exist', (done) ->
- mkdirIfNotExists '/home/new/parent/child', ->
- stat = fs.statSync '/home/new/parent/child'
- expect(stat).to.exist
- expect(stat.isDirectory()).to.equal true
- done()
diff --git a/test/unit/helper.spec.js b/test/unit/helper.spec.js
new file mode 100644
index 000000000..817ca7d6f
--- /dev/null
+++ b/test/unit/helper.spec.js
@@ -0,0 +1,245 @@
+describe('helper', () => {
+ var helper = require('../../lib/helper')
+
+ describe('browserFullNameToShort', () => {
+ // helper function
+ var expecting = name => expect(helper.browserFullNameToShort(name))
+
+ it('should parse iOS', () => {
+ expecting(
+ 'Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 ' +
+ '(KHTML, like Gecko) Version/6.0 Mobile/10A403 Safari/8536.25'
+ )
+ .to.be.equal('Mobile Safari 6.0.0 (iOS 6.0.0)')
+ })
+
+ it('should parse Linux', () => {
+ expecting(
+ 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.19) Gecko/20081216 ' +
+ 'Ubuntu/8.04 (hardy) Firefox/2.0.0.19'
+ )
+ .to.be.equal('Firefox 2.0.0 (Ubuntu 8.04.0)')
+ })
+
+ it('should degrade gracefully when OS not recognized', () => {
+ expecting(
+ 'Mozilla/5.0 (X11; U; FreeBSD; i386; en-US; rv:1.7) Gecko/20081216 ' +
+ 'Firefox/2.0.0.19'
+ ).to.be.equal('Firefox 2.0.0 (FreeBSD 0.0.0)')
+ })
+
+ it('should parse Chrome', () => {
+ expecting(
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.7 ' +
+ '(KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7'
+ )
+ .to.be.equal('Chrome 16.0.912 (Mac OS X 10.6.8)')
+
+ expecting(
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.15 ' +
+ '(KHTML, like Gecko) Chrome/18.0.985.0 Safari/535.15'
+ )
+ .to.be.equal('Chrome 18.0.985 (Mac OS X 10.6.8)')
+ })
+
+ it('should parse Firefox', () => {
+ expecting(
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 ' +
+ 'Firefox/7.0.1'
+ )
+ .to.be.equal('Firefox 7.0.1 (Mac OS X 10.6.0)')
+ })
+
+ it('should parse Opera', () => {
+ expecting(
+ 'Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; en) Presto/2.9.168 ' +
+ 'Version/11.52'
+ )
+ .to.be.equal('Opera 11.52.0 (Mac OS X 10.6.8)')
+ })
+
+ it('should parse Safari', () => {
+ expecting(
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.52.7 ' +
+ '(KHTML, like Gecko) Version/5.1.2 Safari/534.52.7'
+ )
+ .to.be.equal('Safari 5.1.2 (Mac OS X 10.6.8)')
+ })
+
+ it('should parse IE7', () => {
+ expecting(
+ 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; WOW64; SLCC1; ' +
+ '.NET CLR 2.0.50727; .NET4.0C; .NET4.0E)'
+ )
+ .to.be.equal('IE 7.0.0 (Windows Vista 0.0.0)')
+ })
+
+ it('should parse IE8', () => {
+ expecting(
+ 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; ' +
+ 'SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; .NET4.0E; InfoPath.3)"'
+ )
+ .to.be.equal('IE 8.0.0 (Windows 7 0.0.0)')
+ })
+
+ it('should parse IE9', () => {
+ expecting(
+ 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; ' +
+ '.NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0)'
+ )
+ .to.be.equal('IE 9.0.0 (Windows 7 0.0.0)')
+ })
+
+ it('should parse IE10', () => {
+ expecting(
+ 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0; ' +
+ '.NET4.0E; .NET4.0C)'
+ )
+ .to.be.equal('IE 10.0.0 (Windows 8 0.0.0)')
+ })
+
+ it('should parse PhantomJS', () => {
+ expecting(
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X) AppleWebKit/534.34 (KHTML, like Gecko) ' +
+ 'PhantomJS/1.6.0 Safari/534.34'
+ )
+ .to.be.equal('PhantomJS 1.6.0 (Mac OS X 0.0.0)')
+ })
+
+ // Fix for #318
+ it('should parse old Android Browser', () => {
+ expecting(
+ 'Mozilla/5.0 (Linux; U; Android 4.2; en-us; sdk Build/JB_MR1) ' +
+ 'AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30'
+ )
+ .to.be.equal('Android 4.2.0 (Android 4.2.0)')
+ })
+ })
+
+ describe('isDefined', () => {
+ var isDefined = helper.isDefined
+
+ it('should return true if defined', () => {
+ expect(isDefined()).to.equal(false)
+ expect(isDefined(undefined)).to.equal(false)
+
+ expect(isDefined(false)).to.equal(true)
+ expect(isDefined(0)).to.equal(true)
+ expect(isDefined(null)).to.equal(true)
+ expect(isDefined('')).to.equal(true)
+ })
+ })
+
+ describe('camelToSnake', () => {
+ var camelToSnake = helper.camelToSnake
+
+ it('should convert camelCase string to snake_case', () => {
+ expect(camelToSnake('OneMoreThing')).to.equal('one_more_thing')
+ })
+ })
+
+ describe('dashToCamel', () => {
+ var dashToCamel = helper.dashToCamel
+
+ it('should convert dash-case to camelCase', () => {
+ expect(dashToCamel('one-more-thing')).to.equal('oneMoreThing')
+ expect(dashToCamel('one')).to.equal('one')
+ })
+ })
+
+ describe('arrayRemove', () => {
+ var arrayRemove = helper.arrayRemove
+
+ it('should remove object from array', () => {
+ var a = 'one'
+ var b = []
+ var c = {}
+ var d = () => null
+ var collection = [a, b, c, d]
+
+ expect(arrayRemove(collection, b)).to.equal(true)
+ expect(collection).to.deep.equal([a, c, d])
+
+ expect(arrayRemove(collection, {})).to.equal(false)
+ expect(collection).to.deep.equal([a, c, d])
+
+ expect(arrayRemove(collection, d)).to.equal(true)
+ expect(collection).to.deep.equal([a, c])
+
+ expect(arrayRemove(collection, a)).to.equal(true)
+ expect(collection).to.deep.equal([c])
+ })
+ })
+
+ describe('merge', () => {
+ it('should copy properties to first argument', () => {
+ var destination = {a: 1, b: 2}
+ var result = helper.merge(destination, {a: 4, c: 5})
+
+ expect(destination.a).to.equal(1)
+ expect(result).to.deep.equal({a: 4, b: 2, c: 5})
+ })
+ })
+
+ describe('isUrlAbsolute', () => {
+ it('should check http/https protocol', () => {
+ expect(helper.isUrlAbsolute('some/path/http.html')).to.equal(false)
+ expect(helper.isUrlAbsolute('/some/more.py')).to.equal(false)
+ expect(helper.isUrlAbsolute('http://some.com/path')).to.equal(true)
+ expect(helper.isUrlAbsolute('https://more.org/some.js')).to.equal(true)
+ })
+ })
+
+ describe('formatTimeInterval', () => {
+ it('should format into seconds', () => {
+ expect(helper.formatTimeInterval(23000)).to.equal('23 secs')
+ })
+
+ it('should format into minutes', () => {
+ expect(helper.formatTimeInterval(142000)).to.equal('2 mins 22 secs')
+ })
+
+ it('should handle singular minute or second', () => {
+ expect(helper.formatTimeInterval(61000)).to.equal('1 min 1 sec')
+ })
+
+ it('should round to miliseconds', () => {
+ expect(helper.formatTimeInterval(163017)).to.equal('2 mins 43.017 secs')
+ })
+ })
+
+ describe('mkdirIfNotExists', () => {
+ var fsMock = require('mocks').fs
+ var loadFile = require('mocks').loadFile
+
+ var fs = fsMock.create({
+ home: {'some.js': fsMock.file()}
+ })
+
+ // load file under test
+ var m = loadFile(__dirname + '/../../lib/helper.js', {fs: fs, lodash: require('lodash')})
+ var mkdirIfNotExists = m.exports.mkdirIfNotExists
+
+ it('should not do anything, if dir already exists', done => {
+ mkdirIfNotExists('/home', done)
+ })
+
+ it('should create directory if it does not exist', done => {
+ mkdirIfNotExists('/home/new', () => {
+ var stat = fs.statSync('/home/new')
+ expect(stat).to.exist
+ expect(stat.isDirectory()).to.equal(true)
+ done()
+ })
+ })
+
+ it('should create even parent directories if it does not exist', done => {
+ mkdirIfNotExists('/home/new/parent/child', () => {
+ var stat = fs.statSync('/home/new/parent/child')
+ expect(stat).to.exist
+ expect(stat.isDirectory()).to.equal(true)
+ done()
+ })
+ })
+ })
+})
diff --git a/test/unit/init.spec.coffee b/test/unit/init.spec.coffee
deleted file mode 100644
index 91d057859..000000000
--- a/test/unit/init.spec.coffee
+++ /dev/null
@@ -1,276 +0,0 @@
-#==============================================================================
-# lib/init.js module
-#==============================================================================
-describe 'init', ->
- loadFile = require('mocks').loadFile
- path = require 'path'
- m = null
-
- beforeEach ->
- m = loadFile __dirname + '/../../lib/init.js', {glob: require 'glob'}
- sinon.stub m, 'installPackage'
-
-
- describe 'getBasePath', ->
-
- # just for windows.
- replace = (p) -> p.replace(/\//g, path.sep)
-
- it 'should be empty if config file in cwd', ->
- expect(m.getBasePath 'some.conf', replace('/usr/local/whatever')).to.equal ''
-
-
- it 'should handle leading "./', ->
- expect(m.getBasePath replace('./some.conf'), replace('/usr/local/whatever')).to.equal ''
-
-
- it 'should handle config file in subfolder', ->
- # config /usr/local/sub/folder/file.conf
- file = replace('sub/folder/file.conf')
- expect(m.getBasePath file, replace('/usr/local')).to.equal replace('../..')
-
-
- it 'should handle config in a parent path', ->
- # config /home/file.js
- basePath = m.getBasePath replace('../../../file.js'), replace('/home/vojta/tc/project')
- expect(basePath).to.equal replace('vojta/tc/project')
-
-
- it 'should handle config in parent subfolder', ->
- # config /home/vojta/other/f.js
- f = replace('../../other/f.js')
- expect(m.getBasePath f, replace('/home/vojta/tc/prj')).to.equal replace('../tc/prj')
-
-
- it 'should handle absolute paths', ->
- basePath = m.getBasePath replace('/Users/vojta/karma/conf.js'), replace('/Users/vojta')
- expect(basePath).to.equal replace('..')
-
-
- describe 'processAnswers', ->
-
- answers = (obj = {}) ->
- obj.files = obj.files or []
- obj.exclude = obj.exclude or []
- obj.browsers = obj.browsers or []
- obj
-
-
- it 'should add requirejs and set files non-included if requirejs used', ->
- processedAnswers = m.processAnswers answers {
- requirejs: true,
- includedFiles: ['test-main.js'],
- files: ['*.js']
- }
-
- expect(processedAnswers.frameworks).to.contain 'requirejs'
- expect(processedAnswers.files).to.deep.equal ['test-main.js']
- expect(processedAnswers.onlyServedFiles).to.deep.equal ['*.js']
-
-
- it 'should add coffee preprocessor', ->
- processedAnswers = m.processAnswers answers {
- files: ['src/*.coffee']
- }
-
- expect(processedAnswers.preprocessors).to.have.property '**/*.coffee'
- expect(processedAnswers.preprocessors['**/*.coffee']).to.deep.equal ['coffee']
-
-
- describe 'scenario:', ->
- vm = require 'vm'
-
- StateMachine = require '../../lib/init/state_machine'
- JavaScriptFormatter = require('../../lib/init/formatters').JavaScript
- DefaultKarmaConfig = require('../../lib/config').Config
-
- mockRli =
- close: -> null
- write: -> null
- prompt: -> null
- _deleteLineLeft: -> null
- _deleteLineRight: -> null
-
- mockColors =
- question: -> ''
-
- machine = formatter = null
-
- evaluateConfigCode = (code) ->
- sandbox = {module: {}}
- configModule = vm.runInNewContext code, sandbox
- config = new DefaultKarmaConfig
- sandbox.module.exports config
- config
-
-
- beforeEach ->
- machine = new StateMachine mockRli, mockColors
- formatter = new JavaScriptFormatter
-
-
- it 'should generate working config', (done) ->
- machine.process m.questions, (answers) ->
- basePath = m.getBasePath '../karma.conf.js', path.normalize('/some/path')
- processedAnswers = m.processAnswers answers, basePath
- generatedConfigCode = formatter.generateConfigFile processedAnswers
- config = evaluateConfigCode generatedConfigCode
-
- # expect correct configuration
- expect(config.basePath).to.equal 'path'
- expect(config.frameworks).to.deep.equal ['jasmine']
- expect(config.browsers).to.contain 'Chrome'
- expect(config.browsers).to.contain 'Firefox'
- expect(config.files).to.deep.equal ['src/app.js', 'src/**/*.js', 'test/**/*.js']
- expect(config.exclude).to.deep.equal ['src/config.js']
- expect(config.autoWatch).to.equal false
- done()
-
- # frameworks
- machine.onLine 'jasmine'
- machine.onLine ''
-
- # requirejs
- machine.onLine 'no'
-
- # browsers
- machine.onLine 'Chrome'
- machine.onLine 'Firefox'
- machine.onLine ''
-
- # files
- machine.onLine 'src/app.js'
- machine.onLine 'src/**/*.js'
- machine.onLine 'test/**/*.js'
- machine.onLine ''
-
- # excludes
- machine.onLine 'src/config.js'
- machine.onLine ''
-
- # autoWatch
- machine.onLine 'no'
-
-
- it 'should generate config for requirejs', (done) ->
- machine.process m.questions, (answers) ->
- basePath = m.getBasePath '../karma.conf.js', '/some/path'
- processedAnswers = m.processAnswers answers, basePath
- generatedConfigCode = formatter.generateConfigFile processedAnswers
- config = evaluateConfigCode generatedConfigCode
-
- # expect correct configuration
- expect(config.frameworks).to.contain 'requirejs'
- expect(config.files).to.contain 'test/main.js'
- for pattern in config.files.slice(1)
- expect(pattern.included).to.equal false
- done()
-
- # frameworks
- machine.onLine 'jasmine'
- machine.onLine ''
-
- # requirejs
- machine.onLine 'yes'
-
- # browsers
- machine.onLine 'Chrome'
- machine.onLine ''
-
- # files
- machine.onLine 'src/**/*.js'
- machine.onLine 'test/**/*.js'
- machine.onLine ''
-
- # excludes
- machine.onLine ''
- machine.onLine ''
-
- # generate test-main
- machine.onLine 'no'
-
- # included files
- machine.onLine 'test/main.js'
- machine.onLine ''
-
- # autoWatch
- machine.onLine 'yes'
-
-
- it 'should generate the test-main for requirejs', (done) ->
- machine.process m.questions, (answers) ->
- basePath = m.getBasePath '../karma.conf.js', '/some/path'
- processedAnswers = m.processAnswers answers, basePath, 'test-main.js'
- generatedConfigCode = formatter.generateConfigFile processedAnswers
- config = evaluateConfigCode generatedConfigCode
-
- # expect correct processedAnswers
- expect(processedAnswers.generateTestMain).to.be.ok
- expect(processedAnswers.files).to.contain 'test-main.js'
-
- # expect correct configuration
- expect(config.frameworks).to.contain 'requirejs'
- for pattern in config.files.slice(1)
- expect(pattern.included).to.equal false
- done()
-
- # frameworks
- machine.onLine 'jasmine'
- machine.onLine ''
-
- # requirejs
- machine.onLine 'yes'
-
- # browsers
- machine.onLine 'Chrome'
- machine.onLine ''
-
- # files
- machine.onLine 'src/**/*.js'
- machine.onLine 'test/**/*.js'
- machine.onLine ''
-
- # excludes
- machine.onLine ''
- machine.onLine ''
-
- # generate test-main
- machine.onLine 'yes'
-
- # autoWatch
- machine.onLine 'yes'
-
-
- it 'should add coffee preprocessor', (done) ->
- machine.process m.questions, (answers) ->
- basePath = m.getBasePath 'karma.conf.js', '/cwd'
- processedAnswers = m.processAnswers answers, basePath
- generatedConfigCode = formatter.generateConfigFile processedAnswers
- config = evaluateConfigCode generatedConfigCode
-
- # expect correct configuration
- expect(config.preprocessors).to.have.property '**/*.coffee'
- expect(config.preprocessors['**/*.coffee']).to.deep.equal ['coffee']
- done()
-
- # frameworks
- machine.onLine 'jasmine'
- machine.onLine ''
-
- # requirejs
- machine.onLine 'no'
-
- # browsers
- machine.onLine 'Chrome'
- machine.onLine ''
-
- # files
- machine.onLine 'src/*.coffee'
- machine.onLine 'src/**/*.js'
- machine.onLine ''
-
- # excludes
- machine.onLine ''
-
- # autoWatch
- machine.onLine 'no'
diff --git a/test/unit/init.spec.js b/test/unit/init.spec.js
new file mode 100644
index 000000000..0ed9027ad
--- /dev/null
+++ b/test/unit/init.spec.js
@@ -0,0 +1,288 @@
+import path from 'path'
+describe('init', () => {
+ var loadFile = require('mocks').loadFile
+ var m = null
+
+ beforeEach(() => {
+ m = loadFile(__dirname + '/../../lib/init.js', {glob: require('glob')})
+ sinon.stub(m, 'installPackage')
+ })
+
+ describe('getBasePath', () => {
+ // just for windows.
+ var replace = p => p.replace(/\//g, path.sep)
+
+ it('should be empty if config file in cwd', () => {
+ expect(m.getBasePath('some.conf', replace('/usr/local/whatever'))).to.equal('')
+ })
+
+ it('should handle leading "./', () => {
+ expect(m.getBasePath(replace('./some.conf'), replace('/usr/local/whatever'))).to.equal('')
+ })
+
+ it('should handle config file in subfolder', () => {
+ // config /usr/local/sub/folder/file.conf
+ var file = replace('sub/folder/file.conf')
+ expect(m.getBasePath(file, replace('/usr/local'))).to.equal(replace('../..'))
+ })
+
+ it('should handle config in a parent path', () => {
+ // config /home/file.js
+ var basePath = m.getBasePath(replace('../../../file.js'), replace('/home/vojta/tc/project'))
+ expect(basePath).to.equal(replace('vojta/tc/project'))
+ })
+
+ it('should handle config in parent subfolder', () => {
+ // config /home/vojta/other/f.js
+ var f = replace('../../other/f.js')
+ expect(m.getBasePath(f, replace('/home/vojta/tc/prj'))).to.equal(replace('../tc/prj'))
+ })
+
+ it('should handle absolute paths', () => {
+ var basePath = m.getBasePath(replace('/Users/vojta/karma/conf.js'), replace('/Users/vojta'))
+ expect(basePath).to.equal(replace('..'))
+ })
+ })
+
+ describe('processAnswers', () => {
+ var answers = obj => {
+ obj = obj ? obj : {}
+ obj.files = obj.files || []
+ obj.exclude = obj.exclude || []
+ obj.browsers = obj.browsers || []
+ return obj
+ }
+
+ it('should add requirejs and set files non-included if requirejs used', () => {
+ var processedAnswers = m.processAnswers(answers({
+ requirejs: true,
+ includedFiles: ['test-main.js'],
+ files: ['*.js']
+ }))
+
+ expect(processedAnswers.frameworks).to.contain('requirejs')
+ expect(processedAnswers.files).to.deep.equal(['test-main.js'])
+ expect(processedAnswers.onlyServedFiles).to.deep.equal(['*.js'])
+ })
+
+ it('should add coffee preprocessor', () => {
+ var processedAnswers = m.processAnswers(answers({
+ files: ['src/*.coffee']
+ }))
+
+ expect(processedAnswers.preprocessors).to.have.property('**/*.coffee')
+ expect(processedAnswers.preprocessors['**/*.coffee']).to.deep.equal(['coffee'])
+ })
+ })
+
+ describe('scenario:', () => {
+ var formatter
+ var vm = require('vm')
+
+ var StateMachine = require('../../lib/init/state_machine')
+ var JavaScriptFormatter = require('../../lib/init/formatters').JavaScript
+ var DefaultKarmaConfig = require('../../lib/config').Config
+
+ var mockRli = {
+ close: () => null,
+ write: () => null,
+ prompt: () => null,
+ _deleteLineLeft: () => null,
+ _deleteLineRight: () => null
+ }
+
+ var mockColors = {
+ question: () => ''
+ }
+
+ var machine = formatter = null
+
+ var evaluateConfigCode = code => {
+ var sandbox = {module: {}}
+ vm.runInNewContext(code, sandbox)
+ var config = new DefaultKarmaConfig()
+ sandbox.module.exports(config)
+ return config
+ }
+
+ beforeEach(() => {
+ machine = new StateMachine(mockRli, mockColors)
+ formatter = new JavaScriptFormatter()
+ })
+
+ it('should generate working config', done => {
+ machine.process(m.questions, answers => {
+ var basePath = m.getBasePath('../karma.conf.js', path.normalize('/some/path'))
+ var processedAnswers = m.processAnswers(answers, basePath)
+ var generatedConfigCode = formatter.generateConfigFile(processedAnswers)
+ var config = evaluateConfigCode(generatedConfigCode)
+
+ // expect correct configuration
+ expect(config.basePath).to.equal('path')
+ expect(config.frameworks).to.deep.equal(['jasmine'])
+ expect(config.browsers).to.contain('Chrome')
+ expect(config.browsers).to.contain('Firefox')
+ expect(config.files).to.deep.equal(['src/app.js', 'src/**/*.js', 'test/**/*.js'])
+ expect(config.exclude).to.deep.equal(['src/config.js'])
+ expect(config.autoWatch).to.equal(false)
+ done()
+ })
+
+ // frameworks
+ machine.onLine('jasmine')
+ machine.onLine('')
+
+ // requirejs
+ machine.onLine('no')
+
+ // browsers
+ machine.onLine('Chrome')
+ machine.onLine('Firefox')
+ machine.onLine('')
+
+ // files
+ machine.onLine('src/app.js')
+ machine.onLine('src/**/*.js')
+ machine.onLine('test/**/*.js')
+ machine.onLine('')
+
+ // excludes
+ machine.onLine('src/config.js')
+ machine.onLine('')
+
+ // autoWatch
+ machine.onLine('no')
+ })
+
+ it('should generate config for requirejs', done => {
+ machine.process(m.questions, answers => {
+ var basePath = m.getBasePath('../karma.conf.js', '/some/path')
+ var processedAnswers = m.processAnswers(answers, basePath)
+ var generatedConfigCode = formatter.generateConfigFile(processedAnswers)
+ var config = evaluateConfigCode(generatedConfigCode)
+
+ // expect correct configuration
+ expect(config.frameworks).to.contain('requirejs')
+ expect(config.files).to.contain('test/main.js')
+ config.files.slice(1).forEach(pattern => {
+ expect(pattern.included).to.equal(false)
+ })
+
+ done()
+ })
+
+ // frameworks
+ machine.onLine('jasmine')
+ machine.onLine('')
+
+ // requirejs
+ machine.onLine('yes')
+
+ // browsers
+ machine.onLine('Chrome')
+ machine.onLine('')
+
+ // files
+ machine.onLine('src/**/*.js')
+ machine.onLine('test/**/*.js')
+ machine.onLine('')
+
+ // excludes
+ machine.onLine('')
+ machine.onLine('')
+
+ // generate test-main
+ machine.onLine('no')
+
+ // included files
+ machine.onLine('test/main.js')
+ machine.onLine('')
+
+ // autoWatch
+ machine.onLine('yes')
+ })
+
+ it('should generate the test-main for requirejs', done => {
+ machine.process(m.questions, answers => {
+ var basePath = m.getBasePath('../karma.conf.js', '/some/path')
+ var processedAnswers = m.processAnswers(answers, basePath, 'test-main.js')
+ var generatedConfigCode = formatter.generateConfigFile(processedAnswers)
+ var config = evaluateConfigCode(generatedConfigCode)
+
+ // expect correct processedAnswers
+ expect(processedAnswers.generateTestMain).to.be.ok
+ expect(processedAnswers.files).to.contain('test-main.js')
+
+ // expect correct configuration
+ expect(config.frameworks).to.contain('requirejs')
+ config.files.slice(1).forEach(pattern => {
+ expect(pattern.included).to.equal(false)
+ })
+
+ done()
+ })
+
+ // frameworks
+ machine.onLine('jasmine')
+ machine.onLine('')
+
+ // requirejs
+ machine.onLine('yes')
+
+ // browsers
+ machine.onLine('Chrome')
+ machine.onLine('')
+
+ // files
+ machine.onLine('src/**/*.js')
+ machine.onLine('test/**/*.js')
+ machine.onLine('')
+
+ // excludes
+ machine.onLine('')
+ machine.onLine('')
+
+ // generate test-main
+ machine.onLine('yes')
+
+ // autoWatch
+ machine.onLine('yes')
+ })
+
+ it('should add coffee preprocessor', done => {
+ machine.process(m.questions, answers => {
+ var basePath = m.getBasePath('karma.conf.js', '/cwd')
+ var processedAnswers = m.processAnswers(answers, basePath)
+ var generatedConfigCode = formatter.generateConfigFile(processedAnswers)
+ var config = evaluateConfigCode(generatedConfigCode)
+
+ // expect correct configuration
+ expect(config.preprocessors).to.have.property('**/*.coffee')
+ expect(config.preprocessors['**/*.coffee']).to.deep.equal(['coffee'])
+ done()
+ })
+
+ // frameworks
+ machine.onLine('jasmine')
+ machine.onLine('')
+
+ // requirejs
+ machine.onLine('no')
+
+ // browsers
+ machine.onLine('Chrome')
+ machine.onLine('')
+
+ // files
+ machine.onLine('src/*.coffee')
+ machine.onLine('src/**/*.js')
+ machine.onLine('')
+
+ // excludes
+ machine.onLine('')
+
+ // autoWatch
+ machine.onLine('no')
+ })
+ })
+})
diff --git a/test/unit/init/formatters.spec.coffee b/test/unit/init/formatters.spec.coffee
deleted file mode 100644
index 034f36403..000000000
--- a/test/unit/init/formatters.spec.coffee
+++ /dev/null
@@ -1,64 +0,0 @@
-#==============================================================================
-# lib/init/formatters.js module
-#==============================================================================
-describe 'init/formatters', ->
- f = require '../../../lib/init/formatters'
- formatter = null
-
- describe 'JavaScript', ->
-
- beforeEach ->
- formatter = new f.JavaScript
-
- describe 'formatAnswers', ->
- createAnswers = (ans = {}) ->
- ans.frameworks = ans.frameworks or []
- ans.files = ans.files or []
- ans.onlyServedFiles = ans.onlyServedFiles or []
- ans.exclude = ans.exclude or []
- ans.browsers = ans.browsers or []
- ans.preprocessors = ans.preprocessors or {}
- ans
-
- it 'should format FRAMEWORKS', ->
- replacements = formatter.formatAnswers createAnswers {frameworks: ['jasmine', 'requirejs']}
- expect(replacements.FRAMEWORKS).to.equal "'jasmine', 'requirejs'"
-
-
- it 'should format FILES', ->
- replacements = formatter.formatAnswers createAnswers()
- expect(replacements.FILES).to.equal ''
-
- replacements = formatter.formatAnswers createAnswers {files: ['*.js', 'other/file.js']}
- expect(replacements.FILES).to.equal "\n '*.js',\n 'other/file.js'"
-
-
- it 'should format BROWSERS', ->
- replacements = formatter.formatAnswers createAnswers {browsers: ['Chrome', 'Firefox']}
- expect(replacements.BROWSERS).to.equal "'Chrome', 'Firefox'"
-
-
- it 'should format AUTO_WATCH', ->
- replacements = formatter.formatAnswers createAnswers {autoWatch: true}
- expect(replacements.AUTO_WATCH).to.equal 'true'
-
- replacements = formatter.formatAnswers createAnswers {autoWatch: false}
- expect(replacements.AUTO_WATCH).to.equal 'false'
-
-
- it 'should format onlyServedFiles', ->
- replacements = formatter.formatAnswers createAnswers {
- files: ['test-main.js']
- onlyServedFiles: ['src/*.js']
- }
-
- expect(replacements.FILES).to.equal "\n 'test-main.js',\n" +
- " {pattern: 'src/*.js', included: false}"
-
-
- it 'should format PREPROCESSORS', ->
- replacements = formatter.formatAnswers createAnswers {preprocessors: '*.coffee': ['coffee']}
-
- expect(replacements.PREPROCESSORS).to.equal "{\n" +
- " '*.coffee': ['coffee']\n" +
- " }"
diff --git a/test/unit/init/formatters.spec.js b/test/unit/init/formatters.spec.js
new file mode 100644
index 000000000..a311132f6
--- /dev/null
+++ b/test/unit/init/formatters.spec.js
@@ -0,0 +1,69 @@
+import formatters from '../../../lib/init/formatters'
+describe('init/formatters', () => {
+ var formatter
+
+ describe('JavaScript', () => {
+ beforeEach(() => {
+ formatter = new formatters.JavaScript()
+ })
+
+ describe('formatAnswers', () => {
+ var createAnswers = function (ans = {}) {
+ ans.frameworks = ans.frameworks || []
+ ans.files = ans.files || []
+ ans.onlyServedFiles = ans.onlyServedFiles || []
+ ans.exclude = ans.exclude || []
+ ans.browsers = ans.browsers || []
+ ans.preprocessors = ans.preprocessors || {}
+ return ans
+ }
+
+ it('should format FRAMEWORKS', () => {
+ var replacements = formatter.formatAnswers(createAnswers({frameworks: ['jasmine', 'requirejs']}))
+ expect(replacements.FRAMEWORKS).to.equal("'jasmine', 'requirejs'")
+ })
+
+ it('should format FILES', () => {
+ var replacements = formatter.formatAnswers(createAnswers())
+ expect(replacements.FILES).to.equal('')
+
+ replacements = formatter.formatAnswers(createAnswers({files: ['*.js', 'other/file.js']}))
+ expect(replacements.FILES).to.equal(
+ "\n '*.js',\n 'other/file.js'"
+ )
+ })
+
+ it('should format BROWSERS', () => {
+ var replacements = formatter.formatAnswers(createAnswers({browsers: ['Chrome', 'Firefox']}))
+ expect(replacements.BROWSERS).to.equal("'Chrome', 'Firefox'")
+ })
+
+ it('should format AUTO_WATCH', () => {
+ var replacements = formatter.formatAnswers(createAnswers({autoWatch: true}))
+ expect(replacements.AUTO_WATCH).to.equal('true')
+
+ replacements = formatter.formatAnswers(createAnswers({autoWatch: false}))
+ expect(replacements.AUTO_WATCH).to.equal('false')
+ })
+
+ it('should format onlyServedFiles', () => {
+ var replacements = formatter.formatAnswers(createAnswers({
+ files: ['test-main.js'],
+ onlyServedFiles: ['src/*.js']
+ }))
+
+ expect(replacements.FILES).to.equal(
+ "\n 'test-main.js',\n {pattern: 'src/*.js', included: false}"
+ )
+ })
+
+ it('should format PREPROCESSORS', () => {
+ var replacements = formatter.formatAnswers(createAnswers({preprocessors: {'*.coffee': ['coffee']}}))
+
+ expect(replacements.PREPROCESSORS).to.equal(
+ "{\n '*.coffee': ['coffee']\n }"
+ )
+ })
+ })
+ })
+})
diff --git a/test/unit/init/state_machine.spec.coffee b/test/unit/init/state_machine.spec.coffee
deleted file mode 100644
index 8c484ff57..000000000
--- a/test/unit/init/state_machine.spec.coffee
+++ /dev/null
@@ -1,148 +0,0 @@
-#==============================================================================
-# lib/init/state_machine.js module
-#==============================================================================
-describe 'init/StateMachine', ->
- StateMachine = require '../../../lib/init/state_machine'
- machine = done = null
-
- mockRli =
- close: -> null
- write: -> null
- prompt: -> null
- _deleteLineLeft: -> null
- _deleteLineRight: -> null
-
- mockColors =
- question: -> ''
-
-
- beforeEach ->
- machine = new StateMachine mockRli, mockColors
- done = sinon.spy()
-
- it 'should go through all the questions', ->
- questions = [
- {id: 'framework', options: ['jasmine', 'mocha']}
- {id: 'other'}
- ]
-
- done = sinon.spy (answers) ->
- expect(answers.framework).to.equal 'jasmine'
- expect(answers.other).to.equal 'abc'
-
- machine.process questions, done
- machine.onLine 'jasmine'
- machine.onLine 'abc'
- expect(done).to.have.been.called
-
-
- it 'should allow multiple answers', ->
- questions = [
- {id: 'browsers', multiple: true}
- ]
-
- done = sinon.spy (answers) ->
- expect(answers.browsers).to.deep.equal ['Chrome', 'Safari']
-
- machine.process questions, done
- machine.onLine 'Chrome'
- machine.onLine 'Safari'
- machine.onLine ''
- expect(done).to.have.been.called
-
-
- it 'should treat spaces as confirmation of multiple answers', ->
- questions = [
- {id: 'browsers', multiple: true}
- ]
-
- done = sinon.spy (answers) ->
- expect(answers.browsers).to.deep.equal ['Chrome']
-
- machine.process questions, done
- machine.onLine 'Chrome'
- machine.onLine ' '
- expect(done).to.have.been.called
-
-
- it 'should always return array for multiple', ->
- questions = [
- {id: 'empty', multiple: true}
- ]
-
- done = sinon.spy (answers) ->
- expect(answers.empty).to.deep.equal []
-
- machine.process questions, done
- machine.onLine ''
- expect(done).to.have.been.called
-
-
- it 'should validate answers', ->
- validator = sinon.spy()
- questions = [
- {id: 'validated', validate: validator}
- ]
-
- machine.process questions, done
- machine.onLine 'something'
-
- expect(done).to.have.been.called
- expect(validator).to.have.been.calledWith 'something'
-
-
- it 'should allow conditional answers', ->
- ifTrue = sinon.spy (answers) ->
- answers.first is 'true'
- ifFalse = sinon.spy (answers) ->
- answers.first is 'false'
-
- done = sinon.spy (answers) ->
- expect(answers.first).to.equal 'true'
- expect(answers.onlyIfTrue).to.equal 'something'
- expect(answers.onlyIfFalse).to.not.exist
-
- questions = [
- {id: 'first'}
- {id: 'onlyIfTrue', condition: ifTrue}
- {id: 'onlyIfFalse', condition: ifFalse}
- ]
-
- machine.process questions, done
- machine.onLine 'true'
- machine.onLine 'something'
-
- expect(done).to.have.been.called
-
-
- it 'should parse booleans', ->
- done = sinon.spy (answers) ->
- expect(answers.yes).to.equal true
- expect(answers.no).to.equal false
-
- questions = [
- {id: 'yes', options: ['yes', 'no'], boolean: true}
- {id: 'no', options: ['yes', 'no'], boolean: true}
- ]
-
- machine.process questions, done
- machine.onLine 'yes'
- machine.onLine 'no'
-
- expect(done).to.have.been.called
-
-
- it 'should parse booleans before validation', ->
- validator = sinon.spy (value) ->
- expect(typeof value).to.equal 'boolean'
-
- questions = [
- {id: 'what', options: ['yes', 'no'], boolean: true, validate: validator}
- {id: 'really', options: ['yes', 'no'], boolean: true, validate: validator}
- ]
-
- machine.process questions, done
- machine.onLine 'yes'
- machine.onLine 'no'
-
- expect(validator).to.have.been.calledTwice
diff --git a/test/unit/init/state_machine.spec.js b/test/unit/init/state_machine.spec.js
new file mode 100644
index 000000000..a4142d5b8
--- /dev/null
+++ b/test/unit/init/state_machine.spec.js
@@ -0,0 +1,160 @@
+import StateMachine from '../../../lib/init/state_machine'
+
+describe('init/StateMachine', () => {
+ var done
+ var machine
+
+ var mockRli = {
+ close: () => null,
+ write: () => null,
+ prompt: () => null,
+ _deleteLineLeft: () => null,
+ _deleteLineRight: () => null
+ }
+
+ var mockColors = {
+ question: () => ''
+ }
+
+ beforeEach(() => {
+ machine = new StateMachine(mockRli, mockColors)
+ done = sinon.spy()
+ })
+
+ it('should go through all the questions', () => {
+ var questions = [
+ {id: 'framework', options: ['jasmine', 'mocha']},
+ {id: 'other'}
+ ]
+
+ done = sinon.spy(answers => {
+ expect(answers.framework).to.equal('jasmine')
+ expect(answers.other).to.equal('abc')
+ })
+
+ machine.process(questions, done)
+ machine.onLine('jasmine')
+ machine.onLine('abc')
+ expect(done).to.have.been.called
+ })
+
+ it('should allow multiple answers', () => {
+ var questions = [
+ {id: 'browsers', multiple: true}
+ ]
+
+ done = sinon.spy(answers => {
+ expect(answers.browsers).to.deep.equal(['Chrome', 'Safari'])
+ })
+
+ machine.process(questions, done)
+ machine.onLine('Chrome')
+ machine.onLine('Safari')
+ machine.onLine('')
+ expect(done).to.have.been.called
+ })
+
+ it('should treat spaces as confirmation of multiple answers', () => {
+ var questions = [
+ {id: 'browsers', multiple: true}
+ ]
+
+ done = sinon.spy(answers => {
+ expect(answers.browsers).to.deep.equal(['Chrome'])
+ })
+
+ machine.process(questions, done)
+ machine.onLine('Chrome')
+ machine.onLine(' ')
+ expect(done).to.have.been.called
+ })
+
+ it('should always return array for multiple', () => {
+ var questions = [
+ {id: 'empty', multiple: true}
+ ]
+
+ done = sinon.spy(answers => {
+ expect(answers.empty).to.deep.equal([])
+ })
+
+ machine.process(questions, done)
+ machine.onLine('')
+ expect(done).to.have.been.called
+ })
+
+ it('should validate answers', () => {
+ var validator = sinon.spy()
+ var questions = [
+ {id: 'validated', validate: validator}
+ ]
+
+ machine.process(questions, done)
+ machine.onLine('something')
+
+ expect(done).to.have.been.called
+ expect(validator).to.have.been.calledWith('something')
+ })
+
+ it('should allow conditional answers', () => {
+ var ifTrue = sinon.spy(answers => {
+ return answers.first === 'true'
+ })
+ var ifFalse = sinon.spy(answers => {
+ return answers.first === 'false'
+ })
+
+ done = sinon.spy(answers => {
+ expect(answers.first).to.equal('true')
+ expect(answers.onlyIfTrue).to.equal('something')
+ expect(answers.onlyIfFalse).to.not.exist
+ })
+
+ var questions = [
+ {id: 'first'},
+ {id: 'onlyIfTrue', condition: ifTrue},
+ {id: 'onlyIfFalse', condition: ifFalse}
+ ]
+
+ machine.process(questions, done)
+ machine.onLine('true')
+ machine.onLine('something')
+
+ expect(done).to.have.been.called
+ })
+
+ it('should parse booleans', () => {
+ done = sinon.spy(answers => {
+ expect(answers.yes).to.equal(true)
+ expect(answers.no).to.equal(false)
+ })
+
+ var questions = [
+ {id: 'yes', options: ['yes', 'no'], boolean: true},
+ {id: 'no', options: ['yes', 'no'], boolean: true}
+ ]
+
+ machine.process(questions, done)
+ machine.onLine('yes')
+ machine.onLine('no')
+
+ expect(done).to.have.been.called
+ })
+
+ it('should parse booleans before validation', () => {
+ var validator = sinon.spy(value => {
+ expect(typeof value).to.equal('boolean')
+ })
+
+ var questions = [
+ {id: 'what', options: ['yes', 'no'], boolean: true, validate: validator},
+ {id: 'really', options: ['yes', 'no'], boolean: true, validate: validator}
+ ]
+
+ machine.process(questions, done)
+ machine.onLine('yes')
+ machine.onLine('no')
+
+ expect(validator).to.have.been.calledTwice
+ })
+})
diff --git a/test/unit/launcher.spec.coffee b/test/unit/launcher.spec.coffee
deleted file mode 100644
index 1859decab..000000000
--- a/test/unit/launcher.spec.coffee
+++ /dev/null
@@ -1,204 +0,0 @@
-#==============================================================================
-# lib/launcher.js module
-#==============================================================================
-describe 'launcher', ->
- Promise = require 'bluebird'
- di = require 'di'
- events = require '../../lib/events'
- logger = require '../../lib/logger'
- launcher = require '../../lib/launcher'
- createMockTimer = require './mocks/timer'
-
- # mock out id generator
- lastGeneratedId = null
- launcher.Launcher.generateId = ->
- ++lastGeneratedId
-
- # promise mock
- stubPromise = (obj, method, stubAction) ->
- promise = new Promise((resolve) ->
- obj[method].resolve = resolve
- )
- sinon.stub obj, method, ->
- stubAction() if stubAction
- promise
-
-
- class FakeBrowser
- constructor: (@id, @name, baseBrowserDecorator) ->
- baseBrowserDecorator @
- FakeBrowser._instances.push @
- sinon.stub @, 'start', -> @state = @STATE_BEING_CAPTURED
- stubPromise @, 'forceKill'
- sinon.stub @, 'restart'
-
- class ScriptBrowser
- constructor: (@id, @name, baseBrowserDecorator) ->
- baseBrowserDecorator @
- ScriptBrowser._instances.push @
- sinon.stub @, 'start', -> @state = @STATE_BEING_CAPTURED
- stubPromise @, 'forceKill'
- sinon.stub @, 'restart'
-
-
- beforeEach ->
- lastGeneratedId = 0
- FakeBrowser._instances = []
- ScriptBrowser._instances = []
-
-
- #============================================================================
- # launcher.Launcher
- #============================================================================
- describe 'Launcher', ->
- l = emitter = null
-
- beforeEach ->
- emitter = new events.EventEmitter()
- injector = new di.Injector [{
- 'launcher:Fake': ['type', FakeBrowser]
- 'launcher:Script': ['type', ScriptBrowser]
- 'emitter': ['value', emitter]
- 'config': ['value', {captureTimeout: 0}]
- 'timer': ['factory', createMockTimer]
- }]
- l = new launcher.Launcher emitter, injector
-
- describe 'launch', ->
-
- it 'should inject and start all browsers', ->
- l.launch ['Fake'], 'localhost', 1234, '/root/'
-
- browser = FakeBrowser._instances.pop()
- expect(browser.start).to.have.been.calledWith 'http://localhost:1234/root/'
- expect(browser.id).to.equal lastGeneratedId
- expect(browser.name).to.equal 'Fake'
-
-
- it 'should allow launching a script', ->
- l.launch ['/usr/local/bin/special-browser'], 'localhost', 1234, '/'
-
- script = ScriptBrowser._instances.pop()
- expect(script.start).to.have.been.calledWith 'http://localhost:1234/'
- expect(script.name).to.equal '/usr/local/bin/special-browser'
-
-
- it 'should use the non default host', ->
- l.launch ['Fake'], 'whatever', 1234, '/root/'
-
- browser = FakeBrowser._instances.pop()
- expect(browser.start).to.have.been.calledWith 'http://whatever:1234/root/'
-
-
- describe 'restart', ->
- it 'should restart the browser', ->
- l.launch ['Fake'], 'localhost', 1234, '/root/'
- browser = FakeBrowser._instances.pop()
-
- returnedValue = l.restart lastGeneratedId
- expect(returnedValue).to.equal true
- expect(browser.restart).to.have.been.called
-
-
- it 'should return false if the browser was not launched by launcher (manual)', ->
- l.launch [], 'localhost', 1234, '/'
- expect(l.restart 'manual-id').to.equal false
-
-
- describe 'kill', ->
- it 'should kill browser with given id', (done) ->
- killSpy = sinon.spy()
-
- l.launch ['Fake']
- browser = FakeBrowser._instances.pop()
-
- l.kill browser.id, done
- expect(browser.forceKill).to.have.been.called
-
- browser.forceKill.resolve()
-
-
- it 'should return false if browser does not exist, but still resolve the callback', (done) ->
- l.launch ['Fake']
- browser = FakeBrowser._instances.pop()
-
- returnedValue = l.kill 'weird-id', done
- expect(returnedValue).to.equal false
- expect(browser.forceKill).not.to.have.been.called
-
-
- it 'should not require a callback', (done) ->
- l.launch ['Fake']
- browser = FakeBrowser._instances.pop()
-
- l.kill 'weird-id'
- process.nextTick done
-
-
- describe 'killAll', ->
-
- it 'should kill all running processe', ->
- l.launch ['Fake', 'Fake'], 'localhost', 1234
- l.killAll()
-
- browser = FakeBrowser._instances.pop()
- expect(browser.forceKill).to.have.been.called
-
- browser = FakeBrowser._instances.pop()
- expect(browser.forceKill).to.have.been.called
-
-
- it 'should call callback when all processes killed', ->
- exitSpy = sinon.spy()
-
- l.launch ['Fake', 'Fake'], 'localhost', 1234
- l.killAll exitSpy
-
- expect(exitSpy).not.to.have.been.called
-
- # finish the first browser
- browser = FakeBrowser._instances.pop()
- browser.forceKill.resolve()
-
- scheduleNextTick ->
- expect(exitSpy).not.to.have.been.called
-
- scheduleNextTick ->
- # finish the second browser
- browser = FakeBrowser._instances.pop()
- browser.forceKill.resolve()
-
- scheduleNextTick ->
- expect(exitSpy).to.have.been.called
-
-
- it 'should call callback even if no browsers lanunched', (done) ->
- l.killAll done
-
-
- describe 'areAllCaptured', ->
-
- it 'should return true if only if all browsers captured', ->
- l.launch ['Fake', 'Fake'], 'localhost', 1234
-
- expect(l.areAllCaptured()).to.equal false
-
- l.markCaptured 1
- expect(l.areAllCaptured()).to.equal false
-
- l.markCaptured 2
- expect(l.areAllCaptured()).to.equal true
-
-
- describe 'onExit', ->
-
- it 'should kill all browsers', (done) ->
- l.launch ['Fake', 'Fake'], 'localhost', 1234, '/', 0, 1
-
- emitter.emitAsync('exit').then done
-
- browser = FakeBrowser._instances.pop()
- browser.forceKill.resolve()
-
- browser = FakeBrowser._instances.pop()
- browser.forceKill.resolve()
diff --git a/test/unit/launcher.spec.js b/test/unit/launcher.spec.js
new file mode 100644
index 000000000..206eb22ea
--- /dev/null
+++ b/test/unit/launcher.spec.js
@@ -0,0 +1,224 @@
+import Promise from 'bluebird'
+import di from 'di'
+import events from '../../lib/events'
+import launcher from '../../lib/launcher'
+import createMockTimer from './mocks/timer'
+
+// promise mock
+var stubPromise = (obj, method, stubAction) => {
+ var promise = new Promise(resolve => {
+ obj[method].resolve = resolve
+ })
+
+ sinon.stub(obj, method, () => {
+ if (stubAction) stubAction()
+
+ return promise
+ })
+}
+
+class FakeBrowser {
+ constructor (id, name, baseBrowserDecorator) {
+ this.id = id
+ this.name = name
+ baseBrowserDecorator(this)
+ FakeBrowser._instances.push(this)
+ sinon.stub(this, 'start', () => {
+ this.state = this.STATE_BEING_CAPTURED
+ return this.state
+ })
+ stubPromise(this, 'forceKill')
+ sinon.stub(this, 'restart')
+ }
+}
+
+class ScriptBrowser {
+ constructor (id, name, baseBrowserDecorator) {
+ this.id = id
+ this.name = name
+ baseBrowserDecorator(this)
+ ScriptBrowser._instances.push(this)
+ sinon.stub(this, 'start', () => {
+ this.state = this.STATE_BEING_CAPTURED
+ })
+ stubPromise(this, 'forceKill')
+ sinon.stub(this, 'restart')
+ }
+}
+
+describe('launcher', () => {
+ // mock out id generator
+ var lastGeneratedId = null
+ launcher.Launcher.generateId = () => {
+ return ++lastGeneratedId
+ }
+
+ beforeEach(() => {
+ lastGeneratedId = 0
+ FakeBrowser._instances = []
+ ScriptBrowser._instances = []
+ })
+
+ // ============================================================================
+ // launcher.Launcher
+ // ============================================================================
+ describe('Launcher', () => {
+ var emitter
+ var l = emitter = null
+
+ beforeEach(() => {
+ emitter = new events.EventEmitter()
+ var injector = new di.Injector([{
+ 'launcher:Fake': ['type', FakeBrowser],
+ 'launcher:Script': ['type', ScriptBrowser],
+ 'emitter': ['value', emitter],
+ 'config': ['value', {captureTimeout: 0}],
+ 'timer': ['factory', createMockTimer]
+ }])
+ l = new launcher.Launcher(emitter, injector)
+ })
+
+ describe('launch', () => {
+ it('should inject and start all browsers', () => {
+ l.launch(['Fake'], 'localhost', 1234, '/root/')
+
+ var browser = FakeBrowser._instances.pop()
+ expect(browser.start).to.have.been.calledWith('http://localhost:1234/root/')
+ expect(browser.id).to.equal(lastGeneratedId)
+ expect(browser.name).to.equal('Fake')
+ })
+
+ it('should allow launching a script', () => {
+ l.launch(['/usr/local/bin/special-browser'], 'localhost', 1234, '/')
+
+ var script = ScriptBrowser._instances.pop()
+ expect(script.start).to.have.been.calledWith('http://localhost:1234/')
+ expect(script.name).to.equal('/usr/local/bin/special-browser')
+ })
+
+ it('should use the non default host', () => {
+ l.launch(['Fake'], 'whatever', 1234, '/root/')
+
+ var browser = FakeBrowser._instances.pop()
+ expect(browser.start).to.have.been.calledWith('http://whatever:1234/root/')
+ })
+ })
+
+ describe('restart', () => {
+ it('should restart the browser', () => {
+ l.launch(['Fake'], 'localhost', 1234, '/root/')
+ var browser = FakeBrowser._instances.pop()
+
+ var returnedValue = l.restart(lastGeneratedId)
+ expect(returnedValue).to.equal(true)
+ expect(browser.restart).to.have.been.called
+ })
+
+ it('should return false if the browser was not launched by launcher (manual)', () => {
+ l.launch([], 'localhost', 1234, '/')
+ expect(l.restart('manual-id')).to.equal(false)
+ })
+ })
+
+ describe('kill', () => {
+ it('should kill browser with given id', done => {
+ l.launch(['Fake'])
+ var browser = FakeBrowser._instances.pop()
+
+ l.kill(browser.id, done)
+ expect(browser.forceKill).to.have.been.called
+
+ browser.forceKill.resolve()
+ })
+
+ it('should return false if browser does not exist, but still resolve the callback', done => {
+ l.launch(['Fake'])
+ var browser = FakeBrowser._instances.pop()
+
+ var returnedValue = l.kill('weird-id', done)
+ expect(returnedValue).to.equal(false)
+ expect(browser.forceKill).not.to.have.been.called
+ })
+
+ it('should not require a callback', done => {
+ l.launch(['Fake'])
+ FakeBrowser._instances.pop()
+
+ l.kill('weird-id')
+ process.nextTick(done)
+ })
+ })
+
+ describe('killAll', () => {
+ it('should kill all running processe', () => {
+ l.launch(['Fake', 'Fake'], 'localhost', 1234)
+ l.killAll()
+
+ var browser = FakeBrowser._instances.pop()
+ expect(browser.forceKill).to.have.been.called
+
+ browser = FakeBrowser._instances.pop()
+ expect(browser.forceKill).to.have.been.called
+ })
+
+ it('should call callback when all processes killed', () => {
+ var exitSpy = sinon.spy()
+
+ l.launch(['Fake', 'Fake'], 'localhost', 1234)
+ l.killAll(exitSpy)
+
+ expect(exitSpy).not.to.have.been.called
+
+ // finish the first browser
+ var browser = FakeBrowser._instances.pop()
+ browser.forceKill.resolve()
+
+ scheduleNextTick(() => {
+ expect(exitSpy).not.to.have.been.called
+ })
+
+ scheduleNextTick(() => {
+ // finish the second browser
+ browser = FakeBrowser._instances.pop()
+ browser.forceKill.resolve()
+ })
+
+ scheduleNextTick(() => {
+ expect(exitSpy).to.have.been.called
+ })
+ })
+
+ it('should call callback even if no browsers lanunched', done => {
+ l.killAll(done)
+ })
+ })
+
+ describe('areAllCaptured', () => {
+ it('should return true if only if all browsers captured', () => {
+ l.launch(['Fake', 'Fake'], 'localhost', 1234)
+
+ expect(l.areAllCaptured()).to.equal(false)
+
+ l.markCaptured(1)
+ expect(l.areAllCaptured()).to.equal(false)
+
+ l.markCaptured(2)
+ expect(l.areAllCaptured()).to.equal(true)
+ })
+ })
+
+ describe('onExit', () => {
+ it('should kill all browsers', done => {
+ l.launch(['Fake', 'Fake'], 'localhost', 1234, '/', 0, 1)
+
+ emitter.emitAsync('exit').then(done)
+
+ var browser = FakeBrowser._instances.pop()
+ browser.forceKill.resolve()
+
+ browser = FakeBrowser._instances.pop()
+ browser.forceKill.resolve()
+ })
+ })
+ })
+})
diff --git a/test/unit/launchers/base.spec.coffee b/test/unit/launchers/base.spec.coffee
deleted file mode 100644
index 375e0729c..000000000
--- a/test/unit/launchers/base.spec.coffee
+++ /dev/null
@@ -1,239 +0,0 @@
-describe 'launchers/base.js', ->
- _ = require('../../../lib/helper')._
- BaseLauncher = require '../../../lib/launchers/base'
- EventEmitter = require('../../../lib/events').EventEmitter
- launcher = emitter = null
-
- beforeEach ->
- emitter = new EventEmitter
- launcher = new BaseLauncher 'fake-id', emitter
-
- it 'should manage state', ->
- launcher.start 'http://localhost:9876/'
- expect(launcher.state).to.equal launcher.STATE_BEING_CAPTURED
-
- launcher.markCaptured()
- expect(launcher.state).to.equal launcher.STATE_CAPTURED
- expect(launcher.isCaptured()).to.equal true
-
-
- describe 'start', ->
-
- it 'should fire "start" event and pass url with id', ->
- spyOnStart = sinon.spy()
- launcher.on 'start', spyOnStart
- launcher.start 'http://localhost:9876/'
-
- expect(spyOnStart).to.have.been.calledWith 'http://localhost:9876/?id=fake-id'
-
-
- describe 'restart', ->
-
- it 'should kill running browser and start with previous url', (done) ->
- spyOnStart = sinon.spy()
- spyOnKill = sinon.spy()
- launcher.on 'start', spyOnStart
- launcher.on 'kill', spyOnKill
-
- launcher.start 'http://host:9988/'
- spyOnStart.reset()
-
- launcher.restart()
- expect(spyOnKill).to.have.been.called
- expect(spyOnStart).to.not.have.been.called
-
- # the process (or whatever it is) actually finished
- launcher._done()
- spyOnKill.callArg 0
-
- _.defer ->
- expect(spyOnStart).to.have.been.calledWith 'http://host:9988/?id=fake-id'
- done()
-
-
- it 'should start when already finished (crashed)', (done) ->
- spyOnStart = sinon.spy()
- spyOnKill = sinon.spy()
- spyOnDone = sinon.spy()
- launcher.on 'start', spyOnStart
- launcher.on 'kill', spyOnKill
-
- launcher.on 'done', -> launcher.restart()
- launcher.on 'done', spyOnDone
-
-
- launcher.start 'http://host:9988/'
- spyOnStart.reset()
-
- # simulate crash
- # the first onDone will restart
- launcher._done 'crashed'
-
- _.defer ->
- expect(spyOnKill).to.not.have.been.called
- expect(spyOnStart).to.have.been.called
- expect(spyOnDone).to.have.been.called
- expect(spyOnDone).to.have.been.calledBefore spyOnStart
- done()
-
-
- it 'should not restart when being force killed', (done) ->
- spyOnStart = sinon.spy()
- spyOnKill = sinon.spy()
- launcher.on 'start', spyOnStart
- launcher.on 'kill', spyOnKill
-
-
- launcher.start 'http://host:9988/'
- spyOnStart.reset()
-
- onceKilled = launcher.forceKill()
-
- launcher.restart()
-
- # the process (or whatever it is) actually finished
- launcher._done()
- spyOnKill.callArg 0
-
- onceKilled.done ->
- expect(spyOnStart).to.not.have.been.called
- done()
-
-
- describe 'kill', ->
-
- it 'should manage state', (done) ->
- onceKilled = launcher.kill()
- expect(launcher.state).to.equal launcher.STATE_BEING_KILLED
-
- onceKilled.done ->
- expect(launcher.state).to.equal launcher.STATE_FINISHED
- done()
-
- it 'should fire "kill" and wait for all listeners to finish', (done) ->
- spyOnKill1 = sinon.spy()
- spyOnKill2 = sinon.spy()
- spyKillDone = sinon.spy done
-
- launcher.on 'kill', spyOnKill1
- launcher.on 'kill', spyOnKill2
-
- launcher.start 'http://localhost:9876/'
- launcher.kill().then spyKillDone
- expect(spyOnKill1).to.have.been.called
- expect(spyOnKill2).to.have.been.called
- expect(spyKillDone).to.not.have.been.called
-
- spyOnKill1.callArg 0 # the first listener is done
- expect(spyKillDone).to.not.have.been.called
-
- spyOnKill2.callArg 0 # the second listener is done
-
-
- it 'should not fire "kill" if already killed', (done) ->
- spyOnKill = sinon.spy()
- launcher.on 'kill', spyOnKill
-
- launcher.start 'http://localhost:9876/'
- launcher.kill().then ->
- spyOnKill.reset()
- launcher.kill().then ->
- expect(spyOnKill).to.not.have.been.called
- done()
-
- spyOnKill.callArg 0
-
-
- it 'should not fire "kill" if already being killed, but wait for all listeners', (done) ->
- spyOnKill = sinon.spy()
- launcher.on 'kill', spyOnKill
-
- expectOnKillListenerIsAlreadyFinishedAndHasBeenOnlyCalledOnce = ->
- expect(spyOnKill).to.have.been.called
- expect(spyOnKill.callCount).to.equal 1
- expect(spyOnKill.finished).to.equal true
- expect(launcher.state).to.equal launcher.STATE_FINISHED
-
- launcher.start 'http://localhost:9876/'
- firstKilling = launcher.kill().then ->
- expectOnKillListenerIsAlreadyFinishedAndHasBeenOnlyCalledOnce()
-
- secondKilling = launcher.kill().then ->
- expectOnKillListenerIsAlreadyFinishedAndHasBeenOnlyCalledOnce()
-
- expect(launcher.state).to.equal launcher.STATE_BEING_KILLED
-
- _.defer ->
- spyOnKill.finished = true
- spyOnKill.callArg 0
-
- # finish the test once everything is done
- firstKilling.done -> secondKilling.done -> done()
-
-
- it 'should not kill already crashed browser', (done) ->
- spyOnKill = sinon.spy((killDone) -> killDone())
- launcher.on 'kill', spyOnKill
-
- launcher._done 'crash'
- launcher.kill().done ->
- expect(spyOnKill).to.not.have.been.called
- done()
-
-
- describe 'forceKill', ->
-
- it 'should cancel restart', (done) ->
- spyOnStart = sinon.spy()
- launcher.on 'start', spyOnStart
-
- launcher.start 'http://localhost:9876/'
- spyOnStart.reset()
- launcher.restart()
-
- launcher.forceKill().done ->
- expect(launcher.state).to.equal launcher.STATE_FINISHED
- expect(spyOnStart).to.not.have.been.called
- done()
-
-
- it 'should not fire "browser_process_failure" even if browser crashes', (done) ->
- spyOnBrowserProcessFailure = sinon.spy()
- emitter.on 'browser_process_failure', spyOnBrowserProcessFailure
-
- launcher.on 'kill', (killDone) ->
- _.defer ->
- launcher._done 'crashed'
- killDone()
-
- launcher.start 'http://localhost:9876/'
- launcher.forceKill().done ->
- expect(spyOnBrowserProcessFailure).to.not.have.been.called
- done()
-
-
- describe 'markCaptured', ->
-
- it 'should not mark capture when killing', ->
- launcher.kill()
- launcher.markCaptured()
- expect(launcher.state).to.not.equal launcher.STATE_CAPTURED
-
-
- describe '_done', ->
-
- it 'should emit "browser_process_failure" if there is an error', ->
- spyOnBrowserProcessFailure = sinon.spy()
- emitter.on 'browser_process_failure', spyOnBrowserProcessFailure
-
- launcher._done 'crashed'
- expect(spyOnBrowserProcessFailure).to.have.been.called
- expect(spyOnBrowserProcessFailure).to.have.been.calledWith launcher
-
-
- it 'should not emit "browser_process_failure" when no error happend', ->
- spyOnBrowserProcessFailure = sinon.spy()
- emitter.on 'browser_process_failure', spyOnBrowserProcessFailure
-
- launcher._done()
- expect(spyOnBrowserProcessFailure).not.to.have.been.called
diff --git a/test/unit/launchers/base.spec.js b/test/unit/launchers/base.spec.js
new file mode 100644
index 000000000..427b15b53
--- /dev/null
+++ b/test/unit/launchers/base.spec.js
@@ -0,0 +1,258 @@
+var _ = require('../../../lib/helper')._
+import BaseLauncher from '../../../lib/launchers/base'
+import {EventEmitter} from '../../../lib/events'
+
+describe('launchers/base.js', () => {
+ var emitter
+ var launcher
+
+ beforeEach(() => {
+ emitter = new EventEmitter()
+ launcher = new BaseLauncher('fake-id', emitter)
+ })
+
+ it('should manage state', () => {
+ launcher.start('http://localhost:9876/')
+ expect(launcher.state).to.equal(launcher.STATE_BEING_CAPTURED)
+
+ launcher.markCaptured()
+ expect(launcher.state).to.equal(launcher.STATE_CAPTURED)
+ expect(launcher.isCaptured()).to.equal(true)
+ })
+
+ describe('start', () => {
+ it('should fire "start" event and pass url with id', () => {
+ var spyOnStart = sinon.spy()
+ launcher.on('start', spyOnStart)
+ launcher.start('http://localhost:9876/')
+
+ expect(spyOnStart).to.have.been.calledWith('http://localhost:9876/?id=fake-id')
+ })
+ })
+
+ describe('restart', () => {
+ it('should kill running browser and start with previous url', done => {
+ var spyOnStart = sinon.spy()
+ var spyOnKill = sinon.spy()
+ launcher.on('start', spyOnStart)
+ launcher.on('kill', spyOnKill)
+
+ launcher.start('http://host:9988/')
+ spyOnStart.reset()
+
+ launcher.restart()
+ expect(spyOnKill).to.have.been.called
+ expect(spyOnStart).to.not.have.been.called
+
+ // the process (or whatever it is) actually finished
+ launcher._done()
+ spyOnKill.callArg(0)
+
+ _.defer(() => {
+ expect(spyOnStart).to.have.been.calledWith('http://host:9988/?id=fake-id')
+ done()
+ })
+ })
+
+ it('should start when already finished (crashed)', done => {
+ var spyOnStart = sinon.spy()
+ var spyOnKill = sinon.spy()
+ var spyOnDone = sinon.spy()
+ launcher.on('start', spyOnStart)
+ launcher.on('kill', spyOnKill)
+
+ launcher.on('done', () => launcher.restart())
+ launcher.on('done', spyOnDone)
+
+ launcher.start('http://host:9988/')
+ spyOnStart.reset()
+
+ // simulate crash
+ // the first onDone will restart
+ launcher._done('crashed')
+
+ _.defer(() => {
+ expect(spyOnKill).to.not.have.been.called
+ expect(spyOnStart).to.have.been.called
+ expect(spyOnDone).to.have.been.called
+ expect(spyOnDone).to.have.been.calledBefore(spyOnStart)
+ done()
+ })
+ })
+
+ it('should not restart when being force killed', done => {
+ var spyOnStart = sinon.spy()
+ var spyOnKill = sinon.spy()
+ launcher.on('start', spyOnStart)
+ launcher.on('kill', spyOnKill)
+
+ launcher.start('http://host:9988/')
+ spyOnStart.reset()
+
+ var onceKilled = launcher.forceKill()
+
+ launcher.restart()
+
+ // the process (or whatever it is) actually finished
+ launcher._done()
+ spyOnKill.callArg(0)
+
+ onceKilled.done(() => {
+ expect(spyOnStart).to.not.have.been.called
+ done()
+ })
+ })
+ })
+
+ describe('kill', () => {
+ it('should manage state', done => {
+ var onceKilled = launcher.kill()
+ expect(launcher.state).to.equal(launcher.STATE_BEING_KILLED)
+
+ onceKilled.done(() => {
+ expect(launcher.state).to.equal(launcher.STATE_FINISHED)
+ done()
+ })
+ })
+
+ it('should fire "kill" and wait for all listeners to finish', done => {
+ var spyOnKill1 = sinon.spy()
+ var spyOnKill2 = sinon.spy()
+ var spyKillDone = sinon.spy(done)
+
+ launcher.on('kill', spyOnKill1)
+ launcher.on('kill', spyOnKill2)
+
+ launcher.start('http://localhost:9876/')
+ launcher.kill().then(spyKillDone)
+ expect(spyOnKill1).to.have.been.called
+ expect(spyOnKill2).to.have.been.called
+ expect(spyKillDone).to.not.have.been.called
+
+ spyOnKill1.callArg(0) // the first listener is done
+ expect(spyKillDone).to.not.have.been.called
+
+ spyOnKill2.callArg(0)
+ }) // the second listener is done
+
+ it('should not fire "kill" if already killed', done => {
+ var spyOnKill = sinon.spy()
+ launcher.on('kill', spyOnKill)
+
+ launcher.start('http://localhost:9876/')
+ launcher.kill().then(() => {
+ spyOnKill.reset()
+ launcher.kill().then(() => {
+ expect(spyOnKill).to.not.have.been.called
+ done()
+ })
+ })
+
+ spyOnKill.callArg(0)
+ })
+
+ it('should not fire "kill" if already being killed, but wait for all listeners', done => {
+ var spyOnKill = sinon.spy()
+ launcher.on('kill', spyOnKill)
+
+ var expectOnKillListenerIsAlreadyFinishedAndHasBeenOnlyCalledOnce = () => {
+ expect(spyOnKill).to.have.been.called
+ expect(spyOnKill.callCount).to.equal(1)
+ expect(spyOnKill.finished).to.equal(true)
+ expect(launcher.state).to.equal(launcher.STATE_FINISHED)
+ }
+
+ launcher.start('http://localhost:9876/')
+ var firstKilling = launcher.kill().then(() => {
+ expectOnKillListenerIsAlreadyFinishedAndHasBeenOnlyCalledOnce()
+ })
+
+ var secondKilling = launcher.kill().then(() => {
+ expectOnKillListenerIsAlreadyFinishedAndHasBeenOnlyCalledOnce()
+ })
+
+ expect(launcher.state).to.equal(launcher.STATE_BEING_KILLED)
+
+ _.defer(() => {
+ spyOnKill.finished = true
+ spyOnKill.callArg(0)
+ })
+
+ // finish the test once everything is done
+ firstKilling.done(() => secondKilling.done(() => done()))
+ })
+
+ it('should not kill already crashed browser', done => {
+ var spyOnKill = sinon.spy(killDone => killDone())
+ launcher.on('kill', spyOnKill)
+
+ launcher._done('crash')
+ launcher.kill().done(() => {
+ expect(spyOnKill).to.not.have.been.called
+ done()
+ })
+ })
+ })
+
+ describe('forceKill', () => {
+ it('should cancel restart', done => {
+ var spyOnStart = sinon.spy()
+ launcher.on('start', spyOnStart)
+
+ launcher.start('http://localhost:9876/')
+ spyOnStart.reset()
+ launcher.restart()
+
+ launcher.forceKill().done(() => {
+ expect(launcher.state).to.equal(launcher.STATE_FINISHED)
+ expect(spyOnStart).to.not.have.been.called
+ done()
+ })
+ })
+
+ it('should not fire "browser_process_failure" even if browser crashes', done => {
+ var spyOnBrowserProcessFailure = sinon.spy()
+ emitter.on('browser_process_failure', spyOnBrowserProcessFailure)
+
+ launcher.on('kill', killDone => {
+ _.defer(() => {
+ launcher._done('crashed')
+ killDone()
+ })
+ })
+
+ launcher.start('http://localhost:9876/')
+ launcher.forceKill().done(() => {
+ expect(spyOnBrowserProcessFailure).to.not.have.been.called
+ done()
+ })
+ })
+ })
+
+ describe('markCaptured', () => {
+ it('should not mark capture when killing', () => {
+ launcher.kill()
+ launcher.markCaptured()
+ expect(launcher.state).to.not.equal(launcher.STATE_CAPTURED)
+ })
+ })
+
+ describe('_done', () => {
+ it('should emit "browser_process_failure" if there is an error', () => {
+ var spyOnBrowserProcessFailure = sinon.spy()
+ emitter.on('browser_process_failure', spyOnBrowserProcessFailure)
+
+ launcher._done('crashed')
+ expect(spyOnBrowserProcessFailure).to.have.been.called
+ expect(spyOnBrowserProcessFailure).to.have.been.calledWith(launcher)
+ })
+
+ it('should not emit "browser_process_failure" when no error happend', () => {
+ var spyOnBrowserProcessFailure = sinon.spy()
+ emitter.on('browser_process_failure', spyOnBrowserProcessFailure)
+
+ launcher._done()
+ expect(spyOnBrowserProcessFailure).not.to.have.been.called
+ })
+ })
+})
diff --git a/test/unit/launchers/capture_timeout.spec.coffee b/test/unit/launchers/capture_timeout.spec.coffee
deleted file mode 100644
index 7c2fff81d..000000000
--- a/test/unit/launchers/capture_timeout.spec.coffee
+++ /dev/null
@@ -1,54 +0,0 @@
-describe 'launchers/capture_timeout.js', ->
- BaseLauncher = require '../../../lib/launchers/base'
- CaptureTimeoutLauncher = require '../../../lib/launchers/capture_timeout'
- createMockTimer = require '../mocks/timer'
- launcher = timer = null
-
- beforeEach ->
- timer = createMockTimer()
- launcher = new BaseLauncher 'fake-id'
-
- sinon.spy launcher, 'kill'
-
-
- it 'should kill if not captured in captureTimeout', ->
- CaptureTimeoutLauncher.call launcher, timer, 10
-
- launcher.start()
- timer.wind 20
- expect(launcher.kill).to.have.been.called
-
-
- it 'should not kill if browser got captured', ->
- CaptureTimeoutLauncher.call launcher, timer, 10
-
- launcher.start()
- launcher.markCaptured()
- timer.wind 20
- expect(launcher.kill).not.to.have.been.called
-
-
- it 'should not do anything if captureTimeout = 0', ->
- CaptureTimeoutLauncher.call launcher, timer, 0
-
- launcher.start()
- timer.wind 20
- expect(launcher.kill).not.to.have.been.called
-
-
- it 'should clear timeout between restarts', (done) ->
- CaptureTimeoutLauncher.call launcher, timer, 10
-
- # simulate process finished
- launcher.on 'kill', (onKillDone) ->
- launcher._done()
- onKillDone()
-
- launcher.start()
- timer.wind 8
- launcher.kill().done ->
- launcher.kill.reset()
- launcher.start()
- timer.wind 8
- expect(launcher.kill).not.to.have.been.called
- done()
diff --git a/test/unit/launchers/capture_timeout.spec.js b/test/unit/launchers/capture_timeout.spec.js
new file mode 100644
index 000000000..6b5c41a99
--- /dev/null
+++ b/test/unit/launchers/capture_timeout.spec.js
@@ -0,0 +1,60 @@
+import BaseLauncher from '../../../lib/launchers/base'
+import CaptureTimeoutLauncher from '../../../lib/launchers/capture_timeout'
+import createMockTimer from '../mocks/timer'
+
+describe('launchers/capture_timeout.js', () => {
+ var timer
+ var launcher
+
+ beforeEach(() => {
+ timer = createMockTimer()
+ launcher = new BaseLauncher('fake-id')
+
+ sinon.spy(launcher, 'kill')
+ })
+
+ it('should kill if not captured in captureTimeout', () => {
+ CaptureTimeoutLauncher.call(launcher, timer, 10)
+
+ launcher.start()
+ timer.wind(20)
+ expect(launcher.kill).to.have.been.called
+ })
+
+ it('should not kill if browser got captured', () => {
+ CaptureTimeoutLauncher.call(launcher, timer, 10)
+
+ launcher.start()
+ launcher.markCaptured()
+ timer.wind(20)
+ expect(launcher.kill).not.to.have.been.called
+ })
+
+ it('should not do anything if captureTimeout = 0', () => {
+ CaptureTimeoutLauncher.call(launcher, timer, 0)
+
+ launcher.start()
+ timer.wind(20)
+ expect(launcher.kill).not.to.have.been.called
+ })
+
+ it('should clear timeout between restarts', done => {
+ CaptureTimeoutLauncher.call(launcher, timer, 10)
+
+ // simulate process finished
+ launcher.on('kill', onKillDone => {
+ launcher._done()
+ onKillDone()
+ })
+
+ launcher.start()
+ timer.wind(8)
+ launcher.kill().done(() => {
+ launcher.kill.reset()
+ launcher.start()
+ timer.wind(8)
+ expect(launcher.kill).not.to.have.been.called
+ done()
+ })
+ })
+})
diff --git a/test/unit/launchers/process.spec.coffee b/test/unit/launchers/process.spec.coffee
deleted file mode 100644
index d0d232d36..000000000
--- a/test/unit/launchers/process.spec.coffee
+++ /dev/null
@@ -1,225 +0,0 @@
-describe 'launchers/process.js', ->
- path = require 'path'
- _ = require('../../../lib/helper')._
- BaseLauncher = require '../../../lib/launchers/base'
- RetryLauncher = require '../../../lib/launchers/retry'
- CaptureTimeoutLauncher = require '../../../lib/launchers/capture_timeout'
- ProcessLauncher = require '../../../lib/launchers/process'
- EventEmitter = require('../../../lib/events').EventEmitter
- createMockTimer = require '../mocks/timer'
- launcher = timer = emitter = mockSpawn = mockTempDir = null
-
- BROWSER_PATH = path.normalize '/usr/bin/browser'
-
- beforeEach ->
- emitter = new EventEmitter
- launcher = new BaseLauncher 'fake-id', emitter
-
- mockSpawn = sinon.spy (cmd, args) ->
- process = new EventEmitter
- process.stderr = new EventEmitter
- process.kill = sinon.spy()
- process.exitCode = null
- mockSpawn._processes.push process
- process
- mockSpawn._processes = []
-
- mockTempDir =
- getPath: (suffix) -> '/temp' + suffix
- create: sinon.spy()
- remove: sinon.spy()
-
- it 'should create a temp directory', ->
- ProcessLauncher.call launcher, mockSpawn, mockTempDir
- launcher._getCommand = -> null
-
- launcher.start 'http://host:9988/'
- expect(launcher._tempDir).to.equal '/temp/karma-fake-id'
- expect(mockTempDir.create).to.have.been.calledWith '/temp/karma-fake-id'
-
-
- it 'should remove the temp directory', (done) ->
- ProcessLauncher.call launcher, mockSpawn, mockTempDir
- launcher._getCommand = -> null
-
- launcher.start 'http://host:9988/'
- launcher.kill()
-
- _.defer ->
- expect(mockTempDir.remove).to.have.been.called
- expect(mockTempDir.remove.args[0][0]).to.equal '/temp/karma-fake-id'
- done()
-
-
- describe '_normalizeCommand', ->
- it 'should remove quotes from the cmd', ->
- ProcessLauncher.call launcher, null, mockTempDir
-
- expect(launcher._normalizeCommand '"/bin/brow ser"').to.equal path.normalize('/bin/brow ser')
- expect(launcher._normalizeCommand '\'/bin/brow ser\'').to.equal
- path.normalize('/bin/brow ser')
- expect(launcher._normalizeCommand '`/bin/brow ser`').to.equal path.normalize('/bin/brow ser')
-
-
- describe 'with RetryLauncher', ->
- it 'should handle spawn ENOENT error and not even retry', (done) ->
- ProcessLauncher.call launcher, mockSpawn, mockTempDir
- RetryLauncher.call launcher, 2
- launcher._getCommand = -> BROWSER_PATH
-
- failureSpy = sinon.spy()
- emitter.on 'browser_process_failure', failureSpy
-
- launcher.start 'http://host:9876/'
- mockSpawn._processes[0].emit 'error', {code: 'ENOENT'}
- mockSpawn._processes[0].emit 'exit', 1
- mockTempDir.remove.callArg 1
-
- _.defer ->
- expect(launcher.state).to.equal launcher.STATE_FINISHED
- expect(failureSpy).to.have.been.called
- done()
-
-
- # higher level tests with Retry and CaptureTimeout launchers
- describe 'flow', ->
- mockTimer = failureSpy = null
-
- beforeEach ->
- mockTimer = createMockTimer()
- CaptureTimeoutLauncher.call launcher, mockTimer, 100
- ProcessLauncher.call launcher, mockSpawn, mockTempDir, mockTimer
- RetryLauncher.call launcher, 2
-
- launcher._getCommand = -> BROWSER_PATH
-
- failureSpy = sinon.spy()
- emitter.on 'browser_process_failure', failureSpy
-
-
- # the most common scenario, when everything works fine
- it 'start -> capture -> kill', (done) ->
- # start the browser
- launcher.start 'http://localhost/'
- expect(mockSpawn).to.have.been.calledWith BROWSER_PATH, ['http://localhost/?id=fake-id']
-
- # mark captured
- launcher.markCaptured()
-
- # kill it
- killingLauncher = launcher.kill()
- expect(launcher.state).to.equal launcher.STATE_BEING_KILLED
- expect(mockSpawn._processes[0].kill).to.have.been.called
-
- # process exits
- mockSpawn._processes[0].emit 'exit', 0
- mockTempDir.remove.callArg 1
-
- killingLauncher.done ->
- expect(launcher.state).to.equal launcher.STATE_FINISHED
- done()
-
-
- # when the browser fails to get captured in given timeout, it should restart
- it 'start -> timeout -> restart', (done) ->
- # start
- launcher.start 'http://localhost/'
-
- # expect starting the process
- expect(mockSpawn).to.have.been.calledWith BROWSER_PATH, ['http://localhost/?id=fake-id']
- browserProcess = mockSpawn._processes.shift()
-
- # timeout
- mockTimer.wind 101
-
- # expect killing browser
- expect(browserProcess.kill).to.have.been.called
- browserProcess.emit 'exit', 0
- mockTempDir.remove.callArg 1
- mockSpawn.reset()
-
- _.defer -> _.delay ->
- # expect re-starting
- expect(mockSpawn).to.have.been.calledWith BROWSER_PATH, ['http://localhost/?id=fake-id']
- expect(failureSpy).not.to.have.been.called
- done()
- , 100
-
- it 'start -> timeout -> 3xrestart -> failure', (done) ->
- # start
- launcher.start 'http://localhost/'
-
- # expect starting
- expect(mockSpawn).to.have.been.calledWith BROWSER_PATH, ['http://localhost/?id=fake-id']
- browserProcess = mockSpawn._processes.shift()
- mockSpawn.reset()
-
- # timeout - first time
- mockTimer.wind 101
-
- # expect killing browser
- expect(browserProcess.kill).to.have.been.called
- browserProcess.emit 'exit', 0
- mockTempDir.remove.callArg 1
- mockTempDir.remove.reset()
-
- _.defer ->
- # expect re-starting
- expect(mockSpawn).to.have.been.calledWith BROWSER_PATH, ['http://localhost/?id=fake-id']
- browserProcess = mockSpawn._processes.shift()
- expect(failureSpy).not.to.have.been.called
- mockSpawn.reset()
-
- # timeout - second time
- mockTimer.wind 101
-
- # expect killing browser
- expect(browserProcess.kill).to.have.been.called
- browserProcess.emit 'exit', 0
- mockTempDir.remove.callArg 1
- mockTempDir.remove.reset()
-
- _.defer ->
- # expect re-starting
- expect(mockSpawn).to.have.been.calledWith BROWSER_PATH, ['http://localhost/?id=fake-id']
- browserProcess = mockSpawn._processes.shift()
- expect(failureSpy).not.to.have.been.called
- mockSpawn.reset()
-
- # timeout - third time
- mockTimer.wind 201
-
- # expect killing browser
- expect(browserProcess.kill).to.have.been.called
- browserProcess.emit 'exit', 0
- mockTempDir.remove.callArg 1
- mockTempDir.remove.reset()
-
- _.defer ->
- expect(mockSpawn).to.not.have.been.called
- expect(failureSpy).to.have.been.called
- done()
-
-
- # when the browser fails to start, it should restart
- it 'start -> crash -> restart', (done) ->
- # start
- launcher.start 'http://localhost/'
-
- # expect starting the process
- expect(mockSpawn).to.have.been.calledWith BROWSER_PATH, ['http://localhost/?id=fake-id']
- browserProcess = mockSpawn._processes.shift()
- mockSpawn.reset()
-
- # crash
- browserProcess.emit 'exit', 1
- mockTempDir.remove.callArg 1
- mockTempDir.remove.reset()
-
- _.defer ->
- # expect re-starting
- expect(mockSpawn).to.have.been.calledWith BROWSER_PATH, ['http://localhost/?id=fake-id']
- browserProcess = mockSpawn._processes.shift()
-
- expect(failureSpy).not.to.have.been.called
- done()
diff --git a/test/unit/launchers/process.spec.js b/test/unit/launchers/process.spec.js
new file mode 100644
index 000000000..9c5e90456
--- /dev/null
+++ b/test/unit/launchers/process.spec.js
@@ -0,0 +1,247 @@
+import path from 'path'
+var _ = require('../../../lib/helper')._
+import BaseLauncher from '../../../lib/launchers/base'
+import RetryLauncher from '../../../lib/launchers/retry'
+import CaptureTimeoutLauncher from '../../../lib/launchers/capture_timeout'
+import ProcessLauncher from '../../../lib/launchers/process'
+import {EventEmitter} from '../../../lib/events'
+import createMockTimer from '../mocks/timer'
+
+describe('launchers/process.js', () => {
+ var emitter
+ var mockSpawn
+ var mockTempDir
+ var launcher
+
+ var BROWSER_PATH = path.normalize('/usr/bin/browser')
+
+ beforeEach(() => {
+ emitter = new EventEmitter()
+ launcher = new BaseLauncher('fake-id', emitter)
+
+ mockSpawn = sinon.spy(function (cmd, args) {
+ var process = new EventEmitter()
+ process.stderr = new EventEmitter()
+ process.kill = sinon.spy()
+ process.exitCode = null
+ mockSpawn._processes.push(process)
+ return process
+ })
+
+ mockSpawn._processes = []
+
+ mockTempDir = {
+ getPath: suffix => `/temp${suffix}`,
+ create: sinon.spy(),
+ remove: sinon.spy()
+ }
+ })
+
+ it('should create a temp directory', () => {
+ ProcessLauncher.call(launcher, mockSpawn, mockTempDir)
+ launcher._getCommand = () => null
+
+ launcher.start('http://host:9988/')
+ expect(launcher._tempDir).to.equal('/temp/karma-fake-id')
+ expect(mockTempDir.create).to.have.been.calledWith('/temp/karma-fake-id')
+ })
+
+ it('should remove the temp directory', (done) => {
+ ProcessLauncher.call(launcher, mockSpawn, mockTempDir)
+ launcher._getCommand = () => null
+
+ launcher.start('http://host:9988/')
+ launcher.kill()
+
+ _.defer(() => {
+ expect(mockTempDir.remove).to.have.been.called
+ expect(mockTempDir.remove.args[0][0]).to.equal('/temp/karma-fake-id')
+ done()
+ })
+ })
+
+ describe('_normalizeCommand', () => {
+ it('should remove quotes from the cmd', () => {
+ ProcessLauncher.call(launcher, null, mockTempDir)
+
+ expect(launcher._normalizeCommand('"/bin/brow ser"')).to.equal(path.normalize('/bin/brow ser'))
+ expect(launcher._normalizeCommand("'/bin/brow ser'")).to.equal
+ path.normalize('/bin/brow ser')
+ expect(launcher._normalizeCommand('`/bin/brow ser`')).to.equal(path.normalize('/bin/brow ser'))
+ })
+ })
+
+ describe('with RetryLauncher', () => {
+ it('should handle spawn ENOENT error and not even retry', (done) => {
+ ProcessLauncher.call(launcher, mockSpawn, mockTempDir)
+ RetryLauncher.call(launcher, 2)
+ launcher._getCommand = () => BROWSER_PATH
+
+ var failureSpy = sinon.spy()
+ emitter.on('browser_process_failure', failureSpy)
+
+ launcher.start('http://host:9876/')
+ mockSpawn._processes[0].emit('error', {code: 'ENOENT'})
+ mockSpawn._processes[0].emit('exit', 1)
+ mockTempDir.remove.callArg(1)
+
+ _.defer(() => {
+ expect(launcher.state).to.equal(launcher.STATE_FINISHED)
+ expect(failureSpy).to.have.been.called
+ done()
+ })
+ })
+ })
+
+ // higher level tests with Retry and CaptureTimeout launchers
+ describe('flow', () => {
+ var failureSpy
+ var mockTimer = failureSpy = null
+
+ beforeEach(() => {
+ mockTimer = createMockTimer()
+ CaptureTimeoutLauncher.call(launcher, mockTimer, 100)
+ ProcessLauncher.call(launcher, mockSpawn, mockTempDir, mockTimer)
+ RetryLauncher.call(launcher, 2)
+
+ launcher._getCommand = () => BROWSER_PATH
+
+ failureSpy = sinon.spy()
+ emitter.on('browser_process_failure', failureSpy)
+ })
+
+ // the most common scenario, when everything works fine
+ it('start -> capture -> kill', (done) => {
+ // start the browser
+ launcher.start('http://localhost/')
+ expect(mockSpawn).to.have.been.calledWith(BROWSER_PATH, ['http://localhost/?id=fake-id'])
+
+ // mark captured
+ launcher.markCaptured()
+
+ // kill it
+ var killingLauncher = launcher.kill()
+ expect(launcher.state).to.equal(launcher.STATE_BEING_KILLED)
+ expect(mockSpawn._processes[0].kill).to.have.been.called
+
+ // process exits
+ mockSpawn._processes[0].emit('exit', 0)
+ mockTempDir.remove.callArg(1)
+
+ killingLauncher.done(() => {
+ expect(launcher.state).to.equal(launcher.STATE_FINISHED)
+ done()
+ })
+ })
+
+ // when the browser fails to get captured in given timeout, it should restart
+ it('start -> timeout -> restart', (done) => {
+ // start
+ launcher.start('http://localhost/')
+
+ // expect starting the process
+ expect(mockSpawn).to.have.been.calledWith(BROWSER_PATH, ['http://localhost/?id=fake-id'])
+ var browserProcess = mockSpawn._processes.shift()
+
+ // timeout
+ mockTimer.wind(101)
+
+ // expect killing browser
+ expect(browserProcess.kill).to.have.been.called
+ browserProcess.emit('exit', 0)
+ mockTempDir.remove.callArg(1)
+ mockSpawn.reset()
+
+ _.defer(() => _.delay(() => {
+ // expect re-starting
+ expect(mockSpawn).to.have.been.calledWith(BROWSER_PATH, ['http://localhost/?id=fake-id'])
+ expect(failureSpy).not.to.have.been.called
+ done()
+ }, 100))
+ })
+
+ it('start -> timeout -> 3xrestart -> failure', (done) => {
+ // start
+ launcher.start('http://localhost/')
+
+ // expect starting
+ expect(mockSpawn).to.have.been.calledWith(BROWSER_PATH, ['http://localhost/?id=fake-id'])
+ var browserProcess = mockSpawn._processes.shift()
+ mockSpawn.reset()
+
+ // timeout - first time
+ mockTimer.wind(101)
+
+ // expect killing browser
+ expect(browserProcess.kill).to.have.been.called
+ browserProcess.emit('exit', 0)
+ mockTempDir.remove.callArg(1)
+ mockTempDir.remove.reset()
+
+ _.defer(() => {
+ // expect re-starting
+ expect(mockSpawn).to.have.been.calledWith(BROWSER_PATH, ['http://localhost/?id=fake-id'])
+ browserProcess = mockSpawn._processes.shift()
+ expect(failureSpy).not.to.have.been.called
+ mockSpawn.reset()
+
+ // timeout - second time
+ mockTimer.wind(101)
+
+ // expect killing browser
+ expect(browserProcess.kill).to.have.been.called
+ browserProcess.emit('exit', 0)
+ mockTempDir.remove.callArg(1)
+ mockTempDir.remove.reset()
+
+ _.defer(() => {
+ // expect re-starting
+ expect(mockSpawn).to.have.been.calledWith(BROWSER_PATH, ['http://localhost/?id=fake-id'])
+ browserProcess = mockSpawn._processes.shift()
+ expect(failureSpy).not.to.have.been.called
+ mockSpawn.reset()
+
+ // timeout - third time
+ mockTimer.wind(201)
+
+ // expect killing browser
+ expect(browserProcess.kill).to.have.been.called
+ browserProcess.emit('exit', 0)
+ mockTempDir.remove.callArg(1)
+ mockTempDir.remove.reset()
+
+ _.defer(() => {
+ expect(mockSpawn).to.not.have.been.called
+ expect(failureSpy).to.have.been.called
+ done()
+ })
+ })
+ })
+ })
+
+ // when the browser fails to start, it should restart
+ it('start -> crash -> restart', (done) => {
+ // start
+ launcher.start('http://localhost/')
+
+ // expect starting the process
+ expect(mockSpawn).to.have.been.calledWith(BROWSER_PATH, ['http://localhost/?id=fake-id'])
+ var browserProcess = mockSpawn._processes.shift()
+ mockSpawn.reset()
+
+ // crash
+ browserProcess.emit('exit', 1)
+ mockTempDir.remove.callArg(1)
+ mockTempDir.remove.reset()
+
+ _.defer(() => {
+ // expect re-starting
+ expect(mockSpawn).to.have.been.calledWith(BROWSER_PATH, ['http://localhost/?id=fake-id'])
+ browserProcess = mockSpawn._processes.shift()
+
+ expect(failureSpy).not.to.have.been.called
+ done()
+ })
+ })
+ })
+})
diff --git a/test/unit/launchers/retry.spec.coffee b/test/unit/launchers/retry.spec.coffee
deleted file mode 100644
index 90fd0843d..000000000
--- a/test/unit/launchers/retry.spec.coffee
+++ /dev/null
@@ -1,83 +0,0 @@
-describe 'launchers/retry.js', ->
- _ = require('../../../lib/helper')._
- BaseLauncher = require '../../../lib/launchers/base'
- RetryLauncher = require '../../../lib/launchers/retry'
- EventEmitter = require('../../../lib/events').EventEmitter
- createMockTimer = require '../mocks/timer'
- launcher = timer = emitter = null
-
- beforeEach ->
- timer = createMockTimer()
- emitter = new EventEmitter
- launcher = new BaseLauncher 'fake-id', emitter
-
-
- it 'should restart if browser crashed', (done) ->
- RetryLauncher.call launcher, 2
-
- launcher.start 'http://localhost:9876'
-
- sinon.spy launcher, 'start'
- spyOnBrowserProcessFailure = sinon.spy()
- emitter.on 'browser_process_failure', spyOnBrowserProcessFailure
-
- # simulate crash
- launcher._done 'crash'
-
- _.defer ->
- expect(launcher.start).to.have.been.called
- expect(spyOnBrowserProcessFailure).not.to.have.been.called
- done()
-
-
- it 'should eventually fail with "browser_process_failure"', (done) ->
- RetryLauncher.call launcher, 2
-
- launcher.start 'http://localhost:9876'
-
- sinon.spy launcher, 'start'
- spyOnBrowserProcessFailure = sinon.spy()
- emitter.on 'browser_process_failure', spyOnBrowserProcessFailure
-
- # simulate first crash
- launcher._done 'crash'
-
- _.defer ->
- expect(launcher.start).to.have.been.called
- expect(spyOnBrowserProcessFailure).not.to.have.been.called
- launcher.start.reset()
-
- # simulate second crash
- launcher._done 'crash'
-
- _.defer ->
- expect(launcher.start).to.have.been.called
- expect(spyOnBrowserProcessFailure).not.to.have.been.called
- launcher.start.reset()
-
- # simulate third crash
- launcher._done 'crash'
-
- _.defer ->
- expect(launcher.start).not.to.have.been.called
- expect(spyOnBrowserProcessFailure).to.have.been.called
- done()
-
-
- it 'should not restart if killed normally', (done) ->
- RetryLauncher.call launcher, 2
-
- launcher.start 'http://localhost:9876'
-
- sinon.spy launcher, 'start'
- spyOnBrowserProcessFailure = sinon.spy()
- emitter.on 'browser_process_failure', spyOnBrowserProcessFailure
-
- # process just exited normally
- launcher._done()
-
- _.defer ->
- expect(launcher.start).not.to.have.been.called
- expect(spyOnBrowserProcessFailure).not.to.have.been.called
- expect(launcher.state).to.equal launcher.STATE_FINISHED
- done()
diff --git a/test/unit/launchers/retry.spec.js b/test/unit/launchers/retry.spec.js
new file mode 100644
index 000000000..b7cb609a1
--- /dev/null
+++ b/test/unit/launchers/retry.spec.js
@@ -0,0 +1,90 @@
+var _ = require('../../../lib/helper')._
+import BaseLauncher from '../../../lib/launchers/base'
+import RetryLauncher from '../../../lib/launchers/retry'
+import {EventEmitter} from '../../../lib/events'
+
+describe('launchers/retry.js', () => {
+ var emitter
+ var launcher
+
+ beforeEach(() => {
+ emitter = new EventEmitter()
+ launcher = new BaseLauncher('fake-id', emitter)
+ })
+
+ it('should restart if browser crashed', (done) => {
+ RetryLauncher.call(launcher, 2)
+
+ launcher.start('http://localhost:9876')
+
+ sinon.spy(launcher, 'start')
+ var spyOnBrowserProcessFailure = sinon.spy()
+ emitter.on('browser_process_failure', spyOnBrowserProcessFailure)
+
+ // simulate crash
+ launcher._done('crash')
+
+ _.defer(() => {
+ expect(launcher.start).to.have.been.called
+ expect(spyOnBrowserProcessFailure).not.to.have.been.called
+ done()
+ })
+ })
+
+ it('should eventually fail with "browser_process_failure"', (done) => {
+ RetryLauncher.call(launcher, 2)
+
+ launcher.start('http://localhost:9876')
+
+ sinon.spy(launcher, 'start')
+ var spyOnBrowserProcessFailure = sinon.spy()
+ emitter.on('browser_process_failure', spyOnBrowserProcessFailure)
+
+ // simulate first crash
+ launcher._done('crash')
+
+ _.defer(() => {
+ expect(launcher.start).to.have.been.called
+ expect(spyOnBrowserProcessFailure).not.to.have.been.called
+ launcher.start.reset()
+
+ // simulate second crash
+ launcher._done('crash')
+
+ _.defer(() => {
+ expect(launcher.start).to.have.been.called
+ expect(spyOnBrowserProcessFailure).not.to.have.been.called
+ launcher.start.reset()
+
+ // simulate third crash
+ launcher._done('crash')
+
+ _.defer(() => {
+ expect(launcher.start).not.to.have.been.called
+ expect(spyOnBrowserProcessFailure).to.have.been.called
+ done()
+ })
+ })
+ })
+ })
+
+ it('should not restart if killed normally', (done) => {
+ RetryLauncher.call(launcher, 2)
+
+ launcher.start('http://localhost:9876')
+
+ sinon.spy(launcher, 'start')
+ var spyOnBrowserProcessFailure = sinon.spy()
+ emitter.on('browser_process_failure', spyOnBrowserProcessFailure)
+
+ // process just exited normally
+ launcher._done()
+
+ _.defer(() => {
+ expect(launcher.start).not.to.have.been.called
+ expect(spyOnBrowserProcessFailure).not.to.have.been.called
+ expect(launcher.state).to.equal(launcher.STATE_FINISHED)
+ done()
+ })
+ })
+})
diff --git a/test/unit/logger.spec.coffee b/test/unit/logger.spec.coffee
deleted file mode 100644
index 9b91e5763..000000000
--- a/test/unit/logger.spec.coffee
+++ /dev/null
@@ -1,22 +0,0 @@
-#==============================================================================
-# lib/logger.js module
-#==============================================================================
-
-describe 'logger', ->
- loadFile = require('mocks').loadFile
- logSpy = m = null
- beforeEach ->
- logSpy = sinon.spy()
- m = loadFile __dirname + '/../../lib/logger.js'
-
- #============================================================================
- # setup()
- #============================================================================
- describe 'setup', ->
- it 'should allow for configuration via setup() using an array', ->
- m.setup 'INFO', true, [
- type: 'file'
- filename: 'test/unit/test.log'
- ]
-
- expect(m.log4js.appenders).to.have.keys ['console', 'file']
diff --git a/test/unit/logger.spec.js b/test/unit/logger.spec.js
new file mode 100644
index 000000000..a4516b96e
--- /dev/null
+++ b/test/unit/logger.spec.js
@@ -0,0 +1,20 @@
+import {loadFile} from 'mocks'
+
+describe('logger', () => {
+ var m
+
+ beforeEach(() => {
+ m = loadFile(__dirname + '/../../lib/logger.js')
+ })
+
+ describe('setup', () => {
+ it('should allow for configuration via setup() using an array', () => {
+ m.setup('INFO', true, [{
+ type: 'file',
+ filename: 'test/unit/test.log'
+ }])
+
+ expect(m.log4js.appenders).to.have.keys(['console', 'file'])
+ })
+ })
+})
diff --git a/test/unit/middleware/karma.spec.coffee b/test/unit/middleware/karma.spec.coffee
deleted file mode 100644
index 029796e0f..000000000
--- a/test/unit/middleware/karma.spec.coffee
+++ /dev/null
@@ -1,369 +0,0 @@
-describe 'middleware.karma', ->
- helper = require '../../../lib/helper'
- constants = require '../../../lib/constants'
-
- mocks = require 'mocks'
- HttpResponseMock = mocks.http.ServerResponse
- HttpRequestMock = mocks.http.ServerRequest
-
- File = require('../../../lib/file')
- Url = require('../../../lib/url')
-
- MockFile = (path, sha) ->
- File.call @, path
- @sha = sha or 'sha-default'
-
- fsMock = mocks.fs.create
- karma:
- static:
- 'client.html': mocks.fs.file(0, 'CLIENT HTML\n%X_UA_COMPATIBLE%%X_UA_COMPATIBLE_URL%')
- 'context.html': mocks.fs.file(0, 'CONTEXT\n%SCRIPTS%')
- 'debug.html': mocks.fs.file(0, 'DEBUG\n%SCRIPTS%\n%X_UA_COMPATIBLE%')
- 'karma.js': mocks.fs.file(0, 'root: %KARMA_URL_ROOT%, v: %KARMA_VERSION%')
-
- createServeFile = require('../../../lib/middleware/common').createServeFile
- createKarmaMiddleware = require('../../../lib/middleware/karma').create
-
- handler = serveFile = filesDeferred = nextSpy = response = null
-
- beforeEach ->
- clientConfig = foo: 'bar'
- nextSpy = sinon.spy()
- response = new HttpResponseMock
- filesDeferred = helper.defer()
- serveFile = createServeFile fsMock, '/karma/static'
- handler = createKarmaMiddleware filesDeferred.promise, serveFile,
- '/base/path', '/__karma__/', clientConfig
-
- # helpers
- includedFiles = (files) ->
- filesDeferred.resolve {included: files, served: []}
-
- servedFiles = (files) ->
- filesDeferred.resolve {included: [], served: files}
-
- normalizedHttpRequest = (urlPath) ->
- req = new HttpRequestMock(urlPath)
- req.normalizedUrl = req.url
- return req
-
- callHandlerWith = (urlPath, next) ->
- promise = handler normalizedHttpRequest(urlPath), response, next or nextSpy
- if promise and promise.done then promise.done()
-
-
- it 'should redirect urlRoot without trailing slash', (done) ->
- response.once 'end', ->
- expect(nextSpy).not.to.have.been.called
- expect(response).to.beServedAs 301, 'MOVED PERMANENTLY'
- expect(response._headers['Location']).to.equal '/__karma__/'
- done()
-
- callHandlerWith '/__karma__'
-
-
- it 'should not serve outside of urlRoot', ->
- handler normalizedHttpRequest('/'), null, nextSpy
- expect(nextSpy).to.have.been.called
- nextSpy.reset()
-
- handler normalizedHttpRequest('/client.html'), null, nextSpy
- expect(nextSpy).to.have.been.called
- nextSpy.reset()
-
- handler normalizedHttpRequest('/debug.html'), null, nextSpy
- expect(nextSpy).to.have.been.called
- nextSpy.reset()
-
- handler normalizedHttpRequest('/context.html'), null, nextSpy
- expect(nextSpy).to.have.been.called
-
-
- it 'should serve client.html', (done) ->
- handler = createKarmaMiddleware null, serveFile, '/base', '/'
-
- response.once 'end', ->
- expect(nextSpy).not.to.have.been.called
- expect(response).to.beServedAs 200, 'CLIENT HTML'
- done()
-
- callHandlerWith '/'
-
-
- it 'should serve /?id=xxx', (done) ->
- handler = createKarmaMiddleware null, serveFile, '/base', '/'
-
- response.once 'end', ->
- expect(nextSpy).not.to.have.been.called
- expect(response).to.beServedAs 200, 'CLIENT HTML'
- done()
-
- callHandlerWith '/?id=123'
-
- it 'should serve /?x-ua-compatible with replaced values', (done) ->
- handler = createKarmaMiddleware null, serveFile, '/base', '/'
-
- response.once 'end', ->
- expect(nextSpy).not.to.have.been.called
- expect(response).to.beServedAs 200,
- 'CLIENT HTML\n' +
- '?x-ua-compatible=xxx%3Dyyy'
- done()
-
- callHandlerWith '/?x-ua-compatible=xxx%3Dyyy'
-
- it 'should serve debug.html/?x-ua-compatible with replaced values', (done) ->
- includedFiles []
-
- response.once 'end', ->
- expect(nextSpy).not.to.have.been.called
- expect(response).to.beServedAs 200,
- 'DEBUG\n\n'
- done()
-
- callHandlerWith '/__karma__/debug.html?x-ua-compatible=xxx%3Dyyy'
-
- it 'should serve karma.js with version and urlRoot variables', (done) ->
- response.once 'end', ->
- expect(nextSpy).not.to.have.been.called
- expect(response).to.beServedAs 200, 'root: /__karma__/, v: ' + constants.VERSION
- expect(response._headers['Content-Type']).to.equal 'application/javascript'
- done()
-
- callHandlerWith '/__karma__/karma.js'
-
-
- it 'should serve context.html with replaced script tags', (done) ->
- includedFiles [
- new MockFile('/first.js', 'sha123')
- new MockFile('/second.dart', 'sha456')
- ]
-
- response.once 'end', ->
- expect(nextSpy).not.to.have.been.called
- expect(response).to.beServedAs 200, 'CONTEXT\n' +
- '\n' +
- ''
- done()
-
- callHandlerWith '/__karma__/context.html'
-
-
- it 'should serve context.html with replaced link tags', (done) ->
- includedFiles [
- new MockFile('/first.css', 'sha007')
- new MockFile('/second.html', 'sha678')
- ]
-
- response.once 'end', ->
- expect(nextSpy).not.to.have.been.called
- expect(response).to.beServedAs 200, 'CONTEXT\n' +
- '\n' +
- ''
- done()
-
- callHandlerWith '/__karma__/context.html'
-
- it 'should serve context.html with the correct path for the script tags', (done) ->
- includedFiles [
- new MockFile('/some/abc/a.js', 'sha')
- new MockFile('/base/path/b.js', 'shaaa')
- ]
-
- response.once 'end', ->
- expect(nextSpy).not.to.have.been.called
- expect(response).to.beServedAs 200, 'CONTEXT\n' +
- '\n' +
- ''
- done()
-
- callHandlerWith '/__karma__/context.html'
-
-
- it 'should serve context.html with the correct path for link tags', (done) ->
- includedFiles [
- new MockFile('/some/abc/a.css', 'sha1')
- new MockFile('/base/path/b.css', 'sha2')
- new MockFile('/some/abc/c.html', 'sha3')
- new MockFile('/base/path/d.html', 'sha4')
- ]
-
- response.once 'end', ->
- expect(nextSpy).not.to.have.been.called
- expect(response).to.beServedAs 200, 'CONTEXT\n' +
- '\n' +
- '\n' +
- '\n' +
- ''
- done()
-
- callHandlerWith '/__karma__/context.html'
-
- it 'should serve context.json with the correct paths for all files', (done) ->
- includedFiles [
- new MockFile('/some/abc/a.css', 'sha1')
- new MockFile('/base/path/b.css', 'sha2')
- new MockFile('/some/abc/c.html', 'sha3')
- new MockFile('/base/path/d.html', 'sha4')
- ]
-
- response.once 'end', ->
- expect(nextSpy).not.to.have.been.called
- expect(response).to.beServedAs 200, JSON.stringify {
- files: [
- '/__karma__/absolute/some/abc/a.css?sha1',
- '/__karma__/base/b.css?sha2',
- '/__karma__/absolute/some/abc/c.html?sha3',
- '/__karma__/base/d.html?sha4'
- ]
- }
- done()
-
- callHandlerWith '/__karma__/context.json'
-
-
- it 'should not change urls', (done) ->
- includedFiles [
- new Url('http://some.url.com/whatever')
- ]
-
- response.once 'end', ->
- expect(response).to.beServedAs 200, 'CONTEXT\n' +
- ''
- done()
-
- callHandlerWith '/__karma__/context.html'
-
-
- it 'should send non-caching headers for context.html', (done) ->
- ZERO_DATE = (new Date 0).toString()
-
- includedFiles []
-
- response.once 'end', ->
- expect(nextSpy).not.to.have.been.called
- expect(response._headers['Cache-Control']).to.equal 'no-cache'
- # idiotic IE8 needs more
- expect(response._headers['Pragma']).to.equal 'no-cache'
- expect(response._headers['Expires']).to.equal ZERO_DATE
- done()
-
- callHandlerWith '/__karma__/context.html'
-
-
- it 'should inline mappings with all served files', (done) ->
- fsMock._touchFile '/karma/static/context.html', 0, '%MAPPINGS%'
- servedFiles [
- new MockFile('/some/abc/a.js', 'sha_a')
- new MockFile('/base/path/b.js', 'sha_b')
- new MockFile('\\windows\\path\\uuu\\c.js', 'sha_c')
- ]
-
- response.once 'end', ->
- expect(response).to.beServedAs 200, 'window.__karma__.files = {\n' +
- " '/__karma__/absolute/some/abc/a.js': 'sha_a',\n" +
- " '/__karma__/base/b.js': 'sha_b',\n" +
- " '/__karma__/absolute\\\\windows\\\\path\\\\uuu\\\\c.js': 'sha_c'\n" +
- "};\n"
- done()
-
- callHandlerWith '/__karma__/context.html'
-
-
- it 'should serve debug.html with replaced script tags without timestamps', (done) ->
- includedFiles [
- new MockFile('/first.js')
- new MockFile('/base/path/b.js')
- ]
-
- response.once 'end', ->
- expect(nextSpy).not.to.have.been.called
- expect(response).to.beServedAs 200, 'DEBUG\n' +
- '\n' +
- ''
- done()
-
- callHandlerWith '/__karma__/debug.html'
-
-
- it 'should serve debug.html with replaced link tags without timestamps', (done) ->
- includedFiles [
- new MockFile('/first.css')
- new MockFile('/base/path/b.css')
- new MockFile('/second.html')
- new MockFile('/base/path/d.html')
- ]
-
- response.once 'end', ->
- expect(nextSpy).not.to.have.been.called
- expect(response).to.beServedAs 200, 'DEBUG\n' +
- '\n' +
- '\n' +
- '\n' +
- ''
- done()
-
- callHandlerWith '/__karma__/debug.html'
-
-
- it 'should inline client config to debug.html', (done) ->
- includedFiles [
- new MockFile('/first.js')
- ]
- fsMock._touchFile '/karma/static/debug.html', 1, '%CLIENT_CONFIG%'
-
- response.once 'end', ->
- expect(response).to.beServedAs 200, 'window.__karma__.config = {"foo":"bar"};\n'
- done()
-
- callHandlerWith '/__karma__/debug.html'
-
-
- it 'should not serve other files even if they are in urlRoot', (done) ->
- includedFiles []
-
- callHandlerWith '/__karma__/something/else.js', ->
- expect(response).to.beNotServed()
- done()
-
-
-
-
-
-
-
- # it 'should invoke custom handler', (done) ->
- # response.once 'end', ->
- # expect(nextSpy).not.to.have.been.called
- # expect(response.statusCode).to.equal 200
- # expect(response._content.toString()).to.equal 'Hello World'
- # done()
-
- # customHandler =
- # urlRegex: /\/test/,
- # handler: (request, response, staticFolder, adapterFolder, baseFolder, urlRoot) ->
- # response.end 'Hello World'
-
- # karmaSrcHandler = m.createKarmaSourceHandler promiseContainer, staticFolderPath,
- # adapterFolderPath, baseFolder, '/_karma_/', [customHandler], []
- # karmaSrcHandler new httpMock.ServerRequest('/_karma_/test'), response, nextSpy
-
-
- # it 'should set custom script type', (done) ->
- # mocks.fs._touchFile '/karma/static/context.html', 0, 'CONTEXT\n%SCRIPTS%'
- # includedFiles [{path: 'http://some.url.com/whatever.blah', isUrl: true}]
-
- # response.once 'end', ->
- # expect(response._content.toString()).to.equal 'CONTEXT\n' +
- # ''
- # expect(response.statusCode).to.equal 200
- # done()
-
- # customScriptType =
- # extension: 'blah',
- # contentType: 'application/blah'
-
- # karmaSrcHandler = m.createKarmaSourceHandler promiseContainer, staticFolderPath,
- # adapterFolderPath, baseFolder, '/_karma_/', [], [customScriptType]
-
- # karmaSrcHandler new httpMock.ServerRequest('/_karma_/context.html'), response, nextSpy
diff --git a/test/unit/middleware/karma.spec.js b/test/unit/middleware/karma.spec.js
new file mode 100644
index 000000000..841fe8a4f
--- /dev/null
+++ b/test/unit/middleware/karma.spec.js
@@ -0,0 +1,339 @@
+import helper from '../../../lib/helper'
+import constants from '../../../lib/constants'
+import File from '../../../lib/file'
+import Url from '../../../lib/url'
+import mocks from 'mocks'
+
+var HttpResponseMock = mocks.http.ServerResponse
+var HttpRequestMock = mocks.http.ServerRequest
+
+describe('middleware.karma', () => {
+ var serveFile
+ var filesDeferred
+ var nextSpy
+ var response
+
+ var MockFile = function (path, sha) {
+ File.call(this, path)
+ this.sha = sha || 'sha-default'
+ }
+
+ var fsMock = mocks.fs.create({
+ karma: {
+ static: {
+ 'client.html': mocks.fs.file(0, 'CLIENT HTML\n%X_UA_COMPATIBLE%%X_UA_COMPATIBLE_URL%'),
+ 'context.html': mocks.fs.file(0, 'CONTEXT\n%SCRIPTS%'),
+ 'debug.html': mocks.fs.file(0, 'DEBUG\n%SCRIPTS%\n%X_UA_COMPATIBLE%'),
+ 'karma.js': mocks.fs.file(0, 'root: %KARMA_URL_ROOT%, v: %KARMA_VERSION%')
+ }
+ }
+ })
+
+ var createServeFile = require('../../../lib/middleware/common').createServeFile
+ var createKarmaMiddleware = require('../../../lib/middleware/karma').create
+
+ var handler = serveFile = filesDeferred = nextSpy = response = null
+
+ beforeEach(() => {
+ var clientConfig = {foo: 'bar'}
+ nextSpy = sinon.spy()
+ response = new HttpResponseMock()
+ filesDeferred = helper.defer()
+ serveFile = createServeFile(fsMock, '/karma/static')
+ handler = createKarmaMiddleware(filesDeferred.promise, serveFile, '/base/path', '/__karma__/', clientConfig)
+ })
+
+ // helpers
+ var includedFiles = (files) => {
+ return filesDeferred.resolve({included: files, served: []})
+ }
+
+ var servedFiles = (files) => {
+ return filesDeferred.resolve({included: [], served: files})
+ }
+
+ var normalizedHttpRequest = (urlPath) => {
+ var req = new HttpRequestMock(urlPath)
+ req.normalizedUrl = req.url
+ return req
+ }
+
+ var callHandlerWith = function (urlPath, next) {
+ var promise = handler(normalizedHttpRequest(urlPath), response, next || nextSpy)
+ if (promise && promise.done) promise.done()
+ }
+
+ it('should redirect urlRoot without trailing slash', (done) => {
+ response.once('end', () => {
+ expect(nextSpy).not.to.have.been.called
+ expect(response).to.beServedAs(301, 'MOVED PERMANENTLY')
+ expect(response._headers['Location']).to.equal('/__karma__/')
+ done()
+ })
+
+ callHandlerWith('/__karma__')
+ })
+
+ it('should not serve outside of urlRoot', () => {
+ handler(normalizedHttpRequest('/'), null, nextSpy)
+ expect(nextSpy).to.have.been.called
+ nextSpy.reset()
+
+ handler(normalizedHttpRequest('/client.html'), null, nextSpy)
+ expect(nextSpy).to.have.been.called
+ nextSpy.reset()
+
+ handler(normalizedHttpRequest('/debug.html'), null, nextSpy)
+ expect(nextSpy).to.have.been.called
+ nextSpy.reset()
+
+ handler(normalizedHttpRequest('/context.html'), null, nextSpy)
+ expect(nextSpy).to.have.been.called
+ })
+
+ it('should serve client.html', (done) => {
+ handler = createKarmaMiddleware(null, serveFile, '/base', '/')
+
+ response.once('end', () => {
+ expect(nextSpy).not.to.have.been.called
+ expect(response).to.beServedAs(200, 'CLIENT HTML')
+ done()
+ })
+
+ callHandlerWith('/')
+ })
+
+ it('should serve /?id=xxx', (done) => {
+ handler = createKarmaMiddleware(null, serveFile, '/base', '/')
+
+ response.once('end', () => {
+ expect(nextSpy).not.to.have.been.called
+ expect(response).to.beServedAs(200, 'CLIENT HTML')
+ done()
+ })
+
+ callHandlerWith('/?id=123')
+ })
+
+ it('should serve /?x-ua-compatible with replaced values', (done) => {
+ handler = createKarmaMiddleware(null, serveFile, '/base', '/')
+
+ response.once('end', () => {
+ expect(nextSpy).not.to.have.been.called
+ expect(response).to.beServedAs(200, 'CLIENT HTML\n?x-ua-compatible=xxx%3Dyyy')
+ done()
+ })
+
+ callHandlerWith('/?x-ua-compatible=xxx%3Dyyy')
+ })
+
+ it('should serve debug.html/?x-ua-compatible with replaced values', (done) => {
+ includedFiles([])
+
+ response.once('end', () => {
+ expect(nextSpy).not.to.have.been.called
+ expect(response).to.beServedAs(200, 'DEBUG\n\n')
+ done()
+ })
+
+ callHandlerWith('/__karma__/debug.html?x-ua-compatible=xxx%3Dyyy')
+ })
+
+ it('should serve karma.js with version and urlRoot variables', (done) => {
+ response.once('end', () => {
+ expect(nextSpy).not.to.have.been.called
+ expect(response).to.beServedAs(200, 'root: /__karma__/, v: ' + constants.VERSION)
+ expect(response._headers['Content-Type']).to.equal('application/javascript')
+ done()
+ })
+
+ callHandlerWith('/__karma__/karma.js')
+ })
+
+ it('should serve context.html with replaced script tags', (done) => {
+ includedFiles([
+ new MockFile('/first.js', 'sha123'),
+ new MockFile('/second.dart', 'sha456')
+ ])
+
+ response.once('end', () => {
+ expect(nextSpy).not.to.have.been.called
+ expect(response).to.beServedAs(200, 'CONTEXT\n\n')
+ done()
+ })
+
+ callHandlerWith('/__karma__/context.html')
+ })
+
+ it('should serve context.html with replaced link tags', (done) => {
+ includedFiles([
+ new MockFile('/first.css', 'sha007'),
+ new MockFile('/second.html', 'sha678')
+ ])
+
+ response.once('end', () => {
+ expect(nextSpy).not.to.have.been.called
+ expect(response).to.beServedAs(200, 'CONTEXT\n\n')
+ done()
+ })
+
+ callHandlerWith('/__karma__/context.html')
+ })
+
+ it('should serve context.html with the correct path for the script tags', (done) => {
+ includedFiles([
+ new MockFile('/some/abc/a.js', 'sha'),
+ new MockFile('/base/path/b.js', 'shaaa')
+ ])
+
+ response.once('end', () => {
+ expect(nextSpy).not.to.have.been.called
+ expect(response).to.beServedAs(200, 'CONTEXT\n\n')
+ done()
+ })
+
+ callHandlerWith('/__karma__/context.html')
+ })
+
+ it('should serve context.html with the correct path for link tags', (done) => {
+ includedFiles([
+ new MockFile('/some/abc/a.css', 'sha1'),
+ new MockFile('/base/path/b.css', 'sha2'),
+ new MockFile('/some/abc/c.html', 'sha3'),
+ new MockFile('/base/path/d.html', 'sha4')
+ ])
+
+ response.once('end', () => {
+ expect(nextSpy).not.to.have.been.called
+ expect(response).to.beServedAs(200, 'CONTEXT\n\n\n\n')
+ done()
+ })
+
+ callHandlerWith('/__karma__/context.html')
+ })
+
+ it('should serve context.json with the correct paths for all files', (done) => {
+ includedFiles([
+ new MockFile('/some/abc/a.css', 'sha1'),
+ new MockFile('/base/path/b.css', 'sha2'),
+ new MockFile('/some/abc/c.html', 'sha3'),
+ new MockFile('/base/path/d.html', 'sha4')
+ ])
+
+ response.once('end', () => {
+ expect(nextSpy).not.to.have.been.called
+ expect(response).to.beServedAs(200, JSON.stringify({
+ files: [
+ '/__karma__/absolute/some/abc/a.css?sha1',
+ '/__karma__/base/b.css?sha2',
+ '/__karma__/absolute/some/abc/c.html?sha3',
+ '/__karma__/base/d.html?sha4'
+ ]
+ }))
+ done()
+ })
+
+ callHandlerWith('/__karma__/context.json')
+ })
+
+ it('should not change urls', (done) => {
+ includedFiles([
+ new Url('http://some.url.com/whatever')
+ ])
+
+ response.once('end', () => {
+ expect(response).to.beServedAs(200, 'CONTEXT\n')
+ done()
+ })
+
+ callHandlerWith('/__karma__/context.html')
+ })
+
+ it('should send non-caching headers for context.html', (done) => {
+ var ZERO_DATE = (new Date(0)).toString()
+
+ includedFiles([])
+
+ response.once('end', () => {
+ expect(nextSpy).not.to.have.been.called
+ expect(response._headers['Cache-Control']).to.equal('no-cache')
+ // idiotic IE8 needs more
+ expect(response._headers['Pragma']).to.equal('no-cache')
+ expect(response._headers['Expires']).to.equal(ZERO_DATE)
+ done()
+ })
+
+ callHandlerWith('/__karma__/context.html')
+ })
+
+ it('should inline mappings with all served files', (done) => {
+ fsMock._touchFile('/karma/static/context.html', 0, '%MAPPINGS%')
+ servedFiles([
+ new MockFile('/some/abc/a.js', 'sha_a'),
+ new MockFile('/base/path/b.js', 'sha_b'),
+ new MockFile('\\windows\\path\\uuu\\c.js', 'sha_c')
+ ])
+
+ response.once('end', () => {
+ expect(response).to.beServedAs(200, "window.__karma__.files = {\n '/__karma__/absolute/some/abc/a.js': 'sha_a',\n '/__karma__/base/b.js': 'sha_b',\n '/__karma__/absolute\\\\windows\\\\path\\\\uuu\\\\c.js': 'sha_c'\n};\n")
+ done()
+ })
+
+ callHandlerWith('/__karma__/context.html')
+ })
+
+ it('should serve debug.html with replaced script tags without timestamps', (done) => {
+ includedFiles([
+ new MockFile('/first.js'),
+ new MockFile('/base/path/b.js')
+ ])
+
+ response.once('end', () => {
+ expect(nextSpy).not.to.have.been.called
+ expect(response).to.beServedAs(200, 'DEBUG\n\n')
+ done()
+ })
+
+ callHandlerWith('/__karma__/debug.html')
+ })
+
+ it('should serve debug.html with replaced link tags without timestamps', (done) => {
+ includedFiles([
+ new MockFile('/first.css'),
+ new MockFile('/base/path/b.css'),
+ new MockFile('/second.html'),
+ new MockFile('/base/path/d.html')
+ ])
+
+ response.once('end', () => {
+ expect(nextSpy).not.to.have.been.called
+ expect(response).to.beServedAs(200, 'DEBUG\n\n\n\n')
+ done()
+ })
+
+ callHandlerWith('/__karma__/debug.html')
+ })
+
+ it('should inline client config to debug.html', (done) => {
+ includedFiles([
+ new MockFile('/first.js')
+ ])
+ fsMock._touchFile('/karma/static/debug.html', 1, '%CLIENT_CONFIG%')
+
+ response.once('end', () => {
+ expect(response).to.beServedAs(200, 'window.__karma__.config = {"foo":"bar"};\n')
+ done()
+ })
+
+ callHandlerWith('/__karma__/debug.html')
+ })
+
+ it('should not serve other files even if they are in urlRoot', (done) => {
+ includedFiles([])
+
+ callHandlerWith('/__karma__/something/else.js', () => {
+ expect(response).to.beNotServed()
+ done()
+ })
+ })
+})
diff --git a/test/unit/middleware/proxy.spec.coffee b/test/unit/middleware/proxy.spec.coffee
deleted file mode 100644
index 5c9e80ea3..000000000
--- a/test/unit/middleware/proxy.spec.coffee
+++ /dev/null
@@ -1,263 +0,0 @@
-#==============================================================================
-# lib/proxy.js module
-#==============================================================================
-describe 'middleware.proxy', ->
- httpMock = require('mocks').http
- loadFile = require('mocks').loadFile
-
- actualOptions = requestedUrl = response = nextSpy = type = null
-
- m = loadFile __dirname + '/../../../lib/middleware/proxy.js'
-
- mockProxies = [{
- path: '/proxy',
- baseUrl: '',
- host: 'localhost',
- port: '9000',
- proxy: {
- web: (req, res) ->
- type = 'web'
- requestedUrl = req.url
- res.writeHead 200
- res.end 'DONE'
- ws: (req, socket, head) ->
- type = 'ws'
- requestedUrl = req.url
- }
- }, {
- path: '/static',
- baseUrl: '',
- host: 'gstatic.com',
- port: '80',
- proxy: {
- web: (req, res) ->
- type = 'web'
- requestedUrl = req.url
- res.writeHead 200
- res.end 'DONE'
- ws: (req, socket, head) ->
- type = 'ws'
- requestedUrl = req.url
- }
- }, {
- path: '/sub/some',
- baseUrl: '/something',
- host: 'gstatic.com',
- port: '80',
- proxy: {
- web: (req, res) ->
- type = 'web'
- requestedUrl = req.url
- res.writeHead 200
- res.end 'DONE'
- ws: (req, socket, head) ->
- type = 'ws'
- requestedUrl = req.url
- }
- }, {
- path: '/sub',
- baseUrl: '',
- host: 'localhost',
- port: '9000',
- proxy: {
- web: (req, res) ->
- type = 'web'
- requestedUrl = req.url
- res.writeHead 200
- res.end 'DONE'
- ws: (req, socket, head) ->
- type = 'ws'
- requestedUrl = req.url
- }
- }]
-
- beforeEach ->
- actualOptions = {}
- requestedUrl = ''
- type = ''
- response = new httpMock.ServerResponse
- nextSpy = sinon.spy()
-
-
- it 'should proxy requests', (done) ->
- proxy = m.createProxyHandler mockProxies, true, '/', {}
- proxy new httpMock.ServerRequest('/proxy/test.html'), response, nextSpy
-
- expect(nextSpy).not.to.have.been.called
- expect(requestedUrl).to.equal '/test.html'
- expect(type).to.equal 'web'
- done()
-
- it 'should proxy websocket requests', (done) ->
- proxy = m.createProxyHandler mockProxies, true, '/', {}
- proxy.upgrade new httpMock.ServerRequest('/proxy/test.html'), response, nextSpy
-
- expect(nextSpy).not.to.have.been.called
- expect(requestedUrl).to.equal '/test.html'
- expect(type).to.equal 'ws'
- done()
-
- it 'should support multiple proxies', ->
- proxy = m.createProxyHandler mockProxies, true, '/', {}
- proxy new httpMock.ServerRequest('/static/test.html'), response, nextSpy
-
- expect(nextSpy).not.to.have.been.called
- expect(requestedUrl).to.equal '/test.html'
- expect(type).to.equal 'web'
-
- it 'should handle nested proxies', ->
- proxy = m.createProxyHandler mockProxies, true, '/', {}
- proxy new httpMock.ServerRequest('/sub/some/Test.html'), response, nextSpy
-
- expect(nextSpy).not.to.have.been.called
- expect(requestedUrl).to.equal '/something/Test.html'
- expect(type).to.equal 'web'
-
-
- it 'should call next handler if the path is not proxied', ->
- proxy = m.createProxyHandler mockProxies, true, '/', {}
- proxy new httpMock.ServerRequest('/non/proxy/test.html'), response, nextSpy
-
- expect(nextSpy).to.have.been.called
-
-
- it 'should call next handler if no proxy defined', ->
- proxy = m.createProxyHandler {}, true, '/', {}
- proxy new httpMock.ServerRequest('/non/proxy/test.html'), response, nextSpy
-
- expect(nextSpy).to.have.been.called
-
-
- it 'should parse a simple proxy config', ->
- proxy = {'/base/': 'http://localhost:8000/'}
- parsedProxyConfig = m.parseProxyConfig proxy, {}
- expect(parsedProxyConfig).to.have.length 1
- expect(parsedProxyConfig[0]).to.containSubset {
- host: 'localhost',
- port: '8000',
- baseUrl: '/',
- path: '/base/',
- https: false
- }
- expect(parsedProxyConfig[0].proxy).to.exist
-
- it 'should set defualt http port', ->
- proxy = {'/base/': 'http://localhost/'}
- parsedProxyConfig = m.parseProxyConfig proxy, {}
- expect(parsedProxyConfig).to.have.length 1
- expect(parsedProxyConfig[0]).to.containSubset {
- host: 'localhost',
- port: '80',
- baseUrl: '/',
- path: '/base/',
- https: false
- }
- expect(parsedProxyConfig[0].proxy).to.exist
-
- it 'should set defualt https port', ->
- proxy = {'/base/': 'https://localhost/'}
- parsedProxyConfig = m.parseProxyConfig proxy, {}
- expect(parsedProxyConfig).to.have.length 1
- expect(parsedProxyConfig[0]).to.containSubset {
- host: 'localhost',
- port: '443',
- baseUrl: '/',
- path: '/base/',
- https: true
- }
- expect(parsedProxyConfig[0].proxy).to.exist
-
-
- it 'should handle proxy configs with paths', ->
- proxy = {'/base': 'http://localhost:8000/proxy'}
- parsedProxyConfig = m.parseProxyConfig proxy, {}
- expect(parsedProxyConfig).to.have.length 1
- expect(parsedProxyConfig[0]).to.containSubset {
- host: 'localhost',
- port: '8000',
- baseUrl: '/proxy',
- path: '/base',
- https: false
- }
- expect(parsedProxyConfig[0].proxy).to.exist
-
- it 'should determine protocol', ->
- proxy = {'/base':'https://localhost:8000'}
- parsedProxyConfig = m.parseProxyConfig proxy, {}
- expect(parsedProxyConfig).to.have.length 1
- expect(parsedProxyConfig[0]).to.containSubset {
- host: 'localhost',
- port: '8000',
- baseUrl: '',
- path: '/base',
- https: true
- }
- expect(parsedProxyConfig[0].proxy).to.exist
-
- it 'should handle proxy configs with only basepaths', ->
- proxy = {'/base': '/proxy/test'}
- config = {port: 9877, hostname: 'localhost'}
- parsedProxyConfig = m.parseProxyConfig proxy, config
- expect(parsedProxyConfig).to.have.length 1
- expect(parsedProxyConfig[0]).to.containSubset {
- host: 'localhost',
- port: 9877,
- baseUrl: '/proxy/test',
- path: '/base',
- https: false
- }
- expect(parsedProxyConfig[0].proxy).to.exist
-
- it 'should normalize proxy url with only basepaths', ->
- proxy = {'/base/': '/proxy/test'}
- config = {port: 9877, hostname: 'localhost'}
- parsedProxyConfig = m.parseProxyConfig proxy, config
- expect(parsedProxyConfig).to.have.length 1
- expect(parsedProxyConfig[0]).to.containSubset {
- host: 'localhost',
- port: 9877,
- baseUrl: '/proxy/test/',
- path: '/base/',
- https: false
- }
- expect(parsedProxyConfig[0].proxy).to.exist
-
- it 'should normalize proxy url', ->
- proxy = {'/base/': 'http://localhost:8000/proxy/test'}
- parsedProxyConfig = m.parseProxyConfig proxy, {}
- expect(parsedProxyConfig).to.have.length 1
- expect(parsedProxyConfig[0]).to.containSubset {
- host: 'localhost',
- port: '8000',
- baseUrl: '/proxy/test/',
- path: '/base/',
- https: false
- }
- expect(parsedProxyConfig[0].proxy).to.exist
-
- it 'should parse nested proxy config', ->
- proxy = {
- '/sub': 'http://localhost:9000'
- '/sub/some': 'http://gstatic.com/something'
- }
- parsedProxyConfig = m.parseProxyConfig proxy, {}
- expect(parsedProxyConfig).to.have.length 2
- expect(parsedProxyConfig[0]).to.containSubset {
- host: 'gstatic.com',
- port: '80',
- baseUrl: '/something',
- path: '/sub/some',
- https: false
- }
- expect(parsedProxyConfig[0].proxy).to.exist
- expect(parsedProxyConfig[1]).to.containSubset {
- host: 'localhost',
- port: '9000',
- baseUrl: '',
- path: '/sub',
- https: false
- }
- expect(parsedProxyConfig[1].proxy).to.exist
-
- it 'should handle empty proxy config', ->
- expect(m.parseProxyConfig {}).to.deep.equal([])
diff --git a/test/unit/middleware/proxy.spec.js b/test/unit/middleware/proxy.spec.js
new file mode 100644
index 000000000..d44961128
--- /dev/null
+++ b/test/unit/middleware/proxy.spec.js
@@ -0,0 +1,283 @@
+var httpMock = require('mocks').http
+var loadFile = require('mocks').loadFile
+
+describe('middleware.proxy', () => {
+ var requestedUrl
+ var response
+ var nextSpy
+ var type
+
+ var m = loadFile(__dirname + '/../../../lib/middleware/proxy.js')
+
+ var mockProxies = [{
+ path: '/proxy',
+ baseUrl: '',
+ host: 'localhost',
+ port: '9000',
+ proxy: {
+ web: function (req, res) {
+ type = 'web'
+ requestedUrl = req.url
+ res.writeHead(200)
+ res.end('DONE')
+ },
+ ws: function (req, socket, head) {
+ type = 'ws'
+ requestedUrl = req.url
+ }
+ }
+ }, {
+ path: '/static',
+ baseUrl: '',
+ host: 'gstatic.com',
+ port: '80',
+ proxy: {
+ web: function (req, res) {
+ type = 'web'
+ requestedUrl = req.url
+ res.writeHead(200)
+ res.end('DONE')
+ },
+ ws: function (req, socket, head) {
+ type = 'ws'
+ requestedUrl = req.url
+ }
+ }
+ }, {
+ path: '/sub/some',
+ baseUrl: '/something',
+ host: 'gstatic.com',
+ port: '80',
+ proxy: {
+ web: function (req, res) {
+ type = 'web'
+ requestedUrl = req.url
+ res.writeHead(200)
+ res.end('DONE')
+ },
+ ws: function (req, socket, head) {
+ type = 'ws'
+ requestedUrl = req.url
+ }
+ }
+ }, {
+ path: '/sub',
+ baseUrl: '',
+ host: 'localhost',
+ port: '9000',
+ proxy: {
+ web: function (req, res) {
+ type = 'web'
+ requestedUrl = req.url
+ res.writeHead(200)
+ res.end('DONE')
+ },
+ ws: function (req, socket, head) {
+ type = 'ws'
+ requestedUrl = req.url
+ }
+ }
+ }]
+
+ beforeEach(() => {
+ requestedUrl = ''
+ type = ''
+ response = new httpMock.ServerResponse()
+ nextSpy = sinon.spy()
+ })
+
+ it('should proxy requests', (done) => {
+ var proxy = m.createProxyHandler(mockProxies, true, '/', {})
+ proxy(new httpMock.ServerRequest('/proxy/test.html'), response, nextSpy)
+
+ expect(nextSpy).not.to.have.been.called
+ expect(requestedUrl).to.equal('/test.html')
+ expect(type).to.equal('web')
+ done()
+ })
+
+ it('should proxy websocket requests', (done) => {
+ var proxy = m.createProxyHandler(mockProxies, true, '/', {})
+ proxy.upgrade(new httpMock.ServerRequest('/proxy/test.html'), response, nextSpy)
+
+ expect(nextSpy).not.to.have.been.called
+ expect(requestedUrl).to.equal('/test.html')
+ expect(type).to.equal('ws')
+ done()
+ })
+
+ it('should support multiple proxies', () => {
+ var proxy = m.createProxyHandler(mockProxies, true, '/', {})
+ proxy(new httpMock.ServerRequest('/static/test.html'), response, nextSpy)
+
+ expect(nextSpy).not.to.have.been.called
+ expect(requestedUrl).to.equal('/test.html')
+ expect(type).to.equal('web')
+ })
+
+ it('should handle nested proxies', () => {
+ var proxy = m.createProxyHandler(mockProxies, true, '/', {})
+ proxy(new httpMock.ServerRequest('/sub/some/Test.html'), response, nextSpy)
+
+ expect(nextSpy).not.to.have.been.called
+ expect(requestedUrl).to.equal('/something/Test.html')
+ expect(type).to.equal('web')
+ })
+
+ it('should call next handler if the path is not proxied', () => {
+ var proxy = m.createProxyHandler(mockProxies, true, '/', {})
+ proxy(new httpMock.ServerRequest('/non/proxy/test.html'), response, nextSpy)
+
+ expect(nextSpy).to.have.been.called
+ })
+
+ it('should call next handler if no proxy defined', () => {
+ var proxy = m.createProxyHandler({}, true, '/', {})
+ proxy(new httpMock.ServerRequest('/non/proxy/test.html'), response, nextSpy)
+
+ expect(nextSpy).to.have.been.called
+ })
+
+ it('should parse a simple proxy config', () => {
+ var proxy = {'/base/': 'http://localhost:8000/'}
+ var parsedProxyConfig = m.parseProxyConfig(proxy, {})
+ expect(parsedProxyConfig).to.have.length(1)
+ expect(parsedProxyConfig[0]).to.containSubset({
+ host: 'localhost',
+ port: '8000',
+ baseUrl: '/',
+ path: '/base/',
+ https: false
+ })
+ expect(parsedProxyConfig[0].proxy).to.exist
+ })
+
+ it('should set defualt http port', () => {
+ var proxy = {'/base/': 'http://localhost/'}
+ var parsedProxyConfig = m.parseProxyConfig(proxy, {})
+ expect(parsedProxyConfig).to.have.length(1)
+ expect(parsedProxyConfig[0]).to.containSubset({
+ host: 'localhost',
+ port: '80',
+ baseUrl: '/',
+ path: '/base/',
+ https: false
+ })
+ expect(parsedProxyConfig[0].proxy).to.exist
+ })
+
+ it('should set defualt https port', () => {
+ var proxy = {'/base/': 'https://localhost/'}
+ var parsedProxyConfig = m.parseProxyConfig(proxy, {})
+ expect(parsedProxyConfig).to.have.length(1)
+ expect(parsedProxyConfig[0]).to.containSubset({
+ host: 'localhost',
+ port: '443',
+ baseUrl: '/',
+ path: '/base/',
+ https: true
+ })
+ expect(parsedProxyConfig[0].proxy).to.exist
+ })
+
+ it('should handle proxy configs with paths', () => {
+ var proxy = {'/base': 'http://localhost:8000/proxy'}
+ var parsedProxyConfig = m.parseProxyConfig(proxy, {})
+ expect(parsedProxyConfig).to.have.length(1)
+ expect(parsedProxyConfig[0]).to.containSubset({
+ host: 'localhost',
+ port: '8000',
+ baseUrl: '/proxy',
+ path: '/base',
+ https: false
+ })
+ expect(parsedProxyConfig[0].proxy).to.exist
+ })
+
+ it('should determine protocol', () => {
+ var proxy = {'/base': 'https://localhost:8000'}
+ var parsedProxyConfig = m.parseProxyConfig(proxy, {})
+ expect(parsedProxyConfig).to.have.length(1)
+ expect(parsedProxyConfig[0]).to.containSubset({
+ host: 'localhost',
+ port: '8000',
+ baseUrl: '',
+ path: '/base',
+ https: true
+ })
+ expect(parsedProxyConfig[0].proxy).to.exist
+ })
+
+ it('should handle proxy configs with only basepaths', () => {
+ var proxy = {'/base': '/proxy/test'}
+ var config = {port: 9877, hostname: 'localhost'}
+ var parsedProxyConfig = m.parseProxyConfig(proxy, config)
+ expect(parsedProxyConfig).to.have.length(1)
+ expect(parsedProxyConfig[0]).to.containSubset({
+ host: 'localhost',
+ port: 9877,
+ baseUrl: '/proxy/test',
+ path: '/base',
+ https: false
+ })
+ expect(parsedProxyConfig[0].proxy).to.exist
+ })
+
+ it('should normalize proxy url with only basepaths', () => {
+ var proxy = {'/base/': '/proxy/test'}
+ var config = {port: 9877, hostname: 'localhost'}
+ var parsedProxyConfig = m.parseProxyConfig(proxy, config)
+ expect(parsedProxyConfig).to.have.length(1)
+ expect(parsedProxyConfig[0]).to.containSubset({
+ host: 'localhost',
+ port: 9877,
+ baseUrl: '/proxy/test/',
+ path: '/base/',
+ https: false
+ })
+ expect(parsedProxyConfig[0].proxy).to.exist
+ })
+
+ it('should normalize proxy url', () => {
+ var proxy = {'/base/': 'http://localhost:8000/proxy/test'}
+ var parsedProxyConfig = m.parseProxyConfig(proxy, {})
+ expect(parsedProxyConfig).to.have.length(1)
+ expect(parsedProxyConfig[0]).to.containSubset({
+ host: 'localhost',
+ port: '8000',
+ baseUrl: '/proxy/test/',
+ path: '/base/',
+ https: false
+ })
+ expect(parsedProxyConfig[0].proxy).to.exist
+ })
+
+ it('should parse nested proxy config', () => {
+ var proxy = {
+ '/sub': 'http://localhost:9000',
+ '/sub/some': 'http://gstatic.com/something'
+ }
+ var parsedProxyConfig = m.parseProxyConfig(proxy, {})
+ expect(parsedProxyConfig).to.have.length(2)
+ expect(parsedProxyConfig[0]).to.containSubset({
+ host: 'gstatic.com',
+ port: '80',
+ baseUrl: '/something',
+ path: '/sub/some',
+ https: false
+ })
+ expect(parsedProxyConfig[0].proxy).to.exist
+ expect(parsedProxyConfig[1]).to.containSubset({
+ host: 'localhost',
+ port: '9000',
+ baseUrl: '',
+ path: '/sub',
+ https: false
+ })
+ expect(parsedProxyConfig[1].proxy).to.exist
+ })
+
+ it('should handle empty proxy config', () => {
+ expect(m.parseProxyConfig({})).to.deep.equal([])
+ })
+})
diff --git a/test/unit/middleware/runner.spec.coffee b/test/unit/middleware/runner.spec.coffee
deleted file mode 100644
index 6b851aeb3..000000000
--- a/test/unit/middleware/runner.spec.coffee
+++ /dev/null
@@ -1,192 +0,0 @@
-describe 'middleware.runner', ->
-
- mocks = require 'mocks'
- HttpResponseMock = mocks.http.ServerResponse
- HttpRequestMock = mocks.http.ServerRequest
-
- path = require('path')
- EventEmitter = require('events').EventEmitter
- Browser = require '../../../lib/browser'
- BrowserCollection = require '../../../lib/browser_collection'
- MultReporter = require('../../../lib/reporters/multi')
- createRunnerMiddleware = require('../../../lib/middleware/runner').create
- Promise = require('bluebird')
-
- handler = nextSpy = response = mockReporter = capturedBrowsers = emitter = config = null
- fileListMock = executor = null
-
- beforeEach ->
- mockReporter =
- adapters: []
- write: (msg) -> @adapters.forEach (adapter) -> adapter msg
-
- executor =
- schedule: -> emitter.emit 'run_start'
-
- emitter = new EventEmitter
- capturedBrowsers = new BrowserCollection emitter
- fileListMock =
- refresh: -> Promise.resolve(null)
- addFile: -> null
- removeFile: -> null
- changeFile: -> null
-
- nextSpy = sinon.spy()
- response = new HttpResponseMock
- config = {client: {}, basePath: '/'}
-
- handler = createRunnerMiddleware emitter, fileListMock, capturedBrowsers,
- new MultReporter([mockReporter]), executor, 'localhost', 8877, '/', config
-
-
- it 'should trigger test run and stream the reporter', (done) ->
- capturedBrowsers.add new Browser
- sinon.stub capturedBrowsers, 'areAllReady', -> true
-
- response.once 'end', ->
- expect(nextSpy).to.not.have.been.called
- expect(response).to.beServedAs 200, 'result\x1FEXIT0'
- done()
-
- handler new HttpRequestMock('/__run__'), response, nextSpy
-
- # Wrap this in a setTimeout so the fileListPromise has time to resolve.
- setTimeout( ->
- mockReporter.write 'result'
- emitter.emit 'run_complete', capturedBrowsers, {exitCode: 0}
- , 2)
-
-
- it 'should not run if there is no browser captured', (done) ->
- sinon.stub fileListMock, 'refresh'
-
- response.once 'end', ->
- expect(nextSpy).to.not.have.been.called
- expect(response).to.beServedAs 200, 'No captured browser, open http://localhost:8877/\n'
- expect(fileListMock.refresh).not.to.have.been.called
- done()
-
- handler new HttpRequestMock('/__run__'), response, nextSpy
-
-
- it 'should parse body and set client.args', (done) ->
- capturedBrowsers.add new Browser
- sinon.stub capturedBrowsers, 'areAllReady', -> true
-
- emitter.once 'run_start', ->
- expect(config.client.args).to.deep.equal ['arg1', 'arg2']
- done()
-
- RAW_MESSAGE = '{"args": ["arg1", "arg2"]}'
-
- request = new HttpRequestMock '/__run__', {
- 'content-type': 'application/json'
- 'content-length': RAW_MESSAGE.length
- }
-
- handler request, response, nextSpy
-
- request.emit 'data', RAW_MESSAGE
- request.emit 'end'
-
-
- it 'should refresh explicit files if specified', (done) ->
- capturedBrowsers.add new Browser
- sinon.stub capturedBrowsers, 'areAllReady', -> true
- sinon.stub fileListMock, 'refresh'
- sinon.stub fileListMock, 'addFile'
- sinon.stub fileListMock, 'changeFile'
- sinon.stub fileListMock, 'removeFile'
-
- RAW_MESSAGE = JSON.stringify
- addedFiles: ['/new.js']
- removedFiles: ['/foo.js', '/bar.js']
- changedFiles: ['/changed.js']
-
- request = new HttpRequestMock '/__run__', {
- 'content-type': 'application/json'
- 'content-length': RAW_MESSAGE.length
- }
-
- handler request, response, nextSpy
-
- request.emit 'data', RAW_MESSAGE
- request.emit 'end'
-
- process.nextTick ->
- expect(fileListMock.refresh).not.to.have.been.called
- expect(fileListMock.addFile).to.have.been.calledWith path.resolve('/new.js')
- expect(fileListMock.removeFile).to.have.been.calledWith path.resolve('/foo.js')
- expect(fileListMock.removeFile).to.have.been.calledWith path.resolve('/bar.js')
- expect(fileListMock.changeFile).to.have.been.calledWith path.resolve('/changed.js')
- done()
-
- it 'should schedule execution if no refresh', (done) ->
- capturedBrowsers.add new Browser
- sinon.stub capturedBrowsers, 'areAllReady', -> true
-
- sinon.stub fileListMock, 'refresh'
- sinon.stub executor, 'schedule'
-
- RAW_MESSAGE = JSON.stringify {refresh: false}
-
- request = new HttpRequestMock '/__run__', {
- 'content-type': 'application/json'
- 'content-length': RAW_MESSAGE.length
- }
-
- handler request, response, nextSpy
-
- request.emit 'data', RAW_MESSAGE
- request.emit 'end'
-
- process.nextTick ->
- expect(fileListMock.refresh).not.to.have.been.called
- expect(executor.schedule).to.have.been.called
- done()
-
- it 'should wait for refresh to finish if applicable before scheduling execution', (done) ->
- capturedBrowsers.add new Browser
- sinon.stub capturedBrowsers, 'areAllReady', -> true
-
- resolve = null
- fileListPromise = new Promise (_resolve, _reject) ->
- resolve = _resolve
- sinon.stub(fileListMock, 'refresh').returns fileListPromise
- sinon.stub executor, 'schedule'
-
- request = new HttpRequestMock '/__run__'
- handler request, response, nextSpy
-
- process.nextTick ->
- expect(fileListMock.refresh).to.have.been.called
- expect(executor.schedule).to.not.have.been.called
-
- # Now try resolving the promise
- resolve()
- setTimeout(->
- expect(executor.schedule).to.have.been.called
- done()
- , 2)
-
- it 'should not schedule execution if refreshing and autoWatch', (done) ->
- config.autoWatch = true
-
- capturedBrowsers.add new Browser
- sinon.stub capturedBrowsers, 'areAllReady', -> true
-
- sinon.stub(fileListMock, 'refresh').returns Promise.resolve(null)
- sinon.stub executor, 'schedule'
-
- handler new HttpRequestMock('/__run__'), response, nextSpy
-
- process.nextTick ->
- expect(fileListMock.refresh).to.have.been.called
- expect(executor.schedule).not.to.have.been.called
- done()
-
-
- it 'should ignore other urls', (done) ->
- handler new HttpRequestMock('/something'), response, ->
- expect(response).to.beNotServed()
- done()
diff --git a/test/unit/middleware/runner.spec.js b/test/unit/middleware/runner.spec.js
new file mode 100644
index 000000000..d469d5e54
--- /dev/null
+++ b/test/unit/middleware/runner.spec.js
@@ -0,0 +1,218 @@
+import path from 'path'
+import {EventEmitter} from 'events'
+import mocks from 'mocks'
+import {Promise} from 'bluebird'
+import _ from 'lodash'
+import Browser from '../../../lib/browser'
+import BrowserCollection from '../../../lib/browser_collection'
+import MultReporter from '../../../lib/reporters/multi'
+var createRunnerMiddleware = require('../../../lib/middleware/runner').create
+var HttpResponseMock = mocks.http.ServerResponse
+var HttpRequestMock = mocks.http.ServerRequest
+
+describe('middleware.runner', () => {
+ var nextSpy
+ var response
+ var mockReporter
+ var capturedBrowsers
+ var emitter
+ var config
+ var executor
+ var handler
+ var fileListMock
+
+ beforeEach(() => {
+ mockReporter = {
+ adapters: [],
+ write (msg) {
+ return this.adapters.forEach(adapter => adapter(msg))
+ }
+ }
+
+ executor = {
+ schedule: () => emitter.emit('run_start')
+ }
+
+ emitter = new EventEmitter()
+ capturedBrowsers = new BrowserCollection(emitter)
+ fileListMock = {
+ refresh: () => Promise.resolve(),
+ addFile: () => null,
+ removeFile: () => null,
+ changeFile: () => null
+ }
+
+ nextSpy = sinon.spy()
+ response = new HttpResponseMock()
+ config = {client: {}, basePath: '/'}
+
+ handler = createRunnerMiddleware(emitter, fileListMock, capturedBrowsers,
+ new MultReporter([mockReporter]), executor, 'localhost', 8877, '/', config)
+ })
+
+ it('should trigger test run and stream the reporter', (done) => {
+ capturedBrowsers.add(new Browser())
+ sinon.stub(capturedBrowsers, 'areAllReady', () => true)
+
+ response.once('end', () => {
+ expect(nextSpy).to.not.have.been.called
+ expect(response).to.beServedAs(200, 'result\x1FEXIT0')
+ done()
+ })
+
+ handler(new HttpRequestMock('/__run__'), response, nextSpy)
+
+ // Wrap this in a setTimeout so the fileListPromise has time to resolve.
+ _.delay(() => {
+ mockReporter.write('result')
+ emitter.emit('run_complete', capturedBrowsers, {exitCode: 0})
+ })
+ })
+
+ it('should not run if there is no browser captured', (done) => {
+ sinon.stub(fileListMock, 'refresh')
+
+ response.once('end', () => {
+ expect(nextSpy).to.not.have.been.called
+ expect(response).to.beServedAs(200, 'No captured browser, open http://localhost:8877/\n')
+ expect(fileListMock.refresh).not.to.have.been.called
+ done()
+ })
+
+ handler(new HttpRequestMock('/__run__'), response, nextSpy)
+ })
+
+ it('should parse body and set client.args', (done) => {
+ capturedBrowsers.add(new Browser())
+ sinon.stub(capturedBrowsers, 'areAllReady', () => true)
+
+ emitter.once('run_start', () => {
+ expect(config.client.args).to.deep.equal(['arg1', 'arg2'])
+ done()
+ })
+
+ var RAW_MESSAGE = '{"args": ["arg1", "arg2"]}'
+
+ var request = new HttpRequestMock('/__run__', {
+ 'content-type': 'application/json',
+ 'content-length': RAW_MESSAGE.length
+ })
+
+ handler(request, response, nextSpy)
+
+ request.emit('data', RAW_MESSAGE)
+ request.emit('end')
+ })
+
+ it('should refresh explicit files if specified', (done) => {
+ capturedBrowsers.add(new Browser())
+ sinon.stub(capturedBrowsers, 'areAllReady', () => true)
+ sinon.stub(fileListMock, 'refresh')
+ sinon.stub(fileListMock, 'addFile')
+ sinon.stub(fileListMock, 'changeFile')
+ sinon.stub(fileListMock, 'removeFile')
+
+ var RAW_MESSAGE = JSON.stringify({
+ addedFiles: ['/new.js'],
+ removedFiles: ['/foo.js', '/bar.js'],
+ changedFiles: ['/changed.js']
+ })
+
+ var request = new HttpRequestMock('/__run__', {
+ 'content-type': 'application/json',
+ 'content-length': RAW_MESSAGE.length
+ })
+
+ handler(request, response, nextSpy)
+
+ request.emit('data', RAW_MESSAGE)
+ request.emit('end')
+
+ process.nextTick(() => {
+ expect(fileListMock.refresh).not.to.have.been.called
+ expect(fileListMock.addFile).to.have.been.calledWith(path.resolve('/new.js'))
+ expect(fileListMock.removeFile).to.have.been.calledWith(path.resolve('/foo.js'))
+ expect(fileListMock.removeFile).to.have.been.calledWith(path.resolve('/bar.js'))
+ expect(fileListMock.changeFile).to.have.been.calledWith(path.resolve('/changed.js'))
+ done()
+ })
+ })
+
+ it('should wait for refresh to finish if applicable before scheduling execution', (done) => {
+ capturedBrowsers.add(new Browser())
+ sinon.stub(capturedBrowsers, 'areAllReady', () => true)
+
+ var resolve = null
+ var fileListPromise = new Promise((_resolve, _reject) => {
+ resolve = _resolve
+ })
+ sinon.stub(fileListMock, 'refresh').returns(fileListPromise)
+ sinon.stub(executor, 'schedule')
+
+ var request = new HttpRequestMock('/__run__')
+ handler(request, response, nextSpy)
+
+ process.nextTick(() => {
+ expect(fileListMock.refresh).to.have.been.called
+ expect(executor.schedule).to.not.have.been.called
+
+ // Now try resolving the promise
+ resolve()
+ setTimeout(() => {
+ expect(executor.schedule).to.have.been.called
+ done()
+ }, 2)
+ })
+ })
+
+ it('should schedule execution if no refresh', (done) => {
+ capturedBrowsers.add(new Browser())
+ sinon.stub(capturedBrowsers, 'areAllReady', () => true)
+
+ sinon.spy(fileListMock, 'refresh')
+ sinon.stub(executor, 'schedule')
+
+ var RAW_MESSAGE = JSON.stringify({refresh: false})
+
+ var request = new HttpRequestMock('/__run__', {
+ 'content-type': 'application/json',
+ 'content-length': RAW_MESSAGE.length
+ })
+
+ handler(request, response, nextSpy)
+
+ request.emit('data', RAW_MESSAGE)
+ request.emit('end')
+
+ process.nextTick(() => {
+ expect(fileListMock.refresh).not.to.have.been.called
+ expect(executor.schedule).to.have.been.called
+ done()
+ })
+ })
+
+ it('should not schedule execution if refreshing and autoWatch', (done) => {
+ config.autoWatch = true
+
+ capturedBrowsers.add(new Browser())
+ sinon.stub(capturedBrowsers, 'areAllReady', () => true)
+
+ sinon.spy(fileListMock, 'refresh')
+ sinon.stub(executor, 'schedule')
+
+ handler(new HttpRequestMock('/__run__'), response, nextSpy)
+
+ process.nextTick(() => {
+ expect(fileListMock.refresh).to.have.been.called
+ expect(executor.schedule).not.to.have.been.called
+ done()
+ })
+ })
+
+ it('should ignore other urls', (done) => {
+ handler(new HttpRequestMock('/something'), response, () => {
+ expect(response).to.beNotServed()
+ done()
+ })
+ })
+})
diff --git a/test/unit/middleware/source_files.spec.coffee b/test/unit/middleware/source_files.spec.coffee
deleted file mode 100644
index 56c01f8c5..000000000
--- a/test/unit/middleware/source_files.spec.coffee
+++ /dev/null
@@ -1,184 +0,0 @@
-http = require 'http'
-mocks = require 'mocks'
-request = require 'supertest-as-promised'
-helper = require '../../../lib/helper'
-File = require('../../../lib/file')
-Url = require('../../../lib/url')
-createServeFile = require('../../../lib/middleware/common').createServeFile
-createSourceFilesMiddleware = require('../../../lib/middleware/source_files').create
-
-describe 'middleware.source_files', ->
- server = next = files = null
-
- fsMock = mocks.fs.create
- base:
- path:
- 'a.js': mocks.fs.file(0, 'js-src-a')
- 'index.html': mocks.fs.file(0, '')
- src:
- 'some.js': mocks.fs.file(0, 'js-source')
- 'utf8ášč':
- 'some.js': mocks.fs.file(0, 'utf8-file')
-
- serveFile = createServeFile fsMock, null
-
- createServer = (f, s, basePath) ->
- handler = createSourceFilesMiddleware f.promise, s, basePath
- http.createServer (req, res) ->
- next = sinon.spy (err) ->
- if err
- res.statusCode = err.status || 500
- res.end err.message
- else
- res.statusCode = 200
- res.end JSON.stringify(req.body)
-
- handler req, res, next
-
- beforeEach ->
- files = helper.defer()
- server = createServer files, serveFile, '/base/path'
-
- afterEach ->
- next.reset()
-
- # helpers
- includedFiles = (list) ->
- files.resolve {included: list, served: []}
-
- servedFiles = (list) ->
- files.resolve {included: [], served: list}
-
- it 'should serve absolute js source files ignoring timestamp', () ->
- servedFiles [
- new File('/src/some.js')
- ]
-
- request(server)
- .get('/absolute/src/some.js?123345')
- .expect(200, 'js-source')
-
- it 'should serve js source files from base folder ignoring timestamp', () ->
- servedFiles [
- new File('/base/path/a.js')
- ]
-
- request(server)
- .get('/base/a.js?123345')
- .expect(200, 'js-src-a')
- .then(() ->
- expect(next).not.to.have.been.called
- )
-
- it 'should send strict caching headers for js source files with sha', () ->
- servedFiles [
- new File('/src/some.js')
- ]
-
- request(server)
- .get('/absolute/src/some.js?df43b8acf136389a8dd989bda397d1c9b4e048be')
- .expect('Cache-Control', 'public, max-age=31536000')
- .expect(200)
- .then(() ->
- expect(next).not.to.have.been.called
- )
-
- it 'should send strict caching headers for js source files with sha (in basePath)', () ->
- servedFiles [
- new File('/base/path/a.js')
- ]
-
- request(server)
- .get('/base/a.js?df43b8acf136389a8dd989bda397d1c9b4e048be')
- .expect('Cache-Control', 'public, max-age=31536000')
- .expect(200)
-
- it 'should send no-caching headers for js source files without timestamps', () ->
- ZERO_DATE = (new Date 0).toString()
-
- servedFiles [
- new File('/src/some.js')
- ]
-
- request(server)
- .get('/absolute/src/some.js')
- .expect('Cache-Control', 'no-cache')
- # idiotic IE8 needs more
- .expect('Pragma', 'no-cache')
- .expect('Expires', ZERO_DATE)
- .expect(200)
- .then(() ->
- expect(next).not.to.have.been.called
- )
-
- it 'should not serve files that are not in served', () ->
- servedFiles []
-
- request(server)
- .get('/absolute/non-existing.html')
- .expect(200, '')
-
- it 'should serve 404 if file is served but does not exist', () ->
- servedFiles [
- new File('/non-existing.js')
- ]
-
- request(server)
- .get('/absolute/non-existing.js')
- .expect(404, 'NOT FOUND')
-
-
- it 'should serve js source file from base path containing utf8 chars', () ->
- servedFiles [
- new File('/utf8ášč/some.js')
- ]
-
- server = createServer files, serveFile, '/utf8ášč'
-
- request(server)
- .get('/base/some.js')
- .expect(200, 'utf8-file')
- .then(() ->
- expect(next).not.to.have.been.called
- )
-
- it 'should set content-type headers', () ->
- servedFiles [
- new File('/base/path/index.html')
- ]
-
- request(server)
- .get('/base/index.html')
- .expect('Content-Type', 'text/html')
- .expect(200)
-
- it 'should use cached content if available', () ->
- cachedFile = new File('/some/file.js')
- cachedFile.content = 'cached-content'
-
- servedFiles [
- cachedFile
- ]
-
- request(server)
- .get('/absolute/some/file.js')
- .expect(200, 'cached-content')
- .then(() ->
- expect(next).not.to.have.been.called
- )
-
- it 'should not use cached content if doNotCache is set', () ->
- cachedFile = new File('/src/some.js')
- cachedFile.content = 'cached-content'
- cachedFile.doNotCache = true
-
- servedFiles [
- cachedFile
- ]
-
- request(server)
- .get('/absolute/src/some.js')
- .expect(200, 'js-source')
- .then(() ->
- expect(next).not.to.have.been.called
- )
diff --git a/test/unit/middleware/source_files.spec.js b/test/unit/middleware/source_files.spec.js
new file mode 100644
index 000000000..acf675f0c
--- /dev/null
+++ b/test/unit/middleware/source_files.spec.js
@@ -0,0 +1,211 @@
+import http from 'http'
+import mocks from 'mocks'
+import request from 'supertest-as-promised'
+import helper from '../../../lib/helper'
+import File from '../../../lib/file'
+import {createServeFile} from '../../../lib/middleware/common'
+var createSourceFilesMiddleware = require('../../../lib/middleware/source_files').create
+
+describe('middleware.source_files', function () {
+ var next
+ var files
+ var server = next = files = null
+
+ var fsMock = mocks.fs.create({
+ base: {
+ path: {
+ 'a.js': mocks.fs.file(0, 'js-src-a'),
+ 'index.html': mocks.fs.file(0, '')
+ }
+ },
+ src: {
+ 'some.js': mocks.fs.file(0, 'js-source')
+ },
+ 'utf8ášč': {
+ 'some.js': mocks.fs.file(0, 'utf8-file')
+ }
+ })
+
+ var serveFile = createServeFile(fsMock, null)
+
+ var createServer = function (f, s, basePath) {
+ var handler = createSourceFilesMiddleware(f.promise, s, basePath)
+ return http.createServer(function (req, res) {
+ next = sinon.spy(function (err) {
+ if (err) {
+ res.statusCode = err.status || 500
+ return res.end(err.message)
+ } else {
+ res.statusCode = 200
+ return res.end(JSON.stringify(req.body))
+ }
+ })
+
+ return handler(req, res, next)
+ })
+ }
+
+ beforeEach(function () {
+ files = helper.defer()
+ server = createServer(files, serveFile, '/base/path')
+ return server
+ })
+
+ afterEach(function () {
+ return next.reset()
+ })
+
+ var servedFiles = function (list) {
+ return files.resolve({included: [], served: list})
+ }
+
+ it('should serve absolute js source files ignoring timestamp', function () {
+ servedFiles([
+ new File('/src/some.js')
+ ])
+
+ return request(server)
+ .get('/absolute/src/some.js?123345')
+ .expect(200, 'js-source')
+ })
+
+ it('should serve js source files from base folder ignoring timestamp', function () {
+ servedFiles([
+ new File('/base/path/a.js')
+ ])
+
+ return request(server)
+ .get('/base/a.js?123345')
+ .expect(200, 'js-src-a')
+ .then(function () {
+ return expect(next).not.to.have.been.called
+ }
+ )
+ })
+
+ it('should send strict caching headers for js source files with sha', function () {
+ servedFiles([
+ new File('/src/some.js')
+ ])
+
+ return request(server)
+ .get('/absolute/src/some.js?df43b8acf136389a8dd989bda397d1c9b4e048be')
+ .expect('Cache-Control', 'public, max-age=31536000')
+ .expect(200)
+ .then(function () {
+ return expect(next).not.to.have.been.called
+ }
+ )
+ })
+
+ it('should send strict caching headers for js source files with sha (in basePath)', function () {
+ servedFiles([
+ new File('/base/path/a.js')
+ ])
+
+ return request(server)
+ .get('/base/a.js?df43b8acf136389a8dd989bda397d1c9b4e048be')
+ .expect('Cache-Control', 'public, max-age=31536000')
+ .expect(200)
+ })
+
+ it('should send no-caching headers for js source files without timestamps', function () {
+ var ZERO_DATE = (new Date(0)).toString()
+
+ servedFiles([
+ new File('/src/some.js')
+ ])
+
+ return request(server)
+ .get('/absolute/src/some.js')
+ .expect('Cache-Control', 'no-cache')
+ // idiotic IE8 needs more
+ .expect('Pragma', 'no-cache')
+ .expect('Expires', ZERO_DATE)
+ .expect(200)
+ .then(function () {
+ return expect(next).not.to.have.been.called
+ }
+ )
+ })
+
+ it('should not serve files that are not in served', function () {
+ servedFiles([])
+
+ return request(server)
+ .get('/absolute/non-existing.html')
+ .expect(200, '')
+ })
+
+ it('should serve 404 if file is served but does not exist', function () {
+ servedFiles([
+ new File('/non-existing.js')
+ ])
+
+ return request(server)
+ .get('/absolute/non-existing.js')
+ .expect(404, 'NOT FOUND')
+ })
+
+ it('should serve js source file from base path containing utf8 chars', function () {
+ servedFiles([
+ new File('/utf8ášč/some.js')
+ ])
+
+ server = createServer(files, serveFile, '/utf8ášč')
+
+ return request(server)
+ .get('/base/some.js')
+ .expect(200, 'utf8-file')
+ .then(function () {
+ return expect(next).not.to.have.been.called
+ }
+ )
+ })
+
+ it('should set content-type headers', function () {
+ servedFiles([
+ new File('/base/path/index.html')
+ ])
+
+ return request(server)
+ .get('/base/index.html')
+ .expect('Content-Type', 'text/html')
+ .expect(200)
+ })
+
+ it('should use cached content if available', function () {
+ var cachedFile = new File('/some/file.js')
+ cachedFile.content = 'cached-content'
+
+ servedFiles([
+ cachedFile
+ ])
+
+ return request(server)
+ .get('/absolute/some/file.js')
+ .expect(200, 'cached-content')
+ .then(function () {
+ return expect(next).not.to.have.been.called
+ }
+ )
+ })
+
+ return it('should not use cached content if doNotCache is set', function () {
+ var cachedFile = new File('/src/some.js')
+ cachedFile.content = 'cached-content'
+ cachedFile.doNotCache = true
+
+ servedFiles([
+ cachedFile
+ ])
+
+ return request(server)
+ .get('/absolute/src/some.js')
+ .expect(200, 'js-source')
+ .then(function () {
+ return expect(next).not.to.have.been.called
+ }
+ )
+ })
+})
diff --git a/test/unit/middleware/strip_host.spec.coffee b/test/unit/middleware/strip_host.spec.coffee
deleted file mode 100644
index 6d961fccb..000000000
--- a/test/unit/middleware/strip_host.spec.coffee
+++ /dev/null
@@ -1,68 +0,0 @@
-describe 'middleware.strip_host', ->
- mocks = require 'mocks'
- HttpResponseMock = mocks.http.ServerResponse
- HttpRequestMock = mocks.http.ServerRequest
-
- File = require('../../../lib/file')
- Url = require('../../../lib/url')
-
- fsMock = mocks.fs.create
- base:
- path:
- 'a.js': mocks.fs.file(0, 'js-src-a')
- 'index.html': mocks.fs.file(0, '')
- src:
- 'some.js': mocks.fs.file(0, 'js-source')
- 'utf8ášč':
- 'some.js': mocks.fs.file(0, 'utf8-file')
-
-
- serveFile = require('../../../lib/middleware/common').createServeFile fsMock, null
- createStripHostMiddleware = require('../../../lib/middleware/strip_host').create
-
- handler = filesDeferred = nextSpy = response = null
-
- beforeEach ->
- nextSpy = sinon.spy()
- request = null
- handler = createStripHostMiddleware null, null, '/base/path'
-
- it 'should strip request with IP number', (done) ->
- request = new HttpRequestMock('http://192.12.31.100/base/a.js?123345')
- handler request, null, nextSpy
-
- expect(request.normalizedUrl).to.equal '/base/a.js?123345'
- expect(nextSpy).to.have.been.called
- done()
-
- it 'should strip request with absoluteURI', (done) ->
- request = new HttpRequestMock('http://localhost/base/a.js?123345')
- handler request, null, nextSpy
-
- expect(request.normalizedUrl).to.equal '/base/a.js?123345'
- expect(nextSpy).to.have.been.called
- done()
-
- it 'should strip request with absoluteURI and port', (done) ->
- request = new HttpRequestMock('http://localhost:9876/base/a.js?123345')
- handler request, null, nextSpy
-
- expect(request.normalizedUrl).to.equal '/base/a.js?123345'
- expect(nextSpy).to.have.been.called
- done()
-
- it 'should strip request with absoluteURI over HTTPS', (done) ->
- request = new HttpRequestMock('https://karma-runner.github.io/base/a.js?123345')
- handler request, null, nextSpy
-
- expect(request.normalizedUrl).to.equal '/base/a.js?123345'
- expect(nextSpy).to.have.been.called
- done()
-
- it 'should return same url as passed one', (done) ->
- request = new HttpRequestMock('/base/b.js?123345')
- handler request, null, nextSpy
-
- expect(request.normalizedUrl).to.equal '/base/b.js?123345'
- expect(nextSpy).to.have.been.called
- done()
diff --git a/test/unit/middleware/strip_host.spec.js b/test/unit/middleware/strip_host.spec.js
new file mode 100644
index 000000000..39681533a
--- /dev/null
+++ b/test/unit/middleware/strip_host.spec.js
@@ -0,0 +1,61 @@
+import mocks from 'mocks'
+
+describe('middleware.strip_host', function () {
+ var nextSpy
+ var HttpRequestMock = mocks.http.ServerRequest
+
+ var createStripHostMiddleware = require('../../../lib/middleware/strip_host').create
+
+ var handler = nextSpy = null
+
+ beforeEach(function () {
+ nextSpy = sinon.spy()
+ handler = createStripHostMiddleware(null, null, '/base/path')
+ return handler
+ })
+
+ it('should strip request with IP number', function (done) {
+ var request = new HttpRequestMock('http://192.12.31.100/base/a.js?123345')
+ handler(request, null, nextSpy)
+
+ expect(request.normalizedUrl).to.equal('/base/a.js?123345')
+ expect(nextSpy).to.have.been.called
+ return done()
+ })
+
+ it('should strip request with absoluteURI', function (done) {
+ var request = new HttpRequestMock('http://localhost/base/a.js?123345')
+ handler(request, null, nextSpy)
+
+ expect(request.normalizedUrl).to.equal('/base/a.js?123345')
+ expect(nextSpy).to.have.been.called
+ return done()
+ })
+
+ it('should strip request with absoluteURI and port', function (done) {
+ var request = new HttpRequestMock('http://localhost:9876/base/a.js?123345')
+ handler(request, null, nextSpy)
+
+ expect(request.normalizedUrl).to.equal('/base/a.js?123345')
+ expect(nextSpy).to.have.been.called
+ return done()
+ })
+
+ it('should strip request with absoluteURI over HTTPS', function (done) {
+ var request = new HttpRequestMock('https://karma-runner.github.io/base/a.js?123345')
+ handler(request, null, nextSpy)
+
+ expect(request.normalizedUrl).to.equal('/base/a.js?123345')
+ expect(nextSpy).to.have.been.called
+ return done()
+ })
+
+ return it('should return same url as passed one', function (done) {
+ var request = new HttpRequestMock('/base/b.js?123345')
+ handler(request, null, nextSpy)
+
+ expect(request.normalizedUrl).to.equal('/base/b.js?123345')
+ expect(nextSpy).to.have.been.called
+ return done()
+ })
+})
diff --git a/test/unit/mocha-globals.coffee b/test/unit/mocha-globals.coffee
deleted file mode 100644
index e089906f7..000000000
--- a/test/unit/mocha-globals.coffee
+++ /dev/null
@@ -1,77 +0,0 @@
-require 'coffee-errors'
-
-sinon = require 'sinon'
-chai = require 'chai'
-logger = require '../../lib/logger'
-
-require('bluebird').longStackTraces()
-
-# publish globals that all specs can use
-global.expect = chai.expect
-global.should = chai.should()
-global.sinon = sinon
-
-# chai plugins
-chai.use(require 'chai-as-promised')
-chai.use(require 'sinon-chai')
-chai.use(require 'chai-subset')
-
-beforeEach ->
- global.sinon = sinon.sandbox.create()
-
- # set logger to log INFO, but do not append to console
- # so that we can assert logs by logger.on('info', ...)
- logger.setup 'INFO', false, []
-
-afterEach ->
- global.sinon.restore()
-
-
-
-# TODO(vojta): move to helpers or something
-chai.use (chai, utils) ->
- chai.Assertion.addMethod 'beServedAs', (expectedStatus, expectedBody) ->
- response = utils.flag @, 'object'
-
- @assert response._status is expectedStatus,
- "expected response status '#{response._status}' to be '#{expectedStatus}'"
- @assert response._body is expectedBody,
- "expected response body '#{response._body}' to be '#{expectedBody}'"
-
- chai.Assertion.addMethod 'beNotServed', ->
- response = utils.flag @, 'object'
-
- @assert response._status is null,
- "expected response status to not be set, it was '#{response._status}'"
- @assert response._body is null,
- "expected response body to not be set, it was '#{response._body}'"
-
-
-# TODO(vojta): move it somewhere ;-)
-nextTickQueue = []
-nextTickCallback = ->
- if not nextTickQueue.length then throw new Error 'Nothing scheduled!'
- nextTickQueue.shift()()
- if nextTickQueue.length then process.nextTick nextTickCallback
-
-global.scheduleNextTick = (action) ->
- nextTickQueue.push action
- if nextTickQueue.length is 1 then process.nextTick nextTickCallback
-
-nextQueue = []
-nextCallback = ->
- if not nextQueue.length then throw new Error 'Nothing scheduled!'
- nextQueue.shift()()
-
-global.scheduleNextTick = (action) ->
- nextTickQueue.push action
- if nextTickQueue.length is 1 then process.nextTick nextTickCallback
-
-global.scheduleNext = (action) ->
- nextQueue.push action
-
-global.next = nextCallback
-
-beforeEach ->
- nextTickQueue.length = 0
- nextQueue.length = 0
diff --git a/test/unit/mocha-globals.js b/test/unit/mocha-globals.js
new file mode 100644
index 000000000..b61c09596
--- /dev/null
+++ b/test/unit/mocha-globals.js
@@ -0,0 +1,84 @@
+var sinon = require('sinon')
+var chai = require('chai')
+var logger = require('../../lib/logger')
+
+require('bluebird').longStackTraces()
+
+// publish globals that all specs can use
+global.expect = chai.expect
+global.should = chai.should()
+global.sinon = sinon
+
+// chai plugins
+chai.use(require('chai-as-promised'))
+chai.use(require('sinon-chai'))
+chai.use(require('chai-subset'))
+
+beforeEach(() => {
+ global.sinon = sinon.sandbox.create()
+
+ // set logger to log INFO, but do not append to console
+ // so that we can assert logs by logger.on('info', ...)
+ logger.setup('INFO', false, [])
+})
+
+afterEach(() => {
+ global.sinon.restore()
+})
+
+// TODO(vojta): move to helpers or something
+chai.use((chai, utils) => {
+ chai.Assertion.addMethod('beServedAs', function (expectedStatus, expectedBody) {
+ var response = utils.flag(this, 'object')
+
+ this.assert(response._status === expectedStatus,
+ `expected response status '#{response._status}' to be '#{expectedStatus}'`)
+ this.assert(response._body === expectedBody,
+ `expected response body '#{response._body}' to be '#{exp)ectedBody}'`)
+ })
+
+ chai.Assertion.addMethod('beNotServed', function () {
+ var response = utils.flag(this, 'object')
+
+ this.assert(response._status === null,
+ `expected response status to not be set, it was '#{response._status}'`)
+ this.assert(response._body === null,
+ `expected response body to not be set, it was '#{response._body}'`)
+
+ })
+})
+
+// TODO(vojta): move it somewhere ;-)
+var nextTickQueue = []
+var nextTickCallback = () => {
+ if (!nextTickQueue.length) throw new Error('Nothing scheduled!')
+ nextTickQueue.shift()()
+
+ if (nextTickQueue.length) process.nextTick(nextTickCallback)
+}
+global.scheduleNextTick = action => {
+ nextTickQueue.push(action)
+
+ if (nextTickQueue.length === 1) process.nextTick(nextTickCallback)
+}
+var nextQueue = []
+var nextCallback = () => {
+ // if not nextQueue.length then throw new Error 'Nothing scheduled!'
+ nextQueue.shift()()
+}
+
+global.scheduleNextTick = action => {
+ nextTickQueue.push(action)
+
+ if (nextTickQueue.length === 1) process.nextTick(nextTickCallback)
+}
+global.scheduleNext = action => {
+ nextQueue.push(action)
+}
+
+global.next = nextCallback
+
+beforeEach(() => {
+ nextTickQueue.length = 0
+ nextQueue.length = 0
+})
diff --git a/test/unit/mocks/timer.js b/test/unit/mocks/timer.js
index 8abb35e9b..943201fd3 100644
--- a/test/unit/mocks/timer.js
+++ b/test/unit/mocks/timer.js
@@ -1,4 +1,4 @@
-var Timer = require('timer-shim').Timer
+import {Timer} from 'timer-shim'
module.exports = function () {
var timer = new Timer()
diff --git a/test/unit/preprocessor.spec.coffee b/test/unit/preprocessor.spec.coffee
deleted file mode 100644
index d5d96c310..000000000
--- a/test/unit/preprocessor.spec.coffee
+++ /dev/null
@@ -1,216 +0,0 @@
-#==============================================================================
-# lib/preprocessor.js module
-#==============================================================================
-describe 'preprocessor', ->
- mocks = require 'mocks'
- di = require 'di'
-
- m = pp = mockFs = null
-
- beforeEach ->
- mockFs = mocks.fs.create
- some:
- 'a.js': mocks.fs.file 0, 'content'
- 'b.js': mocks.fs.file 0, 'content'
- 'a.txt': mocks.fs.file 0, 'some-text'
- 'photo.png': mocks.fs.file 0, 'binary'
- 'CAM_PHOTO.JPG': mocks.fs.file 0, 'binary'
-
- mocks_ =
- 'graceful-fs': mockFs
- minimatch: require 'minimatch'
-
- m = mocks.loadFile __dirname + '/../../lib/preprocessor.js', mocks_
-
-
- it 'should preprocess matching file', (done) ->
- fakePreprocessor = sinon.spy (content, file, done) ->
- file.path = file.path + '-preprocessed'
- done null, 'new-content'
-
- injector = new di.Injector [{'preprocessor:fake': ['factory', -> fakePreprocessor]}]
- pp = m.createPreprocessor {'**/*.js': ['fake']}, null, injector
-
- file = {originalPath: '/some/a.js', path: 'path'}
-
- pp file, ->
- expect(fakePreprocessor).to.have.been.called
- expect(file.path).to.equal 'path-preprocessed'
- expect(file.content).to.equal 'new-content'
- done()
-
-
- it 'should check patterns after creation when invoked', (done) ->
- fakePreprocessor = sinon.spy (content, file, done) ->
- file.path = file.path + '-preprocessed'
- done null, 'new-content'
-
- injector = new di.Injector [{'preprocessor:fake': ['factory', -> fakePreprocessor]}]
- config = {'**/*.txt': ['fake']}
- pp = m.createPreprocessor config, null, injector
-
- file = {originalPath: '/some/a.js', path: 'path'}
-
- config['**/*.js'] = ['fake']
-
- pp file, ->
- expect(fakePreprocessor).to.have.been.called
- expect(file.path).to.equal 'path-preprocessed'
- expect(file.content).to.equal 'new-content'
- done()
-
-
- it 'should ignore not matching file', (done) ->
- fakePreprocessor = sinon.spy (content, file, done) ->
- done null, ''
-
- injector = new di.Injector [{'preprocessor:fake': ['factory', -> fakePreprocessor]}]
- pp = m.createPreprocessor {'**/*.js': ['fake']}, null, injector
-
- file = {originalPath: '/some/a.txt', path: 'path'}
-
- pp file, ->
- expect(fakePreprocessor).to.not.have.been.called
- done()
-
-
- it 'should apply all preprocessors', (done) ->
- fakePreprocessor1 = sinon.spy (content, file, done) ->
- file.path = file.path + '-p1'
- done null, content + '-c1'
-
- fakePreprocessor2 = sinon.spy (content, file, done) ->
- file.path = file.path + '-p2'
- done content + '-c2'
-
- injector = new di.Injector [{
- 'preprocessor:fake1': ['factory', -> fakePreprocessor1]
- 'preprocessor:fake2': ['factory', -> fakePreprocessor2]
- }]
-
- pp = m.createPreprocessor {'**/*.js': ['fake1', 'fake2']}, null, injector
-
- file = {originalPath: '/some/a.js', path: 'path'}
-
- pp file, ->
- expect(fakePreprocessor1).to.have.been.calledOnce
- expect(fakePreprocessor2).to.have.been.calledOnce
- expect(file.path).to.equal 'path-p1-p2'
- expect(file.content).to.equal 'content-c1-c2'
- done()
-
-
- it 'should compute SHA', (done) ->
- pp = m.createPreprocessor {}, null, new di.Injector([])
- file = {originalPath: '/some/a.js', path: 'path'}
-
- pp file, ->
- expect(file.sha).to.exist
- expect(file.sha.length).to.equal 40
- previousSHA = file.sha
-
- pp file, ->
- expect(file.sha).to.equal previousSHA
- mockFs._touchFile '/some/a.js', null, 'new-content'
-
- pp file, ->
- expect(file.sha.length).to.equal 40
- expect(file.sha).not.to.equal previousSHA
- done()
-
- it 'should compute SHA from content returned by a processor', (done) ->
- fakePreprocessor = sinon.spy (content, file, done) ->
- done null, content + '-processed'
-
- injector = new di.Injector [{
- 'preprocessor:fake': ['factory', -> fakePreprocessor]
- }]
-
- pp = m.createPreprocessor {'**/a.js': ['fake']}, null, injector
-
- fileProcess = {originalPath: '/some/a.js', path: 'path'}
- fileSkip = {originalPath: '/some/b.js', path: 'path'}
-
- pp fileProcess, ->
- pp fileSkip, ->
- expect(fileProcess.sha).to.exist
- expect(fileProcess.sha.length).to.equal 40
- expect(fileSkip.sha).to.exist
- expect(fileSkip.sha.length).to.equal 40
- expect(fileProcess.sha).not.to.equal fileSkip.sha
- done()
-
-
- it 'should return error if any preprocessor fails', (done) ->
- failingPreprocessor = sinon.spy (content, file, done) ->
- done new Error('Some error'), null
-
- injector = new di.Injector [{
- 'preprocessor:failing': ['factory', -> failingPreprocessor]
- }]
-
- pp = m.createPreprocessor {'**/*.js': ['failing']}, null, injector
-
- file = {originalPath: '/some/a.js', path: 'path'}
-
- pp file, (err) ->
- expect(err).to.exist
- done()
-
-
- it 'should stop preprocessing after an error', (done) ->
- failingPreprocessor = sinon.spy (content, file, done) ->
- done new Error('Some error'), null
-
- fakePreprocessor = sinon.spy (content, file, done) ->
- done null, content
-
-
- injector = new di.Injector [{
- 'preprocessor:failing': ['factory', -> failingPreprocessor]
- 'preprocessor:fake': ['factory', -> fakePreprocessor]
- }]
-
- pp = m.createPreprocessor {'**/*.js': ['failing', 'fake']}, null, injector
-
- file = {originalPath: '/some/a.js', path: 'path'}
-
- pp file, (err) ->
- expect(fakePreprocessor).not.to.have.been.called
- done()
-
-
- it 'should not preprocess binary files', (done) ->
- fakePreprocessor = sinon.spy (content, file, done) ->
- done null, content
-
- injector = new di.Injector [{
- 'preprocessor:fake': ['factory', -> fakePreprocessor]
- }]
-
- pp = m.createPreprocessor {'**/*': ['fake']}, null, injector
-
- file = {originalPath: '/some/photo.png', path: 'path'}
-
- pp file, (err) ->
- expect(fakePreprocessor).not.to.have.been.called
- expect(file.content).to.be.an.instanceof Buffer
- done()
-
-
- it 'should not preprocess binary files with capital letters in extension', (done) ->
- fakePreprocessor = sinon.spy (content, file, done) ->
- done null, content
-
- injector = new di.Injector [{
- 'preprocessor:fake': ['factory', -> fakePreprocessor]
- }]
-
- pp = m.createPreprocessor {'**/*': ['fake']}, null, injector
-
- file = {originalPath: '/some/CAM_PHOTO.JPG', path: 'path'}
-
- pp file, (err) ->
- expect(fakePreprocessor).not.to.have.been.called
- expect(file.content).to.be.an.instanceof Buffer
- done()
diff --git a/test/unit/preprocessor.spec.js b/test/unit/preprocessor.spec.js
new file mode 100644
index 000000000..f8c918cf8
--- /dev/null
+++ b/test/unit/preprocessor.spec.js
@@ -0,0 +1,248 @@
+import mocks from 'mocks'
+import di from 'di'
+
+describe('preprocessor', () => {
+ var pp
+ var m
+ var mockFs
+
+ beforeEach(() => {
+ mockFs = mocks.fs.create({
+ some: {
+ 'a.js': mocks.fs.file(0, 'content'),
+ 'b.js': mocks.fs.file(0, 'content'),
+ 'a.txt': mocks.fs.file(0, 'some-text'),
+ 'photo.png': mocks.fs.file(0, 'binary'),
+ 'CAM_PHOTO.JPG': mocks.fs.file(0, 'binary')
+ }
+ })
+
+ var mocks_ = {
+ 'graceful-fs': mockFs,
+ minimatch: require('minimatch')
+ }
+
+ m = mocks.loadFile(__dirname + '/../../lib/preprocessor.js', mocks_)
+ })
+
+ it('should preprocess matching file', done => {
+ var fakePreprocessor = sinon.spy((content, file, done) => {
+ file.path = file.path + '-preprocessed'
+ done(null, 'new-content')
+ })
+
+ var injector = new di.Injector([{'preprocessor:fake': ['factory', () => fakePreprocessor]}])
+ pp = m.createPreprocessor({'**/*.js': ['fake']}, null, injector)
+
+ var file = {originalPath: '/some/a.js', path: 'path'}
+
+ pp(file, () => {
+ expect(fakePreprocessor).to.have.been.called
+ expect(file.path).to.equal('path-preprocessed')
+ expect(file.content).to.equal('new-content')
+ done()
+ })
+ })
+
+ it('should check patterns after creation when invoked', done => {
+ var fakePreprocessor = sinon.spy((content, file, done) => {
+ file.path = file.path + '-preprocessed'
+ done(null, 'new-content')
+ })
+
+ var injector = new di.Injector([{'preprocessor:fake': ['factory', () => fakePreprocessor]}])
+ var config = {'**/*.txt': ['fake']}
+ pp = m.createPreprocessor(config, null, injector)
+
+ var file = {originalPath: '/some/a.js', path: 'path'}
+
+ config['**/*.js'] = ['fake']
+
+ pp(file, () => {
+ expect(fakePreprocessor).to.have.been.called
+ expect(file.path).to.equal('path-preprocessed')
+ expect(file.content).to.equal('new-content')
+ done()
+ })
+ })
+
+ it('should ignore not matching file', done => {
+ var fakePreprocessor = sinon.spy((content, file, done) => {
+ done(null, '')
+ })
+
+ var injector = new di.Injector([{'preprocessor:fake': ['factory', () => fakePreprocessor]}])
+ pp = m.createPreprocessor({'**/*.js': ['fake']}, null, injector)
+
+ var file = {originalPath: '/some/a.txt', path: 'path'}
+
+ pp(file, () => {
+ expect(fakePreprocessor).to.not.have.been.called
+ done()
+ })
+ })
+
+ it('should apply all preprocessors', done => {
+ var fakePreprocessor1 = sinon.spy((content, file, done) => {
+ file.path = file.path + '-p1'
+ done(null, content + '-c1')
+ })
+
+ var fakePreprocessor2 = sinon.spy((content, file, done) => {
+ file.path = file.path + '-p2'
+ done(content + '-c2')
+ })
+
+ var injector = new di.Injector([{
+ 'preprocessor:fake1': ['factory', () => fakePreprocessor1],
+ 'preprocessor:fake2': ['factory', () => fakePreprocessor2]
+ }])
+
+ pp = m.createPreprocessor({'**/*.js': ['fake1', 'fake2']}, null, injector)
+
+ var file = {originalPath: '/some/a.js', path: 'path'}
+
+ pp(file, () => {
+ expect(fakePreprocessor1).to.have.been.calledOnce
+ expect(fakePreprocessor2).to.have.been.calledOnce
+ expect(file.path).to.equal('path-p1-p2')
+ expect(file.content).to.equal('content-c1-c2')
+ done()
+ })
+ })
+
+ it('should compute SHA', done => {
+ pp = m.createPreprocessor({}, null, new di.Injector([]))
+ var file = {originalPath: '/some/a.js', path: 'path'}
+
+ pp(file, () => {
+ expect(file.sha).to.exist
+ expect(file.sha.length).to.equal(40)
+ var previousSHA = file.sha
+
+ pp(file, () => {
+ expect(file.sha).to.equal(previousSHA)
+ mockFs._touchFile('/some/a.js', null, 'new-content')
+
+ pp(file, () => {
+ expect(file.sha.length).to.equal(40)
+ expect(file.sha).not.to.equal(previousSHA)
+ done()
+ })
+ })
+ })
+ })
+
+ it('should compute SHA from content returned by a processor', done => {
+ var fakePreprocessor = sinon.spy((content, file, done) => {
+ done(null, content + '-processed')
+ })
+
+ var injector = new di.Injector([{
+ 'preprocessor:fake': ['factory', () => fakePreprocessor]
+ }])
+
+ pp = m.createPreprocessor({'**/a.js': ['fake']}, null, injector)
+
+ var fileProcess = {originalPath: '/some/a.js', path: 'path'}
+ var fileSkip = {originalPath: '/some/b.js', path: 'path'}
+
+ pp(fileProcess, () => {
+ pp(fileSkip, () => {
+ expect(fileProcess.sha).to.exist
+ expect(fileProcess.sha.length).to.equal(40)
+ expect(fileSkip.sha).to.exist
+ expect(fileSkip.sha.length).to.equal(40)
+ expect(fileProcess.sha).not.to.equal(fileSkip.sha)
+ done()
+ })
+ })
+ })
+
+ it('should return error if any preprocessor fails', done => {
+ var failingPreprocessor = sinon.spy((content, file, done) => {
+ done(new Error('Some error'), null)
+ })
+
+ var injector = new di.Injector([{
+ 'preprocessor:failing': ['factory', () => failingPreprocessor]
+ }])
+
+ pp = m.createPreprocessor({'**/*.js': ['failing']}, null, injector)
+
+ var file = {originalPath: '/some/a.js', path: 'path'}
+
+ pp(file, err => {
+ expect(err).to.exist
+ done()
+ })
+ })
+
+ it('should stop preprocessing after an error', done => {
+ var failingPreprocessor = sinon.spy((content, file, done) => {
+ done(new Error('Some error'), null)
+ })
+
+ var fakePreprocessor = sinon.spy((content, file, done) => {
+ done(null, content)
+ })
+
+ var injector = new di.Injector([{
+ 'preprocessor:failing': ['factory', () => failingPreprocessor],
+ 'preprocessor:fake': ['factory', () => fakePreprocessor]
+ }])
+
+ pp = m.createPreprocessor({'**/*.js': ['failing', 'fake']}, null, injector)
+
+ var file = {originalPath: '/some/a.js', path: 'path'}
+
+ pp(file, () => {
+ expect(fakePreprocessor).not.to.have.been.called
+ done()
+ })
+ })
+
+ it('should not preprocess binary files', done => {
+ var fakePreprocessor = sinon.spy((content, file, done) => {
+ done(null, content)
+ })
+
+ var injector = new di.Injector([{
+ 'preprocessor:fake': ['factory', () => fakePreprocessor]
+ }])
+
+ pp = m.createPreprocessor({'**/*': ['fake']}, null, injector)
+
+ var file = {originalPath: '/some/photo.png', path: 'path'}
+
+ pp(file, err => {
+ if (err) throw err
+
+ expect(fakePreprocessor).not.to.have.been.called
+ expect(file.content).to.be.an.instanceof(Buffer)
+ done()
+ })
+ })
+
+ it('should not preprocess binary files with capital letters in extension', (done) => {
+ var fakePreprocessor = sinon.spy((content, file, done) => {
+ done(null, content)
+ })
+
+ var injector = new di.Injector([{
+ 'preprocessor:fake': ['factory', () => fakePreprocessor]
+ }])
+
+ pp = m.createPreprocessor({'**/*': ['fake']}, null, injector)
+
+ var file = {originalPath: '/some/CAM_PHOTO.JPG', path: 'path'}
+
+ pp(file, err => {
+ if (err) throw err
+
+ expect(fakePreprocessor).not.to.have.been.called
+ expect(file.content).to.be.an.instanceof(Buffer)
+ done()
+ })
+ })
+})
diff --git a/test/unit/reporter.spec.coffee b/test/unit/reporter.spec.coffee
deleted file mode 100644
index 7d05746b8..000000000
--- a/test/unit/reporter.spec.coffee
+++ /dev/null
@@ -1,138 +0,0 @@
-#==============================================================================
-# lib/reporter.js module
-#==============================================================================
-describe 'reporter', ->
- EventEmitter = require('events').EventEmitter
- File = require('../../lib/file')
- loadFile = require('mocks').loadFile
- _ = require('../../lib/helper')._
- m = null
-
- beforeEach ->
- m = loadFile __dirname + '/../../lib/reporter.js'
-
-
- #==============================================================================
- # formatError() [PRIVATE]
- #==============================================================================
- describe 'formatError', ->
- formatError = emitter = null
-
- beforeEach ->
- emitter = new EventEmitter
- formatError = m.createErrorFormatter '', emitter
-
-
- it 'should indent', ->
- expect(formatError 'Something', '\t').to.equal '\tSomething\n'
-
-
- it 'should handle empty message', ->
- expect(formatError null).to.equal '\n'
-
-
- it 'should remove domain from files', ->
- expect(formatError 'file http://localhost:8080/base/usr/a.js and ' +
- 'http://127.0.0.1:8080/base/home/b.js').
- to.be.equal 'file /usr/a.js and /home/b.js\n'
-
-
- # TODO(vojta): enable once we serve source under urlRoot
- it.skip 'should handle non default karma service folders', ->
- formatError = m.createErrorFormatter '', '/_karma_/'
- expect(formatError 'file http://localhost:8080/_karma_/base/usr/a.js and ' +
- 'http://127.0.0.1:8080/_karma_/base/home/b.js').
- to.be.equal 'file /usr/a.js and /home/b.js\n'
-
-
- it 'should remove shas', ->
- ERROR = 'file ' +
- 'http://localhost:8080/base/usr/file.js?6e31cb249ee5b32d91f37ea516ca0f84bddc5aa9 ' +
- 'and ' +
- 'http://127.0.0.1:8080/absolute/home/file.js?6e31cb249ee5b32d91f37ea516ca0f84bddc5aa9'
- expect(formatError ERROR).to.be.equal 'file /usr/file.js and /home/file.js\n'
-
-
- it 'should indent all lines', ->
- expect(formatError 'first\nsecond\nthird', '\t').to.equal '\tfirst\n\tsecond\n\tthird\n'
-
-
- it 'should restore base paths', ->
- formatError = m.createErrorFormatter '/some/base', emitter
- expect(formatError 'at http://localhost:123/base/a.js?123').to.equal 'at /some/base/a.js\n'
-
-
- it 'should restore absolute paths', ->
- ERROR = 'at http://local:1233/absolute/usr/path.js?6e31cb249ee5b32d91f37ea516ca0f84bddc5aa9'
- expect(formatError ERROR).to.equal 'at /usr/path.js\n'
-
-
- it 'should preserve line numbers', ->
- ERROR = 'at http://local:1233/absolute/usr/path.js?6e31cb249ee5b32d91f37ea516ca0f84bddc5aa9:2'
- expect(formatError ERROR).to.equal 'at /usr/path.js:2\n'
-
-
- describe 'source maps', ->
-
- class MockSourceMapConsumer
- constructor: (sourceMap) ->
- @source = sourceMap.content.replace 'SOURCE MAP ', '/original/'
- originalPositionFor: (position) ->
- if position.line == 0
- throw new TypeError('Line must be greater than or equal to 1, got 0')
-
- source: @source
- line: position.line + 2
- column: position.column + 2
-
- it 'should rewrite stack traces', (done) ->
- formatError = m.createErrorFormatter '/some/base', emitter, MockSourceMapConsumer
- servedFiles = [new File('/some/base/a.js'), new File('/some/base/b.js')]
- servedFiles[0].sourceMap = {content: 'SOURCE MAP a.js'}
- servedFiles[1].sourceMap = {content: 'SOURCE MAP b.js'}
-
- emitter.emit 'file_list_modified', served: servedFiles
-
- _.defer -> _.delay ->
- ERROR = 'at http://localhost:123/base/b.js:2:6'
- expect(formatError ERROR).to.equal 'at /some/base/b.js:2:6 <- /original/b.js:4:8\n'
- done()
- , 100
-
- it 'should fall back to non-source-map format if originalPositionFor throws', (done) ->
- formatError = m.createErrorFormatter '/some/base', emitter, MockSourceMapConsumer
- servedFiles = [new File('/some/base/a.js'), new File('/some/base/b.js')]
- servedFiles[0].sourceMap = 'SOURCE MAP a.js'
- servedFiles[1].sourceMap = 'SOURCE MAP b.js'
-
- emitter.emit 'file_list_modified', served: servedFiles
-
- _.defer ->
- ERROR = 'at http://localhost:123/base/b.js:0:0'
- expect(formatError ERROR).to.equal 'at /some/base/b.js\n'
- done()
-
- describe 'Windows', ->
- formatError = null
- servedFiles = null
-
- beforeEach ->
- formatError = m.createErrorFormatter '/some/base', emitter, MockSourceMapConsumer
- servedFiles = [new File('C:/a/b/c.js')]
- servedFiles[0].sourceMap = {content: 'SOURCE MAP b.js'}
-
- it 'should correct rewrite stack traces without sha', (done) ->
- emitter.emit 'file_list_modified', served: servedFiles
-
- _.defer ->
- ERROR = 'at http://localhost:123/absoluteC:/a/b/c.js:2:6'
- expect(formatError ERROR).to.equal 'at C:/a/b/c.js:2:6 <- /original/b.js:4:8\n'
- done()
-
- it 'should correct rewrite stack traces with sha', (done) ->
- emitter.emit 'file_list_modified', served: servedFiles
-
- _.defer ->
- ERROR = 'at http://localhost:123/absoluteC:/a/b/c.js?da39a3ee5e6:2:6'
- expect(formatError ERROR).to.equal 'at C:/a/b/c.js:2:6 <- /original/b.js:4:8\n'
- done()
diff --git a/test/unit/reporter.spec.js b/test/unit/reporter.spec.js
new file mode 100644
index 000000000..2d0130731
--- /dev/null
+++ b/test/unit/reporter.spec.js
@@ -0,0 +1,148 @@
+import {EventEmitter} from 'events'
+import File from '../../lib/file'
+import {loadFile} from 'mocks'
+var _ = require('../../lib/helper')._
+
+describe('reporter', () => {
+ var m
+
+ beforeEach(() => {
+ m = loadFile(__dirname + '/../../lib/reporter.js')
+ })
+
+ // ==============================================================================
+ // formatError() [PRIVATE]
+ // ==============================================================================
+ describe('formatError', () => {
+ var emitter
+ var formatError = emitter = null
+
+ beforeEach(() => {
+ emitter = new EventEmitter()
+ formatError = m.createErrorFormatter('', emitter)
+ })
+
+ it('should indent', () => {
+ expect(formatError('Something', '\t')).to.equal('\tSomething\n')
+ })
+
+ it('should handle empty message', () => {
+ expect(formatError(null)).to.equal('\n')
+ })
+
+ it('should remove domain from files', () => {
+ expect(formatError('file http://localhost:8080/base/usr/a.js and http://127.0.0.1:8080/base/home/b.js')).to.be.equal('file /usr/a.js and /home/b.js\n')
+ })
+
+ // TODO(vojta): enable once we serve source under urlRoot
+ it.skip('should handle non default karma service folders', () => {
+ formatError = m.createErrorFormatter('', '/_karma_/')
+ expect(formatError('file http://localhost:8080/_karma_/base/usr/a.js and http://127.0.0.1:8080/_karma_/base/home/b.js')).to.be.equal('file /usr/a.js and /home/b.js\n')
+ })
+
+ it('should remove shas', () => {
+ var ERROR = 'file http://localhost:8080/base/usr/file.js?6e31cb249ee5b32d91f37ea516ca0f84bddc5aa9 and http://127.0.0.1:8080/absolute/home/file.js?6e31cb249ee5b32d91f37ea516ca0f84bddc5aa9'
+ expect(formatError(ERROR)).to.be.equal('file /usr/file.js and /home/file.js\n')
+ })
+
+ it('should indent all lines', () => {
+ expect(formatError('first\nsecond\nthird', '\t')).to.equal('\tfirst\n\tsecond\n\tthird\n')
+ })
+
+ it('should restore base paths', () => {
+ formatError = m.createErrorFormatter('/some/base', emitter)
+ expect(formatError('at http://localhost:123/base/a.js?123')).to.equal('at /some/base/a.js\n')
+ })
+
+ it('should restore absolute paths', () => {
+ var ERROR = 'at http://local:1233/absolute/usr/path.js?6e31cb249ee5b32d91f37ea516ca0f84bddc5aa9'
+ expect(formatError(ERROR)).to.equal('at /usr/path.js\n')
+ })
+
+ it('should preserve line numbers', () => {
+ var ERROR = 'at http://local:1233/absolute/usr/path.js?6e31cb249ee5b32d91f37ea516ca0f84bddc5aa9:2'
+ expect(formatError(ERROR)).to.equal('at /usr/path.js:2\n')
+ })
+
+ describe('source maps', () => {
+ class MockSourceMapConsumer {
+ constructor (sourceMap) {
+ this.source = sourceMap.content.replace('SOURCE MAP ', '/original/')
+ }
+
+ originalPositionFor (position) {
+ if (position.line === 0) {
+ throw new TypeError('Line must be greater than or equal to 1, got 0')
+ }
+
+ return {
+ source: this.source,
+ line: position.line + 2,
+ column: position.column + 2
+ }
+ }
+ }
+
+ it('should rewrite stack traces', done => {
+ formatError = m.createErrorFormatter('/some/base', emitter, MockSourceMapConsumer)
+ var servedFiles = [new File('/some/base/a.js'), new File('/some/base/b.js')]
+ servedFiles[0].sourceMap = {content: 'SOURCE MAP a.js'}
+ servedFiles[1].sourceMap = {content: 'SOURCE MAP b.js'}
+
+ emitter.emit('file_list_modified', {served: servedFiles})
+
+ _.defer(() => _.delay(() => {
+ var ERROR = 'at http://localhost:123/base/b.js:2:6'
+ expect(formatError(ERROR)).to.equal('at /some/base/b.js:2:6 <- /original/b.js:4:8\n')
+ done()
+ }, 100))
+ })
+
+ it('should fall back to non-source-map format if originalPositionFor throws', done => {
+ formatError = m.createErrorFormatter('/some/base', emitter, MockSourceMapConsumer)
+ var servedFiles = [new File('/some/base/a.js'), new File('/some/base/b.js')]
+ servedFiles[0].sourceMap = 'SOURCE MAP a.js'
+ servedFiles[1].sourceMap = 'SOURCE MAP b.js'
+
+ emitter.emit('file_list_modified', {served: servedFiles})
+
+ _.defer(() => {
+ var ERROR = 'at http://localhost:123/base/b.js:0:0'
+ expect(formatError(ERROR)).to.equal('at /some/base/b.js\n')
+ done()
+ })
+ })
+
+ describe('Windows', () => {
+ formatError = null
+ var servedFiles = null
+
+ beforeEach(() => {
+ formatError = m.createErrorFormatter('/some/base', emitter, MockSourceMapConsumer)
+ servedFiles = [new File('C:/a/b/c.js')]
+ servedFiles[0].sourceMap = {content: 'SOURCE MAP b.js'}
+ })
+
+ it('should correct rewrite stack traces without sha', done => {
+ emitter.emit('file_list_modified', {served: servedFiles})
+
+ _.defer(() => {
+ var ERROR = 'at http://localhost:123/absoluteC:/a/b/c.js:2:6'
+ expect(formatError(ERROR)).to.equal('at C:/a/b/c.js:2:6 <- /original/b.js:4:8\n')
+ done()
+ })
+ })
+
+ it('should correct rewrite stack traces with sha', done => {
+ emitter.emit('file_list_modified', {served: servedFiles})
+
+ _.defer(() => {
+ var ERROR = 'at http://localhost:123/absoluteC:/a/b/c.js?da39a3ee5e6:2:6'
+ expect(formatError(ERROR)).to.equal('at C:/a/b/c.js:2:6 <- /original/b.js:4:8\n')
+ done()
+ })
+ })
+ })
+ })
+ })
+})
diff --git a/test/unit/reporters/base.spec.coffee b/test/unit/reporters/base.spec.coffee
deleted file mode 100644
index 5ee9821c7..000000000
--- a/test/unit/reporters/base.spec.coffee
+++ /dev/null
@@ -1,49 +0,0 @@
-#==============================================================================
-# lib/reporters/Base.js module
-#==============================================================================
-describe 'reporter', ->
- loadFile = require('mocks').loadFile
- m = null
-
- beforeEach ->
- m = loadFile __dirname + '/../../../lib/reporters/base.js'
-
- describe 'Progress', ->
- adapter = reporter = null
-
- beforeEach ->
-
- adapter = sinon.spy()
- reporter = new m.BaseReporter null, null, adapter
-
-
- it 'should write to all registered adapters', ->
- anotherAdapter = sinon.spy()
- reporter.adapters.push anotherAdapter
-
- reporter.write 'some'
- expect(adapter).to.have.been.calledWith 'some'
- expect(anotherAdapter).to.have.been.calledWith 'some'
-
-
- it 'should format', ->
- reporter.write 'Success: %d Failure: %d', 10, 20
-
- expect(adapter).to.have.been.calledWith 'Success: 10 Failure: 20'
-
- it 'should format log messages correctly for single browser', ->
- writeSpy = sinon.spy reporter, 'writeCommonMsg'
-
- reporter._browsers = ['Chrome']
- reporter.onBrowserLog 'Chrome', 'Message', 'LOG'
-
- expect(writeSpy).to.have.been.calledWith 'LOG: Message\n'
-
- it 'should format log messages correctly for multi browsers', ->
- writeSpy = sinon.spy reporter, 'writeCommonMsg'
-
- reporter._browsers = ['Chrome', 'Firefox']
- reporter.onBrowserLog 'Chrome', 'Message', 'LOG'
-
- expect(writeSpy).to.have.been.calledWith 'Chrome LOG: Message\n'
-
diff --git a/test/unit/reporters/base.spec.js b/test/unit/reporters/base.spec.js
new file mode 100644
index 000000000..0eee0cd20
--- /dev/null
+++ b/test/unit/reporters/base.spec.js
@@ -0,0 +1,56 @@
+// ==============================================================================
+// lib/reporters/Base.js module
+// ==============================================================================
+describe('reporter', function () {
+ var loadFile = require('mocks').loadFile
+ var m = null
+
+ beforeEach(function () {
+ m = loadFile(__dirname + '/../../../lib/reporters/base.js')
+ return m
+ })
+
+ return describe('Progress', function () {
+ var reporter
+ var adapter = reporter = null
+
+ beforeEach(function () {
+ adapter = sinon.spy()
+ reporter = new m.BaseReporter(null, null, adapter)
+ return reporter
+ })
+
+ it('should write to all registered adapters', function () {
+ var anotherAdapter = sinon.spy()
+ reporter.adapters.push(anotherAdapter)
+
+ reporter.write('some')
+ expect(adapter).to.have.been.calledWith('some')
+ return expect(anotherAdapter).to.have.been.calledWith('some')
+ })
+
+ it('should format', function () {
+ reporter.write('Success: %d Failure: %d', 10, 20)
+
+ return expect(adapter).to.have.been.calledWith('Success: 10 Failure: 20')
+ })
+
+ it('should format log messages correctly for single browser', function () {
+ var writeSpy = sinon.spy(reporter, 'writeCommonMsg')
+
+ reporter._browsers = ['Chrome']
+ reporter.onBrowserLog('Chrome', 'Message', 'LOG')
+
+ return expect(writeSpy).to.have.been.calledWith('LOG: Message\n')
+ })
+
+ return it('should format log messages correctly for multi browsers', function () {
+ var writeSpy = sinon.spy(reporter, 'writeCommonMsg')
+
+ reporter._browsers = ['Chrome', 'Firefox']
+ reporter.onBrowserLog('Chrome', 'Message', 'LOG')
+
+ return expect(writeSpy).to.have.been.calledWith('Chrome LOG: Message\n')
+ })
+ })
+})
diff --git a/test/unit/runner.spec.coffee b/test/unit/runner.spec.coffee
deleted file mode 100644
index 97a3ad855..000000000
--- a/test/unit/runner.spec.coffee
+++ /dev/null
@@ -1,49 +0,0 @@
-#==============================================================================
-# lib/runner.js module
-#==============================================================================
-describe 'runner', ->
- loadFile = require('mocks').loadFile
- constant = require '../../lib/constants'
- m = null
-
- beforeEach ->
- m = loadFile __dirname + '/../../lib/runner.js'
-
- #============================================================================
- # runner.parseExitCode
- #============================================================================
- describe 'parseExitCode', ->
- EXIT = constant.EXIT_CODE
-
- it 'should return 0 exit code if present in the buffer', ->
- expect(m.parseExitCode new Buffer 'something\nfake' + EXIT + '0').to.equal 0
-
-
- it 'should null the exit code part of the buffer', ->
- buffer = new Buffer 'some' + EXIT + '1'
- m.parseExitCode buffer
-
- expect(buffer.toString()).to.equal 'some\0\0\0\0\0\0'
-
-
- it 'should not touch buffer without exit code and return default', ->
- msg = 'some nice \n messgae {}'
- buffer = new Buffer msg
- code = m.parseExitCode buffer, 10
-
- expect(buffer.toString()).to.equal msg
- expect(code).to.equal 10
-
-
- it 'should not slice buffer if smaller than exit code msg', ->
- # regression
- fakeBuffer = {length: 1, slice: -> null}
- sinon.stub fakeBuffer, 'slice'
-
- code = m.parseExitCode fakeBuffer, 10
- expect(fakeBuffer.slice).not.to.have.been.called
-
-
- it 'should parse any single digit exit code', ->
- expect(m.parseExitCode new Buffer 'something\nfake' + EXIT + '1').to.equal 1
- expect(m.parseExitCode new Buffer 'something\nfake' + EXIT + '7').to.equal 7
diff --git a/test/unit/runner.spec.js b/test/unit/runner.spec.js
new file mode 100644
index 000000000..5d5c7a785
--- /dev/null
+++ b/test/unit/runner.spec.js
@@ -0,0 +1,48 @@
+import {loadFile} from 'mocks'
+import constant from '../../lib/constants'
+
+describe('runner', () => {
+ var m
+
+ beforeEach(() => {
+ m = loadFile(__dirname + '/../../lib/runner.js')
+ })
+
+ describe('parseExitCode', () => {
+ var EXIT = constant.EXIT_CODE
+
+ it('should return 0 exit code if present in the buffer', () => {
+ expect(m.parseExitCode(new Buffer(`something\nfake${EXIT}0`))).to.equal(0)
+ })
+
+ it('should null the exit code part of the buffer', () => {
+ var buffer = new Buffer(`some${EXIT}1`)
+ m.parseExitCode(buffer)
+
+ expect(buffer.toString()).to.equal('some\0\0\0\0\0\0')
+ })
+
+ it('should not touch buffer without exit code and return default', () => {
+ var msg = 'some nice \n messgae {}'
+ var buffer = new Buffer(msg)
+ var code = m.parseExitCode(buffer, 10)
+
+ expect(buffer.toString()).to.equal(msg)
+ expect(code).to.equal(10)
+ })
+
+ it('should not slice buffer if smaller than exit code msg', () => {
+ // regression
+ var fakeBuffer = {length: 1, slice: () => null}
+ sinon.stub(fakeBuffer, 'slice')
+
+ m.parseExitCode(fakeBuffer, 10)
+ expect(fakeBuffer.slice).not.to.have.been.called
+ })
+
+ it('should parse any single digit exit code', () => {
+ expect(m.parseExitCode(new Buffer(`something\nfake${EXIT}1`))).to.equal(1)
+ expect(m.parseExitCode(new Buffer(`something\nfake${EXIT}7`))).to.equal(7)
+ })
+ })
+})
diff --git a/test/unit/server.spec.coffee b/test/unit/server.spec.coffee
deleted file mode 100644
index 3fffb003a..000000000
--- a/test/unit/server.spec.coffee
+++ /dev/null
@@ -1,167 +0,0 @@
-#==============================================================================
-# lib/server.js module
-#==============================================================================
-
-Server = require('../../lib/server')
-BrowserCollection = require('../../lib/browser_collection')
-
-describe 'server', ->
-
- server = mockConfig = browserCollection = injector = webServerOnError = null
- fileListOnResolve = fileListOnReject = mockLauncher = null
- mockFileList = mockWebServer = mockSocketServer = mockExecutor = doneSpy = null
-
- beforeEach ->
- browserCollection = new BrowserCollection
- doneSpy = sinon.spy()
-
- fileListOnResolve = fileListOnReject = null
-
- doneSpy = sinon.spy()
-
- mockConfig =
- frameworks: []
- port: 9876
- autoWatch: true
- hostname: 'localhost'
- urlRoot: '/'
- browsers: ['fake']
- singleRun: true
- logLevel: 'OFF'
- browserDisconnectTolerance: 0
-
- server = new Server(mockConfig, doneSpy)
-
- sinon.stub(server._injector, 'invoke').returns([])
-
- mockExecutor =
- schedule: ->
-
- mockFileList =
- refresh: sinon.spy( -> then: (onResolve, onReject) ->
- fileListOnResolve = onResolve
- fileListOnReject = onReject
- )
-
- mockLauncher =
- launch: ->
- markCaptured: ->
- areAllCaptured: -> false
- restart: -> true
- kill: -> true
-
- mockSocketServer =
- flashPolicyServer:
- close: ->
- sockets:
- sockets: {}
- on: ->
- emit: ->
-
- mockWebServer =
- on: (name, handler) ->
- if name == 'error'
- webServerOnError = handler
- listen: sinon.spy((port, callback) -> callback && callback())
- removeAllListeners: ->
- close: ->
-
- webServerOnError = null
-
-
-
- #============================================================================
- # server._start()
- #============================================================================
- describe '_start', ->
- it 'should start the web server after all files have been preprocessed successfully', ->
- server._start(mockConfig, mockLauncher, null, mockFileList,
- mockWebServer, browserCollection, mockSocketServer, mockExecutor, doneSpy)
-
- expect(mockFileList.refresh).to.have.been.called
- expect(fileListOnResolve).not.to.be.null
- expect(mockWebServer.listen).not.to.have.been.called
- expect(server._injector.invoke).not.to.have.been.calledWith mockLauncher.launch, mockLauncher
-
- fileListOnResolve()
-
- expect(mockWebServer.listen).to.have.been.called
- expect(server._injector.invoke).to.have.been.calledWith mockLauncher.launch, mockLauncher
-
- it 'should start the web server after all files have been preprocessed with an error', ->
- server._start(mockConfig, mockLauncher, null, mockFileList,
- mockWebServer, browserCollection, mockSocketServer, mockExecutor, doneSpy)
-
- expect(mockFileList.refresh).to.have.been.called
- expect(fileListOnReject).not.to.be.null
- expect(mockWebServer.listen).not.to.have.been.called
- expect(server._injector.invoke).not.to.have.been.calledWith mockLauncher.launch, mockLauncher
-
- fileListOnReject()
-
- expect(mockWebServer.listen).to.have.been.called
- expect(server._injector.invoke).to.have.been.calledWith mockLauncher.launch, mockLauncher
-
- it 'should launch browsers after the web server has started', ->
- server._start(mockConfig, mockLauncher, null, mockFileList,
- mockWebServer, browserCollection, mockSocketServer, mockExecutor, doneSpy)
-
- expect(mockWebServer.listen).not.to.have.been.called
- expect(server._injector.invoke).not.to.have.been.calledWith mockLauncher.launch, mockLauncher
-
- fileListOnResolve()
-
- expect(mockWebServer.listen).to.have.been.called
- expect(server._injector.invoke).to.have.been.calledWith mockLauncher.launch, mockLauncher
-
- it 'should try next port if already in use', ->
- server._start(mockConfig, mockLauncher, null, mockFileList,
- mockWebServer, browserCollection, mockSocketServer, mockExecutor, doneSpy)
-
- expect(mockWebServer.listen).not.to.have.been.called
- expect(webServerOnError).not.to.be.null
-
- expect(mockConfig.port).to.be.equal 9876
-
- fileListOnResolve()
-
- expect(mockWebServer.listen).to.have.been.calledWith(9876)
-
- webServerOnError({ code: 'EADDRINUSE'})
-
- expect(mockWebServer.listen).to.have.been.calledWith(9877)
- expect(mockConfig.port).to.be.equal 9877
-
- it 'should emit a browsers_ready event once all the browsers are captured', ->
- server._start(mockConfig, mockLauncher, null, mockFileList,
- mockWebServer, browserCollection, mockSocketServer, mockExecutor, doneSpy)
-
- browsersReady = sinon.spy()
- server.on('browsers_ready', browsersReady)
-
- mockLauncher.areAllCaptured = -> false
- fileListOnResolve()
- expect(browsersReady).not.to.have.been.called
-
- mockLauncher.areAllCaptured = -> true
- server.emit('browser_register', {})
- expect(browsersReady).to.have.been.called
-
- it 'should emit a browser_register event for each browser added', ->
- server._start(mockConfig, mockLauncher, null, mockFileList,
- mockWebServer, browserCollection, mockSocketServer, mockExecutor, doneSpy)
-
- browsersReady = sinon.spy()
- server.on('browsers_ready', browsersReady)
-
- mockLauncher.areAllCaptured = -> false
- fileListOnResolve()
- expect(browsersReady).not.to.have.been.called
-
- mockLauncher.areAllCaptured = -> true
- server.emit('browser_register', {})
- expect(browsersReady).to.have.been.called
-
- describe.skip 'singleRun', ->
- it 'should run tests when all browsers captured', ->
- it 'should run tests when first browser captured if no browser configured', ->
diff --git a/test/unit/server.spec.js b/test/unit/server.spec.js
new file mode 100644
index 000000000..e537aedcf
--- /dev/null
+++ b/test/unit/server.spec.js
@@ -0,0 +1,187 @@
+import Server from '../../lib/server'
+import BrowserCollection from '../../lib/browser_collection'
+
+describe('server', () => {
+ var mockConfig
+ var browserCollection
+ var webServerOnError
+ var fileListOnReject
+ var mockLauncher
+ var mockWebServer
+ var mockSocketServer
+ var mockExecutor
+ var doneSpy
+ var server = mockConfig = browserCollection = webServerOnError = null
+ var fileListOnResolve = fileListOnReject = mockLauncher = null
+ var mockFileList = mockWebServer = mockSocketServer = mockExecutor = doneSpy = null
+
+ beforeEach(() => {
+ browserCollection = new BrowserCollection()
+ doneSpy = sinon.spy()
+
+ fileListOnResolve = fileListOnReject = null
+
+ doneSpy = sinon.spy()
+
+ mockConfig =
+ {frameworks: [],
+ port: 9876,
+ autoWatch: true,
+ hostname: 'localhost',
+ urlRoot: '/',
+ browsers: ['fake'],
+ singleRun: true,
+ logLevel: 'OFF',
+ browserDisconnectTolerance: 0}
+
+ server = new Server(mockConfig, doneSpy)
+
+ sinon.stub(server._injector, 'invoke').returns([])
+
+ mockExecutor =
+ {schedule: () => {}}
+
+ mockFileList = {
+ refresh: sinon.spy(() => {
+ return {
+ then (onResolve, onReject) {
+ fileListOnResolve = onResolve
+ fileListOnReject = onReject
+ }
+ }
+ })
+ }
+
+ mockLauncher = {
+ launch: () => {},
+ markCaptured: () => {},
+ areAllCaptured: () => false,
+ restart: () => true,
+ kill: () => true
+ }
+
+ mockSocketServer = {
+ flashPolicyServer: {
+ close: () => {}
+ },
+ sockets: {
+ sockets: {},
+ on: () => {},
+ emit: () => {}
+ }
+ }
+
+ mockWebServer = {
+ on (name, handler) {
+ if (name === 'error') {
+ webServerOnError = handler
+ }
+ },
+ listen: sinon.spy((port, callback) => {
+ callback && callback()
+ }),
+ removeAllListeners: () => {},
+ close: () => {}
+ }
+
+ webServerOnError = null
+ })
+
+ // ============================================================================
+ // server._start()
+ // ============================================================================
+ describe('_start', () => {
+ it('should start the web server after all files have been preprocessed successfully', () => {
+ server._start(mockConfig, mockLauncher, null, mockFileList, mockWebServer, browserCollection, mockSocketServer, mockExecutor, doneSpy)
+
+ expect(mockFileList.refresh).to.have.been.called
+ expect(fileListOnResolve).not.to.be.null
+ expect(mockWebServer.listen).not.to.have.been.called
+ expect(server._injector.invoke).not.to.have.been.calledWith(mockLauncher.launch, mockLauncher)
+
+ fileListOnResolve()
+
+ expect(mockWebServer.listen).to.have.been.called
+ expect(server._injector.invoke).to.have.been.calledWith(mockLauncher.launch, mockLauncher)
+ })
+
+ it('should start the web server after all files have been preprocessed with an error', () => {
+ server._start(mockConfig, mockLauncher, null, mockFileList, mockWebServer, browserCollection, mockSocketServer, mockExecutor, doneSpy)
+
+ expect(mockFileList.refresh).to.have.been.called
+ expect(fileListOnReject).not.to.be.null
+ expect(mockWebServer.listen).not.to.have.been.called
+ expect(server._injector.invoke).not.to.have.been.calledWith(mockLauncher.launch, mockLauncher)
+
+ fileListOnReject()
+
+ expect(mockWebServer.listen).to.have.been.called
+ expect(server._injector.invoke).to.have.been.calledWith(mockLauncher.launch, mockLauncher)
+ })
+
+ it('should launch browsers after the web server has started', () => {
+ server._start(mockConfig, mockLauncher, null, mockFileList, mockWebServer, browserCollection, mockSocketServer, mockExecutor, doneSpy)
+
+ expect(mockWebServer.listen).not.to.have.been.called
+ expect(server._injector.invoke).not.to.have.been.calledWith(mockLauncher.launch, mockLauncher)
+
+ fileListOnResolve()
+
+ expect(mockWebServer.listen).to.have.been.called
+ expect(server._injector.invoke).to.have.been.calledWith(mockLauncher.launch, mockLauncher)
+ })
+
+ it('should try next port if already in use', () => {
+ server._start(mockConfig, mockLauncher, null, mockFileList, mockWebServer, browserCollection, mockSocketServer, mockExecutor, doneSpy)
+
+ expect(mockWebServer.listen).not.to.have.been.called
+ expect(webServerOnError).not.to.be.null
+
+ expect(mockConfig.port).to.be.equal(9876)
+
+ fileListOnResolve()
+
+ expect(mockWebServer.listen).to.have.been.calledWith(9876)
+
+ webServerOnError({code: 'EADDRINUSE'})
+
+ expect(mockWebServer.listen).to.have.been.calledWith(9877)
+ expect(mockConfig.port).to.be.equal(9877)
+ })
+
+ it('should emit a browsers_ready event once all the browsers are captured', () => {
+ server._start(mockConfig, mockLauncher, null, mockFileList, mockWebServer, browserCollection, mockSocketServer, mockExecutor, doneSpy)
+
+ var browsersReady = sinon.spy()
+ server.on('browsers_ready', browsersReady)
+
+ mockLauncher.areAllCaptured = () => false
+ fileListOnResolve()
+ expect(browsersReady).not.to.have.been.called
+
+ mockLauncher.areAllCaptured = () => true
+ server.emit('browser_register', {})
+ expect(browsersReady).to.have.been.called
+ })
+
+ it('should emit a browser_register event for each browser added', () => {
+ server._start(mockConfig, mockLauncher, null, mockFileList, mockWebServer, browserCollection, mockSocketServer, mockExecutor, doneSpy)
+
+ var browsersReady = sinon.spy()
+ server.on('browsers_ready', browsersReady)
+
+ mockLauncher.areAllCaptured = () => false
+ fileListOnResolve()
+ expect(browsersReady).not.to.have.been.called
+
+ mockLauncher.areAllCaptured = () => true
+ server.emit('browser_register', {})
+ expect(browsersReady).to.have.been.called
+ })
+ })
+
+ describe.skip('singleRun', () => {
+ it('should run tests when all browsers captured', () => {})
+ it('should run tests when first browser captured if no browser configured', () => {})
+ })
+})
diff --git a/test/unit/watcher.spec.coffee b/test/unit/watcher.spec.coffee
deleted file mode 100644
index 866454975..000000000
--- a/test/unit/watcher.spec.coffee
+++ /dev/null
@@ -1,145 +0,0 @@
-#==============================================================================
-# lib/watcher.js module
-#==============================================================================
-describe 'watcher', ->
- mocks = require 'mocks'
- config = require '../../lib/config'
- path = require 'path'
- m = null
-
- beforeEach ->
- mocks_ = chokidar: mocks.chokidar
- m = mocks.loadFile __dirname + '/../../lib/watcher.js', mocks_
-
- #============================================================================
- # baseDirFromPattern() [PRIVATE]
- #============================================================================
- describe 'baseDirFromPattern', ->
-
- it 'should return parent directory without start', ->
- expect(m.baseDirFromPattern '/some/path/**/more.js').to.equal '/some/path'
- expect(m.baseDirFromPattern '/some/p*/file.js').to.equal '/some'
-
-
- it 'should remove part with !(x)', ->
- expect(m.baseDirFromPattern '/some/p/!(a|b).js').to.equal '/some/p'
- expect(m.baseDirFromPattern '/some/p!(c|b)*.js').to.equal '/some'
-
-
- it 'should remove part with +(x)', ->
- expect(m.baseDirFromPattern '/some/p/+(a|b).js').to.equal '/some/p'
- expect(m.baseDirFromPattern '/some/p+(c|bb).js').to.equal '/some'
-
-
- it 'should remove part with (x)?', ->
- expect(m.baseDirFromPattern '/some/p/(a|b)?.js').to.equal '/some/p'
- expect(m.baseDirFromPattern '/some/p(c|b)?.js').to.equal '/some'
-
-
- it 'should allow paths with parentheses', ->
- expect(m.baseDirFromPattern '/some/x (a|b)/a.js').to.equal '/some/x (a|b)/a.js'
- expect(m.baseDirFromPattern '/some/p(c|b)/*.js').to.equal '/some/p(c|b)'
-
-
- it 'should ignore exact files', ->
- expect(m.baseDirFromPattern '/usr/local/bin.js').to.equal '/usr/local/bin.js'
-
-
- #==============================================================================
- # watchPatterns() [PRIVATE]
- #==============================================================================
- describe 'watchPatterns', ->
- chokidarWatcher = null
-
- beforeEach ->
- chokidarWatcher = new mocks.chokidar.FSWatcher
-
- it 'should watch all the patterns', ->
- m.watchPatterns ['/some/*.js', '/a/*'], chokidarWatcher
- expect(chokidarWatcher.watchedPaths_).to.deep.equal ['/some', '/a']
-
-
- it 'should expand braces and watch all the patterns', ->
- m.watchPatterns ['/some/{a,b}/*.js', '/a/*'], chokidarWatcher
- expect(chokidarWatcher.watchedPaths_).to.deep.equal ['/some/a', '/some/b', '/a']
-
-
- it 'should not watch the same path twice', ->
- m.watchPatterns ['/some/a*.js', '/some/*.txt'], chokidarWatcher
- expect(chokidarWatcher.watchedPaths_).to.deep.equal ['/some']
-
-
- it 'should not watch the same path twice when using braces', ->
- m.watchPatterns ['/some/*.{js,txt}'], chokidarWatcher
- expect(chokidarWatcher.watchedPaths_).to.deep.equal ['/some']
-
-
- it 'should not watch subpaths that are already watched', ->
- m.watchPatterns ['/some/sub/*.js', '/some/a*.*'].map(path.normalize), chokidarWatcher
- expect(chokidarWatcher.watchedPaths_).to.deep.equal [path.normalize('/some')]
-
-
- it 'should watch a file matching subpath directory', ->
- # regression #521
- m.watchPatterns ['/some/test-file.js', '/some/test/**'], chokidarWatcher
- expect(chokidarWatcher.watchedPaths_).to.deep.equal ['/some/test-file.js', '/some/test']
-
-
- it 'should watch files matching a subpath directory with braces', ->
- m.watchPatterns ['/some/{a,b}/test.js'], chokidarWatcher
- expect(chokidarWatcher.watchedPaths_).to.deep.equal ['/some/a/test.js', '/some/b/test.js']
-
-
- describe 'getWatchedPatterns', ->
-
- it 'should return list of watched patterns (strings)', ->
- watchedPatterns = m.getWatchedPatterns [
- config.createPatternObject('/watched.js')
- config.createPatternObject(pattern: 'non/*.js', watched: false)
- ]
- expect(watchedPatterns).to.deep.equal ['/watched.js']
-
-
- #============================================================================
- # ignore() [PRIVATE]
- #============================================================================
- describe 'ignore', ->
- FILE_STAT =
- isDirectory: -> false
- isFile: -> true
- DIRECTORY_STAT =
- isDirectory: -> true
- isFile: -> false
-
- it 'should ignore all files', ->
- ignore = m.createIgnore ['**/*'], ['**/*']
- expect(ignore '/some/files/deep/nested.js', FILE_STAT).to.equal true
- expect(ignore '/some/files', FILE_STAT).to.equal true
-
-
- it 'should ignore .# files', ->
- ignore = m.createIgnore ['**/*'], ['**/.#*']
- expect(ignore '/some/files/deep/nested.js', FILE_STAT).to.equal false
- expect(ignore '/some/files', FILE_STAT).to.equal false
- expect(ignore '/some/files/deep/.npm', FILE_STAT).to.equal false
- expect(ignore '.#files.js', FILE_STAT).to.equal true
- expect(ignore '/some/files/deeper/nested/.#files.js', FILE_STAT).to.equal true
-
-
- it 'should ignore files that do not match any pattern', ->
- ignore = m.createIgnore ['/some/*.js'], []
- expect(ignore '/a.js', FILE_STAT).to.equal true
- expect(ignore '/some.js', FILE_STAT).to.equal true
- expect(ignore '/some/a.js', FILE_STAT).to.equal false
-
-
- it 'should not ignore directories', ->
- ignore = m.createIgnore ['**/*'], ['**/*']
- expect(ignore '/some/dir', DIRECTORY_STAT).to.equal false
-
-
- it 'should not ignore items without stat', ->
- # before we know whether it's a directory or file, we can't ignore
- ignore = m.createIgnore ['**/*'], ['**/*']
- expect(ignore '/some.js', undefined).to.equal false
- expect(ignore '/what/ever', undefined).to.equal false
diff --git a/test/unit/watcher.spec.js b/test/unit/watcher.spec.js
new file mode 100644
index 000000000..125a67574
--- /dev/null
+++ b/test/unit/watcher.spec.js
@@ -0,0 +1,145 @@
+import mocks from 'mocks'
+import path from 'path'
+
+describe('watcher', () => {
+
+ var config = require('../../lib/config')
+
+ var m = null
+
+ beforeEach(() => {
+ var mocks_ = {chokidar: mocks.chokidar}
+ m = mocks.loadFile(__dirname + '/../../lib/watcher.js', mocks_)
+ })
+
+ describe('baseDirFromPattern', () => {
+ it('should return parent directory without start', () => {
+ expect(m.baseDirFromPattern('/some/path/**/more.js')).to.equal('/some/path')
+ expect(m.baseDirFromPattern('/some/p*/file.js')).to.equal('/some')
+ })
+
+ it('should remove part with !(x)', () => {
+ expect(m.baseDirFromPattern('/some/p/!(a|b).js')).to.equal('/some/p')
+ expect(m.baseDirFromPattern('/some/p!(c|b)*.js')).to.equal('/some')
+ })
+
+ it('should remove part with +(x)', () => {
+ expect(m.baseDirFromPattern('/some/p/+(a|b).js')).to.equal('/some/p')
+ expect(m.baseDirFromPattern('/some/p+(c|bb).js')).to.equal('/some')
+ })
+
+ it('should remove part with (x)?', () => {
+ expect(m.baseDirFromPattern('/some/p/(a|b)?.js')).to.equal('/some/p')
+ expect(m.baseDirFromPattern('/some/p(c|b)?.js')).to.equal('/some')
+ })
+
+ it('should allow paths with parentheses', () => {
+ expect(m.baseDirFromPattern('/some/x (a|b)/a.js')).to.equal('/some/x (a|b)/a.js')
+ expect(m.baseDirFromPattern('/some/p(c|b)/*.js')).to.equal('/some/p(c|b)')
+ })
+
+ it('should ignore exact files', () => {
+ expect(m.baseDirFromPattern('/usr/local/bin.js')).to.equal('/usr/local/bin.js')
+ })
+ })
+
+ describe('watchPatterns', () => {
+ var chokidarWatcher = null
+
+ beforeEach(() => {
+ chokidarWatcher = new mocks.chokidar.FSWatcher()
+ })
+
+ it('should watch all the patterns', () => {
+ m.watchPatterns(['/some/*.js', '/a/*'], chokidarWatcher)
+ expect(chokidarWatcher.watchedPaths_).to.deep.equal(['/some', '/a'])
+ })
+
+ it('should expand braces and watch all the patterns', () => {
+ m.watchPatterns(['/some/{a,b}/*.js', '/a/*'], chokidarWatcher)
+ expect(chokidarWatcher.watchedPaths_).to.deep.equal(['/some/a', '/some/b', '/a'])
+ })
+
+ it('should not watch the same path twice', () => {
+ m.watchPatterns(['/some/a*.js', '/some/*.txt'], chokidarWatcher)
+ expect(chokidarWatcher.watchedPaths_).to.deep.equal(['/some'])
+ })
+
+ it('should not watch the same path twice when using braces', () => {
+ m.watchPatterns(['/some/*.{js,txt}'], chokidarWatcher)
+ expect(chokidarWatcher.watchedPaths_).to.deep.equal(['/some'])
+ })
+
+ it('should not watch subpaths that are already watched', () => {
+ m.watchPatterns(['/some/sub/*.js', '/some/a*.*'].map(path.normalize), chokidarWatcher)
+ expect(chokidarWatcher.watchedPaths_).to.deep.equal([path.normalize('/some')])
+ })
+
+ it('should watch a file matching subpath directory', () => {
+ // regression #521
+ m.watchPatterns(['/some/test-file.js', '/some/test/**'], chokidarWatcher)
+ expect(chokidarWatcher.watchedPaths_).to.deep.equal(['/some/test-file.js', '/some/test'])
+ })
+
+ it('should watch files matching a subpath directory with braces', () => {
+ m.watchPatterns(['/some/{a,b}/test.js'], chokidarWatcher)
+ expect(chokidarWatcher.watchedPaths_).to.deep.equal(['/some/a/test.js', '/some/b/test.js'])
+ })
+ })
+
+ describe('getWatchedPatterns', () => {
+ it('should return list of watched patterns (strings)', () => {
+ var watchedPatterns = m.getWatchedPatterns([
+ config.createPatternObject('/watched.js'),
+ config.createPatternObject({pattern: 'non/*.js', watched: false})
+ ])
+ expect(watchedPatterns).to.deep.equal(['/watched.js'])
+ })
+ })
+
+ describe('ignore', () => {
+ var FILE_STAT = {
+ isDirectory: () => false,
+ isFile: () => true
+ }
+
+ var DIRECTORY_STAT = {
+ isDirectory: () => true,
+ isFile: () => false
+ }
+
+ it('should ignore all files', () => {
+ var ignore = m.createIgnore(['**/*'], ['**/*'])
+ expect(ignore('/some/files/deep/nested.js', FILE_STAT)).to.equal(true)
+ expect(ignore('/some/files', FILE_STAT)).to.equal(true)
+ })
+
+ it('should ignore .# files', () => {
+ var ignore = m.createIgnore(['**/*'], ['**/.#*'])
+ expect(ignore('/some/files/deep/nested.js', FILE_STAT)).to.equal(false)
+ expect(ignore('/some/files', FILE_STAT)).to.equal(false)
+ expect(ignore('/some/files/deep/.npm', FILE_STAT)).to.equal(false)
+ expect(ignore('.#files.js', FILE_STAT)).to.equal(true)
+ expect(ignore('/some/files/deeper/nested/.#files.js', FILE_STAT)).to.equal(true)
+ })
+
+ it('should ignore files that do not match any pattern', () => {
+ var ignore = m.createIgnore(['/some/*.js'], [])
+ expect(ignore('/a.js', FILE_STAT)).to.equal(true)
+ expect(ignore('/some.js', FILE_STAT)).to.equal(true)
+ expect(ignore('/some/a.js', FILE_STAT)).to.equal(false)
+ })
+
+ it('should not ignore directories', () => {
+ var ignore = m.createIgnore(['**/*'], ['**/*'])
+ expect(ignore('/some/dir', DIRECTORY_STAT)).to.equal(false)
+ })
+
+ it('should not ignore items without stat', () => {
+ // before we know whether it's a directory or file, we can't ignore
+ var ignore = m.createIgnore(['**/*'], ['**/*'])
+ expect(ignore('/some.js', undefined)).to.equal(false)
+ expect(ignore('/what/ever', undefined)).to.equal(false)
+ })
+ })
+})
diff --git a/test/unit/web-server.spec.coffee b/test/unit/web-server.spec.coffee
deleted file mode 100644
index b4e1e015b..000000000
--- a/test/unit/web-server.spec.coffee
+++ /dev/null
@@ -1,93 +0,0 @@
-require 'core-js'
-request = require 'supertest-as-promised'
-di = require 'di'
-Promise = require 'bluebird'
-mocks = require 'mocks'
-_ = require('../../lib/helper')._
-
-describe 'web-server', ->
-
- File = require('../../lib/file')
-
- EventEmitter = require('events').EventEmitter
-
- _mocks = {}
- _globals = {__dirname: '/karma/lib'}
-
- _mocks.fs = mocks.fs.create
- karma:
- static:
- 'client.html': mocks.fs.file(0, 'CLIENT HTML')
- base:
- path:
- 'one.js': mocks.fs.file(0, 'js-source')
- 'new.js': mocks.fs.file(0, 'new-js-source')
-
- # NOTE(vojta): only loading once, to speed things up
- # this relies on the fact that none of these tests mutate fs
- m = mocks.loadFile __dirname + '/../../lib/web-server.js', _mocks, _globals
-
- customFileHandlers = server = emitter = null
-
- servedFiles = (files) ->
- emitter.emit 'file_list_modified', {included: [], served: files}
-
- beforeEach ->
- customFileHandlers = []
- emitter = new EventEmitter
-
- injector = new di.Injector [{
- config: ['value', {basePath: '/base/path', urlRoot: '/'}]
- customFileHandlers: ['value', customFileHandlers],
- emitter: ['value', emitter],
- fileList: ['value', null],
- capturedBrowsers: ['value', null],
- reporter: ['value', null],
- executor: ['value', null]
- }]
-
- server = injector.invoke m.createWebServer
-
- it 'should serve client.html', () ->
- servedFiles new Set()
-
- request(server)
- .get('/')
- .expect(200, 'CLIENT HTML')
-
- it 'should serve source files', () ->
- servedFiles new Set([new File '/base/path/one.js'])
-
- request(server)
- .get('/base/one.js')
- .expect(200, 'js-source')
-
- it 'should serve updated source files on file_list_modified', () ->
- servedFiles new Set([new File '/base/path/one.js'])
- servedFiles new Set([new File '/base/path/new.js'])
-
- request(server)
- .get('/base/new.js')
- .expect(200, 'new-js-source')
-
- it 'should load custom handlers', () ->
- servedFiles new Set()
-
- # TODO(vojta): change this, only keeping because karma-dart is relying on it
- customFileHandlers.push {
- urlRegex: /\/some\/weird/
- handler: (request, response, staticFolder, adapterFolder, baseFolder, urlRoot) ->
- response.writeHead 222
- response.end 'CONTENT'
- }
-
- request(server)
- .get('/some/weird/url')
- .expect(222, 'CONTENT')
-
- it 'should serve 404 for non-existing files', () ->
- servedFiles new Set()
-
- request(server)
- .get('/non/existing.html')
- .expect(404)
diff --git a/test/unit/web-server.spec.js b/test/unit/web-server.spec.js
new file mode 100644
index 000000000..38bac6bcf
--- /dev/null
+++ b/test/unit/web-server.spec.js
@@ -0,0 +1,106 @@
+require('core-js')
+import {EventEmitter} from 'events'
+import request from 'supertest-as-promised'
+import di from 'di'
+import mocks from 'mocks'
+
+describe('web-server', () => {
+ var server
+ var emitter
+ var File = require('../../lib/file')
+
+ var _mocks = {}
+ var _globals = {__dirname: '/karma/lib'}
+
+ _mocks.fs = mocks.fs.create({
+ karma: {
+ static: {
+ 'client.html': mocks.fs.file(0, 'CLIENT HTML')
+ }
+ },
+ base: {
+ path: {
+ 'one.js': mocks.fs.file(0, 'js-source'),
+ 'new.js': mocks.fs.file(0, 'new-js-source')
+ }
+ }
+ })
+
+ // NOTE(vojta): only loading once, to speed things up
+ // this relies on the fact that none of these tests mutate fs
+ var m = mocks.loadFile(__dirname + '/../../lib/web-server.js', _mocks, _globals)
+
+ var customFileHandlers = server = emitter = null
+
+ var servedFiles = (files) => {
+ emitter.emit('file_list_modified', {included: [], served: files})
+ }
+
+ beforeEach(() => {
+ customFileHandlers = []
+ emitter = new EventEmitter()
+
+ var injector = new di.Injector([{
+ config: ['value', {basePath: '/base/path', urlRoot: '/'}],
+ customFileHandlers: ['value', customFileHandlers],
+ emitter: ['value', emitter],
+ fileList: ['value', null],
+ capturedBrowsers: ['value', null],
+ reporter: ['value', null],
+ executor: ['value', null],
+ proxies: ['value', null]
+ }])
+
+ server = injector.invoke(m.createWebServer)
+ })
+
+ it('should serve client.html', () => {
+ servedFiles(new Set())
+
+ return request(server)
+ .get('/')
+ .expect(200, 'CLIENT HTML')
+ })
+
+ it('should serve source files', () => {
+ servedFiles(new Set([new File('/base/path/one.js')]))
+
+ return request(server)
+ .get('/base/one.js')
+ .expect(200, 'js-source')
+ })
+
+ it('should serve updated source files on file_list_modified', () => {
+ servedFiles(new Set([new File('/base/path/one.js')]))
+ servedFiles(new Set([new File('/base/path/new.js')]))
+
+ return request(server)
+ .get('/base/new.js')
+ .expect(200, 'new-js-source')
+ })
+
+ it('should load custom handlers', () => {
+ servedFiles(new Set())
+
+ // TODO(vojta): change this, only keeping because karma-dart is relying on it
+ customFileHandlers.push({
+ urlRegex: /\/some\/weird/,
+ handler (request, response, staticFolder, adapterFolder, baseFolder, urlRoot) {
+ response.writeHead(222)
+ response.end('CONTENT')
+ }
+ })
+
+ return request(server)
+ .get('/some/weird/url')
+ .expect(222, 'CONTENT')
+ })
+
+ it('should serve 404 for non-existing files', () => {
+ servedFiles(new Set())
+
+ return request(server)
+ .get('/non/existing.html')
+ .expect(404)
+ })
+})