Parallel: Cleaner interface for reporter dispatching
This gets jasmine-npm out of having to deal with QueueRunner, GlobalErrors, and ReportDispatcher directly.
This commit is contained in:
@@ -89,7 +89,9 @@ var getJasmineRequireObj = (function(jasmineGlobal) {
|
|||||||
j$.CompleteOnFirstErrorSkipPolicy = jRequire.CompleteOnFirstErrorSkipPolicy(
|
j$.CompleteOnFirstErrorSkipPolicy = jRequire.CompleteOnFirstErrorSkipPolicy(
|
||||||
j$
|
j$
|
||||||
);
|
);
|
||||||
|
j$.reporterEvents = jRequire.reporterEvents(j$);
|
||||||
j$.ReportDispatcher = jRequire.ReportDispatcher(j$);
|
j$.ReportDispatcher = jRequire.ReportDispatcher(j$);
|
||||||
|
j$.ParallelReportDispatcher = jRequire.ParallelReportDispatcher(j$);
|
||||||
j$.RunableResources = jRequire.RunableResources(j$);
|
j$.RunableResources = jRequire.RunableResources(j$);
|
||||||
j$.Runner = jRequire.Runner(j$);
|
j$.Runner = jRequire.Runner(j$);
|
||||||
j$.Spec = jRequire.Spec(j$);
|
j$.Spec = jRequire.Spec(j$);
|
||||||
@@ -1555,72 +1557,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
* @see custom_reporter
|
* @see custom_reporter
|
||||||
*/
|
*/
|
||||||
reporter = new j$.ReportDispatcher(
|
reporter = new j$.ReportDispatcher(
|
||||||
[
|
j$.reporterEvents,
|
||||||
/**
|
|
||||||
* `jasmineStarted` is called after all of the specs have been loaded, but just before execution starts.
|
|
||||||
* @function
|
|
||||||
* @name Reporter#jasmineStarted
|
|
||||||
* @param {JasmineStartedInfo} suiteInfo Information about the full Jasmine suite that is being run
|
|
||||||
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
|
|
||||||
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
|
|
||||||
* @see async
|
|
||||||
*/
|
|
||||||
'jasmineStarted',
|
|
||||||
/**
|
|
||||||
* When the entire suite has finished execution `jasmineDone` is called
|
|
||||||
* @function
|
|
||||||
* @name Reporter#jasmineDone
|
|
||||||
* @param {JasmineDoneInfo} suiteInfo Information about the full Jasmine suite that just finished running.
|
|
||||||
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
|
|
||||||
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
|
|
||||||
* @see async
|
|
||||||
*/
|
|
||||||
'jasmineDone',
|
|
||||||
/**
|
|
||||||
* `suiteStarted` is invoked when a `describe` starts to run
|
|
||||||
* @function
|
|
||||||
* @name Reporter#suiteStarted
|
|
||||||
* @param {SuiteResult} result Information about the individual {@link describe} being run
|
|
||||||
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
|
|
||||||
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
|
|
||||||
* @see async
|
|
||||||
*/
|
|
||||||
'suiteStarted',
|
|
||||||
/**
|
|
||||||
* `suiteDone` is invoked when all of the child specs and suites for a given suite have been run
|
|
||||||
*
|
|
||||||
* While jasmine doesn't require any specific functions, not defining a `suiteDone` will make it impossible for a reporter to know when a suite has failures in an `afterAll`.
|
|
||||||
* @function
|
|
||||||
* @name Reporter#suiteDone
|
|
||||||
* @param {SuiteResult} result
|
|
||||||
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
|
|
||||||
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
|
|
||||||
* @see async
|
|
||||||
*/
|
|
||||||
'suiteDone',
|
|
||||||
/**
|
|
||||||
* `specStarted` is invoked when an `it` starts to run (including associated `beforeEach` functions)
|
|
||||||
* @function
|
|
||||||
* @name Reporter#specStarted
|
|
||||||
* @param {SpecResult} result Information about the individual {@link it} being run
|
|
||||||
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
|
|
||||||
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
|
|
||||||
* @see async
|
|
||||||
*/
|
|
||||||
'specStarted',
|
|
||||||
/**
|
|
||||||
* `specDone` is invoked when an `it` and its associated `beforeEach` and `afterEach` functions have been run.
|
|
||||||
*
|
|
||||||
* While jasmine doesn't require any specific functions, not defining a `specDone` will make it impossible for a reporter to know when a spec has failed.
|
|
||||||
* @function
|
|
||||||
* @name Reporter#specDone
|
|
||||||
* @param {SpecResult} result
|
|
||||||
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
|
|
||||||
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
|
|
||||||
* @see async
|
|
||||||
*/
|
|
||||||
'specDone'
|
|
||||||
],
|
|
||||||
function(options) {
|
function(options) {
|
||||||
options.SkipPolicy = j$.NeverSkipPolicy;
|
options.SkipPolicy = j$.NeverSkipPolicy;
|
||||||
return queueRunnerFactory(options);
|
return queueRunnerFactory(options);
|
||||||
@@ -7172,6 +7109,72 @@ getJasmineRequireObj().NeverSkipPolicy = function(j$) {
|
|||||||
return NeverSkipPolicy;
|
return NeverSkipPolicy;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
getJasmineRequireObj().ParallelReportDispatcher = function(j$) {
|
||||||
|
/*
|
||||||
|
A report dispatcher packaged for convenient use from outside jasmine-core.
|
||||||
|
|
||||||
|
This isn't part of the public interface, but it is used by
|
||||||
|
jasmine-npm. -core and -npm version in lockstep at the major and minor
|
||||||
|
levels but version independently at the patch level. Any changes that
|
||||||
|
would break -npm should be done in a major or minor release, never a
|
||||||
|
patch release, and accompanied by a change to -npm that's released in
|
||||||
|
the same version.
|
||||||
|
*/
|
||||||
|
function ParallelReportDispatcher(onError, deps = {}) {
|
||||||
|
const ReportDispatcher = deps.ReportDispatcher || j$.ReportDispatcher;
|
||||||
|
const QueueRunner = deps.QueueRunner || j$.QueueRunner;
|
||||||
|
const globalErrors = deps.globalErrors || new j$.GlobalErrors();
|
||||||
|
const dispatcher = ReportDispatcher(
|
||||||
|
j$.reporterEvents,
|
||||||
|
function(queueRunnerOptions) {
|
||||||
|
queueRunnerOptions = {
|
||||||
|
...queueRunnerOptions,
|
||||||
|
globalErrors,
|
||||||
|
timeout: { setTimeout, clearTimeout },
|
||||||
|
fail: function(error) {
|
||||||
|
// A callback-style async reporter called either done.fail()
|
||||||
|
// or done(anError).
|
||||||
|
if (!error) {
|
||||||
|
error = new Error('A reporter called done.fail()');
|
||||||
|
}
|
||||||
|
|
||||||
|
onError(error);
|
||||||
|
},
|
||||||
|
onException: function(error) {
|
||||||
|
// A reporter method threw an exception or returned a rejected
|
||||||
|
// promise, or there was an unhandled exception or unhandled promise
|
||||||
|
// rejection while an asynchronous reporter method was running.
|
||||||
|
onError(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
new QueueRunner(queueRunnerOptions).execute();
|
||||||
|
},
|
||||||
|
function(error) {
|
||||||
|
// A reporter called done() more than once.
|
||||||
|
onError(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const self = {
|
||||||
|
addReporter: dispatcher.addReporter.bind(dispatcher),
|
||||||
|
clearReporters: dispatcher.clearReporters.bind(dispatcher),
|
||||||
|
installGlobalErrors: globalErrors.install.bind(globalErrors),
|
||||||
|
uninstallGlobalErrors: function() {
|
||||||
|
// late-bind uninstall because it doesn't exist until install is called
|
||||||
|
globalErrors.uninstall(globalErrors);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const eventName of j$.reporterEvents) {
|
||||||
|
self[eventName] = dispatcher[eventName].bind(dispatcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParallelReportDispatcher;
|
||||||
|
};
|
||||||
|
|
||||||
getJasmineRequireObj().makePrettyPrinter = function(j$) {
|
getJasmineRequireObj().makePrettyPrinter = function(j$) {
|
||||||
class SinglePrettyPrintRun {
|
class SinglePrettyPrintRun {
|
||||||
constructor(customObjectFormatters, pp) {
|
constructor(customObjectFormatters, pp) {
|
||||||
@@ -7798,17 +7801,21 @@ getJasmineRequireObj().QueueRunner = function(j$) {
|
|||||||
// on the stack at this point.
|
// on the stack at this point.
|
||||||
if (j$.isAsyncFunction_(fn)) {
|
if (j$.isAsyncFunction_(fn)) {
|
||||||
this.onException(
|
this.onException(
|
||||||
'An asynchronous before/it/after ' +
|
new Error(
|
||||||
'function was defined with the async keyword but also took a ' +
|
'An asynchronous before/it/after ' +
|
||||||
'done callback. Either remove the done callback (recommended) or ' +
|
'function was defined with the async keyword but also took a ' +
|
||||||
'remove the async keyword.'
|
'done callback. Either remove the done callback (recommended) or ' +
|
||||||
|
'remove the async keyword.'
|
||||||
|
)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
this.onException(
|
this.onException(
|
||||||
'An asynchronous before/it/after ' +
|
new Error(
|
||||||
'function took a done callback but also returned a promise. ' +
|
'An asynchronous before/it/after ' +
|
||||||
'Either remove the done callback (recommended) or change the ' +
|
'function took a done callback but also returned a promise. ' +
|
||||||
'function to not return a promise.'
|
'Either remove the done callback (recommended) or change the ' +
|
||||||
|
'function to not return a promise.'
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7917,6 +7924,77 @@ getJasmineRequireObj().ReportDispatcher = function(j$) {
|
|||||||
return ReportDispatcher;
|
return ReportDispatcher;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
getJasmineRequireObj().reporterEvents = function() {
|
||||||
|
const events = [
|
||||||
|
/**
|
||||||
|
* `jasmineStarted` is called after all of the specs have been loaded, but just before execution starts.
|
||||||
|
* @function
|
||||||
|
* @name Reporter#jasmineStarted
|
||||||
|
* @param {JasmineStartedInfo} suiteInfo Information about the full Jasmine suite that is being run
|
||||||
|
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
|
||||||
|
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
|
||||||
|
* @see async
|
||||||
|
*/
|
||||||
|
'jasmineStarted',
|
||||||
|
/**
|
||||||
|
* When the entire suite has finished execution `jasmineDone` is called
|
||||||
|
* @function
|
||||||
|
* @name Reporter#jasmineDone
|
||||||
|
* @param {JasmineDoneInfo} suiteInfo Information about the full Jasmine suite that just finished running.
|
||||||
|
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
|
||||||
|
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
|
||||||
|
* @see async
|
||||||
|
*/
|
||||||
|
'jasmineDone',
|
||||||
|
/**
|
||||||
|
* `suiteStarted` is invoked when a `describe` starts to run
|
||||||
|
* @function
|
||||||
|
* @name Reporter#suiteStarted
|
||||||
|
* @param {SuiteResult} result Information about the individual {@link describe} being run
|
||||||
|
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
|
||||||
|
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
|
||||||
|
* @see async
|
||||||
|
*/
|
||||||
|
'suiteStarted',
|
||||||
|
/**
|
||||||
|
* `suiteDone` is invoked when all of the child specs and suites for a given suite have been run
|
||||||
|
*
|
||||||
|
* While jasmine doesn't require any specific functions, not defining a `suiteDone` will make it impossible for a reporter to know when a suite has failures in an `afterAll`.
|
||||||
|
* @function
|
||||||
|
* @name Reporter#suiteDone
|
||||||
|
* @param {SuiteResult} result
|
||||||
|
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
|
||||||
|
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
|
||||||
|
* @see async
|
||||||
|
*/
|
||||||
|
'suiteDone',
|
||||||
|
/**
|
||||||
|
* `specStarted` is invoked when an `it` starts to run (including associated `beforeEach` functions)
|
||||||
|
* @function
|
||||||
|
* @name Reporter#specStarted
|
||||||
|
* @param {SpecResult} result Information about the individual {@link it} being run
|
||||||
|
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
|
||||||
|
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
|
||||||
|
* @see async
|
||||||
|
*/
|
||||||
|
'specStarted',
|
||||||
|
/**
|
||||||
|
* `specDone` is invoked when an `it` and its associated `beforeEach` and `afterEach` functions have been run.
|
||||||
|
*
|
||||||
|
* While jasmine doesn't require any specific functions, not defining a `specDone` will make it impossible for a reporter to know when a spec has failed.
|
||||||
|
* @function
|
||||||
|
* @name Reporter#specDone
|
||||||
|
* @param {SpecResult} result
|
||||||
|
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
|
||||||
|
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
|
||||||
|
* @see async
|
||||||
|
*/
|
||||||
|
'specDone'
|
||||||
|
];
|
||||||
|
Object.freeze(events);
|
||||||
|
return events;
|
||||||
|
};
|
||||||
|
|
||||||
getJasmineRequireObj().interface = function(jasmine, env) {
|
getJasmineRequireObj().interface = function(jasmine, env) {
|
||||||
const jasmineInterface = {
|
const jasmineInterface = {
|
||||||
/**
|
/**
|
||||||
|
|||||||
176
spec/core/ParallelReportDispatcherSpec.js
Normal file
176
spec/core/ParallelReportDispatcherSpec.js
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
describe('ParallelReportDispatcher', function() {
|
||||||
|
it('dispatches the standard reporter events', async function() {
|
||||||
|
const subject = new jasmineUnderTest.ParallelReportDispatcher(() => {}, {
|
||||||
|
globalErrors: mockGlobalErrors()
|
||||||
|
});
|
||||||
|
const events = [
|
||||||
|
'jasmineStarted',
|
||||||
|
'jasmineDone',
|
||||||
|
'suiteStarted',
|
||||||
|
'suiteDone',
|
||||||
|
'specStarted',
|
||||||
|
'specDone'
|
||||||
|
];
|
||||||
|
const reporter = jasmine.createSpyObj('reporter', events);
|
||||||
|
subject.addReporter(reporter);
|
||||||
|
|
||||||
|
for (const eventName of events) {
|
||||||
|
const payload = { payloadFor: eventName };
|
||||||
|
await subject[eventName](payload);
|
||||||
|
expect(reporter[eventName]).toHaveBeenCalledWith(payload);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('installs and uninstalls the global error handler', function() {
|
||||||
|
const globalErrors = mockGlobalErrors();
|
||||||
|
const subject = new jasmineUnderTest.ParallelReportDispatcher(() => {}, {
|
||||||
|
globalErrors
|
||||||
|
});
|
||||||
|
|
||||||
|
subject.installGlobalErrors();
|
||||||
|
expect(globalErrors.install).toHaveBeenCalled();
|
||||||
|
|
||||||
|
subject.uninstallGlobalErrors();
|
||||||
|
expect(globalErrors.uninstall).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles global errors from async reporters', async function() {
|
||||||
|
const globalErrors = mockGlobalErrors();
|
||||||
|
const onError = jasmine.createSpy('onError');
|
||||||
|
const subject = new jasmineUnderTest.ParallelReportDispatcher(onError, {
|
||||||
|
globalErrors
|
||||||
|
});
|
||||||
|
const reporter = jasmine.createSpyObj('reporter', [
|
||||||
|
'jasmineStarted',
|
||||||
|
'jasmineDone'
|
||||||
|
]);
|
||||||
|
let resolveStarted;
|
||||||
|
reporter.jasmineStarted.and.callFake(function() {
|
||||||
|
return new Promise(function(res) {
|
||||||
|
resolveStarted = res;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
subject.addReporter(reporter);
|
||||||
|
|
||||||
|
const promise = subject.jasmineStarted({});
|
||||||
|
expect(globalErrors.pushListener).toHaveBeenCalled();
|
||||||
|
expect(globalErrors.popListener).not.toHaveBeenCalled();
|
||||||
|
const error = new Error('nope');
|
||||||
|
globalErrors.pushListener.calls.argsFor(0)[0](error);
|
||||||
|
expect(onError).toHaveBeenCalledWith(error);
|
||||||
|
|
||||||
|
resolveStarted();
|
||||||
|
await promise;
|
||||||
|
expect(globalErrors.popListener).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles done(error) from callback-style async reporters', function() {
|
||||||
|
const globalErrors = mockGlobalErrors();
|
||||||
|
const onError = jasmine.createSpy('onError');
|
||||||
|
const subject = new jasmineUnderTest.ParallelReportDispatcher(onError, {
|
||||||
|
globalErrors
|
||||||
|
});
|
||||||
|
const reporter = jasmine.createSpyObj('reporter', [
|
||||||
|
'jasmineStarted',
|
||||||
|
'jasmineDone'
|
||||||
|
]);
|
||||||
|
let callback;
|
||||||
|
reporter.jasmineStarted = function(event, cb) {
|
||||||
|
callback = cb;
|
||||||
|
};
|
||||||
|
subject.addReporter(reporter);
|
||||||
|
|
||||||
|
subject.jasmineStarted({});
|
||||||
|
|
||||||
|
expect(callback).toBeInstanceOf(Function);
|
||||||
|
const error = new Error('nope');
|
||||||
|
callback(error);
|
||||||
|
|
||||||
|
expect(onError).toHaveBeenCalledWith(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles done.fail() from callback-style async reporters', function() {
|
||||||
|
const globalErrors = mockGlobalErrors();
|
||||||
|
const onError = jasmine.createSpy('onError');
|
||||||
|
const subject = new jasmineUnderTest.ParallelReportDispatcher(onError, {
|
||||||
|
globalErrors
|
||||||
|
});
|
||||||
|
const reporter = jasmine.createSpyObj('reporter', [
|
||||||
|
'jasmineStarted',
|
||||||
|
'jasmineDone'
|
||||||
|
]);
|
||||||
|
let callback;
|
||||||
|
reporter.jasmineStarted = function(event, cb) {
|
||||||
|
callback = cb;
|
||||||
|
};
|
||||||
|
subject.addReporter(reporter);
|
||||||
|
|
||||||
|
subject.jasmineStarted({});
|
||||||
|
|
||||||
|
expect(callback).toBeInstanceOf(Function);
|
||||||
|
const error = new Error('nope');
|
||||||
|
callback.fail(error);
|
||||||
|
expect(onError).toHaveBeenCalledWith(error);
|
||||||
|
onError.calls.reset();
|
||||||
|
|
||||||
|
callback.fail();
|
||||||
|
expect(onError).toHaveBeenCalledWith(
|
||||||
|
new Error('A reporter called done.fail()')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles errors due to mixed async style in reporters', async function() {
|
||||||
|
const globalErrors = mockGlobalErrors();
|
||||||
|
const onError = jasmine.createSpy('onError');
|
||||||
|
const subject = new jasmineUnderTest.ParallelReportDispatcher(onError, {
|
||||||
|
globalErrors
|
||||||
|
});
|
||||||
|
subject.addReporter({
|
||||||
|
async jasmineStarted(event, done) {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await subject.jasmineStarted({});
|
||||||
|
expect(onError).toHaveBeenCalledWith(
|
||||||
|
new Error(
|
||||||
|
'An asynchronous before/it/after function took a done callback but also returned a promise. Either remove the done callback (recommended) or change the function to not return a promise.'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles errors due to multiple done calls in reporters', async function() {
|
||||||
|
const globalErrors = mockGlobalErrors();
|
||||||
|
const onError = jasmine.createSpy('onError');
|
||||||
|
const subject = new jasmineUnderTest.ParallelReportDispatcher(onError, {
|
||||||
|
globalErrors
|
||||||
|
});
|
||||||
|
subject.addReporter({
|
||||||
|
jasmineStarted(event, done) {
|
||||||
|
done();
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await subject.jasmineStarted({});
|
||||||
|
expect(onError).toHaveBeenCalledWith(
|
||||||
|
new Error(
|
||||||
|
"An asynchronous reporter callback called its 'done' callback more than once."
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
function mockGlobalErrors() {
|
||||||
|
const globalErrors = jasmine.createSpyObj('globalErrors', [
|
||||||
|
'install',
|
||||||
|
'pushListener',
|
||||||
|
'popListener'
|
||||||
|
]);
|
||||||
|
|
||||||
|
globalErrors.install.and.callFake(function() {
|
||||||
|
globalErrors.uninstall = jasmine.createSpy('globalErrors.uninstall');
|
||||||
|
});
|
||||||
|
|
||||||
|
return globalErrors;
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -595,11 +595,13 @@ describe('QueueRunner', function() {
|
|||||||
queueRunner.execute();
|
queueRunner.execute();
|
||||||
|
|
||||||
expect(onException).toHaveBeenCalledWith(
|
expect(onException).toHaveBeenCalledWith(
|
||||||
'An asynchronous ' +
|
new Error(
|
||||||
'before/it/after function took a done callback but also returned a ' +
|
'An asynchronous ' +
|
||||||
'promise. ' +
|
'before/it/after function took a done callback but also returned a ' +
|
||||||
'Either remove the done callback (recommended) or change the function ' +
|
'promise. ' +
|
||||||
'to not return a promise.'
|
'Either remove the done callback (recommended) or change the function ' +
|
||||||
|
'to not return a promise.'
|
||||||
|
)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -615,10 +617,12 @@ describe('QueueRunner', function() {
|
|||||||
queueRunner.execute();
|
queueRunner.execute();
|
||||||
|
|
||||||
expect(onException).toHaveBeenCalledWith(
|
expect(onException).toHaveBeenCalledWith(
|
||||||
'An asynchronous ' +
|
new Error(
|
||||||
'before/it/after function was defined with the async keyword but ' +
|
'An asynchronous ' +
|
||||||
'also took a done callback. Either remove the done callback ' +
|
'before/it/after function was defined with the async keyword but ' +
|
||||||
'(recommended) or remove the async keyword.'
|
'also took a done callback. Either remove the done callback ' +
|
||||||
|
'(recommended) or remove the async keyword.'
|
||||||
|
)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -420,72 +420,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
* @see custom_reporter
|
* @see custom_reporter
|
||||||
*/
|
*/
|
||||||
reporter = new j$.ReportDispatcher(
|
reporter = new j$.ReportDispatcher(
|
||||||
[
|
j$.reporterEvents,
|
||||||
/**
|
|
||||||
* `jasmineStarted` is called after all of the specs have been loaded, but just before execution starts.
|
|
||||||
* @function
|
|
||||||
* @name Reporter#jasmineStarted
|
|
||||||
* @param {JasmineStartedInfo} suiteInfo Information about the full Jasmine suite that is being run
|
|
||||||
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
|
|
||||||
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
|
|
||||||
* @see async
|
|
||||||
*/
|
|
||||||
'jasmineStarted',
|
|
||||||
/**
|
|
||||||
* When the entire suite has finished execution `jasmineDone` is called
|
|
||||||
* @function
|
|
||||||
* @name Reporter#jasmineDone
|
|
||||||
* @param {JasmineDoneInfo} suiteInfo Information about the full Jasmine suite that just finished running.
|
|
||||||
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
|
|
||||||
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
|
|
||||||
* @see async
|
|
||||||
*/
|
|
||||||
'jasmineDone',
|
|
||||||
/**
|
|
||||||
* `suiteStarted` is invoked when a `describe` starts to run
|
|
||||||
* @function
|
|
||||||
* @name Reporter#suiteStarted
|
|
||||||
* @param {SuiteResult} result Information about the individual {@link describe} being run
|
|
||||||
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
|
|
||||||
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
|
|
||||||
* @see async
|
|
||||||
*/
|
|
||||||
'suiteStarted',
|
|
||||||
/**
|
|
||||||
* `suiteDone` is invoked when all of the child specs and suites for a given suite have been run
|
|
||||||
*
|
|
||||||
* While jasmine doesn't require any specific functions, not defining a `suiteDone` will make it impossible for a reporter to know when a suite has failures in an `afterAll`.
|
|
||||||
* @function
|
|
||||||
* @name Reporter#suiteDone
|
|
||||||
* @param {SuiteResult} result
|
|
||||||
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
|
|
||||||
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
|
|
||||||
* @see async
|
|
||||||
*/
|
|
||||||
'suiteDone',
|
|
||||||
/**
|
|
||||||
* `specStarted` is invoked when an `it` starts to run (including associated `beforeEach` functions)
|
|
||||||
* @function
|
|
||||||
* @name Reporter#specStarted
|
|
||||||
* @param {SpecResult} result Information about the individual {@link it} being run
|
|
||||||
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
|
|
||||||
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
|
|
||||||
* @see async
|
|
||||||
*/
|
|
||||||
'specStarted',
|
|
||||||
/**
|
|
||||||
* `specDone` is invoked when an `it` and its associated `beforeEach` and `afterEach` functions have been run.
|
|
||||||
*
|
|
||||||
* While jasmine doesn't require any specific functions, not defining a `specDone` will make it impossible for a reporter to know when a spec has failed.
|
|
||||||
* @function
|
|
||||||
* @name Reporter#specDone
|
|
||||||
* @param {SpecResult} result
|
|
||||||
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
|
|
||||||
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
|
|
||||||
* @see async
|
|
||||||
*/
|
|
||||||
'specDone'
|
|
||||||
],
|
|
||||||
function(options) {
|
function(options) {
|
||||||
options.SkipPolicy = j$.NeverSkipPolicy;
|
options.SkipPolicy = j$.NeverSkipPolicy;
|
||||||
return queueRunnerFactory(options);
|
return queueRunnerFactory(options);
|
||||||
|
|||||||
65
src/core/ParallelReportDispatcher.js
Normal file
65
src/core/ParallelReportDispatcher.js
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
getJasmineRequireObj().ParallelReportDispatcher = function(j$) {
|
||||||
|
/*
|
||||||
|
A report dispatcher packaged for convenient use from outside jasmine-core.
|
||||||
|
|
||||||
|
This isn't part of the public interface, but it is used by
|
||||||
|
jasmine-npm. -core and -npm version in lockstep at the major and minor
|
||||||
|
levels but version independently at the patch level. Any changes that
|
||||||
|
would break -npm should be done in a major or minor release, never a
|
||||||
|
patch release, and accompanied by a change to -npm that's released in
|
||||||
|
the same version.
|
||||||
|
*/
|
||||||
|
function ParallelReportDispatcher(onError, deps = {}) {
|
||||||
|
const ReportDispatcher = deps.ReportDispatcher || j$.ReportDispatcher;
|
||||||
|
const QueueRunner = deps.QueueRunner || j$.QueueRunner;
|
||||||
|
const globalErrors = deps.globalErrors || new j$.GlobalErrors();
|
||||||
|
const dispatcher = ReportDispatcher(
|
||||||
|
j$.reporterEvents,
|
||||||
|
function(queueRunnerOptions) {
|
||||||
|
queueRunnerOptions = {
|
||||||
|
...queueRunnerOptions,
|
||||||
|
globalErrors,
|
||||||
|
timeout: { setTimeout, clearTimeout },
|
||||||
|
fail: function(error) {
|
||||||
|
// A callback-style async reporter called either done.fail()
|
||||||
|
// or done(anError).
|
||||||
|
if (!error) {
|
||||||
|
error = new Error('A reporter called done.fail()');
|
||||||
|
}
|
||||||
|
|
||||||
|
onError(error);
|
||||||
|
},
|
||||||
|
onException: function(error) {
|
||||||
|
// A reporter method threw an exception or returned a rejected
|
||||||
|
// promise, or there was an unhandled exception or unhandled promise
|
||||||
|
// rejection while an asynchronous reporter method was running.
|
||||||
|
onError(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
new QueueRunner(queueRunnerOptions).execute();
|
||||||
|
},
|
||||||
|
function(error) {
|
||||||
|
// A reporter called done() more than once.
|
||||||
|
onError(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const self = {
|
||||||
|
addReporter: dispatcher.addReporter.bind(dispatcher),
|
||||||
|
clearReporters: dispatcher.clearReporters.bind(dispatcher),
|
||||||
|
installGlobalErrors: globalErrors.install.bind(globalErrors),
|
||||||
|
uninstallGlobalErrors: function() {
|
||||||
|
// late-bind uninstall because it doesn't exist until install is called
|
||||||
|
globalErrors.uninstall(globalErrors);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const eventName of j$.reporterEvents) {
|
||||||
|
self[eventName] = dispatcher[eventName].bind(dispatcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParallelReportDispatcher;
|
||||||
|
};
|
||||||
@@ -264,17 +264,21 @@ getJasmineRequireObj().QueueRunner = function(j$) {
|
|||||||
// on the stack at this point.
|
// on the stack at this point.
|
||||||
if (j$.isAsyncFunction_(fn)) {
|
if (j$.isAsyncFunction_(fn)) {
|
||||||
this.onException(
|
this.onException(
|
||||||
'An asynchronous before/it/after ' +
|
new Error(
|
||||||
'function was defined with the async keyword but also took a ' +
|
'An asynchronous before/it/after ' +
|
||||||
'done callback. Either remove the done callback (recommended) or ' +
|
'function was defined with the async keyword but also took a ' +
|
||||||
'remove the async keyword.'
|
'done callback. Either remove the done callback (recommended) or ' +
|
||||||
|
'remove the async keyword.'
|
||||||
|
)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
this.onException(
|
this.onException(
|
||||||
'An asynchronous before/it/after ' +
|
new Error(
|
||||||
'function took a done callback but also returned a promise. ' +
|
'An asynchronous before/it/after ' +
|
||||||
'Either remove the done callback (recommended) or change the ' +
|
'function took a done callback but also returned a promise. ' +
|
||||||
'function to not return a promise.'
|
'Either remove the done callback (recommended) or change the ' +
|
||||||
|
'function to not return a promise.'
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
70
src/core/reporterEvents.js
Normal file
70
src/core/reporterEvents.js
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
getJasmineRequireObj().reporterEvents = function() {
|
||||||
|
const events = [
|
||||||
|
/**
|
||||||
|
* `jasmineStarted` is called after all of the specs have been loaded, but just before execution starts.
|
||||||
|
* @function
|
||||||
|
* @name Reporter#jasmineStarted
|
||||||
|
* @param {JasmineStartedInfo} suiteInfo Information about the full Jasmine suite that is being run
|
||||||
|
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
|
||||||
|
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
|
||||||
|
* @see async
|
||||||
|
*/
|
||||||
|
'jasmineStarted',
|
||||||
|
/**
|
||||||
|
* When the entire suite has finished execution `jasmineDone` is called
|
||||||
|
* @function
|
||||||
|
* @name Reporter#jasmineDone
|
||||||
|
* @param {JasmineDoneInfo} suiteInfo Information about the full Jasmine suite that just finished running.
|
||||||
|
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
|
||||||
|
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
|
||||||
|
* @see async
|
||||||
|
*/
|
||||||
|
'jasmineDone',
|
||||||
|
/**
|
||||||
|
* `suiteStarted` is invoked when a `describe` starts to run
|
||||||
|
* @function
|
||||||
|
* @name Reporter#suiteStarted
|
||||||
|
* @param {SuiteResult} result Information about the individual {@link describe} being run
|
||||||
|
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
|
||||||
|
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
|
||||||
|
* @see async
|
||||||
|
*/
|
||||||
|
'suiteStarted',
|
||||||
|
/**
|
||||||
|
* `suiteDone` is invoked when all of the child specs and suites for a given suite have been run
|
||||||
|
*
|
||||||
|
* While jasmine doesn't require any specific functions, not defining a `suiteDone` will make it impossible for a reporter to know when a suite has failures in an `afterAll`.
|
||||||
|
* @function
|
||||||
|
* @name Reporter#suiteDone
|
||||||
|
* @param {SuiteResult} result
|
||||||
|
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
|
||||||
|
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
|
||||||
|
* @see async
|
||||||
|
*/
|
||||||
|
'suiteDone',
|
||||||
|
/**
|
||||||
|
* `specStarted` is invoked when an `it` starts to run (including associated `beforeEach` functions)
|
||||||
|
* @function
|
||||||
|
* @name Reporter#specStarted
|
||||||
|
* @param {SpecResult} result Information about the individual {@link it} being run
|
||||||
|
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
|
||||||
|
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
|
||||||
|
* @see async
|
||||||
|
*/
|
||||||
|
'specStarted',
|
||||||
|
/**
|
||||||
|
* `specDone` is invoked when an `it` and its associated `beforeEach` and `afterEach` functions have been run.
|
||||||
|
*
|
||||||
|
* While jasmine doesn't require any specific functions, not defining a `specDone` will make it impossible for a reporter to know when a spec has failed.
|
||||||
|
* @function
|
||||||
|
* @name Reporter#specDone
|
||||||
|
* @param {SpecResult} result
|
||||||
|
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
|
||||||
|
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
|
||||||
|
* @see async
|
||||||
|
*/
|
||||||
|
'specDone'
|
||||||
|
];
|
||||||
|
Object.freeze(events);
|
||||||
|
return events;
|
||||||
|
};
|
||||||
@@ -67,7 +67,9 @@ var getJasmineRequireObj = (function(jasmineGlobal) {
|
|||||||
j$.CompleteOnFirstErrorSkipPolicy = jRequire.CompleteOnFirstErrorSkipPolicy(
|
j$.CompleteOnFirstErrorSkipPolicy = jRequire.CompleteOnFirstErrorSkipPolicy(
|
||||||
j$
|
j$
|
||||||
);
|
);
|
||||||
|
j$.reporterEvents = jRequire.reporterEvents(j$);
|
||||||
j$.ReportDispatcher = jRequire.ReportDispatcher(j$);
|
j$.ReportDispatcher = jRequire.ReportDispatcher(j$);
|
||||||
|
j$.ParallelReportDispatcher = jRequire.ParallelReportDispatcher(j$);
|
||||||
j$.RunableResources = jRequire.RunableResources(j$);
|
j$.RunableResources = jRequire.RunableResources(j$);
|
||||||
j$.Runner = jRequire.Runner(j$);
|
j$.Runner = jRequire.Runner(j$);
|
||||||
j$.Spec = jRequire.Spec(j$);
|
j$.Spec = jRequire.Spec(j$);
|
||||||
|
|||||||
Reference in New Issue
Block a user