469 lines
14 KiB
JavaScript
469 lines
14 KiB
JavaScript
describe('Suite', function() {
|
|
let env;
|
|
|
|
beforeEach(function() {
|
|
env = new privateUnderTest.Env();
|
|
});
|
|
|
|
afterEach(function() {
|
|
env.cleanup_();
|
|
});
|
|
|
|
it('keeps its id', function() {
|
|
const suite = new privateUnderTest.Suite({
|
|
env: env,
|
|
id: 456,
|
|
description: 'I am a suite'
|
|
});
|
|
|
|
expect(suite.id).toEqual(456);
|
|
});
|
|
|
|
it('returns blank full name for top level suite', function() {
|
|
const suite = new privateUnderTest.Suite({
|
|
env: env,
|
|
description: 'I am a suite'
|
|
});
|
|
|
|
expect(suite.getFullName()).toEqual('');
|
|
});
|
|
|
|
it('returns its full name when it has parent suites', function() {
|
|
const parentSuite = new privateUnderTest.Suite({
|
|
env: env,
|
|
description: 'I am a parent suite',
|
|
parentSuite: jasmine.createSpy('pretend top level suite')
|
|
}),
|
|
suite = new privateUnderTest.Suite({
|
|
env: env,
|
|
description: 'I am a suite',
|
|
parentSuite: parentSuite
|
|
});
|
|
|
|
expect(suite.getFullName()).toEqual('I am a parent suite I am a suite');
|
|
});
|
|
|
|
it('adds beforeEach functions in order of needed execution', function() {
|
|
const suite = new privateUnderTest.Suite({
|
|
env: env,
|
|
description: 'I am a suite'
|
|
}),
|
|
outerBefore = { fn: 'outerBeforeEach' },
|
|
innerBefore = { fn: 'insideBeforeEach' };
|
|
|
|
suite.beforeEach(outerBefore);
|
|
suite.beforeEach(innerBefore);
|
|
|
|
expect(suite.beforeFns).toEqual([
|
|
{ fn: innerBefore.fn, suite },
|
|
{ fn: outerBefore.fn, suite }
|
|
]);
|
|
});
|
|
|
|
it('adds beforeAll functions in order of needed execution', function() {
|
|
const suite = new privateUnderTest.Suite({
|
|
env: env,
|
|
description: 'I am a suite'
|
|
}),
|
|
outerBefore = { fn: 'outerBeforeAll' },
|
|
innerBefore = { fn: 'insideBeforeAll' };
|
|
|
|
suite.beforeAll(outerBefore);
|
|
suite.beforeAll(innerBefore);
|
|
|
|
expect(suite.beforeAllFns).toEqual([
|
|
{ fn: outerBefore.fn, type: 'beforeAll', suite: jasmine.is(suite) },
|
|
{ fn: innerBefore.fn, type: 'beforeAll', suite: jasmine.is(suite) }
|
|
]);
|
|
});
|
|
|
|
it('adds afterEach functions in order of needed execution', function() {
|
|
const suite = new privateUnderTest.Suite({
|
|
env: env,
|
|
description: 'I am a suite'
|
|
}),
|
|
outerAfter = { fn: 'outerAfterEach' },
|
|
innerAfter = { fn: 'insideAfterEach' };
|
|
|
|
suite.afterEach(outerAfter);
|
|
suite.afterEach(innerAfter);
|
|
|
|
expect(suite.afterFns).toEqual([
|
|
{ fn: innerAfter.fn, suite, type: 'afterEach' },
|
|
{ fn: outerAfter.fn, suite, type: 'afterEach' }
|
|
]);
|
|
});
|
|
|
|
it('adds afterAll functions in order of needed execution', function() {
|
|
const suite = new privateUnderTest.Suite({
|
|
env: env,
|
|
description: 'I am a suite'
|
|
}),
|
|
outerAfter = { fn: 'outerAfterAll' },
|
|
innerAfter = { fn: 'insideAfterAl' };
|
|
|
|
suite.afterAll(outerAfter);
|
|
suite.afterAll(innerAfter);
|
|
|
|
expect(suite.afterAllFns).toEqual([
|
|
{ fn: innerAfter.fn, type: 'afterAll' },
|
|
{ fn: outerAfter.fn, type: 'afterAll' }
|
|
]);
|
|
});
|
|
|
|
it('has a status of failed if any expectations have failed', function() {
|
|
const suite = new privateUnderTest.Suite({});
|
|
|
|
suite.addExpectationResult(false, {});
|
|
expect(suite.doneEvent().status).toBe('failed');
|
|
});
|
|
|
|
it('retrieves a result with updated status', function() {
|
|
const suite = new privateUnderTest.Suite({});
|
|
|
|
expect(suite.doneEvent().status).toBe('passed');
|
|
});
|
|
|
|
it('retrieves a result with pending status', function() {
|
|
const suite = new privateUnderTest.Suite({});
|
|
suite.pend();
|
|
|
|
expect(suite.doneEvent().status).toBe('pending');
|
|
});
|
|
|
|
it('throws an ExpectationFailed when receiving a failed expectation when throwOnExpectationFailure is set', function() {
|
|
const suite = new privateUnderTest.Suite({
|
|
throwOnExpectationFailure: true
|
|
});
|
|
|
|
expect(function() {
|
|
suite.addExpectationResult(false, { message: 'failed' });
|
|
}).toThrowError(jasmineUnderTest.private.errors.ExpectationFailed);
|
|
|
|
expect(suite.doneEvent().status).toBe('failed');
|
|
expect(suite.doneEvent().failedExpectations).toEqual([
|
|
jasmine.objectContaining({ message: 'failed' })
|
|
]);
|
|
});
|
|
|
|
it('does not add an additional failure when an expectation fails', function() {
|
|
const suite = new privateUnderTest.Suite({});
|
|
|
|
suite.handleException(
|
|
new jasmineUnderTest.private.errors.ExpectationFailed()
|
|
);
|
|
|
|
expect(suite.doneEvent().failedExpectations).toEqual([]);
|
|
});
|
|
|
|
it('forwards late expectation failures to onLateError', function() {
|
|
const onLateError = jasmine.createSpy('onLateError');
|
|
const suite = new privateUnderTest.Suite({ onLateError });
|
|
const data = {
|
|
matcherName: '',
|
|
passed: false,
|
|
expected: '',
|
|
actual: '',
|
|
error: new Error('nope')
|
|
};
|
|
|
|
suite.reportedDone = true;
|
|
suite.addExpectationResult(false, data, true);
|
|
|
|
expect(onLateError).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
message: jasmine.stringMatching(/^Error: nope/)
|
|
})
|
|
);
|
|
expect(suite.doneEvent().failedExpectations).toEqual([]);
|
|
});
|
|
|
|
it('does not forward non-late expectation failures to onLateError', function() {
|
|
const onLateError = jasmine.createSpy('onLateError');
|
|
const suite = new privateUnderTest.Suite({
|
|
onLateError
|
|
});
|
|
const data = {
|
|
matcherName: '',
|
|
passed: false,
|
|
expected: '',
|
|
actual: '',
|
|
error: new Error('nope')
|
|
};
|
|
|
|
suite.addExpectationResult(false, data, true);
|
|
|
|
expect(onLateError).not.toHaveBeenCalled();
|
|
expect(suite.doneEvent().failedExpectations.length).toEqual(1);
|
|
});
|
|
|
|
it('forwards late handleException calls to onLateError', function() {
|
|
const onLateError = jasmine.createSpy('onLateError');
|
|
const suite = new privateUnderTest.Suite({
|
|
onLateError
|
|
});
|
|
const error = new Error('oops');
|
|
|
|
suite.reportedDone = true;
|
|
suite.handleException(error);
|
|
|
|
expect(onLateError).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
message: jasmine.stringMatching(/^Error: oops/)
|
|
})
|
|
);
|
|
expect(suite.doneEvent().failedExpectations).toEqual([]);
|
|
});
|
|
|
|
it('does not forward non-late handleException calls to onLateError', function() {
|
|
const onLateError = jasmine.createSpy('onLateError');
|
|
const suite = new privateUnderTest.Suite({
|
|
onLateError
|
|
});
|
|
const error = new Error('oops');
|
|
|
|
suite.handleException(error);
|
|
|
|
expect(onLateError).not.toHaveBeenCalled();
|
|
expect(suite.doneEvent().failedExpectations.length).toEqual(1);
|
|
});
|
|
|
|
it('clears the reportedDone flag when reset', function() {
|
|
const suite = new privateUnderTest.Suite({
|
|
queueableFn: { fn: function() {} }
|
|
});
|
|
suite.reportedDone = true;
|
|
|
|
suite.reset();
|
|
|
|
expect(suite.reportedDone).toBeFalse();
|
|
});
|
|
|
|
it('calls timer to compute duration', function() {
|
|
const suite = new privateUnderTest.Suite({
|
|
env: env,
|
|
id: 456,
|
|
description: 'I am a suite',
|
|
timer: jasmine.createSpyObj('timer', { start: null, elapsed: 77000 })
|
|
});
|
|
suite.startTimer();
|
|
suite.endTimer();
|
|
expect(suite.doneEvent().duration).toEqual(77000);
|
|
});
|
|
|
|
describe('#sharedUserContext', function() {
|
|
beforeEach(function() {
|
|
this.suite = new privateUnderTest.Suite({});
|
|
});
|
|
|
|
it('returns a UserContext', function() {
|
|
expect(this.suite.sharedUserContext().constructor).toBe(
|
|
privateUnderTest.UserContext
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('attr.autoCleanClosures', function() {
|
|
function arrangeSuite(attrs) {
|
|
const suite = new privateUnderTest.Suite(attrs);
|
|
suite.beforeAll(function() {});
|
|
suite.beforeEach(function() {});
|
|
suite.afterEach(function() {});
|
|
suite.afterAll(function() {});
|
|
return suite;
|
|
}
|
|
|
|
it('should clean closures when "attr.autoCleanClosures" is missing', function() {
|
|
const suite = arrangeSuite({});
|
|
suite.cleanupBeforeAfter();
|
|
expect(suite.beforeAllFns[0].fn).toBe(null);
|
|
expect(suite.beforeFns[0].fn).toBe(null);
|
|
expect(suite.afterFns[0].fn).toBe(null);
|
|
expect(suite.afterAllFns[0].fn).toBe(null);
|
|
});
|
|
|
|
it('should clean closures when "attr.autoCleanClosures" is true', function() {
|
|
const suite = arrangeSuite({ autoCleanClosures: true });
|
|
suite.cleanupBeforeAfter();
|
|
expect(suite.beforeAllFns[0].fn).toBe(null);
|
|
expect(suite.beforeFns[0].fn).toBe(null);
|
|
expect(suite.afterFns[0].fn).toBe(null);
|
|
expect(suite.afterAllFns[0].fn).toBe(null);
|
|
});
|
|
|
|
it('should NOT clean closures when "attr.autoCleanClosures" is false', function() {
|
|
const suite = arrangeSuite({ autoCleanClosures: false });
|
|
suite.cleanupBeforeAfter();
|
|
expect(suite.beforeAllFns[0].fn).not.toBe(null);
|
|
expect(suite.beforeFns[0].fn).not.toBe(null);
|
|
expect(suite.afterFns[0].fn).not.toBe(null);
|
|
expect(suite.afterAllFns[0].fn).not.toBe(null);
|
|
});
|
|
});
|
|
|
|
describe('#reset', function() {
|
|
it('should reset the "pending" status', function() {
|
|
const suite = new privateUnderTest.Suite({});
|
|
suite.pend();
|
|
suite.reset();
|
|
expect(suite.doneEvent().status).toBe('passed');
|
|
});
|
|
|
|
it('should not reset the "pending" status when the suite was excluded', function() {
|
|
const suite = new privateUnderTest.Suite({});
|
|
suite.exclude();
|
|
suite.reset();
|
|
expect(suite.doneEvent().status).toBe('pending');
|
|
});
|
|
|
|
it('should also reset the children', function() {
|
|
const suite = new privateUnderTest.Suite({});
|
|
const child1 = jasmine.createSpyObj(['reset']);
|
|
const child2 = jasmine.createSpyObj(['reset']);
|
|
suite.addChild(child1);
|
|
suite.addChild(child2);
|
|
|
|
suite.reset();
|
|
|
|
expect(child1.reset).toHaveBeenCalled();
|
|
expect(child2.reset).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should reset the failedExpectations', function() {
|
|
const suite = new privateUnderTest.Suite({});
|
|
suite.handleException(new Error());
|
|
|
|
suite.reset();
|
|
|
|
const result = suite.doneEvent();
|
|
expect(result.status).toBe('passed');
|
|
expect(result.failedExpectations).toHaveSize(0);
|
|
});
|
|
});
|
|
|
|
describe('#onMultipleDone', function() {
|
|
it('reports a special error when it is the top suite', function() {
|
|
const onLateError = jasmine.createSpy('onLateError');
|
|
const suite = new privateUnderTest.Suite({
|
|
onLateError,
|
|
parentSuite: null
|
|
});
|
|
|
|
suite.onMultipleDone();
|
|
|
|
expect(onLateError).toHaveBeenCalledTimes(1);
|
|
expect(onLateError.calls.argsFor(0)[0]).toBeInstanceOf(Error);
|
|
expect(onLateError.calls.argsFor(0)[0].message).toEqual(
|
|
'A top-level beforeAll or afterAll function called its ' +
|
|
"'done' callback more than once."
|
|
);
|
|
});
|
|
|
|
it('reports an error including the suite name when it is a normal suite', function() {
|
|
const onLateError = jasmine.createSpy('onLateError');
|
|
const suite = new privateUnderTest.Suite({
|
|
onLateError,
|
|
description: 'the suite',
|
|
parentSuite: {
|
|
description: 'the parent suite',
|
|
parentSuite: {}
|
|
}
|
|
});
|
|
|
|
suite.onMultipleDone();
|
|
|
|
expect(onLateError).toHaveBeenCalledTimes(1);
|
|
expect(onLateError.calls.argsFor(0)[0]).toBeInstanceOf(Error);
|
|
expect(onLateError.calls.argsFor(0)[0].message).toEqual(
|
|
"An asynchronous beforeAll or afterAll function called its 'done' " +
|
|
'callback more than once.\n(in suite: the parent suite the suite)'
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('#hasChildWithDescription', function() {
|
|
it('returns true if there is a child with the given description', function() {
|
|
const subject = new privateUnderTest.Suite({});
|
|
const description = 'a spec';
|
|
subject.addChild({ description });
|
|
|
|
expect(subject.hasChildWithDescription(description)).toBeTrue();
|
|
});
|
|
|
|
it('returns false if there is no child with the given description', function() {
|
|
const subject = new privateUnderTest.Suite({});
|
|
subject.addChild({ description: 'a different spec' });
|
|
|
|
expect(subject.hasChildWithDescription('a spec')).toBeFalse();
|
|
});
|
|
|
|
it('does not recurse into child suites', function() {
|
|
const subject = new privateUnderTest.Suite({});
|
|
const childSuite = new privateUnderTest.Suite({});
|
|
subject.addChild(childSuite);
|
|
const description = 'a spec';
|
|
childSuite.addChild(description);
|
|
|
|
expect(subject.hasChildWithDescription('a spec')).toBeFalse();
|
|
});
|
|
});
|
|
|
|
describe('#setSuiteProperty', function() {
|
|
it('throws if the key is not a string', function() {
|
|
const suite = new privateUnderTest.Suite({});
|
|
|
|
expect(function() {
|
|
suite.setSuiteProperty({}, '');
|
|
}).toThrowError('Key must be a string');
|
|
});
|
|
|
|
it('throws if the value is not structured-cloneable', function() {
|
|
const suite = new privateUnderTest.Suite({});
|
|
|
|
expect(function() {
|
|
suite.setSuiteProperty('k', new Promise(() => {}));
|
|
}).toThrowError("Value can't be cloned");
|
|
});
|
|
|
|
it('throws if the value is not JSON-serializable', function() {
|
|
const suite = new privateUnderTest.Suite({});
|
|
|
|
expect(function() {
|
|
const v = {};
|
|
v.self = v;
|
|
suite.setSuiteProperty('k', v);
|
|
}).toThrowError("Value can't be cloned");
|
|
});
|
|
});
|
|
|
|
describe('#startedEvent', function() {
|
|
it('includes only properties that are known before execution', function() {
|
|
const topSuite = new privateUnderTest.Suite({});
|
|
const parentSuite = new privateUnderTest.Suite({
|
|
id: 'suite1',
|
|
parentSuite: topSuite,
|
|
description: 'a parent suite'
|
|
});
|
|
const suite = new privateUnderTest.Suite({
|
|
id: 'suite2',
|
|
parentSuite,
|
|
reportedParentSuiteId: parentSuite.id,
|
|
description: 'a suite',
|
|
filename: 'somefile.js',
|
|
getPath() {
|
|
return ['a parent suite', 'a spec'];
|
|
},
|
|
queueableFn: { fn: () => {} }
|
|
});
|
|
|
|
expect(suite.startedEvent()).toEqual({
|
|
id: 'suite2',
|
|
parentSuiteId: 'suite1',
|
|
description: 'a suite',
|
|
fullName: 'a parent suite a suite',
|
|
filename: 'somefile.js'
|
|
});
|
|
});
|
|
});
|
|
});
|