diff --git a/lib/browser/client-scripts/gemini.calibrate.min.js b/lib/browser/client-scripts/gemini.calibrate.min.js new file mode 100644 index 000000000..ff106a748 --- /dev/null +++ b/lib/browser/client-scripts/gemini.calibrate.min.js @@ -0,0 +1 @@ +(function(t){"use strict";function e(){return!/MSIE 8\.0/.test(navigator.userAgent)}function n(){var t=document.createElement("meta");t.name="viewport";t.content="width=device-width,initial-scale=1.0,user-scalable=no";document.getElementsByTagName("head")[0].appendChild(t)}function i(){var t=document.body.style;t.margin=0;t.padding=0;if(e()){t.border=0}t.backgroundColor="#96fa00"}function r(){try{document.querySelector("body:nth-child(1)")}catch(t){return false}return true}function o(){return!r()||!t.getComputedStyle||!t.matchMedia||!String.prototype.trim}function d(){var e={needsCompatLib:o(),pixelRatio:t.devicePixelRatio,innerWidth:t.innerWidth||document.documentElement.clientWidth||document.body.clientWidth};return e}n();i();return d()})(window); diff --git a/lib/capture-session/index.js b/lib/capture-session/index.js index 34db594e7..bafddda1f 100644 --- a/lib/capture-session/index.js +++ b/lib/capture-session/index.js @@ -3,7 +3,8 @@ const inherit = require('inherit'); const _ = require('lodash'); const debug = require('debug'); -const promiseUtil = require('q-promise-utils'); +const Promise = require('bluebird'); + const ActionsBuilder = require('../tests-api/actions-builder'); const Browser = require('../browser'); const temp = require('../temp'); @@ -25,7 +26,7 @@ var CaptureSession = inherit({ runActions: function(actions) { this.log('run actions'); - return promiseUtil.sequence(actions, this.browser, new ActionsBuilder(this._postActions)); + return Promise.mapSeries(actions, (a) => a(this.browser, new ActionsBuilder(this._postActions))); }, prepareScreenshot: function(state) { @@ -45,7 +46,7 @@ var CaptureSession = inherit({ }, runPostActions: function() { - return promiseUtil.sequence(this._postActions.reverse(), this.browser); + return Promise.mapSeries(this._postActions.reverse(), (a) => a(this.browser)); }, extendWithPageScreenshot: function(obj) { diff --git a/lib/gemini.js b/lib/gemini.js index 36cbf0b8d..877ea2480 100644 --- a/lib/gemini.js +++ b/lib/gemini.js @@ -3,9 +3,8 @@ const debug = require('debug'); const chalk = require('chalk'); const _ = require('lodash'); -const PassthroughEmitter = require('./passthrough-emitter'); +const PassthroughEmitter = require('gemini-core').PassthroughEmitter; const Promise = require('bluebird'); -const q = require('bluebird-q'); const pluginsLoader = require('plugins-loader'); const gracefulFs = require('graceful-fs'); @@ -129,14 +128,14 @@ module.exports = class Gemini extends PassthroughEmitter { options = _.assignIn(options, {paths}); - return q(readTests(this, this.config, options) + return readTests(this, this.config, options) .then((rootSuite) => { if (options.grep) { applyGrep_(options.grep, rootSuite); } return new SuiteCollection(rootSuite.children); - })); + }); function applyGrep_(grep, suite) { if (!suite.hasStates) { @@ -156,11 +155,11 @@ module.exports = class Gemini extends PassthroughEmitter { } update(paths, options) { - return q(this._run(StateProcessor.createScreenUpdater(options), paths, options)); + return this._run(StateProcessor.createScreenUpdater(options), paths, options); } test(paths, options) { - return q(this._run(StateProcessor.createTester(this.config), paths, options)); + return this._run(StateProcessor.createTester(this.config), paths, options); } getScreenshotPath(suite, stateName, browserId) { diff --git a/lib/passthrough-emitter.js b/lib/passthrough-emitter.js deleted file mode 100644 index 5299c2af4..000000000 --- a/lib/passthrough-emitter.js +++ /dev/null @@ -1,35 +0,0 @@ -'use strict'; - -const _ = require('lodash'), - QEmitter = require('qemitter'); - -module.exports = class PassthroughEmitter extends QEmitter { - // Allow to pass only one argument with event - emit(type, data) { - return super.emit(type, data); - } - - emitAndWait(type, data) { - return super.emitAndWait(type, data, {shouldWait: true}); - } - - /** - * Emit event emitted by emitter - * @param {EventEmitter} emitter - * @param {String|String[]} event or array of events to passthrough - */ - passthroughEvent(emitter, event) { - if (_.isArray(event)) { - event.forEach(this.passthroughEvent.bind(this, emitter)); - return; - } - - emitter.on(event, function(data, opts) { - if (opts && opts.shouldWait) { - return this.emitAndWait(event, data); - } else { - this.emit(event, data); - } - }.bind(this)); - } -}; diff --git a/lib/runner/browser-runner/index.js b/lib/runner/browser-runner/index.js index 2d9e0339c..957ed22b9 100644 --- a/lib/runner/browser-runner/index.js +++ b/lib/runner/browser-runner/index.js @@ -3,8 +3,8 @@ const _ = require('lodash'); const url = require('url'); const path = require('path'); -const promiseUtils = require('q-promise-utils'); const BrowserAgent = require('gemini-core').BrowserAgent; +const promiseUtils = require('gemini-core').promiseUtils; const Runner = require('../runner'); const SuiteRunner = require('../suite-runner'); const Events = require('../../constants/events'); diff --git a/lib/runner/index.js b/lib/runner/index.js index 562a3c7a2..2085a90a9 100644 --- a/lib/runner/index.js +++ b/lib/runner/index.js @@ -1,9 +1,6 @@ 'use strict'; -const Promise = require('bluebird'); const _ = require('lodash'); -const promiseUtils = require('q-promise-utils'); - const pool = require('../browser-pool'); const BrowserRunner = require('./browser-runner'); const Events = require('../constants/events'); @@ -11,6 +8,7 @@ const Coverage = require('../coverage'); const Runner = require('./runner'); const RunnerStats = require('../stats'); const SuiteMonitor = require('../suite-monitor'); +const promiseUtils = require('gemini-core').promiseUtils; module.exports = class TestsRunner extends Runner { static create(config, stateProcessor) { @@ -37,7 +35,7 @@ module.exports = class TestsRunner extends Runner { } run(suiteCollection) { - return Promise.resolve(this.emitAndWait(Events.START_RUNNER, this)) + return this.emitAndWait(Events.START_RUNNER, this) .then(() => this.emit(Events.BEGIN, this._formatBeginEventData(suiteCollection))) .then(() => this._stateProcessor.prepare(this)) .then(() => !this._cancelled && this._runTests(suiteCollection)) diff --git a/lib/runner/runner.js b/lib/runner/runner.js index 5dd60a738..61f2b849c 100644 --- a/lib/runner/runner.js +++ b/lib/runner/runner.js @@ -1,10 +1,9 @@ 'use strict'; -const PassthroughEmitter = require('../passthrough-emitter'); +const PassthroughEmitter = require('gemini-core').PassthroughEmitter; module.exports = class Runner extends PassthroughEmitter { run() { throw 'Not implemented'; } }; - diff --git a/package.json b/package.json index bd05b6b43..a7174f2a1 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "debug": "^2.2.0", "fs-extra": "^0.30.0", "gemini-configparser": "^0.4.0", - "gemini-core": "^1.3.0", + "gemini-core": "gemini-testing/gemini-core#feature/emitters", "gemini-coverage": "^1.0.0", "graceful-fs": "^4.1.11", "handlebars": "^4.0.5", @@ -32,8 +32,6 @@ "node-fetch": "^1.6.3", "plugins-loader": "^1.0.1", "png-img": "^2.1.0", - "q-promise-utils": "^1.1.0", - "qemitter": "^1.0.0", "resolve": "^1.1.0", "sizzle": "^2.2.0", "source-map": "^0.5.3", diff --git a/test/assert-ext.js b/test/assert-ext.js new file mode 100644 index 000000000..8bbe698c6 --- /dev/null +++ b/test/assert-ext.js @@ -0,0 +1,6 @@ +'use strict'; + +global.assert.calledOnceWith = function() { + assert.calledOnce(arguments[0]); + assert.calledWith.apply(null, arguments); +}; diff --git a/test/mocha.opts b/test/mocha.opts index 6a2c7fc46..6b0553d2b 100644 --- a/test/mocha.opts +++ b/test/mocha.opts @@ -1,2 +1,3 @@ --require ./test/setup +--require ./test/assert-ext -t 0 diff --git a/test/unit/browser-pool.js b/test/unit/browser-pool.js index ec95415a9..0e7b21a23 100644 --- a/test/unit/browser-pool.js +++ b/test/unit/browser-pool.js @@ -5,7 +5,7 @@ const BrowserFabric = require('lib/browser'); const Calibrator = require('lib/calibrator'); const RunnerEvents = require('lib/constants/events'); const CoreBrowserPool = require('gemini-core').BrowserPool; -const QEmitter = require('qemitter'); +const AsyncEmitter = require('gemini-core').AsyncEmitter; const _ = require('lodash'); const Promise = require('bluebird'); @@ -120,7 +120,7 @@ describe('browser-pool', () => { describe('events', () => { it('should emit START_BROWSER on start', () => { - const emitter = new QEmitter(); + const emitter = new AsyncEmitter(); const onBrowserStart = sinon.spy(); emitter.on(RunnerEvents.START_BROWSER, onBrowserStart); @@ -134,7 +134,7 @@ describe('browser-pool', () => { }); it('should wait START_BROWSER handler', () => { - const emitter = new QEmitter(); + const emitter = new AsyncEmitter(); const spy1 = sinon.spy(); const spy2 = sinon.spy(); @@ -148,7 +148,7 @@ describe('browser-pool', () => { }); it('should emit STOP_BROWSER on quit', () => { - const emitter = new QEmitter(); + const emitter = new AsyncEmitter(); const onBrowserQuit = sinon.spy(); emitter.on(RunnerEvents.STOP_BROWSER, onBrowserQuit); @@ -162,7 +162,7 @@ describe('browser-pool', () => { }); it('should wait STOP_BROWSER handler', () => { - const emitter = new QEmitter(); + const emitter = new AsyncEmitter(); const spy1 = sinon.spy(); const spy2 = sinon.spy(); diff --git a/test/unit/capture-session/index.js b/test/unit/capture-session/index.js index 0d6c2429d..19e4f82fd 100644 --- a/test/unit/capture-session/index.js +++ b/test/unit/capture-session/index.js @@ -2,7 +2,6 @@ const Promise = require('bluebird'); const _ = require('lodash'); -const promiseUtils = require('q-promise-utils'); const CaptureSession = require('lib/capture-session'); const ActionsBuilder = require('lib/tests-api/actions-builder'); @@ -17,15 +16,13 @@ describe('capture session', () => { beforeEach(() => { imageStub = sinon.createStubInstance(Image); - sandbox.stub(promiseUtils); - promiseUtils.sequence.returns(Promise.resolve()); sandbox.stub(temp); }); afterEach(() => sandbox.restore()); - describe('runActions', () => { + describe('run methods', () => { let browser; let session; @@ -34,67 +31,78 @@ describe('capture session', () => { session = new CaptureSession(browser); }); - it('should perform passed action sequence', () => { - const actions = []; + describe('runActions', () => { + it('should call action in associated browser and with "postActions"', () => { + const action = sinon.spy().named('action'); - session.runActions(actions); - - assert.calledOnce(promiseUtils.sequence); - assert.calledWith(promiseUtils.sequence, actions); - }); - - it('should perform actions sequence in associated browser', () => { - session.runActions([]); + return session.runActions([action]) + .then(() => assert.calledOnceWith(action, browser, sinon.match.instanceOf(ActionsBuilder))); + }); - assert.calledWith(promiseUtils.sequence, sinon.match.any, browser); - }); + it('should perform all actions with the same postActions instance', () => { + const action = sinon.spy().named('action'); + sandbox.stub(ActionsBuilder.prototype, '__constructor').returnsArg(0); - it('should peform actions sequence with postActions', () => { - session.runActions([]); + return session.runActions([action]) + .then(() => session.runActions([action])) + .then(() => assert.deepEqual(action.firstCall.args[1], action.secondCall.args[1])); + }); - assert.calledWith(promiseUtils.sequence, - sinon.match.any, - sinon.match.any, - sinon.match.instanceOf(ActionsBuilder) - ); - }); + it('should perform passed actions in order', () => { + const mediator = sinon.spy().named('mediator'); + const action1 = sinon.stub().named('action1').callsFake(() => Promise.delay(1).then(mediator)); + const action2 = sinon.spy().named('action2'); - it('should perform all actions with the same postActions instance', () => { - sandbox.stub(ActionsBuilder.prototype, '__constructor').returnsArg(0); + return session.runActions([action1, action2]) + .then(() => assert.callOrder(action1, mediator, action2)); + }); - session.runActions([]); - session.runActions([]); + it('should reject if any of passed actions rejected', () => { + const action1 = sinon.stub().named('action1').returns(Promise.resolve()); + const action2 = sinon.stub().named('action2').returns(Promise.reject('foo')); - assert.equal( - promiseUtils.sequence.firstCall.args[2], - promiseUtils.sequence.secondCall.args[2] - ); + return assert.isRejected(session.runActions([action1, action2]), /foo/); + }); }); - }); - describe('runPostActions', () => { - it('should not pass postActions while performing postActions', () => { - const browser = {config: {}}; - const session = new CaptureSession(browser); + describe('runPostActions', () => { + it('should call action in associated browser', () => { + const action = sinon.spy().named('action'); - session.runPostActions(); + sandbox.stub(ActionsBuilder.prototype, '__constructor').callsFake((postActions) => { + postActions.push(action); + }); - assert.lengthOf(promiseUtils.sequence.firstCall.args, 2); - }); + return session.runActions([action]) + .then(() => session.runPostActions()) + .then(() => assert.deepEqual(action.secondCall.args, [browser])); + }); - it('should perform post actions in reverse order', () => { - const browser = {config: {}}; - const session = new CaptureSession(browser); + it('should perform post actions in reverse order', () => { + const mediator = sinon.spy().named('mediator'); + const action1 = sinon.spy().named('action1'); + const action2 = sinon.stub().named('action2').callsFake(() => Promise.delay(1).then(mediator)); - sandbox.stub(ActionsBuilder.prototype, '__constructor').callsFake((postActions) => { - postActions.push(1, 2, 3); + sandbox.stub(ActionsBuilder.prototype, '__constructor').callsFake((postActions) => { + postActions.push(action1, action2); + }); + + return session.runActions([action1, action2]) + .then(() => session.runPostActions()) + .then(() => assert.callOrder(action2, mediator, action1)); }); - session.runActions([]); - session.runActions([]); - session.runPostActions(); + it('should reject if any of post actions rejected', () => { + const action1 = sinon.stub().named('action1').returns(Promise.resolve()); + const action2 = sinon.stub().named('action2').returns(Promise.reject('foo')); - assert.calledWith(promiseUtils.sequence, [3, 2, 1, 3, 2, 1]); + sandbox.stub(ActionsBuilder.prototype, '__constructor').callsFake((postActions) => { + postActions.push(action1, action2); + }); + + return session.runActions([action1, action2]) + .catch(() => assert.isRejected(session.runPostActions(), /foo/)); + }); }); }); diff --git a/test/unit/passthrough-emitter.js b/test/unit/passthrough-emitter.js index c36bfd6b4..3c09e9444 100644 --- a/test/unit/passthrough-emitter.js +++ b/test/unit/passthrough-emitter.js @@ -1,5 +1,6 @@ 'use strict'; -const PassthroughEmitter = require('lib/passthrough-emitter'); + +const PassthroughEmitter = require('gemini-core').PassthroughEmitter; describe('PassthroughEmitter', () => { let runner, @@ -47,4 +48,3 @@ describe('PassthroughEmitter', () => { }); }); }); - diff --git a/test/unit/runner/index.js b/test/unit/runner/index.js index 34b319b74..161a1aa04 100644 --- a/test/unit/runner/index.js +++ b/test/unit/runner/index.js @@ -1,7 +1,6 @@ 'use strict'; const Promise = require('bluebird'); -const q = require('bluebird-q'); const pool = require('lib/browser-pool'); const Config = require('lib/config'); const Events = require('lib/constants/events'); @@ -274,8 +273,8 @@ describe('runner', () => { it('should not be immediately rejected if running of tests in some browser was rejected', () => { const runner = createRunner(); - const rejected = q.reject(); - const delayed = q.delay(50); + const rejected = Promise.reject(); + const delayed = Promise.delay(50); runner.config.getBrowserIds.returns(['bro1', 'bro2']); @@ -287,8 +286,8 @@ describe('runner', () => { it('should be rejected with the first error if running of tests in several browsers were rejected', () => { const runner = createRunner(); - const firstReject = q.reject('first-runner'); - const secondReject = q.reject('second-runner'); + const firstReject = Promise.reject('first-runner'); + const secondReject = Promise.reject('second-runner'); runner.config.getBrowserIds.returns(['bro1', 'bro2']); @@ -313,7 +312,7 @@ describe('runner', () => { runner.on(Events.END_SESSION, onEndSession); - BrowserRunner.prototype.run.returns(q.reject()); + BrowserRunner.prototype.run.returns(Promise.reject()); return run(runner).catch(() => assert.calledOnce(onEndSession)); }); @@ -327,7 +326,7 @@ describe('runner', () => { it('should be rejected if collecting of coverage fails', () => { const runner = createRunner({config: stubConfig({isCoverageEnabled: true})}); - Coverage.prototype.processStats.returns(q.reject()); + Coverage.prototype.processStats.returns(Promise.reject()); return assert.isRejected(run(runner)); }); @@ -376,7 +375,7 @@ describe('runner', () => { runner.on(Events.END, onEnd); - BrowserRunner.prototype.run.returns(q.reject()); + BrowserRunner.prototype.run.returns(Promise.reject()); return run(runner).catch(() => assert.calledOnce(onEnd)); }); @@ -416,7 +415,7 @@ describe('runner', () => { runner.on(Events.END_RUNNER, onEndRunner); - BrowserRunner.prototype.run.returns(q.reject()); + BrowserRunner.prototype.run.returns(Promise.reject()); return run(runner).catch(() => assert.calledOnce(onEndRunner)); }); diff --git a/test/unit/state-processor/state-processor.js b/test/unit/state-processor/state-processor.js index 140637d4d..0f1350d28 100644 --- a/test/unit/state-processor/state-processor.js +++ b/test/unit/state-processor/state-processor.js @@ -7,7 +7,7 @@ var CaptureSession = require('lib/capture-session'), errorUtils = require('lib/errors/utils'), proxyquire = require('proxyquire').noCallThru(), _ = require('lodash'), - QEmitter = require('qemitter'), + AsyncEmitter = require('gemini-core').AsyncEmitter, Promise = require('bluebird'); describe('state-processor/state-processor', () => { @@ -56,7 +56,7 @@ describe('state-processor/state-processor', () => { var StateProcessor = proxyquire('lib/state-processor/state-processor', stubs), stateProcessor = new StateProcessor(opts.captureProcessorInfo); - stateProcessor.prepare(new QEmitter()); + stateProcessor.prepare(new AsyncEmitter()); return stateProcessor.exec(opts.state, browserSession, opts.page); }