Skip to content

Commit 33a069f

Browse files
authored
refactor: use native Promise instead of Bluebird (karma-runner#3436)
All supported Node versions support native promises and async/await, current code has a minimal usage of Bluebird-specific methods, so dropping a third-party library in favor of native Promises. Tests were using `Promise.setScheduler()` from Bluebird, which allowed to customize how Promises are scheduled and made test work very different from the real code, which created tricky issues (like karma-runner#3060 (comment)). Affected tests were updated to not rely on `Promise.setScheduler()`, which improved readability in some situations. Also removed some test helpers as they are not necessary and not used anymore. BREAKING CHANGE: Karma plugins which rely on the fact that Karma uses Bluebird promises may break as Bluebird-specific API is no longer available on Promises returned by the Karma core
1 parent 131d154 commit 33a069f

18 files changed

+69
-159
lines changed

lib/file-list.js

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
'use strict'
22

3-
const Promise = require('bluebird')
3+
const { promisify } = require('util')
44
const mm = require('minimatch')
55
const Glob = require('glob').Glob
6-
const fs = Promise.promisifyAll(require('graceful-fs'))
6+
const fs = require('graceful-fs')
7+
fs.statAsync = promisify(fs.stat)
78
const pathLib = require('path')
89
const _ = require('lodash')
910

@@ -60,8 +61,8 @@ class FileList {
6061
const matchedFiles = new Set()
6162

6263
let lastCompletedRefresh = this._refreshing
63-
lastCompletedRefresh = Promise
64-
.map(this._patterns, async ({ pattern, type, nocache, isBinary }) => {
64+
lastCompletedRefresh = Promise.all(
65+
this._patterns.map(async ({ pattern, type, nocache, isBinary }) => {
6566
if (helper.isUrlAbsolute(pattern)) {
6667
this.buckets.set(pattern, [new Url(pattern, type)])
6768
return
@@ -86,7 +87,7 @@ class FileList {
8687
if (nocache) {
8788
log.debug(`Not preprocessing "${pattern}" due to nocache`)
8889
} else {
89-
await Promise.map(files, (file) => this._preprocess(file))
90+
await Promise.all(files.map((file) => this._preprocess(file)))
9091
}
9192

9293
this.buckets.set(pattern, files)
@@ -97,6 +98,7 @@ class FileList {
9798
log.warn(`All files matched by "${pattern}" were excluded or matched by prior matchers.`)
9899
}
99100
})
101+
)
100102
.then(() => {
101103
// When we return from this function the file processing chain will be
102104
// complete. In the case of two fast refresh() calls, the second call
@@ -202,7 +204,7 @@ class FileList {
202204

203205
if (!file) {
204206
log.debug(`Changed file "${path}" ignored. Does not match any file in the list.`)
205-
return Promise.resolve(this.files)
207+
return this.files
206208
}
207209

208210
const [stat] = await Promise.all([fs.statAsync(path), this._refreshing])

lib/helper.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ const fs = require('graceful-fs')
44
const path = require('path')
55
const _ = require('lodash')
66
const useragent = require('useragent')
7-
const Promise = require('bluebird')
87
const mm = require('minimatch')
98

109
exports.browserFullNameToShort = (fullName) => {

lib/launcher.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
'use strict'
22

3-
const Promise = require('bluebird')
43
const Jobs = require('qjobs')
54

65
const log = require('./logger').create('launcher')

lib/launchers/base.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
const KarmaEventEmitter = require('../events').EventEmitter
22
const EventEmitter = require('events').EventEmitter
3-
const Promise = require('bluebird')
43

54
const log = require('../logger').create('launcher')
65
const helper = require('../helper')

lib/server.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
const SocketIO = require('socket.io')
44
const di = require('di')
55
const util = require('util')
6-
const Promise = require('bluebird')
76
const spawn = require('child_process').spawn
87
const tmp = require('tmp')
98
const fs = require('fs')

lib/utils/bundle-utils.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
'use strict'
22
const PathUtils = require('./path-utils')
33
const fs = require('fs')
4-
const Promise = require('bluebird')
54

65
const BundleUtils = {
76
bundleResource (inPath, outPath) {

lib/utils/net-utils.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
'use strict'
22

3-
const Promise = require('bluebird')
43
const net = require('net')
54

65
const NetUtils = {

package-lock.json

Lines changed: 10 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,6 @@
390390
"Karl Lindmark <[email protected]>"
391391
],
392392
"dependencies": {
393-
"bluebird": "^3.3.0",
394393
"body-parser": "^1.16.1",
395394
"braces": "^3.0.2",
396395
"chokidar": "^3.0.0",

test/.eslintrc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44
},
55
"globals": {
66
"expect": true,
7-
"sinon": true,
8-
"scheduleNextTick": true
7+
"sinon": true
98
},
109
"rules": {
1110
"no-unused-expressions": "off"

test/unit/file-list.spec.js

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
'use strict'
22

3-
const Promise = require('bluebird')
43
const EventEmitter = require('events').EventEmitter
54
const mocks = require('mocks')
65
const proxyquire = require('proxyquire')
@@ -448,16 +447,14 @@ describe('FileList', () => {
448447
helper: helper,
449448
glob: glob,
450449
'graceful-fs': mockFs,
451-
path: pathLib.posix,
452-
bluebird: Promise
450+
path: pathLib.posix
453451
})
454452

455453
list = new List(patterns('/some/*.js', '*.txt'), ['/secret/*.txt'], emitter, preprocess, 100)
456454
})
457455

458456
afterEach(() => {
459457
clock.restore()
460-
Promise.setScheduler((fn) => process.nextTick(fn))
461458
})
462459

463460
it('does not add excluded files', () => {
@@ -514,14 +511,14 @@ describe('FileList', () => {
514511

515512
return list.refresh().then(() => {
516513
preprocess.resetHistory()
517-
sinon.spy(mockFs, 'stat')
514+
sinon.spy(mockFs, 'statAsync')
518515

519516
return Promise.all([
520517
list.addFile('/some/d.js'),
521518
list.addFile('/some/d.js')
522519
]).then(() => {
523520
expect(preprocess).to.have.been.calledOnce
524-
expect(mockFs.stat).to.have.been.calledOnce
521+
expect(mockFs.statAsync).to.have.been.calledOnce
525522
})
526523
})
527524
})
@@ -555,7 +552,6 @@ describe('FileList', () => {
555552
beforeEach(() => {
556553
patternList = PATTERN_LIST
557554
mg = MG
558-
Promise.setScheduler((fn) => fn())
559555

560556
emitter = new EventEmitter()
561557

@@ -576,8 +572,7 @@ describe('FileList', () => {
576572
helper: helper,
577573
glob: glob,
578574
'graceful-fs': mockFs,
579-
path: pathLib.posix,
580-
bluebird: Promise
575+
path: pathLib.posix
581576
})
582577

583578
mockFs._touchFile('/some/a.js', '2012-04-04')
@@ -586,7 +581,6 @@ describe('FileList', () => {
586581

587582
afterEach(() => {
588583
clock.restore()
589-
Promise.setScheduler((fn) => process.nextTick(fn))
590584
})
591585

592586
it('updates mtime and fires "file_list_modified"', () => {
@@ -680,7 +674,6 @@ describe('FileList', () => {
680674
beforeEach(() => {
681675
patternList = PATTERN_LIST
682676
mg = MG
683-
Promise.setScheduler((fn) => fn())
684677

685678
emitter = new EventEmitter()
686679

@@ -701,8 +694,7 @@ describe('FileList', () => {
701694
helper: helper,
702695
glob: glob,
703696
'graceful-fs': mockFs,
704-
path: pathLib.posix,
705-
bluebird: Promise
697+
path: pathLib.posix
706698
})
707699

708700
modified = sinon.stub()
@@ -711,7 +703,6 @@ describe('FileList', () => {
711703

712704
afterEach(() => {
713705
clock.restore()
714-
Promise.setScheduler((fn) => process.nextTick(fn))
715706
})
716707

717708
it('removes the file from the list and fires "file_list_modified"', () => {
@@ -762,7 +753,6 @@ describe('FileList', () => {
762753
beforeEach(() => {
763754
patternList = PATTERN_LIST
764755
mg = MG
765-
Promise.setScheduler((fn) => { fn() })
766756

767757
emitter = new EventEmitter()
768758

@@ -786,14 +776,12 @@ describe('FileList', () => {
786776
helper: helper,
787777
glob: glob,
788778
'graceful-fs': mockFs,
789-
path: pathLib.posix,
790-
bluebird: Promise
779+
path: pathLib.posix
791780
})
792781
})
793782

794783
afterEach(() => {
795784
clock.restore()
796-
Promise.setScheduler((fn) => process.nextTick(fn))
797785
})
798786

799787
it('debounces calls to emitModified', () => {

test/unit/launcher.spec.js

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
'use strict'
22

3-
const Promise = require('bluebird')
43
const di = require('di')
54

65
const events = require('../../lib/events')
@@ -65,14 +64,6 @@ describe('launcher', () => {
6564
let lastGeneratedId = null
6665
launcher.Launcher.generateId = () => ++lastGeneratedId
6766

68-
before(() => {
69-
Promise.setScheduler((fn) => fn())
70-
})
71-
72-
after(() => {
73-
Promise.setScheduler((fn) => process.nextTick(fn))
74-
})
75-
7667
beforeEach(() => {
7768
lastGeneratedId = 0
7869
FakeBrowser._instances = []
@@ -252,7 +243,7 @@ describe('launcher', () => {
252243
expect(browser.forceKill).to.have.been.called
253244
})
254245

255-
it('should call callback when all processes killed', () => {
246+
it('should call callback when all processes killed', (done) => {
256247
const exitSpy = sinon.spy()
257248

258249
l.launch(['Fake', 'Fake'], 1)
@@ -264,18 +255,17 @@ describe('launcher', () => {
264255
let browser = FakeBrowser._instances.pop()
265256
browser.forceKill.resolve()
266257

267-
scheduleNextTick(() => {
258+
setImmediate(() => {
268259
expect(exitSpy).not.to.have.been.called
269-
})
270260

271-
scheduleNextTick(() => {
272261
// finish the second browser
273262
browser = FakeBrowser._instances.pop()
274263
browser.forceKill.resolve()
275-
})
276264

277-
scheduleNextTick(() => {
278-
expect(exitSpy).to.have.been.called
265+
setImmediate(() => {
266+
expect(exitSpy).to.have.been.called
267+
done()
268+
})
279269
})
280270
})
281271

0 commit comments

Comments
 (0)