Skip to content

Commit

Permalink
Reimplement _run() to use run().
Browse files Browse the repository at this point in the history
  • Loading branch information
mshima committed Nov 17, 2020
1 parent 6b074ab commit f61d58c
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 83 deletions.
54 changes: 20 additions & 34 deletions lib/run-context.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,6 @@ const {EventEmitter} = require('events');
const helpers = require('.');
const RunResult = require('./run-result');

/**
* Wrap callback so it can't get called twice
*/
const callbackWrapper = (done) => {
let callbackHandled = false;
const callback = (err) => {
if (!callbackHandled) {
callbackHandled = true;
done(err);
}
};

return callback;
};

/**
* This class provide a run context object to façade the complexity involved in setting
* up a generator for testing
Expand Down Expand Up @@ -170,26 +155,27 @@ RunContext.prototype._run = function () {
this.buildAsync = true;
if (this.build() === false) return false;

const endCallback = callbackWrapper((envOrGenerator) => {
helpers.restorePrompt(envOrGenerator);
this.emit('end');
this.completed = true;
});

const callback = callbackWrapper((err) => {
helpers.restorePrompt(this.env);
this.errored = true;
this.emit('error', err);
});

// Yeoman-generator >=5.0.0 doesn't emits error on itself, it emits on the environment.
this.generator.on('error', callback);

this.env.on('error', callback);
this.env.runLoop.once('end', () => endCallback(this.generator));
this.emit('ready', this.generator);
this.run()
.catch((error) => {
if (
this.listenerCount('end') === 0 &&
this.listenerCount('error') === 0
) {
// When there is no listeners throw a unhandled rejection.
setImmediate(function () {
return Promise.reject(error);
});
} else {
this.errored = true;
this.emit('error', error);
}
})
.finally(() => {
this.emit('end');
this.completed = true;
});

this.generator.run().catch(callback);
return true;
};

Expand All @@ -198,7 +184,7 @@ RunContext.prototype._run = function () {
* @return {Promise} Promise
*/
RunContext.prototype.run = function () {
if (!this.settings.runEnvironment) {
if (!this.settings.runEnvironment && this.buildAsync === undefined) {
throw new Error('Should be called with runEnvironment option');
}

Expand Down
53 changes: 4 additions & 49 deletions test/run-context.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,51 +215,11 @@ describe('RunContext', function () {
});

describe('error handling', function () {
function removeListeners(host, handlerName) {
if (!host) {
return;
}

// Store the original handlers for the host
const originalHandlers = host.listeners(handlerName);
// Remove the current handlers for the host
host.removeAllListeners(handlerName);
return originalHandlers;
}

function setListeners(host, handlerName, handlers) {
if (!host) {
return;
}

handlers.forEach((handler) => host.on(handlerName, handler));
}

function processError(host, handlerName, cb) {
if (!host) {
return;
}

host.once(handlerName, cb);
}

beforeEach(function () {
this.originalHandlersProcess = removeListeners(
process,
'uncaughtException'
);
this.originalHandlersProcessDomain = removeListeners(
process.domain,
'error'
);
});

afterEach(function () {
setListeners(process, 'uncaughtException', this.originalHandlersProcess);
setListeners(process.domain, 'error', this.originalHandlersProcessDomain);
afterEach(() => {
process.removeAllListeners('unhandledRejection');
});

it('throw an error when no listener is present', function (done) {
it('throw an unhandledRejection when no listener is present', function (done) {
const error = new Error('dummy exception');
const execSpy = sinon.stub().throws(error);
const errorHandler = function (err) {
Expand All @@ -268,12 +228,7 @@ describe('RunContext', function () {
done();
};

// Tests can be run via 2 commands : 'gulp test' or 'mocha'
// in 'mocha' case the error has to be caught using process.on('uncaughtException')
// in 'gulp' case the error has to be caught using process.domain.on('error')
// as we don't know in which case we are, we set the error handler for both
processError(process, 'uncaughtException', errorHandler);
processError(process.domain, 'error', errorHandler);
process.once('unhandledRejection', errorHandler);

const Dummy = helpers.createDummyGenerator();
Dummy.prototype.exec = execSpy;
Expand Down

0 comments on commit f61d58c

Please sign in to comment.