The old style of merging all of a function's variable declarations into a single statement made some sense back in the days of var, but there's no reason to keep doing it now that we use const and let.
3913 lines
109 KiB
JavaScript
3913 lines
109 KiB
JavaScript
describe('Env integration', function() {
|
|
let env;
|
|
const isBrowser = typeof window !== 'undefined';
|
|
|
|
beforeEach(function() {
|
|
specHelpers.registerIntegrationMatchers();
|
|
env = new privateUnderTest.Env();
|
|
});
|
|
|
|
afterEach(function() {
|
|
env.cleanup_();
|
|
});
|
|
|
|
it('Suites execute as expected (no nesting)', async function() {
|
|
const calls = [];
|
|
|
|
env.configure({ random: false });
|
|
|
|
env.describe('A Suite', function() {
|
|
env.it('with a spec', function() {
|
|
calls.push('with a spec');
|
|
});
|
|
env.it('and another spec', function() {
|
|
calls.push('and another spec');
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(calls).toEqual(['with a spec', 'and another spec']);
|
|
});
|
|
|
|
it('Nested Suites execute as expected', async function() {
|
|
const calls = [];
|
|
|
|
env.configure({ random: false });
|
|
|
|
env.describe('Outer suite', function() {
|
|
env.it('an outer spec', function() {
|
|
calls.push('an outer spec');
|
|
});
|
|
env.describe('Inner suite', function() {
|
|
env.it('an inner spec', function() {
|
|
calls.push('an inner spec');
|
|
});
|
|
env.it('another inner spec', function() {
|
|
calls.push('another inner spec');
|
|
});
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(calls).toEqual([
|
|
'an outer spec',
|
|
'an inner spec',
|
|
'another inner spec'
|
|
]);
|
|
});
|
|
|
|
it('Multiple top-level Suites execute as expected', async function() {
|
|
const calls = [];
|
|
|
|
env.configure({ random: false });
|
|
|
|
env.describe('Outer suite', function() {
|
|
env.it('an outer spec', function() {
|
|
calls.push('an outer spec');
|
|
});
|
|
env.describe('Inner suite', function() {
|
|
env.it('an inner spec', function() {
|
|
calls.push('an inner spec');
|
|
});
|
|
env.it('another inner spec', function() {
|
|
calls.push('another inner spec');
|
|
});
|
|
});
|
|
});
|
|
|
|
env.describe('Another outer suite', function() {
|
|
env.it('a 2nd outer spec', function() {
|
|
calls.push('a 2nd outer spec');
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(calls).toEqual([
|
|
'an outer spec',
|
|
'an inner spec',
|
|
'another inner spec',
|
|
'a 2nd outer spec'
|
|
]);
|
|
});
|
|
|
|
it('explicitly fails a spec', async function() {
|
|
const specDone = jasmine.createSpy('specDone');
|
|
|
|
env.addReporter({ specDone: specDone });
|
|
|
|
env.describe('failing', function() {
|
|
env.it('has a default message', function() {
|
|
env.fail();
|
|
});
|
|
|
|
env.it('specifies a message', function() {
|
|
env.fail('messy message');
|
|
});
|
|
|
|
env.it('has a message and stack trace from an Error', function() {
|
|
env.fail(new Error('error message'));
|
|
});
|
|
|
|
env.it('pretty prints objects', function() {
|
|
env.fail({ prop: 'value', arr: ['works', true] });
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(specDone).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
description: 'has a default message',
|
|
failedExpectations: [
|
|
jasmine.objectContaining({
|
|
message: 'Failed'
|
|
})
|
|
]
|
|
})
|
|
);
|
|
expect(specDone).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
description: 'specifies a message',
|
|
failedExpectations: [
|
|
jasmine.objectContaining({
|
|
message: 'Failed: messy message'
|
|
})
|
|
]
|
|
})
|
|
);
|
|
expect(specDone).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
description: 'has a message and stack trace from an Error',
|
|
failedExpectations: [
|
|
jasmine.objectContaining({
|
|
message: 'Failed: error message',
|
|
stack: {
|
|
asymmetricMatch: function(other) {
|
|
const split = other.split('\n');
|
|
let firstLine = split[0];
|
|
if (firstLine.indexOf('error message') >= 0) {
|
|
// Chrome inserts the message and a newline before the first stacktrace line.
|
|
firstLine = split[1];
|
|
}
|
|
return firstLine.indexOf('EnvSpec') >= 0;
|
|
}
|
|
}
|
|
})
|
|
]
|
|
})
|
|
);
|
|
expect(specDone).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
description: 'pretty prints objects',
|
|
failedExpectations: [
|
|
jasmine.objectContaining({
|
|
message: "Failed: Object({ prop: 'value', arr: [ 'works', true ] })"
|
|
})
|
|
]
|
|
})
|
|
);
|
|
});
|
|
|
|
it("produces an understandable error message when 'fail' is used outside of a current spec", async function() {
|
|
env.describe('A Suite', function() {
|
|
env.it('an async spec that is actually synchronous', function(
|
|
underTestCallback
|
|
) {
|
|
underTestCallback();
|
|
});
|
|
expect(function() {
|
|
env.fail();
|
|
}).toThrowError(/'fail' was used when there was no current spec/);
|
|
});
|
|
|
|
await env.execute();
|
|
});
|
|
|
|
it("calls associated befores/specs/afters with the same 'this'", async function() {
|
|
env.configure({ random: false });
|
|
env.describe('tests', function() {
|
|
let firstTimeThrough = true;
|
|
let firstSpecContext;
|
|
let secondSpecContext;
|
|
|
|
env.beforeEach(function() {
|
|
if (firstTimeThrough) {
|
|
firstSpecContext = this;
|
|
} else {
|
|
secondSpecContext = this;
|
|
}
|
|
expect(this).toEqual(new privateUnderTest.UserContext());
|
|
});
|
|
|
|
env.it('sync spec', function() {
|
|
expect(this).toBe(firstSpecContext);
|
|
});
|
|
|
|
env.it('another sync spec', function() {
|
|
expect(this).toBe(secondSpecContext);
|
|
});
|
|
|
|
env.afterEach(function() {
|
|
if (firstTimeThrough) {
|
|
expect(this).toBe(firstSpecContext);
|
|
firstTimeThrough = false;
|
|
} else {
|
|
expect(this).toBe(secondSpecContext);
|
|
}
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
});
|
|
|
|
it("calls associated befores/its/afters with the same 'this' for an async spec", async function() {
|
|
env.describe('with an async spec', function() {
|
|
let specContext;
|
|
|
|
env.beforeEach(function() {
|
|
specContext = this;
|
|
expect(this).toEqual(new privateUnderTest.UserContext());
|
|
});
|
|
|
|
env.it('sync spec', function(underTestCallback) {
|
|
expect(this).toBe(specContext);
|
|
underTestCallback();
|
|
});
|
|
|
|
env.afterEach(function() {
|
|
expect(this).toBe(specContext);
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
});
|
|
|
|
it('calls associated beforeAlls/afterAlls only once per suite', async function() {
|
|
const before = jasmine.createSpy('beforeAll');
|
|
const after = jasmine.createSpy('afterAll');
|
|
|
|
env.describe('with beforeAll and afterAll', function() {
|
|
env.it('spec', function() {
|
|
expect(before).toHaveBeenCalled();
|
|
expect(after).not.toHaveBeenCalled();
|
|
});
|
|
|
|
env.it('another spec', function() {
|
|
expect(before).toHaveBeenCalled();
|
|
expect(after).not.toHaveBeenCalled();
|
|
});
|
|
|
|
env.beforeAll(before);
|
|
env.afterAll(after);
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(after).toHaveBeenCalled();
|
|
expect(after.calls.count()).toBe(1);
|
|
expect(before.calls.count()).toBe(1);
|
|
});
|
|
|
|
it('calls associated beforeAlls/afterAlls only once per suite for async', async function() {
|
|
const before = jasmine.createSpy('beforeAll');
|
|
const after = jasmine.createSpy('afterAll');
|
|
|
|
env.describe('with beforeAll and afterAll', function() {
|
|
env.it('spec', function() {
|
|
expect(before).toHaveBeenCalled();
|
|
expect(after).not.toHaveBeenCalled();
|
|
});
|
|
|
|
env.it('another spec', function() {
|
|
expect(before).toHaveBeenCalled();
|
|
expect(after).not.toHaveBeenCalled();
|
|
});
|
|
|
|
env.beforeAll(function(beforeCallbackUnderTest) {
|
|
before();
|
|
beforeCallbackUnderTest();
|
|
});
|
|
|
|
env.afterAll(function(afterCallbackUnderTest) {
|
|
after();
|
|
afterCallbackUnderTest();
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(after).toHaveBeenCalled();
|
|
expect(after.calls.count()).toBe(1);
|
|
expect(before.calls.count()).toBe(1);
|
|
});
|
|
|
|
it("calls associated beforeAlls/afterAlls with the cascaded 'this'", async function() {
|
|
env.describe('with beforeAll and afterAll', function() {
|
|
env.beforeAll(function() {
|
|
this.x = 1;
|
|
});
|
|
|
|
env.it('has an x at the root', function() {
|
|
expect(this.x).toBe(1);
|
|
});
|
|
|
|
env.describe('child that deletes', function() {
|
|
env.beforeAll(function() {
|
|
expect(this.x).toBe(1);
|
|
delete this.x;
|
|
});
|
|
|
|
env.it('has no x', function() {
|
|
expect(this.x).not.toBeDefined();
|
|
});
|
|
});
|
|
|
|
env.describe('child should still have x', function() {
|
|
env.beforeAll(function(innerDone) {
|
|
expect(this.x).toBe(1);
|
|
innerDone();
|
|
});
|
|
|
|
env.it('has an x', function() {
|
|
expect(this.x).toBe(1);
|
|
delete this.x;
|
|
});
|
|
|
|
env.it('still has an x', function() {
|
|
expect(this.x).toBe(1);
|
|
});
|
|
|
|
env.it('adds a y', function() {
|
|
this.y = 2;
|
|
expect(this.y).toBe(2);
|
|
});
|
|
|
|
env.it("doesn't have y that was added in sibling", function() {
|
|
expect(this.y).not.toBeDefined();
|
|
});
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
});
|
|
|
|
it('tags top-level afterAll failures with a type', async function() {
|
|
const jasmineDone = jasmine.createSpy('jasmineDone');
|
|
|
|
env.it('has a spec', function() {});
|
|
|
|
env.afterAll(function() {
|
|
throw 'nope';
|
|
});
|
|
|
|
env.addReporter({ jasmineDone: jasmineDone });
|
|
|
|
await env.execute();
|
|
|
|
const result = jasmineDone.calls.argsFor(0)[0];
|
|
expect(result.failedExpectations[0].globalErrorType).toEqual('afterAll');
|
|
});
|
|
|
|
it('does not tag suite afterAll failures with a type', async function() {
|
|
const reporter = {
|
|
suiteDone: jasmine.createSpy('suiteDone').and.callFake(function(result) {
|
|
expect(result.failedExpectations[0].globalErrorType).toBeFalsy();
|
|
})
|
|
};
|
|
|
|
env.addReporter(reporter);
|
|
|
|
env.describe('a suite', function() {
|
|
env.it('has a spec', function() {});
|
|
|
|
env.afterAll(function() {
|
|
throw 'nope';
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(reporter.suiteDone).toHaveBeenCalled();
|
|
});
|
|
|
|
it('when the beforeAll fails, error at suite level', async function() {
|
|
const reporter = jasmine.createSpyObj('fakeReporter', [
|
|
'specDone',
|
|
'suiteDone'
|
|
]);
|
|
|
|
env.addReporter(reporter);
|
|
|
|
env.describe('A suite', function() {
|
|
env.beforeAll(function() {
|
|
env.expect(1).toBe(2);
|
|
});
|
|
|
|
env.it('spec that will pass', function() {});
|
|
|
|
env.describe('nesting', function() {
|
|
env.it('another spec to pass', function() {});
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(reporter.specDone.calls.count()).toEqual(2);
|
|
expect(reporter.specDone).toHaveFailedExpectationsForRunnable(
|
|
'A suite spec that will pass',
|
|
[]
|
|
);
|
|
expect(reporter.specDone).toHaveFailedExpectationsForRunnable(
|
|
'A suite nesting another spec to pass',
|
|
[]
|
|
);
|
|
expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable('A suite', [
|
|
'Expected 1 to be 2.'
|
|
]);
|
|
});
|
|
|
|
it('reports multiple calls to done in the top suite as errors', async function() {
|
|
const reporter = jasmine.createSpyObj('fakeReporter', ['jasmineDone']);
|
|
const message =
|
|
'A top-level beforeAll or afterAll function called its ' +
|
|
"'done' callback more than once.";
|
|
|
|
env.addReporter(reporter);
|
|
env.beforeAll(function(innerDone) {
|
|
innerDone();
|
|
innerDone();
|
|
});
|
|
env.it('a spec, so the beforeAll runs', function() {});
|
|
env.afterAll(function(innerDone) {
|
|
innerDone();
|
|
innerDone();
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(reporter.jasmineDone).toHaveBeenCalled();
|
|
const errors = reporter.jasmineDone.calls.argsFor(0)[0].failedExpectations;
|
|
expect(errors.length).toEqual(2);
|
|
expect(errors[0].message)
|
|
.withContext('top beforeAll')
|
|
.toContain(message);
|
|
expect(errors[0].globalErrorType).toEqual('lateError');
|
|
expect(errors[1].message)
|
|
.withContext('top afterAll')
|
|
.toContain(message);
|
|
expect(errors[1].globalErrorType).toEqual('lateError');
|
|
});
|
|
|
|
it('reports multiple calls to done in a non-top suite as errors', async function() {
|
|
const reporter = jasmine.createSpyObj('fakeReporter', [
|
|
'jasmineDone',
|
|
'suiteDone'
|
|
]);
|
|
const message =
|
|
"An asynchronous beforeAll or afterAll function called its 'done' " +
|
|
'callback more than once.\n(in suite: a suite)';
|
|
let lateDone;
|
|
reporter.suiteDone.and.callFake(function() {
|
|
lateDone();
|
|
});
|
|
|
|
env.addReporter(reporter);
|
|
env.describe('a suite', function() {
|
|
env.beforeAll(function(innerDone) {
|
|
innerDone();
|
|
innerDone();
|
|
});
|
|
env.it('a spec, so that before/afters run', function() {});
|
|
env.afterAll(function(innerDone) {
|
|
innerDone();
|
|
innerDone();
|
|
lateDone = innerDone;
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(reporter.suiteDone).toHaveBeenCalled();
|
|
const suiteErrors = reporter.suiteDone.calls.argsFor(0)[0]
|
|
.failedExpectations;
|
|
expect(suiteErrors.length).toEqual(2);
|
|
expect(suiteErrors[0].message)
|
|
.withContext('suite beforeAll')
|
|
.toContain(message);
|
|
expect(suiteErrors[1].message)
|
|
.withContext('suite afterAll')
|
|
.toContain(message);
|
|
|
|
expect(reporter.jasmineDone).toHaveBeenCalled();
|
|
const topErrors = reporter.jasmineDone.calls.argsFor(0)[0]
|
|
.failedExpectations;
|
|
expect(topErrors.length).toEqual(1);
|
|
expect(topErrors[0].message)
|
|
.withContext('late suite afterAll')
|
|
.toContain(message);
|
|
expect(topErrors[0].globalErrorType).toEqual('lateError');
|
|
expect(topErrors[0].globalErrorType).toEqual('lateError');
|
|
});
|
|
|
|
it('reports multiple calls to done in a spec as errors', async function() {
|
|
const reporter = jasmine.createSpyObj('fakeReporter', [
|
|
'specDone',
|
|
'suiteDone',
|
|
'jasmineDone'
|
|
]);
|
|
const message =
|
|
'An asynchronous spec, beforeEach, or afterEach function called its ' +
|
|
"'done' callback more than once.\n(in spec: a suite a spec)";
|
|
let lateDone;
|
|
reporter.specDone.and.callFake(function() {
|
|
lateDone();
|
|
});
|
|
reporter.suiteDone.and.callFake(function() {
|
|
lateDone();
|
|
});
|
|
|
|
env.addReporter(reporter);
|
|
env.describe('a suite', function() {
|
|
env.beforeEach(function(innerDone) {
|
|
innerDone();
|
|
innerDone();
|
|
});
|
|
env.it('a spec', function(innerDone) {
|
|
innerDone();
|
|
innerDone();
|
|
});
|
|
env.afterEach(function(innerDone) {
|
|
innerDone();
|
|
innerDone();
|
|
lateDone = innerDone;
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(reporter.specDone).toHaveBeenCalled();
|
|
const specErrors = reporter.specDone.calls.argsFor(0)[0].failedExpectations;
|
|
expect(specErrors.length).toEqual(3);
|
|
expect(specErrors[0].message)
|
|
.withContext('error caused by beforeEach')
|
|
.toContain(message);
|
|
expect(specErrors[1].message)
|
|
.withContext('error caused by it')
|
|
.toContain(message);
|
|
expect(specErrors[2].message)
|
|
.withContext('error caused by afterEach')
|
|
.toContain(message);
|
|
|
|
const suiteErrors = reporter.suiteDone.calls.argsFor(0)[0]
|
|
.failedExpectations;
|
|
expect(suiteErrors.length).toEqual(1);
|
|
expect(suiteErrors[0].message)
|
|
.withContext('late error caused by afterEach')
|
|
.toContain(message);
|
|
|
|
const topErrors = reporter.jasmineDone.calls.argsFor(0)[0]
|
|
.failedExpectations;
|
|
expect(topErrors.length).toEqual(1);
|
|
expect(topErrors[0].message)
|
|
.withContext('really late error caused by afterEach')
|
|
.toContain(message);
|
|
expect(topErrors[0].globalErrorType).toEqual('lateError');
|
|
});
|
|
|
|
it('reports multiple calls to done in reporters as errors', async function() {
|
|
const message =
|
|
"An asynchronous reporter callback called its 'done' callback more " +
|
|
'than once.';
|
|
const reporter = jasmine.createSpyObj('fakeReport', ['jasmineDone']);
|
|
reporter.specDone = function(result, done) {
|
|
done();
|
|
done();
|
|
};
|
|
env.addReporter(reporter);
|
|
|
|
env.it('a spec', function() {});
|
|
|
|
await env.execute();
|
|
|
|
expect(reporter.jasmineDone).toHaveBeenCalled();
|
|
const errors = reporter.jasmineDone.calls.argsFor(0)[0].failedExpectations;
|
|
expect(errors.length).toEqual(1);
|
|
expect(errors[0].message).toContain(message);
|
|
expect(errors[0].globalErrorType).toEqual('lateError');
|
|
});
|
|
|
|
it('does not report an error for a call to done that comes after a timeout', async function() {
|
|
const reporter = jasmine.createSpyObj('fakeReporter', ['jasmineDone']);
|
|
let firstSpecDone;
|
|
|
|
reporter.specDone = function(result, reporterDone) {
|
|
setTimeout(function() {
|
|
firstSpecDone();
|
|
reporterDone();
|
|
});
|
|
};
|
|
env.addReporter(reporter);
|
|
|
|
env.it(
|
|
'a spec',
|
|
function(innerDone) {
|
|
firstSpecDone = innerDone;
|
|
},
|
|
1
|
|
);
|
|
|
|
await env.execute();
|
|
|
|
expect(reporter.jasmineDone).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
failedExpectations: []
|
|
})
|
|
);
|
|
});
|
|
|
|
describe('suiteDone reporting', function() {
|
|
it('reports when an afterAll fails an expectation', async function() {
|
|
const reporter = jasmine.createSpyObj('fakeReport', ['suiteDone']);
|
|
|
|
env.addReporter(reporter);
|
|
|
|
env.describe('my suite', function() {
|
|
env.it('my spec', function() {});
|
|
|
|
env.afterAll(function() {
|
|
env.expect(1).toEqual(2);
|
|
env.expect(2).toEqual(3);
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable(
|
|
'my suite',
|
|
['Expected 1 to equal 2.', 'Expected 2 to equal 3.']
|
|
);
|
|
});
|
|
|
|
it('if there are no specs, it still reports correctly', async function() {
|
|
const reporter = jasmine.createSpyObj('fakeReport', ['suiteDone']);
|
|
env.addReporter(reporter);
|
|
|
|
env.describe('outer suite', function() {
|
|
env.describe('inner suite', function() {
|
|
env.it('spec', function() {});
|
|
});
|
|
|
|
env.afterAll(function() {
|
|
env.expect(1).toEqual(2);
|
|
env.expect(2).toEqual(3);
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable(
|
|
'outer suite',
|
|
['Expected 1 to equal 2.', 'Expected 2 to equal 3.']
|
|
);
|
|
});
|
|
|
|
it('reports when afterAll throws an exception', async function() {
|
|
const error = new Error('After All Exception');
|
|
const reporter = jasmine.createSpyObj('fakeReport', ['suiteDone']);
|
|
|
|
env.addReporter(reporter);
|
|
|
|
env.describe('my suite', function() {
|
|
env.it('my spec', function() {});
|
|
|
|
env.afterAll(function() {
|
|
throw error;
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable(
|
|
'my suite',
|
|
[/^Error: After All Exception/]
|
|
);
|
|
});
|
|
|
|
it('reports when an async afterAll fails an expectation', async function() {
|
|
const reporter = jasmine.createSpyObj('fakeReport', ['suiteDone']);
|
|
|
|
env.addReporter(reporter);
|
|
|
|
env.describe('my suite', function() {
|
|
env.it('my spec', function() {});
|
|
|
|
env.afterAll(function(afterAllDone) {
|
|
env.expect(1).toEqual(2);
|
|
afterAllDone();
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable(
|
|
'my suite',
|
|
['Expected 1 to equal 2.']
|
|
);
|
|
});
|
|
|
|
it('reports when an async afterAll throws an exception', async function() {
|
|
const error = new Error('After All Exception');
|
|
const reporter = jasmine.createSpyObj('fakeReport', ['suiteDone']);
|
|
|
|
env.addReporter(reporter);
|
|
|
|
env.describe('my suite', function() {
|
|
env.it('my spec', function() {});
|
|
|
|
env.afterAll(function(afterAllDone) {
|
|
throw error;
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable(
|
|
'my suite',
|
|
[/^Error: After All Exception/]
|
|
);
|
|
});
|
|
|
|
it('reports the duration of the suite', async function() {
|
|
let duration;
|
|
|
|
env.addReporter({
|
|
suiteDone: function(result) {
|
|
expect(duration).toBeUndefined();
|
|
duration = result.duration;
|
|
}
|
|
});
|
|
|
|
env.describe('my suite', function() {
|
|
env.it('takes time', function(done) {
|
|
// We can't just use the mock clock here because the timer is designed
|
|
// to record real time even when the mock clock is installed.
|
|
setTimeout(done, 10);
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
// Expect > 0 to compensate for clock imprecision
|
|
expect(duration).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
|
|
describe('specDone reporting', function() {
|
|
it('reports the duration of the spec', async function() {
|
|
let duration;
|
|
|
|
env.addReporter({
|
|
specDone: function(result) {
|
|
expect(duration).toBeUndefined();
|
|
duration = result.duration;
|
|
}
|
|
});
|
|
|
|
env.describe('my suite', function() {
|
|
env.it('takes time', function(done) {
|
|
// We can't just use the mock clock here because the timer is designed
|
|
// to record real time even when the mock clock is installed.
|
|
setTimeout(done, 10);
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
// Expect > 0 to compensate for clock imprecision
|
|
expect(duration).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
|
|
it('reports expectation failures in global beforeAll', async function() {
|
|
const reporter = jasmine.createSpyObj(['specDone', 'jasmineDone']);
|
|
|
|
env.beforeAll(function() {
|
|
env.expect(1).toBe(0);
|
|
});
|
|
|
|
env.it('is a spec', function() {
|
|
env.expect(true).toBe(true);
|
|
});
|
|
|
|
env.addReporter(reporter);
|
|
|
|
await env.execute();
|
|
|
|
const results = reporter.jasmineDone.calls.argsFor(0)[0];
|
|
expect(results.failedExpectations).toEqual([
|
|
jasmine.objectContaining({ message: 'Expected 1 to be 0.' })
|
|
]);
|
|
expect(reporter.specDone).toHaveFailedExpectationsForRunnable(
|
|
'is a spec',
|
|
[]
|
|
);
|
|
});
|
|
|
|
it('reports expectation failures in global afterAll', async function() {
|
|
const reporter = jasmine.createSpyObj(['jasmineDone']);
|
|
|
|
env.afterAll(function() {
|
|
env.expect(1).toBe(0);
|
|
});
|
|
|
|
env.it('is a spec', function() {
|
|
env.expect(true).toBe(true);
|
|
});
|
|
|
|
env.addReporter(reporter);
|
|
|
|
await env.execute();
|
|
|
|
const results = reporter.jasmineDone.calls.argsFor(0)[0];
|
|
expect(results.failedExpectations).toEqual([
|
|
jasmine.objectContaining({ message: 'Expected 1 to be 0.' })
|
|
]);
|
|
});
|
|
|
|
it('Allows specifying which specs and suites to run', async function() {
|
|
const calls = [];
|
|
const suiteCallback = jasmine.createSpy('suite callback');
|
|
let firstSpec;
|
|
let secondSuite;
|
|
|
|
env.addReporter({ suiteDone: suiteCallback });
|
|
|
|
env.describe('first suite', function() {
|
|
firstSpec = env.it('first spec', function() {
|
|
calls.push('first spec');
|
|
});
|
|
env.it('second spec', function() {
|
|
calls.push('second spec');
|
|
});
|
|
});
|
|
|
|
secondSuite = env.describe('second suite', function() {
|
|
env.it('third spec', function() {
|
|
calls.push('third spec');
|
|
});
|
|
});
|
|
|
|
await env.execute([secondSuite.id, firstSpec.id]);
|
|
|
|
expect(calls).toEqual(['third spec', 'first spec']);
|
|
expect(suiteCallback).toHaveBeenCalled();
|
|
});
|
|
|
|
it('runs before and after all functions for runnables provided to .execute()', async function() {
|
|
const calls = [];
|
|
let first_spec;
|
|
let second_spec;
|
|
|
|
env.describe('first suite', function() {
|
|
env.beforeAll(function() {
|
|
calls.push('before');
|
|
});
|
|
env.afterAll(function() {
|
|
calls.push('after');
|
|
});
|
|
first_spec = env.it('spec', function() {
|
|
calls.push('first spec');
|
|
});
|
|
second_spec = env.it('spec 2', function() {
|
|
calls.push('second spec');
|
|
});
|
|
});
|
|
|
|
await env.execute([first_spec.id, second_spec.id]);
|
|
|
|
expect(calls).toEqual(['before', 'first spec', 'second spec', 'after']);
|
|
});
|
|
|
|
it('Allows filtering out specs and suites to run programmatically', async function() {
|
|
const calls = [];
|
|
const suiteCallback = jasmine.createSpy('suite callback');
|
|
|
|
env.addReporter({ suiteDone: suiteCallback });
|
|
|
|
env.describe('first suite', function() {
|
|
env.it('first spec', function() {
|
|
calls.push('first spec');
|
|
});
|
|
env.it('second spec', function() {
|
|
calls.push('second spec');
|
|
});
|
|
});
|
|
|
|
env.describe('second suite', function() {
|
|
env.it('third spec', function() {
|
|
calls.push('third spec');
|
|
});
|
|
});
|
|
|
|
env.configure({
|
|
random: false,
|
|
specFilter: function(spec) {
|
|
return /^first suite/.test(spec.getFullName());
|
|
}
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(calls).toEqual(['first spec', 'second spec']);
|
|
expect(suiteCallback).toHaveBeenCalled();
|
|
});
|
|
|
|
it('Functions can be spied on and have their calls tracked', async function() {
|
|
let originalFunctionWasCalled = false;
|
|
const subject = {
|
|
spiedFunc: function() {
|
|
originalFunctionWasCalled = true;
|
|
return 'original result';
|
|
}
|
|
};
|
|
|
|
env.it('works with spies', function() {
|
|
const spy = env
|
|
.spyOn(subject, 'spiedFunc')
|
|
.and.returnValue('stubbed result');
|
|
|
|
expect(subject.spiedFunc).toEqual(spy);
|
|
expect(subject.spiedFunc.calls.any()).toEqual(false);
|
|
expect(subject.spiedFunc.calls.count()).toEqual(0);
|
|
|
|
subject.spiedFunc('foo');
|
|
|
|
expect(subject.spiedFunc.calls.any()).toEqual(true);
|
|
expect(subject.spiedFunc.calls.count()).toEqual(1);
|
|
expect(subject.spiedFunc.calls.mostRecent().args).toEqual(['foo']);
|
|
expect(subject.spiedFunc.calls.mostRecent().object).toEqual(subject);
|
|
expect(subject.spiedFunc.calls.mostRecent().returnValue).toEqual(
|
|
'stubbed result'
|
|
);
|
|
expect(originalFunctionWasCalled).toEqual(false);
|
|
|
|
subject.spiedFunc.and.callThrough();
|
|
subject.spiedFunc('bar');
|
|
expect(subject.spiedFunc.calls.count()).toEqual(2);
|
|
expect(subject.spiedFunc.calls.mostRecent().args).toEqual(['bar']);
|
|
expect(subject.spiedFunc.calls.mostRecent().returnValue).toEqual(
|
|
'original result'
|
|
);
|
|
expect(originalFunctionWasCalled).toEqual(true);
|
|
});
|
|
|
|
env.it(
|
|
'works with constructors when using callThrough spy strategy',
|
|
function() {
|
|
function MyClass(foo) {
|
|
if (!(this instanceof MyClass)) {
|
|
throw new Error('You must use the new keyword.');
|
|
}
|
|
this.foo = foo;
|
|
}
|
|
const subject = { MyClass: MyClass };
|
|
const spy = env.spyOn(subject, 'MyClass').and.callThrough();
|
|
|
|
expect(function() {
|
|
const result = new spy('hello world');
|
|
expect(result instanceof MyClass).toBeTruthy();
|
|
expect(result.foo).toEqual('hello world');
|
|
}).not.toThrow();
|
|
|
|
expect(function() {
|
|
const result = new spy(
|
|
'passing',
|
|
'extra',
|
|
'arguments',
|
|
'to',
|
|
'constructor'
|
|
);
|
|
expect(result instanceof MyClass).toBeTruthy();
|
|
expect(result.foo).toEqual('passing');
|
|
}).not.toThrow();
|
|
|
|
expect(function() {
|
|
spy('hello world');
|
|
}).toThrowError('You must use the new keyword.');
|
|
}
|
|
);
|
|
|
|
await env.execute();
|
|
});
|
|
|
|
it('can be configured to allow respying on functions', async function() {
|
|
const foo = {
|
|
bar: function() {
|
|
return 1;
|
|
}
|
|
};
|
|
|
|
env.allowRespy(true);
|
|
|
|
env.describe('test suite', function() {
|
|
env.it('spec 0', function() {
|
|
env.spyOn(foo, 'bar');
|
|
|
|
expect(function() {
|
|
env.spyOn(foo, 'bar');
|
|
}).not.toThrow();
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
});
|
|
|
|
it('removes all spies added in a spec after the spec is complete', async function() {
|
|
const originalFoo = function() {};
|
|
const testObj = {
|
|
foo: originalFoo
|
|
};
|
|
const firstSpec = jasmine.createSpy('firstSpec').and.callFake(function() {
|
|
env.spyOn(testObj, 'foo');
|
|
});
|
|
const secondSpec = jasmine.createSpy('secondSpec').and.callFake(function() {
|
|
expect(testObj.foo).toBe(originalFoo);
|
|
});
|
|
env.describe('test suite', function() {
|
|
env.it('spec 0', firstSpec);
|
|
env.it('spec 1', secondSpec);
|
|
});
|
|
|
|
env.configure({ random: false });
|
|
await env.execute();
|
|
|
|
expect(firstSpec).toHaveBeenCalled();
|
|
expect(secondSpec).toHaveBeenCalled();
|
|
});
|
|
|
|
it('removes all spies added in a suite after the suite is complete', async function() {
|
|
const originalFoo = function() {};
|
|
const testObj = {
|
|
foo: originalFoo
|
|
};
|
|
|
|
env.describe('test suite', function() {
|
|
env.beforeAll(function() {
|
|
env.spyOn(testObj, 'foo');
|
|
});
|
|
|
|
env.it('spec 0', function() {
|
|
expect(jasmineUnderTest.isSpy(testObj.foo)).toBe(true);
|
|
});
|
|
|
|
env.it('spec 1', function() {
|
|
expect(jasmineUnderTest.isSpy(testObj.foo)).toBe(true);
|
|
});
|
|
});
|
|
|
|
env.describe('another suite', function() {
|
|
env.it('spec 2', function() {
|
|
expect(jasmineUnderTest.isSpy(testObj.foo)).toBe(false);
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
});
|
|
|
|
it('removes a spy from the top suite after the run is complete', async function() {
|
|
const originalFoo = function() {};
|
|
const testObj = {
|
|
foo: originalFoo
|
|
};
|
|
|
|
env.beforeAll(function() {
|
|
env.spyOn(testObj, 'foo');
|
|
});
|
|
|
|
env.it('spec', function() {
|
|
expect(jasmineUnderTest.isSpy(testObj.foo)).toBe(true);
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(jasmineUnderTest.isSpy(testObj.foo)).toBe(false);
|
|
});
|
|
|
|
it('Mock clock can be installed and used in tests', async function() {
|
|
const globalSetTimeout = jasmine
|
|
.createSpy('globalSetTimeout')
|
|
.and.callFake(function(cb, t) {
|
|
return setTimeout(cb, t);
|
|
});
|
|
const delayedFunctionForGlobalClock = jasmine.createSpy(
|
|
'delayedFunctionForGlobalClock'
|
|
);
|
|
const delayedFunctionForMockClock = jasmine.createSpy(
|
|
'delayedFunctionForMockClock'
|
|
);
|
|
|
|
env.cleanup_();
|
|
env = new privateUnderTest.Env({
|
|
global: {
|
|
setTimeout: globalSetTimeout,
|
|
clearTimeout: clearTimeout,
|
|
addEventListener() {},
|
|
removeEventListener() {},
|
|
queueMicrotask: function(fn) {
|
|
queueMicrotask(fn);
|
|
},
|
|
// Enough Node globals to make getStackClearer() return the microtask
|
|
// implementation, which is the easiest to mock
|
|
process: {
|
|
versions: {
|
|
node: ''
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
env.configure({ random: false });
|
|
|
|
env.describe('tests', function() {
|
|
env.it('test with mock clock', function() {
|
|
env.clock.install();
|
|
env.clock.setTimeout(delayedFunctionForMockClock, 100);
|
|
env.clock.tick(100);
|
|
env.clock.uninstall();
|
|
});
|
|
env.it('test without mock clock', function() {
|
|
env.clock.setTimeout(delayedFunctionForGlobalClock, 100);
|
|
});
|
|
});
|
|
|
|
expect(globalSetTimeout).not.toHaveBeenCalled();
|
|
expect(delayedFunctionForMockClock).not.toHaveBeenCalled();
|
|
|
|
await env.execute();
|
|
|
|
expect(delayedFunctionForMockClock).toHaveBeenCalled();
|
|
expect(globalSetTimeout).toHaveBeenCalledWith(
|
|
delayedFunctionForGlobalClock,
|
|
100
|
|
);
|
|
});
|
|
|
|
it('should run async specs in order, waiting for them to complete', async function() {
|
|
let mutatedVar;
|
|
|
|
env.describe('tests', function() {
|
|
env.beforeEach(function() {
|
|
mutatedVar = 2;
|
|
});
|
|
|
|
env.it('async spec', function(underTestCallback) {
|
|
setTimeout(function() {
|
|
expect(mutatedVar).toEqual(2);
|
|
underTestCallback();
|
|
}, 0);
|
|
});
|
|
|
|
env.it('after async spec', function() {
|
|
mutatedVar = 3;
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
});
|
|
|
|
describe('with a mock clock', function() {
|
|
let realSetTimeout;
|
|
function createMockedEnv() {
|
|
env.cleanup_();
|
|
// explicitly pass in timing functions so we can make sure that clear stack always works
|
|
// no matter how long the suite in the spec is
|
|
env = new privateUnderTest.Env({
|
|
global: {
|
|
setTimeout: function(cb, t) {
|
|
const stack = new Error().stack;
|
|
if (stack.indexOf('clearStack') >= 0) {
|
|
return realSetTimeout(cb, t);
|
|
} else {
|
|
return setTimeout(cb, t);
|
|
}
|
|
},
|
|
clearTimeout: clearTimeout,
|
|
setInterval: setInterval,
|
|
clearInterval: clearInterval,
|
|
addEventListener() {},
|
|
removeEventListener() {},
|
|
queueMicrotask: function(fn) {
|
|
queueMicrotask(fn);
|
|
},
|
|
// Enough Node globals to make getStackClearer() return the microtask
|
|
// implementation, which is the easiest to mock
|
|
process: {
|
|
versions: {
|
|
node: ''
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
beforeEach(function() {
|
|
this.originalTimeout = jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL;
|
|
realSetTimeout = setTimeout;
|
|
jasmine.clock().install();
|
|
});
|
|
|
|
afterEach(function() {
|
|
jasmine.clock().tick(1);
|
|
jasmine.clock().tick(1);
|
|
jasmine.clock().uninstall();
|
|
jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = this.originalTimeout;
|
|
});
|
|
|
|
it("should wait a default interval before failing specs that haven't called done yet", async function() {
|
|
createMockedEnv();
|
|
const reporter = jasmine.createSpyObj('fakeReporter', ['specDone']);
|
|
|
|
reporter.specDone.and.callFake(function(result) {
|
|
expect(result).toEqual(jasmine.objectContaining({ status: 'failed' }));
|
|
realSetTimeout(function() {
|
|
jasmine.clock().tick(1);
|
|
}, 0);
|
|
});
|
|
|
|
env.addReporter(reporter);
|
|
jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = 8414;
|
|
|
|
env.it("async spec that doesn't call done", function(underTestCallback) {
|
|
env.expect(true).toBeTruthy();
|
|
jasmine.clock().tick(8416);
|
|
jasmine.clock().tick(1);
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(reporter.specDone.calls.count()).toEqual(1);
|
|
jasmine.clock().tick(1);
|
|
await new Promise(resolve => realSetTimeout(resolve));
|
|
});
|
|
|
|
it('should not use the mock clock for asynchronous timeouts', async function() {
|
|
createMockedEnv();
|
|
const reporter = jasmine.createSpyObj('fakeReporter', ['specDone']);
|
|
const clock = env.clock;
|
|
|
|
reporter.specDone.and.callFake(function() {
|
|
realSetTimeout(function() {
|
|
jasmine.debugLog('Ticking after specDone');
|
|
jasmine.clock().tick(1);
|
|
}, 0);
|
|
});
|
|
|
|
env.addReporter(reporter);
|
|
jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = 500;
|
|
|
|
env.beforeAll(function() {
|
|
clock.install();
|
|
});
|
|
|
|
env.afterAll(function() {
|
|
clock.uninstall();
|
|
});
|
|
|
|
env.it('spec that should not time out', function(innerDone) {
|
|
clock.tick(1000);
|
|
expect(true).toEqual(true);
|
|
jasmine.debugLog('Calling realSetTimeout in spec');
|
|
realSetTimeout(function() {
|
|
jasmine.debugLog('Calling innerDone');
|
|
innerDone();
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
expect(reporter.specDone).toHaveBeenCalledTimes(1);
|
|
const event = reporter.specDone.calls.argsFor(0)[0];
|
|
jasmine.debugLog(
|
|
'Spec result: ' + jasmine.private.basicPrettyPrinter(event)
|
|
);
|
|
expect(event).toEqual(jasmine.objectContaining({ status: 'passed' }));
|
|
jasmine.clock().tick(1);
|
|
|
|
await new Promise(resolve => realSetTimeout(resolve));
|
|
});
|
|
|
|
it('should wait a custom interval before reporting async functions that fail to complete', async function() {
|
|
createMockedEnv();
|
|
const reporter = jasmine.createSpyObj('fakeReport', [
|
|
'jasmineDone',
|
|
'suiteDone',
|
|
'specDone'
|
|
]);
|
|
|
|
env.addReporter(reporter);
|
|
jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = 10000;
|
|
|
|
env.describe('suite', function() {
|
|
env.afterAll(function() {
|
|
realSetTimeout(function() {
|
|
try {
|
|
jasmine.clock().tick(10);
|
|
// eslint-disable-next-line no-unused-vars
|
|
} catch (e) {
|
|
// don't worry if the clock is already uninstalled
|
|
}
|
|
}, 100);
|
|
});
|
|
env.describe('beforeAll', function() {
|
|
env.beforeAll(function(innerDone) {
|
|
realSetTimeout(function() {
|
|
jasmine.clock().tick(5001);
|
|
}, 0);
|
|
}, 5000);
|
|
|
|
env.it('times out', function(innerDone) {
|
|
realSetTimeout(function() {
|
|
jasmine.clock().tick(1);
|
|
innerDone();
|
|
}, 0);
|
|
});
|
|
});
|
|
|
|
env.describe('afterAll', function() {
|
|
env.afterAll(function(innerDone) {
|
|
realSetTimeout(function() {
|
|
jasmine.clock().tick(2001);
|
|
}, 0);
|
|
}, 2000);
|
|
|
|
env.it('times out', function(innerDone) {
|
|
realSetTimeout(function() {
|
|
jasmine.clock().tick(1);
|
|
innerDone();
|
|
}, 0);
|
|
});
|
|
});
|
|
|
|
env.describe('beforeEach', function() {
|
|
env.beforeEach(function(innerDone) {
|
|
realSetTimeout(function() {
|
|
jasmine.clock().tick(1001);
|
|
}, 0);
|
|
}, 1000);
|
|
|
|
env.it('times out', function(innerDone) {
|
|
realSetTimeout(function() {
|
|
jasmine.clock().tick(1);
|
|
innerDone();
|
|
}, 0);
|
|
});
|
|
});
|
|
|
|
env.describe('afterEach', function() {
|
|
env.afterEach(function(innerDone) {
|
|
realSetTimeout(function() {
|
|
jasmine.clock().tick(4001);
|
|
}, 0);
|
|
}, 4000);
|
|
|
|
env.it('times out', function(innerDone) {
|
|
realSetTimeout(function() {
|
|
jasmine.clock().tick(1);
|
|
innerDone();
|
|
}, 0);
|
|
});
|
|
});
|
|
|
|
env.it(
|
|
'it times out',
|
|
function(innerDone) {
|
|
realSetTimeout(function() {
|
|
jasmine.clock().tick(6001);
|
|
}, 0);
|
|
},
|
|
6000
|
|
);
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
const r = reporter.jasmineDone.calls.argsFor(0)[0];
|
|
expect(r.failedExpectations).toEqual([]);
|
|
expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable(
|
|
'suite beforeAll',
|
|
[
|
|
/^Error: Timeout - Async function did not complete within 5000ms \(custom timeout\)/
|
|
]
|
|
);
|
|
expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable(
|
|
'suite afterAll',
|
|
[
|
|
/^Error: Timeout - Async function did not complete within 2000ms \(custom timeout\)/
|
|
]
|
|
);
|
|
expect(reporter.specDone).toHaveFailedExpectationsForRunnable(
|
|
'suite beforeEach times out',
|
|
[
|
|
/^Error: Timeout - Async function did not complete within 1000ms \(custom timeout\)/
|
|
]
|
|
);
|
|
expect(reporter.specDone).toHaveFailedExpectationsForRunnable(
|
|
'suite afterEach times out',
|
|
[
|
|
/^Error: Timeout - Async function did not complete within 4000ms \(custom timeout\)/
|
|
]
|
|
);
|
|
expect(reporter.specDone).toHaveFailedExpectationsForRunnable(
|
|
'suite it times out',
|
|
[
|
|
/^Error: Timeout - Async function did not complete within 6000ms \(custom timeout\)/
|
|
]
|
|
);
|
|
|
|
jasmine.clock().tick(1);
|
|
await new Promise(resolve => realSetTimeout(resolve));
|
|
});
|
|
});
|
|
|
|
it('explicitly fails an async spec', async function() {
|
|
const specDone = jasmine.createSpy('specDone');
|
|
|
|
env.addReporter({ specDone: specDone });
|
|
|
|
env.describe('failing', function() {
|
|
env.it('has a default message', function(innerDone) {
|
|
setTimeout(function() {
|
|
env.fail();
|
|
innerDone();
|
|
}, 1);
|
|
});
|
|
|
|
env.it('specifies a message', function(innerDone) {
|
|
setTimeout(function() {
|
|
env.fail('messy message');
|
|
innerDone();
|
|
}, 1);
|
|
});
|
|
|
|
env.it('fails via the done callback', function(innerDone) {
|
|
setTimeout(function() {
|
|
innerDone.fail('done failed');
|
|
}, 1);
|
|
});
|
|
|
|
env.it('has a message from an Error', function(innerDone) {
|
|
setTimeout(function() {
|
|
env.fail(new Error('error message'));
|
|
innerDone();
|
|
}, 1);
|
|
});
|
|
|
|
env.it('has a message from an Error to done', function(innerDone) {
|
|
setTimeout(function() {
|
|
innerDone(new Error('done error'));
|
|
}, 1);
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(specDone).toHaveFailedExpectationsForRunnable(
|
|
'failing has a default message',
|
|
['Failed']
|
|
);
|
|
expect(specDone).toHaveFailedExpectationsForRunnable(
|
|
'failing specifies a message',
|
|
['Failed: messy message']
|
|
);
|
|
expect(specDone).toHaveFailedExpectationsForRunnable(
|
|
'failing fails via the done callback',
|
|
['Failed: done failed']
|
|
);
|
|
expect(specDone).toHaveFailedExpectationsForRunnable(
|
|
'failing has a message from an Error',
|
|
['Failed: error message']
|
|
);
|
|
expect(specDone).toHaveFailedExpectationsForRunnable(
|
|
'failing has a message from an Error to done',
|
|
['Failed: done error']
|
|
);
|
|
|
|
await new Promise(resolve => setTimeout(resolve));
|
|
});
|
|
|
|
describe('focused tests', function() {
|
|
it('should only run the focused tests', async function() {
|
|
const calls = [];
|
|
|
|
env.describe('a suite', function() {
|
|
env.fit('is focused', function() {
|
|
calls.push('focused');
|
|
});
|
|
|
|
env.it('is not focused', function() {
|
|
calls.push('freakout');
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(calls).toEqual(['focused']);
|
|
});
|
|
|
|
it('should only run focused suites', async function() {
|
|
const calls = [];
|
|
|
|
env.fdescribe('a focused suite', function() {
|
|
env.it('is focused', function() {
|
|
calls.push('focused');
|
|
});
|
|
});
|
|
|
|
env.describe('a regular suite', function() {
|
|
env.it('is not focused', function() {
|
|
calls.push('freakout');
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(calls).toEqual(['focused']);
|
|
});
|
|
|
|
it('should run focused tests inside an xdescribe', async function() {
|
|
const reporter = jasmine.createSpyObj('fakeReporter', [
|
|
'jasmineStarted',
|
|
'suiteStarted',
|
|
'suiteDone',
|
|
'specStarted',
|
|
'specDone'
|
|
]);
|
|
|
|
env.addReporter(reporter);
|
|
|
|
env.xdescribe('xd suite', function() {
|
|
env.fit('with a fit spec', function() {
|
|
env.expect(true).toBe(false);
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(reporter.jasmineStarted).toHaveBeenCalledWith({
|
|
totalSpecsDefined: 1,
|
|
numExcludedSpecs: 0,
|
|
order: { random: true, seed: jasmine.any(String) },
|
|
parallel: false
|
|
});
|
|
|
|
expect(reporter.specDone).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
description: 'with a fit spec',
|
|
status: 'failed'
|
|
})
|
|
);
|
|
});
|
|
|
|
it('should run focused suites inside an xdescribe', async function() {
|
|
const reporter = jasmine.createSpyObj('fakeReporter', [
|
|
'jasmineStarted',
|
|
'suiteStarted',
|
|
'suiteDone',
|
|
'specStarted',
|
|
'specDone'
|
|
]);
|
|
|
|
env.addReporter(reporter);
|
|
|
|
env.xdescribe('xd suite', function() {
|
|
env.fdescribe('fd suite', function() {
|
|
env.it('with a spec', function() {
|
|
env.expect(true).toBe(false);
|
|
});
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(reporter.jasmineStarted).toHaveBeenCalledWith({
|
|
totalSpecsDefined: 1,
|
|
numExcludedSpecs: 0,
|
|
order: { random: true, seed: jasmine.any(String) },
|
|
parallel: false
|
|
});
|
|
|
|
expect(reporter.specDone).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
description: 'with a spec',
|
|
status: 'failed'
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
it('should report as expected', async function() {
|
|
const reporter = jasmine.createSpyObj('fakeReporter', [
|
|
'jasmineStarted',
|
|
'suiteStarted',
|
|
'suiteDone',
|
|
'specStarted',
|
|
'specDone'
|
|
]);
|
|
const suiteFullNameToId = {};
|
|
reporter.suiteStarted.and.callFake(function(e) {
|
|
suiteFullNameToId[e.fullName] = e.id;
|
|
});
|
|
|
|
env.configure({ random: false });
|
|
env.addReporter(reporter);
|
|
|
|
env.it('a top level spec', function() {});
|
|
|
|
env.describe('A Suite', function() {
|
|
env.it('with a spec', function() {
|
|
env.expect(true).toBe(true);
|
|
});
|
|
env.describe('with a nested suite', function() {
|
|
env.xit("with an x'ed spec", function() {
|
|
env.expect(true).toBe(true);
|
|
});
|
|
env.it('with a spec', function() {
|
|
env.expect(true).toBe(false);
|
|
});
|
|
});
|
|
|
|
env.describe('with only non-executable specs', function() {
|
|
env.it('is pending');
|
|
env.xit('is xed', function() {
|
|
env.expect(true).toBe(true);
|
|
});
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(reporter.jasmineStarted).toHaveBeenCalledWith({
|
|
totalSpecsDefined: 6,
|
|
numExcludedSpecs: 3,
|
|
order: { random: false },
|
|
parallel: false
|
|
});
|
|
|
|
expect(reporter.specStarted.calls.count()).toBe(6);
|
|
expect(reporter.specDone.calls.count()).toBe(6);
|
|
|
|
const baseSpecEvent = {
|
|
id: jasmine.any(String),
|
|
filename: jasmine.any(String)
|
|
};
|
|
const baseSpecDoneEvent = {
|
|
...baseSpecEvent,
|
|
passedExpectations: [],
|
|
failedExpectations: [],
|
|
deprecationWarnings: [],
|
|
pendingReason: '',
|
|
duration: null,
|
|
properties: null,
|
|
debugLogs: null
|
|
};
|
|
|
|
expect(reporter.specStarted.calls.argsFor(0)[0]).toEqual({
|
|
...baseSpecEvent,
|
|
description: 'a top level spec',
|
|
fullName: 'a top level spec',
|
|
parentSuiteId: null
|
|
});
|
|
expect(reporter.specDone.calls.argsFor(0)[0]).toEqual({
|
|
...baseSpecDoneEvent,
|
|
description: 'a top level spec',
|
|
fullName: 'a top level spec',
|
|
status: 'passed',
|
|
parentSuiteId: null,
|
|
duration: jasmine.any(Number)
|
|
});
|
|
expect(reporter.specStarted.calls.argsFor(1)[0]).toEqual({
|
|
...baseSpecEvent,
|
|
description: 'with a spec',
|
|
fullName: 'A Suite with a spec',
|
|
parentSuiteId: suiteFullNameToId['A Suite']
|
|
});
|
|
expect(reporter.specDone.calls.argsFor(1)[0]).toEqual({
|
|
...baseSpecDoneEvent,
|
|
description: 'with a spec',
|
|
fullName: 'A Suite with a spec',
|
|
status: 'passed',
|
|
parentSuiteId: suiteFullNameToId['A Suite'],
|
|
passedExpectations: [
|
|
{
|
|
matcherName: 'toBe',
|
|
message: 'Passed.',
|
|
stack: '',
|
|
passed: true,
|
|
globalErrorType: undefined
|
|
}
|
|
],
|
|
duration: jasmine.any(Number)
|
|
});
|
|
|
|
expect(reporter.specStarted.calls.argsFor(2)[0]).toEqual({
|
|
...baseSpecEvent,
|
|
description: "with an x'ed spec",
|
|
fullName: "A Suite with a nested suite with an x'ed spec",
|
|
parentSuiteId: suiteFullNameToId['A Suite with a nested suite']
|
|
});
|
|
expect(reporter.specDone.calls.argsFor(2)[0]).toEqual({
|
|
...baseSpecDoneEvent,
|
|
description: "with an x'ed spec",
|
|
fullName: "A Suite with a nested suite with an x'ed spec",
|
|
status: 'pending',
|
|
parentSuiteId: suiteFullNameToId['A Suite with a nested suite'],
|
|
pendingReason: 'Temporarily disabled with xit',
|
|
duration: jasmine.any(Number)
|
|
});
|
|
|
|
expect(reporter.specStarted.calls.argsFor(3)[0]).toEqual({
|
|
...baseSpecEvent,
|
|
description: 'with a spec',
|
|
fullName: 'A Suite with a nested suite with a spec',
|
|
parentSuiteId: suiteFullNameToId['A Suite with a nested suite']
|
|
});
|
|
expect(reporter.specDone.calls.argsFor(3)[0]).toEqual({
|
|
...baseSpecDoneEvent,
|
|
description: 'with a spec',
|
|
fullName: 'A Suite with a nested suite with a spec',
|
|
status: 'failed',
|
|
parentSuiteId: suiteFullNameToId['A Suite with a nested suite'],
|
|
failedExpectations: [
|
|
jasmine.objectContaining({
|
|
matcherName: 'toBe',
|
|
message: 'Expected true to be false.'
|
|
})
|
|
],
|
|
duration: jasmine.any(Number)
|
|
});
|
|
|
|
expect(reporter.specStarted.calls.argsFor(4)[0]).toEqual({
|
|
...baseSpecEvent,
|
|
description: 'is pending',
|
|
fullName: 'A Suite with only non-executable specs is pending',
|
|
parentSuiteId: suiteFullNameToId['A Suite with only non-executable specs']
|
|
});
|
|
expect(reporter.specDone.calls.argsFor(4)[0]).toEqual({
|
|
...baseSpecDoneEvent,
|
|
description: 'is pending',
|
|
status: 'pending',
|
|
fullName: 'A Suite with only non-executable specs is pending',
|
|
parentSuiteId:
|
|
suiteFullNameToId['A Suite with only non-executable specs'],
|
|
duration: jasmine.any(Number)
|
|
});
|
|
|
|
expect(reporter.specStarted.calls.argsFor(5)[0]).toEqual({
|
|
...baseSpecEvent,
|
|
description: 'is xed',
|
|
fullName: 'A Suite with only non-executable specs is xed',
|
|
parentSuiteId: suiteFullNameToId['A Suite with only non-executable specs']
|
|
});
|
|
expect(reporter.specDone.calls.argsFor(5)[0]).toEqual({
|
|
...baseSpecDoneEvent,
|
|
description: 'is xed',
|
|
status: 'pending',
|
|
fullName: 'A Suite with only non-executable specs is xed',
|
|
parentSuiteId:
|
|
suiteFullNameToId['A Suite with only non-executable specs'],
|
|
pendingReason: 'Temporarily disabled with xit',
|
|
duration: jasmine.any(Number)
|
|
});
|
|
|
|
expect(reporter.suiteStarted.calls.count()).toBe(3);
|
|
expect(reporter.suiteDone.calls.count()).toBe(3);
|
|
|
|
const baseSuiteEvent = {
|
|
id: jasmine.any(String),
|
|
filename: jasmine.any(String)
|
|
};
|
|
const baseSuiteDoneEvent = {
|
|
...baseSuiteEvent,
|
|
failedExpectations: [],
|
|
deprecationWarnings: [],
|
|
properties: null
|
|
};
|
|
|
|
expect(reporter.suiteStarted.calls.argsFor(0)[0]).toEqual({
|
|
...baseSuiteEvent,
|
|
description: 'A Suite',
|
|
fullName: 'A Suite',
|
|
parentSuiteId: null
|
|
});
|
|
expect(reporter.suiteDone.calls.argsFor(2)[0]).toEqual({
|
|
...baseSuiteDoneEvent,
|
|
description: 'A Suite',
|
|
fullName: 'A Suite',
|
|
status: 'passed',
|
|
parentSuiteId: null,
|
|
duration: jasmine.any(Number)
|
|
});
|
|
|
|
expect(reporter.suiteStarted.calls.argsFor(1)[0]).toEqual({
|
|
...baseSuiteEvent,
|
|
description: 'with a nested suite',
|
|
fullName: 'A Suite with a nested suite',
|
|
parentSuiteId: suiteFullNameToId['A Suite']
|
|
});
|
|
expect(reporter.suiteDone.calls.argsFor(0)[0]).toEqual({
|
|
...baseSuiteDoneEvent,
|
|
description: 'with a nested suite',
|
|
status: 'passed',
|
|
fullName: 'A Suite with a nested suite',
|
|
parentSuiteId: suiteFullNameToId['A Suite'],
|
|
duration: jasmine.any(Number)
|
|
});
|
|
|
|
expect(reporter.suiteStarted.calls.argsFor(2)[0]).toEqual({
|
|
...baseSuiteEvent,
|
|
description: 'with only non-executable specs',
|
|
fullName: 'A Suite with only non-executable specs',
|
|
parentSuiteId: suiteFullNameToId['A Suite']
|
|
});
|
|
expect(reporter.suiteDone.calls.argsFor(1)[0]).toEqual({
|
|
...baseSuiteDoneEvent,
|
|
description: 'with only non-executable specs',
|
|
status: 'passed',
|
|
fullName: 'A Suite with only non-executable specs',
|
|
parentSuiteId: suiteFullNameToId['A Suite'],
|
|
duration: jasmine.any(Number)
|
|
});
|
|
});
|
|
|
|
it('reports focused specs and suites as expected', async function() {
|
|
const reporter = jasmine.createSpyObj('fakeReporter', [
|
|
'suiteStarted',
|
|
'suiteDone',
|
|
'specStarted',
|
|
'specDone'
|
|
]);
|
|
const suiteFullNameToId = {};
|
|
reporter.suiteStarted.and.callFake(function(e) {
|
|
suiteFullNameToId[e.fullName] = e.id;
|
|
});
|
|
|
|
env.fit('a focused top level spec', function() {});
|
|
|
|
env.describe('a suite', function() {
|
|
env.fdescribe('a focused suite', function() {
|
|
env.fit('a focused spec', function() {});
|
|
});
|
|
});
|
|
|
|
env.addReporter(reporter);
|
|
await env.execute();
|
|
|
|
expect(reporter.specStarted).toHaveBeenCalledTimes(2);
|
|
expect(reporter.specDone).toHaveBeenCalledTimes(2);
|
|
|
|
expect(reporter.specStarted).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
description: 'a focused top level spec',
|
|
parentSuiteId: null
|
|
})
|
|
);
|
|
expect(reporter.specDone).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
description: 'a focused top level spec',
|
|
status: 'passed',
|
|
parentSuiteId: null
|
|
})
|
|
);
|
|
|
|
expect(reporter.specStarted).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
description: 'a focused spec',
|
|
parentSuiteId: suiteFullNameToId['a suite a focused suite']
|
|
})
|
|
);
|
|
expect(reporter.specDone).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
description: 'a focused spec',
|
|
status: 'passed',
|
|
parentSuiteId: suiteFullNameToId['a suite a focused suite']
|
|
})
|
|
);
|
|
|
|
expect(reporter.suiteStarted).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
description: 'a suite',
|
|
parentSuiteId: null
|
|
})
|
|
);
|
|
expect(reporter.suiteDone).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
description: 'a suite',
|
|
status: 'passed',
|
|
parentSuiteId: null
|
|
})
|
|
);
|
|
|
|
expect(reporter.suiteStarted).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
description: 'a focused suite',
|
|
parentSuiteId: suiteFullNameToId['a suite']
|
|
})
|
|
);
|
|
expect(reporter.suiteDone).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
description: 'a focused suite',
|
|
status: 'passed',
|
|
parentSuiteId: suiteFullNameToId['a suite']
|
|
})
|
|
);
|
|
});
|
|
|
|
it('should report the random seed at the beginning and end of execution', async function() {
|
|
const reporter = jasmine.createSpyObj('fakeReporter', [
|
|
'jasmineStarted',
|
|
'jasmineDone',
|
|
'suiteStarted',
|
|
'suiteDone',
|
|
'specStarted',
|
|
'specDone'
|
|
]);
|
|
env.configure({ random: true, seed: '123456' });
|
|
|
|
env.addReporter(reporter);
|
|
env.configure({ random: true });
|
|
await env.execute();
|
|
|
|
expect(reporter.jasmineStarted).toHaveBeenCalled();
|
|
const startedArg = reporter.jasmineStarted.calls.argsFor(0)[0];
|
|
expect(startedArg.order).toEqual({ random: true, seed: '123456' });
|
|
|
|
const doneArg = reporter.jasmineDone.calls.argsFor(0)[0];
|
|
expect(doneArg.order).toEqual({ random: true, seed: '123456' });
|
|
});
|
|
|
|
it('coerces the random seed to a string if it is a number', async function() {
|
|
const reporter = jasmine.createSpyObj('fakeReporter', [
|
|
'jasmineStarted',
|
|
'jasmineDone',
|
|
'suiteStarted',
|
|
'suiteDone',
|
|
'specStarted',
|
|
'specDone'
|
|
]);
|
|
env.configure({ random: true, seed: 123456 });
|
|
|
|
env.addReporter(reporter);
|
|
env.configure({ random: true });
|
|
await env.execute();
|
|
|
|
expect(reporter.jasmineStarted).toHaveBeenCalled();
|
|
const startedArg = reporter.jasmineStarted.calls.argsFor(0)[0];
|
|
expect(startedArg.order.seed).toEqual('123456');
|
|
|
|
const doneArg = reporter.jasmineDone.calls.argsFor(0)[0];
|
|
expect(doneArg.order.seed).toEqual('123456');
|
|
});
|
|
|
|
it('should report pending spec messages', async function() {
|
|
const reporter = jasmine.createSpyObj('fakeReporter', ['specDone']);
|
|
|
|
env.addReporter(reporter);
|
|
|
|
env.it('will be pending', function() {
|
|
env.pending('with a message');
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
const specStatus = reporter.specDone.calls.argsFor(0)[0];
|
|
expect(specStatus.status).toBe('pending');
|
|
expect(specStatus.pendingReason).toBe('with a message');
|
|
});
|
|
|
|
it('should report pending spec messages from promise-returning functions', async function() {
|
|
function StubPromise(fn) {
|
|
try {
|
|
fn();
|
|
} catch (e) {
|
|
this.exception = e;
|
|
}
|
|
}
|
|
|
|
StubPromise.prototype.then = function(resolve, reject) {
|
|
reject(this.exception);
|
|
};
|
|
|
|
const reporter = jasmine.createSpyObj('fakeReporter', ['specDone']);
|
|
|
|
env.addReporter(reporter);
|
|
|
|
env.it('will be pending', function() {
|
|
return new StubPromise(function() {
|
|
env.pending('with a message');
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
const specStatus = reporter.specDone.calls.argsFor(0)[0];
|
|
expect(specStatus.status).toBe('pending');
|
|
expect(specStatus.pendingReason).toBe('with a message');
|
|
});
|
|
|
|
it('should report using fallback reporter', function(done) {
|
|
const reporter = jasmine.createSpyObj('fakeReporter', [
|
|
'specDone',
|
|
'jasmineDone'
|
|
]);
|
|
|
|
reporter.jasmineDone.and.callFake(function() {
|
|
expect(reporter.specDone).toHaveBeenCalled();
|
|
|
|
done();
|
|
});
|
|
|
|
env.provideFallbackReporter(reporter);
|
|
|
|
env.it('will be pending', function() {
|
|
env.pending('with a message');
|
|
});
|
|
|
|
env.execute();
|
|
});
|
|
|
|
it('should report xdescribes as expected', async function() {
|
|
const reporter = jasmine.createSpyObj('fakeReporter', [
|
|
'jasmineStarted',
|
|
'suiteStarted',
|
|
'suiteDone',
|
|
'specStarted',
|
|
'specDone'
|
|
]);
|
|
|
|
env.addReporter(reporter);
|
|
|
|
env.describe('A Suite', function() {
|
|
env.describe('nested', function() {
|
|
env.xdescribe('xd out', function() {
|
|
env.describe('nested again', function() {
|
|
env.it('with a spec', function() {
|
|
env.expect(true).toBe(false);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(reporter.jasmineStarted).toHaveBeenCalledWith({
|
|
totalSpecsDefined: 1,
|
|
numExcludedSpecs: 1,
|
|
order: { random: true, seed: jasmine.any(String) },
|
|
parallel: false
|
|
});
|
|
|
|
expect(reporter.specDone).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({ status: 'pending' })
|
|
);
|
|
expect(reporter.suiteDone).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({ description: 'xd out', status: 'pending' })
|
|
);
|
|
expect(reporter.suiteDone.calls.count()).toBe(4);
|
|
});
|
|
|
|
it('should be possible to get full name from a spec', function() {
|
|
let topLevelSpec, nestedSpec, doublyNestedSpec;
|
|
|
|
env.describe('my tests', function() {
|
|
topLevelSpec = env.it('are sometimes top level', function() {});
|
|
env.describe('are sometimes', function() {
|
|
nestedSpec = env.it('singly nested', function() {});
|
|
env.describe('even', function() {
|
|
doublyNestedSpec = env.it('doubly nested', function() {});
|
|
});
|
|
});
|
|
});
|
|
|
|
expect(topLevelSpec.getFullName()).toBe('my tests are sometimes top level');
|
|
expect(nestedSpec.getFullName()).toBe(
|
|
'my tests are sometimes singly nested'
|
|
);
|
|
expect(doublyNestedSpec.getFullName()).toBe(
|
|
'my tests are sometimes even doubly nested'
|
|
);
|
|
});
|
|
|
|
it('Custom equality testers should be per spec', async function() {
|
|
const reporter = jasmine.createSpyObj('fakeReporter', ['specDone']);
|
|
|
|
env.addReporter(reporter);
|
|
env.configure({ random: false });
|
|
|
|
env.describe('testing custom equality testers', function() {
|
|
env.it('with a custom tester', function() {
|
|
env.addCustomEqualityTester(function() {
|
|
return true;
|
|
});
|
|
env.expect('a').toEqual('b');
|
|
});
|
|
|
|
env.it('without a custom tester', function() {
|
|
env.expect('a').toEqual('b');
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
const firstSpecResult = reporter.specDone.calls.first().args[0];
|
|
const secondSpecResult = reporter.specDone.calls.mostRecent().args[0];
|
|
|
|
expect(firstSpecResult.status).toEqual('passed');
|
|
expect(secondSpecResult.status).toEqual('failed');
|
|
});
|
|
|
|
it('Custom equality testers should be per suite', async function() {
|
|
const reporter = jasmine.createSpyObj('fakeReporter', ['specDone']);
|
|
|
|
env.addReporter(reporter);
|
|
env.configure({ random: false });
|
|
|
|
env.describe('testing custom equality testers', function() {
|
|
env.beforeAll(function() {
|
|
env.addCustomEqualityTester(function() {
|
|
return true;
|
|
});
|
|
});
|
|
|
|
env.it('with a custom tester', function() {
|
|
env.expect('a').toEqual('b');
|
|
});
|
|
|
|
env.it('with the same custom tester', function() {
|
|
env.expect('a').toEqual('b');
|
|
});
|
|
});
|
|
|
|
env.describe('another suite', function() {
|
|
env.it('without the custom tester', function() {
|
|
env.expect('a').toEqual('b');
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
const firstSpecResult = reporter.specDone.calls.first().args[0];
|
|
const secondSpecResult = reporter.specDone.calls.argsFor(0)[0];
|
|
const thirdSpecResult = reporter.specDone.calls.mostRecent().args[0];
|
|
|
|
expect(firstSpecResult.status).toEqual('passed');
|
|
expect(secondSpecResult.status).toEqual('passed');
|
|
expect(thirdSpecResult.status).toEqual('failed');
|
|
});
|
|
|
|
it('Custom equality testers for toContain should be per spec', async function() {
|
|
const reporter = jasmine.createSpyObj('fakeReporter', ['specDone']);
|
|
|
|
env.addReporter(reporter);
|
|
env.configure({ random: false });
|
|
|
|
env.describe('testing custom equality testers', function() {
|
|
env.it('with a custom tester', function() {
|
|
env.addCustomEqualityTester(function() {
|
|
return true;
|
|
});
|
|
env.expect(['a']).toContain('b');
|
|
});
|
|
|
|
env.it('without a custom tester', function() {
|
|
env.expect(['a']).toContain('b');
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
const firstSpecResult = reporter.specDone.calls.first().args[0];
|
|
const secondSpecResult = reporter.specDone.calls.mostRecent().args[0];
|
|
|
|
expect(firstSpecResult.status).toEqual('passed');
|
|
expect(secondSpecResult.status).toEqual('failed');
|
|
});
|
|
|
|
it("produces an understandable error message when an 'expect' is used outside of a current spec", async function() {
|
|
env.describe('A Suite', function() {
|
|
env.it('an async spec that is actually synchronous', function(
|
|
underTestCallback
|
|
) {
|
|
underTestCallback();
|
|
});
|
|
expect(function() {
|
|
env.expect('a').toEqual('a');
|
|
}).toThrowError(/'expect' was used when there was no current spec/);
|
|
});
|
|
|
|
await env.execute();
|
|
});
|
|
|
|
it('Custom equality testers for toContain should be per suite', async function() {
|
|
const reporter = jasmine.createSpyObj('fakeReporter', ['specDone']);
|
|
|
|
env.addReporter(reporter);
|
|
env.configure({ random: false });
|
|
|
|
env.describe('testing custom equality testers', function() {
|
|
env.beforeAll(function() {
|
|
env.addCustomEqualityTester(function() {
|
|
return true;
|
|
});
|
|
});
|
|
|
|
env.it('with a custom tester', function() {
|
|
env.expect(['a']).toContain('b');
|
|
});
|
|
|
|
env.it('also with the custom tester', function() {
|
|
env.expect(['a']).toContain('b');
|
|
});
|
|
});
|
|
|
|
env.describe('another suite', function() {
|
|
env.it('without the custom tester', function() {
|
|
env.expect(['a']).toContain('b');
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
const firstSpecResult = reporter.specDone.calls.first().args[0];
|
|
const secondSpecResult = reporter.specDone.calls.argsFor(1)[0];
|
|
const thirdSpecResult = reporter.specDone.calls.mostRecent().args[0];
|
|
|
|
expect(firstSpecResult.status).toEqual('passed');
|
|
expect(secondSpecResult.status).toEqual('passed');
|
|
expect(thirdSpecResult.status).toEqual('failed');
|
|
});
|
|
|
|
it('Custom matchers should be per spec', async function() {
|
|
const matchers = {
|
|
toFoo: function() {}
|
|
};
|
|
|
|
env.describe('testing custom matchers', function() {
|
|
env.it('with a custom matcher', function() {
|
|
env.addMatchers(matchers);
|
|
expect(env.expect().toFoo).toBeDefined();
|
|
});
|
|
|
|
env.it('without a custom matcher', function() {
|
|
expect(env.expect().toFoo).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
});
|
|
|
|
it('Custom matchers should be per suite', async function() {
|
|
const matchers = {
|
|
toFoo: function() {}
|
|
};
|
|
|
|
env.describe('testing custom matchers', function() {
|
|
env.beforeAll(function() {
|
|
env.addMatchers(matchers);
|
|
});
|
|
|
|
env.it('with a custom matcher', function() {
|
|
expect(env.expect().toFoo).toBeDefined();
|
|
});
|
|
|
|
env.it('with the same custom matcher', function() {
|
|
expect(env.expect().toFoo).toBeDefined();
|
|
});
|
|
});
|
|
|
|
env.describe('another suite', function() {
|
|
env.it('no longer has the custom matcher', function() {
|
|
expect(env.expect().toFoo).not.toBeDefined();
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
});
|
|
|
|
it('Custom matchers set in top-level beforeAll should be available to all specs and suites', async function() {
|
|
const matchers = {
|
|
toFoo: function() {}
|
|
};
|
|
|
|
env.beforeAll(function() {
|
|
env.addMatchers(matchers);
|
|
});
|
|
|
|
env.describe('suite - top-level', function() {
|
|
env.it('has access to the custom matcher', function() {
|
|
expect(env.expect().toFoo).toBeDefined();
|
|
});
|
|
|
|
env.describe('suite - nested', function() {
|
|
env.it('has access to the custom matcher', function() {
|
|
expect(env.expect().toFoo).toBeDefined();
|
|
});
|
|
});
|
|
});
|
|
|
|
env.it('spec - top-level - has access to the custom matcher', function() {
|
|
expect(env.expect().toFoo).toBeDefined();
|
|
});
|
|
|
|
await env.execute();
|
|
});
|
|
|
|
it('throws an exception if you try to create a spy outside of a runnable', async function() {
|
|
const obj = { fn: function() {} };
|
|
let exception;
|
|
|
|
env.describe('a suite', function() {
|
|
try {
|
|
env.spyOn(obj, 'fn');
|
|
} catch (e) {
|
|
exception = e;
|
|
}
|
|
env.it('has a test', function() {});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(exception.message).toBe(
|
|
'Spies must be created in a before function or a spec'
|
|
);
|
|
});
|
|
|
|
it('throws an exception if you try to add a matcher outside of a runnable', async function() {
|
|
let exception;
|
|
|
|
env.describe('a suite', function() {
|
|
try {
|
|
env.addMatchers({
|
|
myMatcher: function() {
|
|
return false;
|
|
}
|
|
});
|
|
} catch (e) {
|
|
exception = e;
|
|
}
|
|
env.it('has a test', function() {});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(exception.message).toBe(
|
|
'Matchers must be added in a before function or a spec'
|
|
);
|
|
});
|
|
|
|
it('throws an exception if you try to add a custom equality outside of a runnable', async function() {
|
|
let exception;
|
|
|
|
env.describe('a suite', function() {
|
|
try {
|
|
env.addCustomEqualityTester(function() {
|
|
return true;
|
|
});
|
|
} catch (e) {
|
|
exception = e;
|
|
}
|
|
env.it('has a test', function() {});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(exception.message).toBe(
|
|
'Custom Equalities must be added in a before function or a spec'
|
|
);
|
|
});
|
|
|
|
it('throws an exception if you try to getSpecProperty outside of a spec', async function() {
|
|
const env = new privateUnderTest.Env();
|
|
let exception;
|
|
|
|
env.describe('a suite', function() {
|
|
env.it('a spec');
|
|
try {
|
|
env.getSpecProperty('a prop');
|
|
} catch (e) {
|
|
exception = e;
|
|
}
|
|
env.it('has a test', function() {});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(exception.message).toBe(
|
|
"'getSpecProperty' was used when there was no current spec"
|
|
);
|
|
});
|
|
|
|
it('reports test properties on specs', async function() {
|
|
const env = new privateUnderTest.Env();
|
|
const reporter = jasmine.createSpyObj('reporter', [
|
|
'suiteDone',
|
|
'specDone'
|
|
]);
|
|
|
|
reporter.specDone.and.callFake(function(e) {
|
|
expect(e.properties).toEqual({
|
|
fromBeforeEach: 'Pie',
|
|
fromSpecInnerCallback: 'Bee',
|
|
willChangeInAfterEach: 2,
|
|
fromAfterEach: 'Cheese'
|
|
});
|
|
});
|
|
|
|
env.addReporter(reporter);
|
|
env.beforeEach(function() {
|
|
env.setSpecProperty('fromBeforeEach', 'Pie');
|
|
});
|
|
env.afterEach(function() {
|
|
env.setSpecProperty(
|
|
'willChangeInAfterEach',
|
|
env.getSpecProperty('willChangeInAfterEach') + 1
|
|
);
|
|
env.setSpecProperty('fromAfterEach', 'Cheese');
|
|
});
|
|
env.it('calls setSpecProperty', function() {
|
|
env.setSpecProperty('fromSpecInnerCallback', 'Bee');
|
|
env.setSpecProperty('willChangeInAfterEach', 1);
|
|
});
|
|
await env.execute();
|
|
|
|
expect(reporter.specDone).toHaveBeenCalled();
|
|
});
|
|
|
|
it('throws an exception if you try to setSpecProperty outside of a spec', async function() {
|
|
const env = new privateUnderTest.Env();
|
|
let exception;
|
|
|
|
env.describe('a suite', function() {
|
|
env.it('a spec');
|
|
try {
|
|
env.setSpecProperty('a prop', 'val');
|
|
} catch (e) {
|
|
exception = e;
|
|
}
|
|
env.it('has a test', function() {});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(exception.message).toBe(
|
|
"'setSpecProperty' was used when there was no current spec"
|
|
);
|
|
});
|
|
|
|
it('reports test properties on suites', async function() {
|
|
const env = new privateUnderTest.Env();
|
|
const reporter = jasmine.createSpyObj('reporter', [
|
|
'jasmineDone',
|
|
'suiteDone',
|
|
'specDone'
|
|
]);
|
|
|
|
reporter.suiteDone.and.callFake(function(e) {
|
|
expect(e.properties).toEqual({ b: 'Sweet' });
|
|
});
|
|
|
|
env.addReporter(reporter);
|
|
env.describe('calls setSuiteProperty', function() {
|
|
env.beforeEach(function() {
|
|
env.setSuiteProperty('b', 'Sweet');
|
|
});
|
|
env.it('a passing spec', function() {
|
|
expect.nothing();
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(reporter.suiteDone).toHaveBeenCalled();
|
|
});
|
|
|
|
it('throws an exception if you try to setSuiteProperty outside of a suite', function(done) {
|
|
const env = new privateUnderTest.Env();
|
|
|
|
try {
|
|
env.setSuiteProperty('a', 'Bee');
|
|
} catch (e) {
|
|
expect(e.message).toBe(
|
|
"'setSuiteProperty' was used when there was no current suite"
|
|
);
|
|
done();
|
|
}
|
|
});
|
|
|
|
it('should associate errors thrown from async code with the correct runnable', async function() {
|
|
const reporter = jasmine.createSpyObj('fakeReport', [
|
|
'suiteDone',
|
|
'specDone'
|
|
]);
|
|
|
|
env.addReporter(reporter);
|
|
|
|
env.describe('async suite', function() {
|
|
env.afterAll(function(innerDone) {
|
|
setTimeout(function() {
|
|
throw new Error('suite');
|
|
}, 1);
|
|
}, 50);
|
|
|
|
env.it('spec', function() {});
|
|
});
|
|
|
|
env.describe('suite', function() {
|
|
env.it(
|
|
'async spec',
|
|
function(innerDone) {
|
|
setTimeout(function() {
|
|
throw new Error('spec');
|
|
}, 1);
|
|
},
|
|
50
|
|
);
|
|
});
|
|
|
|
await jasmine.spyOnGlobalErrorsAsync(async function(globalErrorSpy) {
|
|
await env.execute();
|
|
|
|
if (isBrowser) {
|
|
// Verify that there were no unexpected errors
|
|
expect(globalErrorSpy).toHaveBeenCalledTimes(2);
|
|
expect(globalErrorSpy).toHaveBeenCalledWith(new Error('suite'));
|
|
expect(globalErrorSpy).toHaveBeenCalledWith(new Error('spec'));
|
|
}
|
|
});
|
|
|
|
expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable(
|
|
'async suite',
|
|
[/Error: suite/]
|
|
);
|
|
expect(reporter.specDone).toHaveFailedExpectationsForRunnable(
|
|
'suite async spec',
|
|
[/Error: spec/]
|
|
);
|
|
});
|
|
|
|
it("should throw on suites/specs/befores/afters nested in methods other than 'describe'", async function() {
|
|
const reporter = jasmine.createSpyObj('reporter', [
|
|
'suiteDone',
|
|
'specDone'
|
|
]);
|
|
|
|
env.addReporter(reporter);
|
|
|
|
env.describe('suite', function() {
|
|
env.it('describe', function() {
|
|
env.describe('inner suite', function() {});
|
|
});
|
|
env.it('xdescribe', function() {
|
|
env.xdescribe('inner suite', function() {});
|
|
});
|
|
env.it('fdescribe', function() {
|
|
env.fdescribe('inner suite', function() {});
|
|
});
|
|
});
|
|
|
|
env.describe('spec', function() {
|
|
env.it('it', function() {
|
|
env.it('inner spec', function() {});
|
|
});
|
|
env.it('xit', function() {
|
|
env.xit('inner spec', function() {});
|
|
});
|
|
env.it('fit', function() {
|
|
env.fit('inner spec', function() {});
|
|
});
|
|
});
|
|
|
|
env.describe('beforeAll', function() {
|
|
env.beforeAll(function() {
|
|
env.beforeAll(function() {});
|
|
});
|
|
env.it('spec', function() {});
|
|
});
|
|
|
|
env.describe('beforeEach', function() {
|
|
env.beforeEach(function() {
|
|
env.beforeEach(function() {});
|
|
});
|
|
env.it('spec', function() {});
|
|
});
|
|
|
|
env.describe('afterAll', function() {
|
|
env.afterAll(function() {
|
|
env.afterAll(function() {});
|
|
});
|
|
env.it('spec', function() {});
|
|
});
|
|
|
|
env.describe('afterEach', function() {
|
|
env.afterEach(function() {
|
|
env.afterEach(function() {});
|
|
});
|
|
env.it('spec', function() {});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
const msg = /\'.*\' should only be used in \'describe\' function/;
|
|
|
|
expect(reporter.specDone).toHaveFailedExpectationsForRunnable(
|
|
'suite describe',
|
|
[msg]
|
|
);
|
|
expect(reporter.specDone).toHaveFailedExpectationsForRunnable(
|
|
'suite xdescribe',
|
|
[msg]
|
|
);
|
|
expect(reporter.specDone).toHaveFailedExpectationsForRunnable(
|
|
'suite fdescribe',
|
|
[msg]
|
|
);
|
|
|
|
expect(reporter.specDone).toHaveFailedExpectationsForRunnable('spec it', [
|
|
msg
|
|
]);
|
|
expect(reporter.specDone).toHaveFailedExpectationsForRunnable('spec xit', [
|
|
msg
|
|
]);
|
|
expect(reporter.specDone).toHaveFailedExpectationsForRunnable('spec fit', [
|
|
msg
|
|
]);
|
|
|
|
expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable(
|
|
'beforeAll',
|
|
[msg]
|
|
);
|
|
expect(reporter.specDone).toHaveFailedExpectationsForRunnable(
|
|
'beforeEach spec',
|
|
[msg]
|
|
);
|
|
|
|
expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable('afterAll', [
|
|
msg
|
|
]);
|
|
expect(reporter.specDone).toHaveFailedExpectationsForRunnable(
|
|
'afterEach spec',
|
|
[msg]
|
|
);
|
|
});
|
|
|
|
describe('Overall status in the jasmineDone event', function() {
|
|
describe('When everything passes', function() {
|
|
it('is "passed"', async function() {
|
|
const reporter = jasmine.createSpyObj('reporter', [
|
|
'jasmineDone',
|
|
'suiteDone',
|
|
'specDone'
|
|
]);
|
|
|
|
env.addReporter(reporter);
|
|
env.it('passes', function() {});
|
|
await env.execute();
|
|
|
|
const e = reporter.jasmineDone.calls.argsFor(0)[0];
|
|
expect(e.overallStatus).toEqual('passed');
|
|
});
|
|
});
|
|
|
|
describe('When a spec fails', function() {
|
|
it('is "failed"', async function() {
|
|
const reporter = jasmine.createSpyObj('reporter', [
|
|
'jasmineDone',
|
|
'suiteDone',
|
|
'specDone'
|
|
]);
|
|
|
|
env.addReporter(reporter);
|
|
env.it('fails', function() {
|
|
env.expect(true).toBe(false);
|
|
});
|
|
await env.execute();
|
|
|
|
const e = reporter.jasmineDone.calls.argsFor(0)[0];
|
|
expect(e.overallStatus).toEqual('failed');
|
|
});
|
|
});
|
|
|
|
describe('when spec has no expectations', function() {
|
|
let reporter;
|
|
|
|
beforeEach(function() {
|
|
reporter = jasmine.createSpyObj('reporter', [
|
|
'jasmineDone',
|
|
'suiteDone',
|
|
'specDone'
|
|
]);
|
|
|
|
env.addReporter(reporter);
|
|
env.it('is a spec without any expectations', function() {
|
|
// does nothing, just a mock spec without expectations
|
|
});
|
|
});
|
|
|
|
it('should report "failed" status if "failSpecWithNoExpectations" is enabled', async function() {
|
|
env.configure({ failSpecWithNoExpectations: true });
|
|
await env.execute();
|
|
|
|
const e = reporter.jasmineDone.calls.argsFor(0)[0];
|
|
expect(e.overallStatus).toEqual('failed');
|
|
});
|
|
|
|
it('should report "passed" status if "failSpecWithNoExpectations" is disabled', async function() {
|
|
env.configure({ failSpecWithNoExpectations: false });
|
|
await env.execute();
|
|
|
|
const e = reporter.jasmineDone.calls.argsFor(0)[0];
|
|
expect(e.overallStatus).toEqual('passed');
|
|
});
|
|
});
|
|
|
|
describe('When a top-level beforeAll fails', function() {
|
|
it('is "failed"', async function() {
|
|
const reporter = jasmine.createSpyObj('reporter', [
|
|
'jasmineDone',
|
|
'suiteDone',
|
|
'specDone'
|
|
]);
|
|
|
|
env.addReporter(reporter);
|
|
env.beforeAll(function() {
|
|
throw new Error('nope');
|
|
});
|
|
env.it('does not run', function() {});
|
|
await env.execute();
|
|
|
|
const e = reporter.jasmineDone.calls.argsFor(0)[0];
|
|
expect(e.overallStatus).toEqual('failed');
|
|
});
|
|
});
|
|
|
|
describe('When a suite beforeAll fails', function() {
|
|
it('is "failed"', async function() {
|
|
const reporter = jasmine.createSpyObj('reporter', [
|
|
'jasmineDone',
|
|
'suiteDone',
|
|
'specDone'
|
|
]);
|
|
|
|
env.addReporter(reporter);
|
|
env.describe('something', function() {
|
|
env.beforeAll(function() {
|
|
throw new Error('nope');
|
|
});
|
|
env.it('does not run', function() {});
|
|
});
|
|
await env.execute();
|
|
|
|
const e = reporter.jasmineDone.calls.argsFor(0)[0];
|
|
expect(e.overallStatus).toEqual('failed');
|
|
});
|
|
});
|
|
|
|
describe('When a top-level afterAll fails', function() {
|
|
it('is "failed"', async function() {
|
|
const reporter = jasmine.createSpyObj('reporter', [
|
|
'jasmineDone',
|
|
'suiteDone',
|
|
'specDone'
|
|
]);
|
|
|
|
env.addReporter(reporter);
|
|
env.afterAll(function() {
|
|
throw new Error('nope');
|
|
});
|
|
env.it('does not run', function() {});
|
|
await env.execute();
|
|
|
|
const e = reporter.jasmineDone.calls.argsFor(0)[0];
|
|
expect(e.overallStatus).toEqual('failed');
|
|
});
|
|
});
|
|
|
|
describe('When a suite afterAll fails', function() {
|
|
it('is "failed"', async function() {
|
|
const reporter = jasmine.createSpyObj('reporter', [
|
|
'jasmineDone',
|
|
'suiteDone',
|
|
'specDone'
|
|
]);
|
|
|
|
env.addReporter(reporter);
|
|
env.describe('something', function() {
|
|
env.afterAll(function() {
|
|
throw new Error('nope');
|
|
});
|
|
env.it('does not run', function() {});
|
|
});
|
|
await env.execute();
|
|
|
|
const e = reporter.jasmineDone.calls.argsFor(0)[0];
|
|
expect(e.overallStatus).toEqual('failed');
|
|
});
|
|
});
|
|
|
|
describe('When there are load errors', function() {
|
|
it('is "failed"', async function() {
|
|
const global = {
|
|
...browserEventMethods(),
|
|
setTimeout: function(fn, delay) {
|
|
return setTimeout(fn, delay);
|
|
},
|
|
clearTimeout: function(fn, delay) {
|
|
return clearTimeout(fn, delay);
|
|
},
|
|
queueMicrotask: function(fn) {
|
|
queueMicrotask(fn);
|
|
},
|
|
// Enough Node globals to make getStackClearer() return the microtask
|
|
// implementation, which is the easiest to mock
|
|
process: {
|
|
versions: {
|
|
node: ''
|
|
}
|
|
}
|
|
};
|
|
|
|
env.cleanup_();
|
|
env = new privateUnderTest.Env({ global });
|
|
const reporter = jasmine.createSpyObj('reporter', [
|
|
'jasmineDone',
|
|
'suiteDone',
|
|
'specDone'
|
|
]);
|
|
|
|
reporter.jasmineDone.and.callFake(function(e) {
|
|
expect(e.overallStatus).toEqual('failed');
|
|
});
|
|
|
|
env.addReporter(reporter);
|
|
env.it('passes', function() {});
|
|
dispatchErrorEvent(global, { error: 'ENOCHEESE' });
|
|
await env.execute();
|
|
|
|
expect(reporter.jasmineDone).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('When there are no specs', function() {
|
|
it('is "incomplete"', async function() {
|
|
const reporter = jasmine.createSpyObj('reporter', [
|
|
'jasmineDone',
|
|
'suiteDone',
|
|
'specDone'
|
|
]);
|
|
|
|
env.addReporter(reporter);
|
|
await env.execute();
|
|
|
|
const e = reporter.jasmineDone.calls.argsFor(0)[0];
|
|
expect(e.overallStatus).toEqual('incomplete');
|
|
expect(e.incompleteReason).toEqual('No specs found');
|
|
expect(e.incompleteCode).toEqual('noSpecsFound');
|
|
});
|
|
});
|
|
|
|
describe('When a spec is focused', function() {
|
|
it('is "incomplete"', async function() {
|
|
const reporter = jasmine.createSpyObj('reporter', [
|
|
'jasmineDone',
|
|
'suiteDone',
|
|
'specDone'
|
|
]);
|
|
|
|
env.addReporter(reporter);
|
|
env.fit('is focused', function() {});
|
|
await env.execute();
|
|
|
|
const e = reporter.jasmineDone.calls.argsFor(0)[0];
|
|
expect(e.overallStatus).toEqual('incomplete');
|
|
expect(e.incompleteReason).toEqual('fit() or fdescribe() was found');
|
|
expect(e.incompleteCode).toEqual('focused');
|
|
});
|
|
});
|
|
|
|
describe('When a suite is focused', function() {
|
|
it('is "incomplete"', async function() {
|
|
const reporter = jasmine.createSpyObj('reporter', [
|
|
'jasmineDone',
|
|
'suiteDone',
|
|
'specDone'
|
|
]);
|
|
|
|
env.addReporter(reporter);
|
|
env.fdescribe('something focused', function() {
|
|
env.it('does a thing', function() {});
|
|
});
|
|
await env.execute();
|
|
|
|
const e = reporter.jasmineDone.calls.argsFor(0)[0];
|
|
expect(e.overallStatus).toEqual('incomplete');
|
|
expect(e.incompleteReason).toEqual('fit() or fdescribe() was found');
|
|
expect(e.incompleteCode).toEqual('focused');
|
|
});
|
|
});
|
|
|
|
describe('When there are both failures and focused specs', function() {
|
|
it('is "failed"', async function() {
|
|
const reporter = jasmine.createSpyObj('reporter', [
|
|
'jasmineDone',
|
|
'suiteDone',
|
|
'specDone'
|
|
]);
|
|
|
|
env.addReporter(reporter);
|
|
env.fit('is focused', function() {
|
|
env.expect(true).toBe(false);
|
|
});
|
|
await env.execute();
|
|
|
|
const e = reporter.jasmineDone.calls.argsFor(0)[0];
|
|
expect(e.overallStatus).toEqual('failed');
|
|
expect(e.incompleteReason).toBeUndefined();
|
|
expect(e.incompleteCode).toBeUndefined();
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should report deprecation stack with an error object', async function() {
|
|
const exceptionFormatter = new privateUnderTest.ExceptionFormatter();
|
|
const reporter = jasmine.createSpyObj('reporter', [
|
|
'jasmineDone',
|
|
'suiteDone',
|
|
'specDone'
|
|
]);
|
|
const topLevelError = new Error('top level deprecation');
|
|
const suiteLevelError = new Error('suite level deprecation');
|
|
const specLevelError = new Error('spec level deprecation');
|
|
|
|
// prevent deprecation from being displayed
|
|
spyOn(console, 'error');
|
|
|
|
env.addReporter(reporter);
|
|
|
|
env.deprecated(topLevelError);
|
|
|
|
env.describe('suite', function() {
|
|
env.beforeAll(function() {
|
|
env.deprecated(suiteLevelError);
|
|
});
|
|
|
|
env.it('spec', function() {
|
|
env.deprecated(specLevelError);
|
|
});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
const result = reporter.jasmineDone.calls.argsFor(0)[0];
|
|
expect(result.deprecationWarnings).toEqual([
|
|
jasmine.objectContaining({
|
|
message: topLevelError.message,
|
|
stack: exceptionFormatter.stack(topLevelError, { omitMessage: true })
|
|
})
|
|
]);
|
|
|
|
expect(reporter.suiteDone).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
fullName: 'suite',
|
|
deprecationWarnings: [
|
|
jasmine.objectContaining({
|
|
message: suiteLevelError.message,
|
|
stack: exceptionFormatter.stack(suiteLevelError, {
|
|
omitMessage: true
|
|
})
|
|
})
|
|
]
|
|
})
|
|
);
|
|
|
|
expect(reporter.specDone).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
fullName: 'suite spec',
|
|
deprecationWarnings: [
|
|
jasmine.objectContaining({
|
|
message: specLevelError.message,
|
|
stack: exceptionFormatter.stack(specLevelError, {
|
|
omitMessage: true
|
|
})
|
|
})
|
|
]
|
|
})
|
|
);
|
|
});
|
|
|
|
it('supports async matchers', async function() {
|
|
const specDone = jasmine.createSpy('specDone');
|
|
const suiteDone = jasmine.createSpy('suiteDone');
|
|
const jasmineDone = jasmine.createSpy('jasmineDone');
|
|
|
|
env.addReporter({
|
|
specDone: specDone,
|
|
suiteDone: suiteDone,
|
|
jasmineDone: jasmineDone
|
|
});
|
|
|
|
function fail(innerDone) {
|
|
let resolve;
|
|
const p = new Promise(function(res) {
|
|
resolve = res;
|
|
});
|
|
env
|
|
.expectAsync(p)
|
|
.toBeRejected()
|
|
.then(innerDone);
|
|
resolve();
|
|
}
|
|
|
|
env.afterAll(fail);
|
|
env.describe('a suite', function() {
|
|
env.afterAll(fail);
|
|
env.it('has an async failure', fail);
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
const result = jasmineDone.calls.argsFor(0)[0];
|
|
expect(result.failedExpectations).toEqual([
|
|
jasmine.objectContaining({
|
|
message: 'Expected [object Promise] to be rejected.'
|
|
})
|
|
]);
|
|
|
|
expect(specDone).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
description: 'has an async failure',
|
|
failedExpectations: [
|
|
jasmine.objectContaining({
|
|
message: 'Expected [object Promise] to be rejected.'
|
|
})
|
|
]
|
|
})
|
|
);
|
|
|
|
expect(suiteDone).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
description: 'a suite',
|
|
failedExpectations: [
|
|
jasmine.objectContaining({
|
|
message: 'Expected [object Promise] to be rejected.'
|
|
})
|
|
]
|
|
})
|
|
);
|
|
});
|
|
|
|
it('provides custom equality testers to async matchers', async function() {
|
|
const specDone = jasmine.createSpy('specDone');
|
|
|
|
env.addReporter({ specDone: specDone });
|
|
|
|
env.it('has an async failure', function() {
|
|
env.addCustomEqualityTester(function() {
|
|
return true;
|
|
});
|
|
const p = Promise.resolve('something');
|
|
return env.expectAsync(p).toBeResolvedTo('something else');
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(specDone).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
description: 'has an async failure',
|
|
failedExpectations: []
|
|
})
|
|
);
|
|
});
|
|
|
|
it('includes useful stack frames in async matcher failures', async function() {
|
|
const specDone = jasmine.createSpy('specDone');
|
|
|
|
env.addReporter({ specDone: specDone });
|
|
|
|
env.it('has an async failure', function() {
|
|
env.addCustomEqualityTester(function() {
|
|
return true;
|
|
});
|
|
const p = Promise.resolve();
|
|
return env.expectAsync(p).toBeRejected();
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(specDone).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
failedExpectations: [
|
|
jasmine.objectContaining({
|
|
stack: jasmine.stringMatching('EnvSpec.js')
|
|
})
|
|
]
|
|
})
|
|
);
|
|
});
|
|
|
|
it('reports an error when an async expectation occurs after the spec finishes', async function() {
|
|
const jasmineDone = jasmine.createSpy('jasmineDone');
|
|
let resolve;
|
|
const promise = new Promise(function(res) {
|
|
resolve = res;
|
|
});
|
|
|
|
env.configure({ random: false });
|
|
|
|
env.describe('a suite', function() {
|
|
env.it('does not wait', function() {
|
|
// Note: we intentionally don't return the result of each expectAsync.
|
|
// This causes the spec to finish before the expectations are evaluated.
|
|
env.expectAsync(promise).toBeResolved();
|
|
env.expectAsync(promise).toBeResolvedTo('something else');
|
|
});
|
|
});
|
|
|
|
env.it('another spec', function(done) {
|
|
// This is here to make sure that the async expectation evaluates
|
|
// before the Jasmine under test finishes, especially on Safari 8 and 9.
|
|
setTimeout(done, 10);
|
|
});
|
|
|
|
env.addReporter({
|
|
specDone: function() {
|
|
resolve();
|
|
},
|
|
jasmineDone: jasmineDone
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
const result = jasmineDone.calls.argsFor(0)[0];
|
|
expect(result.failedExpectations).toEqual([
|
|
jasmine.objectContaining({
|
|
passed: false,
|
|
globalErrorType: 'lateExpectation',
|
|
message:
|
|
'Spec "a suite does not wait" ran a "toBeResolved" expectation ' +
|
|
'after it finished.\n' +
|
|
'1. Did you forget to return or await the result of expectAsync?\n' +
|
|
'2. Was done() invoked before an async operation completed?\n' +
|
|
'3. Did an expectation follow a call to done()?',
|
|
matcherName: 'toBeResolved'
|
|
}),
|
|
jasmine.objectContaining({
|
|
passed: false,
|
|
globalErrorType: 'lateExpectation',
|
|
message:
|
|
'Spec "a suite does not wait" ran a "toBeResolvedTo" expectation ' +
|
|
'after it finished.\n' +
|
|
"Message: \"Expected a promise to be resolved to 'something else' " +
|
|
'but it was resolved to undefined."\n' +
|
|
'1. Did you forget to return or await the result of expectAsync?\n' +
|
|
'2. Was done() invoked before an async operation completed?\n' +
|
|
'3. Did an expectation follow a call to done()?',
|
|
matcherName: 'toBeResolvedTo'
|
|
})
|
|
]);
|
|
});
|
|
|
|
it('reports an error when an async expectation occurs after the suite finishes', async function() {
|
|
const jasmineDone = jasmine.createSpy('jasmineDone');
|
|
let resolve;
|
|
const promise = new Promise(function(res) {
|
|
resolve = res;
|
|
});
|
|
|
|
env.configure({ random: false });
|
|
|
|
env.describe('a suite', function() {
|
|
env.afterAll(function() {
|
|
// Note: we intentionally don't return the result of expectAsync.
|
|
// This causes the suite to finish before the expectations are evaluated.
|
|
env.expectAsync(promise).toBeResolved();
|
|
});
|
|
|
|
env.it('is a spec', function() {});
|
|
});
|
|
|
|
env.it('another spec', function(done) {
|
|
// This is here to make sure that the async expectation evaluates
|
|
// before the Jasmine under test finishes, especially on Safari 8 and 9.
|
|
setTimeout(done, 10);
|
|
});
|
|
|
|
env.addReporter({
|
|
suiteDone: function() {
|
|
resolve();
|
|
},
|
|
jasmineDone: jasmineDone
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
const result = jasmineDone.calls.argsFor(0)[0];
|
|
expect(result.failedExpectations).toEqual([
|
|
{
|
|
passed: false,
|
|
globalErrorType: 'lateExpectation',
|
|
message:
|
|
'Suite "a suite" ran a "toBeResolved" expectation ' +
|
|
'after it finished.\n' +
|
|
'1. Did you forget to return or await the result of expectAsync?\n' +
|
|
'2. Was done() invoked before an async operation completed?\n' +
|
|
'3. Did an expectation follow a call to done()?',
|
|
matcherName: 'toBeResolved',
|
|
stack: jasmine.any(String)
|
|
}
|
|
]);
|
|
});
|
|
|
|
it('supports asymmetric equality testers that take a matchersUtil', async function() {
|
|
const env = new privateUnderTest.Env();
|
|
|
|
env.it('spec using custom asymmetric equality tester', function() {
|
|
const customEqualityFn = function(a, b) {
|
|
if (a === 2 && b === 'two') {
|
|
return true;
|
|
}
|
|
};
|
|
const arrayWithFirstElement = function(sample) {
|
|
return {
|
|
asymmetricMatch: function(actual, matchersUtil) {
|
|
return matchersUtil.equals(sample, actual[0]);
|
|
}
|
|
};
|
|
};
|
|
|
|
env.addCustomEqualityTester(customEqualityFn);
|
|
env.expect(['two']).toEqual(arrayWithFirstElement(2));
|
|
});
|
|
|
|
const specExpectations = function(result) {
|
|
expect(result.status).toEqual('passed');
|
|
};
|
|
|
|
env.addReporter({ specDone: specExpectations });
|
|
await env.execute();
|
|
});
|
|
|
|
describe('The promise returned by #execute', function() {
|
|
beforeEach(function() {
|
|
this.savedInterval = jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL;
|
|
});
|
|
|
|
afterEach(function() {
|
|
jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = this.savedInterval;
|
|
});
|
|
|
|
it('is resolved after reporter events are dispatched', function() {
|
|
const reporter = jasmine.createSpyObj('reporter', [
|
|
'specDone',
|
|
'suiteDone',
|
|
'jasmineDone'
|
|
]);
|
|
|
|
env.addReporter(reporter);
|
|
env.describe('suite', function() {
|
|
env.it('spec', function() {});
|
|
});
|
|
|
|
return env.execute(null).then(function() {
|
|
expect(reporter.specDone).toHaveBeenCalled();
|
|
expect(reporter.suiteDone).toHaveBeenCalled();
|
|
expect(reporter.jasmineDone).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
it('is resolved after the stack is cleared', function(done) {
|
|
const stackClearer = privateUnderTest.getStackClearer(
|
|
jasmineUnderTest.getGlobal()
|
|
);
|
|
spyOn(stackClearer, 'clearStack').and.callThrough();
|
|
spyOn(privateUnderTest, 'getStackClearer').and.returnValue(stackClearer);
|
|
|
|
// Create a new env that has the clearStack defined above
|
|
env.cleanup_();
|
|
env = new privateUnderTest.Env();
|
|
|
|
env.describe('suite', function() {
|
|
env.it('spec', function() {});
|
|
});
|
|
|
|
env.execute(null).then(function() {
|
|
expect(stackClearer.clearStack).toHaveBeenCalled(); // (many times)
|
|
stackClearer.clearStack.calls.reset();
|
|
setTimeout(function() {
|
|
expect(stackClearer.clearStack).not.toHaveBeenCalled();
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
|
|
it('is resolved after QueueRunner timeouts are cleared', function() {
|
|
const setTimeoutSpy = spyOn(
|
|
jasmineUnderTest.getGlobal(),
|
|
'setTimeout'
|
|
).and.callThrough();
|
|
const clearTimeoutSpy = spyOn(
|
|
jasmineUnderTest.getGlobal(),
|
|
'clearTimeout'
|
|
).and.callThrough();
|
|
|
|
jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = 123456; // a distinctive value
|
|
|
|
env = new privateUnderTest.Env();
|
|
|
|
env.describe('suite', function() {
|
|
env.it('spec', function() {});
|
|
});
|
|
|
|
return env.execute(null).then(function() {
|
|
const timeoutIds = setTimeoutSpy.calls
|
|
.all()
|
|
.filter(function(call) {
|
|
return call.args[1] === 123456;
|
|
})
|
|
.map(function(call) {
|
|
return call.returnValue;
|
|
});
|
|
|
|
expect(timeoutIds.length).toBeGreaterThan(0);
|
|
|
|
timeoutIds.forEach(function(timeoutId) {
|
|
expect(clearTimeoutSpy).toHaveBeenCalledWith(timeoutId);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('is resolved to the value of the jasmineDone event', async function() {
|
|
env.describe('suite', function() {
|
|
env.it('spec', function() {
|
|
env.expect(true).toBe(false);
|
|
});
|
|
});
|
|
|
|
let event;
|
|
env.addReporter({
|
|
jasmineDone: e => (event = e)
|
|
});
|
|
const result = await env.execute();
|
|
|
|
expect(event.overallStatus).toEqual('failed');
|
|
expect(result).toEqual(event);
|
|
});
|
|
});
|
|
|
|
describe('The optional callback argument to #execute', function() {
|
|
beforeEach(function() {
|
|
this.savedInterval = jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL;
|
|
});
|
|
|
|
afterEach(function() {
|
|
jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = this.savedInterval;
|
|
});
|
|
|
|
it('is called after reporter events are dispatched', async function() {
|
|
const reporter = jasmine.createSpyObj('reporter', [
|
|
'specDone',
|
|
'suiteDone',
|
|
'jasmineDone'
|
|
]);
|
|
|
|
env.addReporter(reporter);
|
|
env.describe('suite', function() {
|
|
env.it('spec', function() {});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(reporter.specDone).toHaveBeenCalled();
|
|
expect(reporter.suiteDone).toHaveBeenCalled();
|
|
expect(reporter.jasmineDone).toHaveBeenCalled();
|
|
});
|
|
|
|
it('is called after the stack is cleared', async function() {
|
|
const stackClearer = privateUnderTest.getStackClearer(
|
|
jasmineUnderTest.getGlobal()
|
|
);
|
|
spyOn(stackClearer, 'clearStack').and.callThrough();
|
|
spyOn(privateUnderTest, 'getStackClearer').and.returnValue(stackClearer);
|
|
|
|
// Create a new env that has the clearStack defined above
|
|
env.cleanup_();
|
|
env = new privateUnderTest.Env();
|
|
|
|
env.describe('suite', function() {
|
|
env.it('spec', function() {});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(stackClearer.clearStack).toHaveBeenCalled(); // (many times)
|
|
stackClearer.clearStack.calls.reset();
|
|
|
|
await new Promise(resolve => setTimeout(resolve));
|
|
|
|
expect(stackClearer.clearStack).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('is called after QueueRunner timeouts are cleared', async function() {
|
|
const setTimeoutSpy = spyOn(
|
|
jasmineUnderTest.getGlobal(),
|
|
'setTimeout'
|
|
).and.callThrough();
|
|
const clearTimeoutSpy = spyOn(
|
|
jasmineUnderTest.getGlobal(),
|
|
'clearTimeout'
|
|
).and.callThrough();
|
|
|
|
jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = 123456; // a distinctive value
|
|
|
|
env = new privateUnderTest.Env();
|
|
|
|
env.describe('suite', function() {
|
|
env.it('spec', function() {});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
const timeoutIds = setTimeoutSpy.calls
|
|
.all()
|
|
.filter(function(call) {
|
|
return call.args[1] === 123456;
|
|
})
|
|
.map(function(call) {
|
|
return call.returnValue;
|
|
});
|
|
|
|
expect(timeoutIds.length).toBeGreaterThan(0);
|
|
|
|
timeoutIds.forEach(function(timeoutId) {
|
|
expect(clearTimeoutSpy).toHaveBeenCalledWith(timeoutId);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('sends debug logs to the reporter when the spec fails', async function() {
|
|
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
|
|
|
|
env.addReporter(reporter);
|
|
env.configure({ random: false });
|
|
|
|
env.it('fails', function() {
|
|
env.debugLog('message 1');
|
|
env.debugLog('message 2');
|
|
env.expect(1).toBe(2);
|
|
});
|
|
|
|
env.it('passes', function() {
|
|
env.debugLog('message that should not be reported');
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
function numberInRange(min, max) {
|
|
return {
|
|
asymmetricMatch: function(compareTo) {
|
|
return compareTo >= min && compareTo <= max;
|
|
},
|
|
jasmineToString: function() {
|
|
return '<number from ' + min + ' to ' + max + ' inclusive>';
|
|
}
|
|
};
|
|
}
|
|
|
|
expect(reporter.specDone).toHaveBeenCalledTimes(2);
|
|
const duration = reporter.specDone.calls.argsFor(0)[0].duration;
|
|
expect(reporter.specDone.calls.argsFor(0)[0]).toEqual(
|
|
jasmine.objectContaining({
|
|
debugLogs: [
|
|
{
|
|
timestamp: numberInRange(0, duration),
|
|
message: 'message 1'
|
|
},
|
|
{
|
|
timestamp: numberInRange(0, duration),
|
|
message: 'message 2'
|
|
}
|
|
]
|
|
})
|
|
);
|
|
expect(reporter.specDone.calls.argsFor(1)[0].debugLogs).toBeFalsy();
|
|
});
|
|
|
|
it('reports an error when debugLog is used when a spec is not running', async function() {
|
|
const reporter = jasmine.createSpyObj('reporter', ['suiteDone']);
|
|
|
|
env.describe('a suite', function() {
|
|
env.beforeAll(function() {
|
|
env.debugLog('a message');
|
|
});
|
|
|
|
env.it('a spec', function() {});
|
|
});
|
|
|
|
env.addReporter(reporter);
|
|
await env.execute();
|
|
|
|
expect(reporter.suiteDone).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
failedExpectations: [
|
|
jasmine.objectContaining({
|
|
message: jasmine.stringContaining(
|
|
"'debugLog' was called when there was no current spec"
|
|
)
|
|
})
|
|
]
|
|
})
|
|
);
|
|
});
|
|
|
|
it('uses custom equality testers in Spy#withArgs', async function() {
|
|
env.it('a spec', function() {
|
|
const createSpySpy = env.createSpy('via createSpy');
|
|
const spiedOn = { foo: function() {} };
|
|
env.spyOn(spiedOn, 'foo');
|
|
const spyObj = env.createSpyObj('spyObj', ['foo']);
|
|
const spiedOnAllFuncs = { foo: function() {} };
|
|
env.spyOnAllFunctions(spiedOnAllFuncs);
|
|
|
|
for (const spy of [
|
|
createSpySpy,
|
|
spiedOn.foo,
|
|
spyObj.foo,
|
|
spiedOnAllFuncs.foo
|
|
]) {
|
|
spy.and.returnValue('default strategy');
|
|
spy.withArgs(42).and.returnValue('custom strategy');
|
|
}
|
|
|
|
env.addCustomEqualityTester(function(a, b) {
|
|
if ((a === 'x' && b === 42) || (a === 42 && b === 'x')) {
|
|
return true;
|
|
}
|
|
});
|
|
|
|
env
|
|
.expect(createSpySpy('x'))
|
|
.withContext('createSpy')
|
|
.toEqual('custom strategy');
|
|
env
|
|
.expect(spiedOn.foo('x'))
|
|
.withContext('spyOn')
|
|
.toEqual('custom strategy');
|
|
env
|
|
.expect(spyObj.foo('x'))
|
|
.withContext('createSpyObj')
|
|
.toEqual('custom strategy');
|
|
env
|
|
.expect(spiedOnAllFuncs.foo('x'))
|
|
.withContext('spyOnAllFunctions')
|
|
.toEqual('custom strategy');
|
|
});
|
|
|
|
let failedExpectations;
|
|
env.addReporter({
|
|
specDone: r => (failedExpectations = r.failedExpectations)
|
|
});
|
|
|
|
await env.execute();
|
|
expect(failedExpectations).toEqual([]);
|
|
});
|
|
|
|
it('uses custom object formatters in spy strategy argument mismatch errors', async function() {
|
|
env.it('a spec', function() {
|
|
env.addCustomObjectFormatter(function(value) {
|
|
if (typeof value === 'string') {
|
|
return 'custom:' + value;
|
|
}
|
|
});
|
|
const spy = env
|
|
.createSpy('foo')
|
|
.withArgs('x')
|
|
.and.returnValue('');
|
|
spy('y');
|
|
});
|
|
|
|
let failedExpectations;
|
|
env.addReporter({
|
|
specDone: r => (failedExpectations = r.failedExpectations)
|
|
});
|
|
|
|
await env.execute();
|
|
expect(failedExpectations).toEqual([
|
|
jasmine.objectContaining({
|
|
message: jasmine.stringContaining(
|
|
'received a call with arguments [ custom:y ]'
|
|
)
|
|
})
|
|
]);
|
|
});
|
|
|
|
it('reports a suite level error when a describe fn throws', async function() {
|
|
const reporter = jasmine.createSpyObj('reporter', ['suiteDone']);
|
|
env.addReporter(reporter);
|
|
|
|
env.describe('throws before defining specs', function() {
|
|
throw new Error('nope');
|
|
});
|
|
|
|
env.describe('throws after defining specs', function() {
|
|
env.it('is a spec');
|
|
throw new Error('nope');
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
expect(reporter.suiteDone).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
fullName: 'throws after defining specs',
|
|
failedExpectations: [
|
|
jasmine.objectContaining({
|
|
message: jasmine.stringContaining('Error: nope')
|
|
})
|
|
]
|
|
})
|
|
);
|
|
|
|
expect(reporter.suiteDone).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
fullName: 'throws after defining specs',
|
|
failedExpectations: [
|
|
jasmine.objectContaining({
|
|
message: jasmine.stringContaining('Error: nope')
|
|
})
|
|
]
|
|
})
|
|
);
|
|
});
|
|
|
|
it('reports suite and spec filenames', async function() {
|
|
const methods = ['suiteStarted', 'suiteDone', 'specStarted', 'specDone'];
|
|
const reporter = jasmine.createSpyObj('reporter', methods);
|
|
env.addReporter(reporter);
|
|
|
|
// Simulate calling through global it and describe,
|
|
// which add another stack frame vs calling env methods directly
|
|
function describeShim(name, fn) {
|
|
env.describe(name, fn);
|
|
}
|
|
function itShim(name, fn) {
|
|
env.it(name, fn);
|
|
}
|
|
|
|
describeShim('a suite', function() {
|
|
itShim('a spec', function() {});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
for (const method of methods) {
|
|
expect(reporter[method])
|
|
.withContext(method)
|
|
.toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
filename: jasmine.stringMatching(/EnvSpec\.js$/)
|
|
})
|
|
);
|
|
}
|
|
});
|
|
|
|
it('reports skipped suite and spec filenames', async function() {
|
|
const methods = ['suiteStarted', 'suiteDone', 'specStarted', 'specDone'];
|
|
const reporter = jasmine.createSpyObj('reporter', methods);
|
|
env.addReporter(reporter);
|
|
|
|
// Simulate calling through global it and describe,
|
|
// which add another stack frame vs calling env methods directly
|
|
function xdescribeShim(name, fn) {
|
|
env.xdescribe(name, fn);
|
|
}
|
|
function xitShim(name, fn) {
|
|
env.xit(name, fn);
|
|
}
|
|
|
|
xdescribeShim('a suite', function() {
|
|
xitShim('a spec', function() {});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
for (const method of methods) {
|
|
expect(reporter[method])
|
|
.withContext(method)
|
|
.toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
filename: jasmine.stringMatching(/EnvSpec\.js$/)
|
|
})
|
|
);
|
|
}
|
|
});
|
|
|
|
it('reports focused suite and spec filenames', async function() {
|
|
const methods = ['suiteStarted', 'suiteDone', 'specStarted', 'specDone'];
|
|
const reporter = jasmine.createSpyObj('reporter', methods);
|
|
env.addReporter(reporter);
|
|
|
|
// Simulate calling through global it and describe,
|
|
// which add another stack frame vs calling env methods directly
|
|
function fdescribeShim(name, fn) {
|
|
env.fdescribe(name, fn);
|
|
}
|
|
function fitShim(name, fn) {
|
|
env.fit(name, fn);
|
|
}
|
|
|
|
fdescribeShim('a suite', function() {
|
|
fitShim('a spec', function() {});
|
|
});
|
|
|
|
await env.execute();
|
|
|
|
for (const method of methods) {
|
|
expect(reporter[method])
|
|
.withContext(method)
|
|
.toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
filename: jasmine.stringMatching(/EnvSpec\.js$/)
|
|
})
|
|
);
|
|
}
|
|
});
|
|
|
|
describe('throwUnless', function() {
|
|
it('throws when the matcher fails', async function() {
|
|
let thrown;
|
|
|
|
env.it('a spec', function() {
|
|
try {
|
|
env.throwUnless(1).toEqual(2);
|
|
} catch (e) {
|
|
thrown = e;
|
|
}
|
|
});
|
|
|
|
await env.execute();
|
|
expect(thrown).toBeInstanceOf(Error);
|
|
expect(thrown.matcherName).toEqual('toEqual');
|
|
expect(thrown.message).toEqual('Expected 1 to equal 2.');
|
|
});
|
|
|
|
it('does not throw when the matcher passes', async function() {
|
|
let threw = false;
|
|
|
|
env.it('a spec', function() {
|
|
try {
|
|
env.throwUnless(1).toEqual(1);
|
|
// eslint-disable-next-line no-unused-vars
|
|
} catch (e) {
|
|
threw = true;
|
|
}
|
|
});
|
|
|
|
await env.execute();
|
|
expect(threw).toBe(false);
|
|
});
|
|
|
|
it('does not cause a failure if the error does not propagate back to jasmine', async function() {
|
|
env.it('a spec', function() {
|
|
try {
|
|
env.throwUnless(1).toEqual(2);
|
|
// eslint-disable-next-line no-unused-vars
|
|
} catch (e) {}
|
|
});
|
|
|
|
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
|
|
env.addReporter(reporter);
|
|
|
|
await env.execute();
|
|
expect(reporter.specDone).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({ status: 'passed' })
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('throwUnlessAsync', function() {
|
|
it('throws when the matcher fails', async function() {
|
|
const promise = Promise.resolve('a');
|
|
let thrown;
|
|
|
|
env.it('a spec', async function() {
|
|
try {
|
|
await env.throwUnlessAsync(promise).toBeResolvedTo('b');
|
|
} catch (e) {
|
|
thrown = e;
|
|
}
|
|
});
|
|
|
|
await env.execute();
|
|
expect(thrown).toBeInstanceOf(Error);
|
|
expect(thrown.matcherName).toEqual('toBeResolvedTo');
|
|
expect(thrown.message).toEqual(
|
|
"Expected a promise to be resolved to 'b' but it was resolved to 'a'."
|
|
);
|
|
});
|
|
|
|
it('does not throw when the matcher passes', async function() {
|
|
let threw = false;
|
|
|
|
env.it('a spec', async function() {
|
|
try {
|
|
await env.throwUnlessAsync(Promise.resolve()).toBeResolved();
|
|
// eslint-disable-next-line no-unused-vars
|
|
} catch (e) {
|
|
threw = true;
|
|
}
|
|
});
|
|
|
|
await env.execute();
|
|
expect(threw).toBe(false);
|
|
});
|
|
|
|
it('does not cause a failure if the error does not propagate back to jasmine', async function() {
|
|
env.it('a spec', async function() {
|
|
try {
|
|
await env.throwUnlessAsync(Promise.resolve()).toBeRejected();
|
|
// eslint-disable-next-line no-unused-vars
|
|
} catch (e) {}
|
|
});
|
|
|
|
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
|
|
env.addReporter(reporter);
|
|
|
|
await env.execute();
|
|
expect(reporter.specDone).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({ status: 'passed' })
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('pp', function() {
|
|
it("pretty-prints using the current runable's custom object formatters", async function() {
|
|
env.it('a spec', function() {
|
|
env.addCustomObjectFormatter(function(x) {
|
|
if (x === 1) {
|
|
return 'hi!';
|
|
}
|
|
});
|
|
env.expect(env.pp(1)).toEqual('hi!');
|
|
});
|
|
|
|
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
|
|
env.addReporter(reporter);
|
|
|
|
await env.execute();
|
|
|
|
expect(reporter.specDone).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
failedExpectations: []
|
|
})
|
|
);
|
|
});
|
|
|
|
it('works when there is no current runable', function() {
|
|
expect(env.pp({ some: 'thing' })).toEqual("Object({ some: 'thing' })");
|
|
});
|
|
});
|
|
|
|
it('forbids duplicates when forbidDuplicateNames is true', function() {
|
|
env.configure({ forbidDuplicateNames: true });
|
|
env.it('a spec');
|
|
|
|
expect(function() {
|
|
env.it('a spec');
|
|
}).toThrowError('Duplicate spec name "a spec" found in top suite');
|
|
});
|
|
|
|
function browserEventMethods() {
|
|
return {
|
|
listeners_: { error: [], unhandledrejection: [], rejectionhandled: [] },
|
|
addEventListener(eventName, listener) {
|
|
this.listeners_[eventName].push(listener);
|
|
},
|
|
removeEventListener(eventName, listener) {
|
|
this.listeners_[eventName] = this.listeners_[eventName].filter(
|
|
l => l !== listener
|
|
);
|
|
}
|
|
};
|
|
}
|
|
|
|
function dispatchErrorEvent(global, event) {
|
|
expect(global.listeners_.error.length)
|
|
.withContext('number of error listeners')
|
|
.toBeGreaterThan(0);
|
|
|
|
for (const l of global.listeners_.error) {
|
|
l(event);
|
|
}
|
|
}
|
|
});
|