Compare commits

...

21 Commits

Author SHA1 Message Date
Steve Gravrock
e5e0e6481d Bump version to 4.2.0 2022-06-09 18:18:45 -07:00
Steve Gravrock
bcf69b86b4 Removed duplicate Suite and Spec jsdocs 2022-06-03 12:22:58 -07:00
Steve Gravrock
a5f79fac81 Removed remaining jshint config comments 2022-06-02 18:22:23 -07:00
Steve Gravrock
18a00822c5 Built distribution 2022-06-02 11:37:10 -07:00
Steve Gravrock
4cc8437f79 Call buildExpectationResult directly from Suite and Spec
This removes quite a bit of indirection from result processing, at the
cost of making a few of the tests more awkward.
2022-06-01 10:18:23 -07:00
Steve Gravrock
8e58305b0a ExpectationResult.js -> buildExpectationResult.js 2022-06-01 09:26:21 -07:00
Steve Gravrock
bd368aceee Replaced var with const and let in expectation related code 2022-06-01 09:22:03 -07:00
Steve Gravrock
8f16021887 Replaced var with const and let in ExpectationResult 2022-06-01 09:02:43 -07:00
Steve Gravrock
bbb1b69b2e More reliably report errors that occur late in the suite/spec lifecycle
Previously, an error that occurred after Jasmine started to report the
suiteDone or specDone event for the current runable would not be reliably
reported. Now such an error is reported on the nearest ancestor suite whose
suiteDone event has not yet been reported.
2022-05-28 18:10:55 -07:00
Steve Gravrock
9ea8a2096f Additional integration tests for existing async error handling 2022-05-28 18:01:19 -07:00
Steve Gravrock
66340e2b19 Updated browserslist to match 4.0 envs 2022-05-28 18:00:45 -07:00
Steve Gravrock
fe29dfa89c Update release process instructions
* Need to tag the release manually since the Ruby tooling for that was
  removed
* Windows CI works again, so no need to manually test on Windows
2022-05-21 09:43:43 -07:00
Steve Gravrock
41f7fabe2f Renamed jasmine.exactly to jasmine.is, for similarity with toBe 2022-05-21 08:30:53 -07:00
Steve Gravrock
856a040a2d Fixed flaky spec 2022-05-19 16:39:48 -07:00
Steve Gravrock
f7eaa5ec29 Fixed failing CI builds for Node 12 and 14
See https://github.com/npm/cli/issues/4896
2022-05-16 19:53:20 -07:00
Steve Gravrock
0c87d47318 Added a jasmine.exactly asymmetric equality tester 2022-05-14 17:01:38 -07:00
Steve Gravrock
c24b2f5a73 Converted some integration specs to async/await 2022-05-14 12:05:53 -07:00
Steve Gravrock
774c83a36e Don't report a deprecation when a runnable uses two forms of async
This was made into an error in 4.0, so the deprecation is redundant
(and broken).
2022-05-14 11:21:40 -07:00
Steve Gravrock
751cf6ab5b Converted DiffBuilder, ObjectPath, MismatchTree, and SinglePrettyPrintRun to ES6 classes 2022-05-14 11:15:08 -07:00
Steve Gravrock
2fd76c954c Replaced var with let and const in PrettyPrinter, DiffBuilder, and friends 2022-05-14 09:42:07 -07:00
Steve Gravrock
bb4d18f959 Include property getter values in pretty-printed objects
We already call getters when comparing objects for equality and generating
diffs, so it should be safe to do it here too.

See #1966.
2022-05-12 17:14:13 -07:00
38 changed files with 2458 additions and 2053 deletions

View File

@@ -36,9 +36,10 @@ When ready to release - specs are all green and the stories are done:
### Commit and push core changes
1. Run the browser tests using `scripts/run-all-browsers`.
1. Commit release notes and version changes (jasmine.js, package.json)
1. Push
1. Wait for Circle CI to go green
2. Commit release notes and version changes (jasmine.js, package.json)
3. Push
4. Tag the release and push the tag.
5. Wait for Circle CI to go green
### Build standalone distribution
@@ -47,7 +48,6 @@ When ready to release - specs are all green and the stories are done:
### Release the core NPM module
1. Run the tests on Windows. (CI only tests on Linux.)
1. `npm adduser` to save your credentials locally
1. `npm publish .` to publish what's in `package.json`

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{
"name": "jasmine-core",
"license": "MIT",
"version": "4.1.1",
"version": "4.2.0",
"repository": {
"type": "git",
"url": "https://github.com/jasmine/jasmine.git"
@@ -43,8 +43,8 @@
"grunt-contrib-concat": "^2.0.0",
"grunt-css-url-embed": "^1.11.1",
"grunt-sass": "^3.0.2",
"jasmine": "github:jasmine/jasmine-npm#main",
"jasmine-browser-runner": "github:jasmine/jasmine-browser#main",
"jasmine": "^4.1.0",
"jasmine-browser-runner": "^1.0.0",
"jsdom": "^19.0.0",
"load-grunt-tasks": "^5.1.0",
"prettier": "1.17.1",
@@ -95,14 +95,15 @@
"error",
"always"
],
"space-before-blocks": "error"
"space-before-blocks": "error",
"no-eval": "error"
}
},
"browserslist": [
"Safari >= 13",
"Safari >= 14",
"last 2 Chrome versions",
"last 2 Firefox versions",
"Firefox >= 68",
"Firefox >= 91",
"last 2 Edge versions"
]
}

29
release_notes/4.2.0.md Normal file
View File

@@ -0,0 +1,29 @@
# Jasmine 4.2.0 Release Notes
## New Features
* Added a jasmine.is asymmetric equality tester
* Allows the use of === comparisons for specific fields of an object that
should otherwise be compared with the default deep value equality logic.
## Bug Fixes
* More reliably report errors that occur late in the suite/spec lifecycle
* Previously, an error that occurred after Jasmine started to report the
suiteDone or specDone event for the current runable would not be reliably
reported. Now such an error is reported on the nearest ancestor suite whose
suiteDone event has not yet been reported.
* Don't report a deprecation when a runnable uses two forms of async
* This was made into an error in 4.0, so the deprecation is redundant.
* Include property getter values in pretty-printed objects
## Documentation Updates
* Removed duplicate Suite and Spec jsdocs
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

View File

@@ -323,16 +323,16 @@ describe('PrettyPrinter', function() {
);
});
it('should indicate getters on objects as such', function() {
it('should use the return value of getters', function() {
const pp = jasmineUnderTest.makePrettyPrinter();
const sampleValue = {
id: 1,
get calculatedValue() {
throw new Error("don't call me!");
return 'the getter return value';
}
};
expect(pp(sampleValue)).toEqual(
'Object({ id: 1, calculatedValue: <getter> })'
"Object({ id: 1, calculatedValue: 'the getter return value' })"
);
});

View File

@@ -632,7 +632,8 @@ describe('QueueRunner', function() {
});
it('issues a more specific error if the function is `async`', function() {
eval('var fn = async function(done){};');
// eslint-disable-next-line no-unused-vars
async function fn(done) {}
const onException = jasmine.createSpy('onException'),
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [{ fn: fn }],

View File

@@ -334,7 +334,7 @@ describe('Spec', function() {
const spec = new jasmineUnderTest.Spec({
queueableFn: { fn: jasmine.createSpy('spec body') }
});
spec.addExpectationResult(true);
spec.addExpectationResult(true, {});
expect(spec.status()).toBe('passed');
});
@@ -342,8 +342,8 @@ describe('Spec', function() {
const spec = new jasmineUnderTest.Spec({
queueableFn: { fn: jasmine.createSpy('spec body') }
});
spec.addExpectationResult(true);
spec.addExpectationResult(false);
spec.addExpectationResult(true, {});
spec.addExpectationResult(false, {});
expect(spec.status()).toBe('failed');
});
@@ -352,14 +352,11 @@ describe('Spec', function() {
resultCallback = jasmine.createSpy('resultCallback'),
spec = new jasmineUnderTest.Spec({
queueableFn: { fn: jasmine.createSpy('spec body') },
expectationResultFactory: function(data) {
return data;
},
queueRunnerFactory: fakeQueueRunner,
resultCallback: resultCallback
});
spec.addExpectationResult(true, 'expectation1');
spec.addExpectationResult(false, 'expectation2');
spec.addExpectationResult(true, { message: 'expectation1' });
spec.addExpectationResult(false, { message: 'expectation2' });
spec.execute();
@@ -367,10 +364,10 @@ describe('Spec', function() {
fns[fns.length - 1].fn();
expect(resultCallback.calls.first().args[0].passedExpectations).toEqual([
'expectation1'
jasmine.objectContaining({ message: 'expectation1' })
]);
expect(resultCallback.calls.first().args[0].failedExpectations).toEqual([
'expectation2'
jasmine.objectContaining({ message: 'expectation2' })
]);
});
@@ -379,17 +376,14 @@ describe('Spec', function() {
resultCallback = jasmine.createSpy('resultCallback'),
spec = new jasmineUnderTest.Spec({
queueableFn: { fn: function() {} },
expectationResultFactory: function(data) {
return data;
},
queueRunnerFactory: fakeQueueRunner,
resultCallback: resultCallback,
throwOnExpectationFailure: true
});
spec.addExpectationResult(true, 'passed');
spec.addExpectationResult(true, { message: 'passed' });
expect(function() {
spec.addExpectationResult(false, 'failed');
spec.addExpectationResult(false, { message: 'failed' });
}).toThrowError(jasmineUnderTest.errors.ExpectationFailed);
spec.execute();
@@ -397,20 +391,104 @@ describe('Spec', function() {
const fns = fakeQueueRunner.calls.mostRecent().args[0].queueableFns;
fns[fns.length - 1].fn();
expect(resultCallback.calls.first().args[0].passedExpectations).toEqual([
'passed'
jasmine.objectContaining({ message: 'passed' })
]);
expect(resultCallback.calls.first().args[0].failedExpectations).toEqual([
'failed'
jasmine.objectContaining({ message: 'failed' })
]);
});
it('forwards late expectation failures to onLateError', function() {
const onLateError = jasmine.createSpy('onLateError');
const spec = new jasmineUnderTest.Spec({
onLateError,
queueableFn: { fn: function() {} }
});
const data = {
matcherName: '',
passed: false,
expected: '',
actual: '',
error: new Error('nope')
};
spec.reportedDone = true;
spec.addExpectationResult(false, data, true);
expect(onLateError).toHaveBeenCalledWith(
jasmine.objectContaining({
message: jasmine.stringMatching(/^Error: nope/)
})
);
expect(spec.result.failedExpectations).toEqual([]);
});
it('does not forward non-late expectation failures to onLateError', function() {
const onLateError = jasmine.createSpy('onLateError');
const spec = new jasmineUnderTest.Spec({
onLateError,
queueableFn: { fn: function() {} }
});
const data = {
matcherName: '',
passed: false,
expected: '',
actual: '',
error: new Error('nope')
};
spec.addExpectationResult(false, data, true);
expect(onLateError).not.toHaveBeenCalled();
});
it('forwards late handleException calls to onLateError', function() {
const onLateError = jasmine.createSpy('onLateError');
const spec = new jasmineUnderTest.Spec({
onLateError,
queueableFn: { fn: function() {} }
});
spec.reportedDone = true;
spec.handleException(new Error('oops'));
expect(onLateError).toHaveBeenCalledWith(
jasmine.objectContaining({
message: jasmine.stringMatching(/^Error: oops/)
})
);
expect(spec.result.failedExpectations).toEqual([]);
});
it('does not forward non-late handleException calls to onLateError', function() {
const onLateError = jasmine.createSpy('onLateError');
const spec = new jasmineUnderTest.Spec({
onLateError,
queueableFn: { fn: function() {} }
});
const error = new Error('oops');
spec.handleException(error);
expect(onLateError).not.toHaveBeenCalled();
expect(spec.result.failedExpectations.length).toEqual(1);
});
it('clears the reportedDone flag when reset', function() {
const spec = new jasmineUnderTest.Spec({
queueableFn: { fn: function() {} }
});
spec.reportedDone = true;
spec.reset();
expect(spec.reportedDone).toBeFalse();
});
it('does not throw an ExpectationFailed error when handling an error', function() {
const resultCallback = jasmine.createSpy('resultCallback'),
spec = new jasmineUnderTest.Spec({
queueableFn: { fn: function() {} },
expectationResultFactory: function(data) {
return data;
},
queueRunnerFactory: function(attrs) {
attrs.onComplete();
},
@@ -418,7 +496,7 @@ describe('Spec', function() {
throwOnExpectationFailure: true
});
spec.onException('failing exception');
spec.handleException('failing exception');
});
it('can return its full name', function() {
@@ -483,25 +561,23 @@ describe('Spec', function() {
resultCallback = jasmine.createSpy('resultCallback'),
spec = new jasmineUnderTest.Spec({
queueableFn: { fn: function() {} },
expectationResultFactory: function(data) {
return data;
},
queueRunnerFactory: fakeQueueRunner,
resultCallback: resultCallback
});
spec.onException('foo');
spec.handleException('foo');
spec.execute();
const args = fakeQueueRunner.calls.mostRecent().args[0];
args.queueableFns[args.queueableFns.length - 1].fn();
expect(resultCallback.calls.first().args[0].failedExpectations).toEqual([
{
error: 'foo',
message: 'foo thrown',
matcherName: '',
passed: false,
expected: '',
actual: ''
actual: '',
stack: null
}
]);
});
@@ -511,14 +587,11 @@ describe('Spec', function() {
resultCallback = jasmine.createSpy('resultCallback'),
spec = new jasmineUnderTest.Spec({
queueableFn: { fn: function() {} },
expectationResultFactory: function(data) {
return data;
},
queueRunnerFactory: fakeQueueRunner,
resultCallback: resultCallback
});
spec.onException(new jasmineUnderTest.errors.ExpectationFailed());
spec.handleException(new jasmineUnderTest.errors.ExpectationFailed());
spec.execute();
const args = fakeQueueRunner.calls.mostRecent().args[0];
@@ -636,7 +709,7 @@ describe('Spec', function() {
resultCallback: resultCallback,
queueRunnerFactory: function(config) {
spec.debugLog('msg');
spec.onException(new Error('nope'));
spec.handleException(new Error('nope'));
for (const fn of config.queueableFns) {
fn.fn();
}

View File

@@ -106,9 +106,9 @@ describe('SpyStrategy', function() {
it('allows a fake async function to be called instead', function(done) {
const originalFn = jasmine.createSpy('original'),
fakeFn = jasmine
.createSpy('fake')
.and.callFake(eval('async () => { return 67; }')),
fakeFn = jasmine.createSpy('fake').and.callFake(async () => {
return 67;
}),
spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn });
spyStrategy.callFake(fakeFn);

View File

@@ -71,20 +71,9 @@ describe('Suite', function() {
suite.beforeAll(outerBefore);
suite.beforeAll(innerBefore);
function sameInstance(expected) {
return {
asymmetricMatch: function(actual) {
return actual === expected;
},
jasmineToString: function() {
return `<same instance as ${expected}>`;
}
};
}
expect(suite.beforeAllFns).toEqual([
{ fn: outerBefore.fn, type: 'beforeAll', suite: sameInstance(suite) },
{ fn: innerBefore.fn, type: 'beforeAll', suite: sameInstance(suite) }
{ fn: outerBefore.fn, type: 'beforeAll', suite: jasmine.is(suite) },
{ fn: innerBefore.fn, type: 'beforeAll', suite: jasmine.is(suite) }
]);
});
@@ -123,13 +112,9 @@ describe('Suite', function() {
});
it('has a status of failed if any expectations have failed', function() {
const suite = new jasmineUnderTest.Suite({
expectationResultFactory: function() {
return 'hi';
}
});
const suite = new jasmineUnderTest.Suite({});
suite.addExpectationResult(false);
suite.addExpectationResult(false, {});
expect(suite.status()).toBe('failed');
});
@@ -148,28 +133,110 @@ describe('Suite', function() {
it('throws an ExpectationFailed when receiving a failed expectation when throwOnExpectationFailure is set', function() {
const suite = new jasmineUnderTest.Suite({
expectationResultFactory: function(data) {
return data;
},
throwOnExpectationFailure: true
});
expect(function() {
suite.addExpectationResult(false, 'failed');
suite.addExpectationResult(false, { message: 'failed' });
}).toThrowError(jasmineUnderTest.errors.ExpectationFailed);
expect(suite.status()).toBe('failed');
expect(suite.result.failedExpectations).toEqual(['failed']);
expect(suite.result.failedExpectations).toEqual([
jasmine.objectContaining({ message: 'failed' })
]);
});
it('does not add an additional failure when an expectation fails', function() {
const suite = new jasmineUnderTest.Suite({});
suite.onException(new jasmineUnderTest.errors.ExpectationFailed());
suite.handleException(new jasmineUnderTest.errors.ExpectationFailed());
expect(suite.getResult().failedExpectations).toEqual([]);
});
it('forwards late expectation failures to onLateError', function() {
const onLateError = jasmine.createSpy('onLateError');
const suite = new jasmineUnderTest.Suite({ onLateError });
const data = {
matcherName: '',
passed: false,
expected: '',
actual: '',
error: new Error('nope')
};
suite.reportedDone = true;
suite.addExpectationResult(false, data, true);
expect(onLateError).toHaveBeenCalledWith(
jasmine.objectContaining({
message: jasmine.stringMatching(/^Error: nope/)
})
);
expect(suite.result.failedExpectations).toEqual([]);
});
it('does not forward non-late expectation failures to onLateError', function() {
const onLateError = jasmine.createSpy('onLateError');
const suite = new jasmineUnderTest.Suite({
onLateError
});
const data = {
matcherName: '',
passed: false,
expected: '',
actual: '',
error: new Error('nope')
};
suite.addExpectationResult(false, data, true);
expect(onLateError).not.toHaveBeenCalled();
expect(suite.result.failedExpectations.length).toEqual(1);
});
it('forwards late handleException calls to onLateError', function() {
const onLateError = jasmine.createSpy('onLateError');
const suite = new jasmineUnderTest.Suite({
onLateError
});
const error = new Error('oops');
suite.reportedDone = true;
suite.handleException(error);
expect(onLateError).toHaveBeenCalledWith(
jasmine.objectContaining({
message: jasmine.stringMatching(/^Error: oops/)
})
);
expect(suite.result.failedExpectations).toEqual([]);
});
it('does not forward non-late handleException calls to onLateError', function() {
const onLateError = jasmine.createSpy('onLateError');
const suite = new jasmineUnderTest.Suite({
onLateError
});
const error = new Error('oops');
suite.handleException(error);
expect(onLateError).not.toHaveBeenCalled();
expect(suite.result.failedExpectations.length).toEqual(1);
});
it('clears the reportedDone flag when reset', function() {
const suite = new jasmineUnderTest.Suite({
queueableFn: { fn: function() {} }
});
suite.reportedDone = true;
suite.reset();
expect(suite.reportedDone).toBeFalse();
});
it('calls timer to compute duration', function() {
const suite = new jasmineUnderTest.Suite({
env: env,
@@ -261,12 +328,8 @@ describe('Suite', function() {
});
it('should reset the failedExpectations', function() {
const suite = new jasmineUnderTest.Suite({
expectationResultFactory: function(error) {
return error;
}
});
suite.onException(new Error());
const suite = new jasmineUnderTest.Suite({});
suite.handleException(new Error());
suite.reset();

View File

@@ -0,0 +1,30 @@
describe('Is', function() {
it('passes for primitives that are ===', function() {
const exactly = new jasmineUnderTest.Is(17);
expect(exactly.asymmetricMatch(17)).toBeTrue();
});
it('fails for primitives that are not ===', function() {
const exactly = new jasmineUnderTest.Is(42);
expect(exactly.asymmetricMatch('42')).toBeFalse();
});
it('passes for the same object instance', function() {
const obj = {};
const exactly = new jasmineUnderTest.Is(obj);
expect(exactly.asymmetricMatch(obj)).toBeTrue();
});
it('fails for different object instances, even if they are deep value equal', function() {
const exactly = new jasmineUnderTest.Is({});
expect(exactly.asymmetricMatch({})).toBeFalse();
});
it('describes itself for use in diffs and pretty printing', function() {
const exactly = new jasmineUnderTest.Is({ foo: ['bar'] });
const pp = jasmineUnderTest.basicPrettyPrinter_;
expect(exactly.jasmineToString(pp)).toEqual(
"<jasmine.is(Object({ foo: [ 'bar' ] }))>"
);
});
});

View File

@@ -22,56 +22,38 @@ describe('buildExpectationResult', function() {
expect(result.message).toBe('some-value');
});
it('delegates message formatting to the provided formatter if there was an Error', function() {
const fakeError = { message: 'foo' },
messageFormatter = jasmine
.createSpy('exception message formatter')
.and.returnValue(fakeError.message);
describe('When the error property is provided', function() {
it('sets the message to the formatted error', function() {
const result = jasmineUnderTest.buildExpectationResult({
passed: false,
error: { message: 'foo', fileName: 'somefile.js' }
});
const result = jasmineUnderTest.buildExpectationResult({
passed: false,
error: fakeError,
messageFormatter: messageFormatter
expect(result.message).toEqual('foo in somefile.js');
});
expect(messageFormatter).toHaveBeenCalledWith(fakeError);
expect(result.message).toEqual('foo');
it('delegates stack formatting to the provided formatter', function() {
const result = jasmineUnderTest.buildExpectationResult({
passed: false,
error: { stack: 'foo', extra: 'wombat' }
});
expect(result.stack).toEqual(
"error properties: Object({ extra: 'wombat' })\nfoo"
);
});
});
it('delegates stack formatting to the provided formatter if there was an Error', function() {
const fakeError = { stack: 'foo' },
stackFormatter = jasmine
.createSpy('stack formatter')
.and.returnValue(fakeError.stack);
describe('When the errorForStack property is provided', function() {
it('builds the stack trace using errorForStack instead of Error', function() {
const result = jasmineUnderTest.buildExpectationResult({
passed: false,
errorForStack: { stack: 'foo' },
error: { stack: 'bar' }
});
const result = jasmineUnderTest.buildExpectationResult({
passed: false,
error: fakeError,
stackFormatter: stackFormatter
expect(result.stack).toEqual('bar');
});
expect(stackFormatter).toHaveBeenCalledWith(fakeError, {
omitMessage: true
});
expect(result.stack).toEqual('foo');
});
it('delegates stack formatting to the provided formatter if there was a provided errorForStack', function() {
const fakeError = { stack: 'foo' },
stackFormatter = jasmine
.createSpy('stack formatter')
.and.returnValue(fakeError.stack);
const result = jasmineUnderTest.buildExpectationResult({
passed: false,
errorForStack: fakeError,
stackFormatter: stackFormatter
});
expect(stackFormatter).toHaveBeenCalledWith(fakeError, {
omitMessage: true
});
expect(result.stack).toEqual('foo');
});
it('matcherName returns passed matcherName', function() {

View File

@@ -1,55 +1,57 @@
describe('Asymmetric equality testers (Integration)', function() {
function verifyPasses(expectations) {
it('passes', function(done) {
it('passes', async function() {
const env = new jasmineUnderTest.Env();
env.it('a spec', function() {
expectations(env);
});
const specExpectations = function(result) {
expect(result.status).toEqual('passed');
expect(result.passedExpectations.length)
.withContext('Number of passed expectations')
.toEqual(1);
expect(result.failedExpectations.length)
.withContext('Number of failed expectations')
.toEqual(0);
expect(
result.failedExpectations[0] && result.failedExpectations[0].message
)
.withContext('Failure message')
.toBeUndefined();
};
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
env.addReporter(reporter);
await env.execute();
env.addReporter({ specDone: specExpectations });
env.execute(null, done);
expect(reporter.specDone).toHaveBeenCalledTimes(1);
const result = reporter.specDone.calls.argsFor(0)[0];
expect(result.status).toEqual('passed');
expect(result.passedExpectations.length)
.withContext('Number of passed expectations')
.toEqual(1);
expect(result.failedExpectations.length)
.withContext('Number of failed expectations')
.toEqual(0);
expect(
result.failedExpectations[0] && result.failedExpectations[0].message
)
.withContext('Failure message')
.toBeUndefined();
});
}
function verifyFails(expectations) {
it('fails', function(done) {
it('fails', async function() {
const env = new jasmineUnderTest.Env();
env.it('a spec', function() {
expectations(env);
});
const specExpectations = function(result) {
expect(result.status).toEqual('failed');
expect(result.failedExpectations.length)
.withContext('Number of failed expectations')
.toEqual(1);
expect(result.failedExpectations[0].message)
.withContext(
'Failed with a thrown error rather than a matcher failure'
)
.not.toMatch(/^Error: /);
expect(result.failedExpectations[0].matcherName)
.withContext('Matcher name')
.not.toEqual('');
};
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
env.addReporter(reporter);
await env.execute();
env.addReporter({ specDone: specExpectations });
env.execute(null, done);
expect(reporter.specDone).toHaveBeenCalledTimes(1);
const result = reporter.specDone.calls.argsFor(0)[0];
expect(result.status).toEqual('failed');
expect(result.failedExpectations.length)
.withContext('Number of failed expectations')
.toEqual(1);
expect(result.failedExpectations[0].message)
.withContext('Failed with a thrown error rather than a matcher failure')
.not.toMatch(/^Error: /);
expect(result.failedExpectations[0].matcherName)
.withContext('Matcher name')
.not.toEqual('');
});
}

View File

@@ -10,7 +10,7 @@ describe('Custom Matchers (Integration)', function() {
env.cleanup_();
});
it('allows adding more matchers local to a spec', function(done) {
it('allows adding more matchers local to a spec', async function() {
env.it('spec defining a custom matcher', function() {
env.addMatchers({
matcherForSpec: function() {
@@ -37,20 +37,18 @@ describe('Custom Matchers (Integration)', function() {
});
const specDoneSpy = jasmine.createSpy('specDoneSpy');
const expectations = function() {
const firstSpecResult = specDoneSpy.calls.first().args[0];
expect(firstSpecResult.status).toEqual('failed');
expect(firstSpecResult.failedExpectations[0].message).toEqual(
'matcherForSpec: actual: zzz; expected: yyy'
);
done();
};
env.addReporter({ specDone: specDoneSpy });
env.execute(null, expectations);
await env.execute();
const firstSpecResult = specDoneSpy.calls.first().args[0];
expect(firstSpecResult.status).toEqual('failed');
expect(firstSpecResult.failedExpectations[0].message).toEqual(
'matcherForSpec: actual: zzz; expected: yyy'
);
});
it('passes the spec if the custom matcher passes', function(done) {
it('passes the spec if the custom matcher passes', async function() {
env.it('spec using custom matcher', function() {
env.addMatchers({
toBeReal: function() {
@@ -65,15 +63,16 @@ describe('Custom Matchers (Integration)', function() {
env.expect(true).toBeReal();
});
const specExpectations = function(result) {
expect(result.status).toEqual('passed');
};
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
env.addReporter(reporter);
await env.execute();
env.addReporter({ specDone: specExpectations });
env.execute(null, done);
expect(reporter.specDone).toHaveBeenCalledTimes(1);
const result = reporter.specDone.calls.argsFor(0)[0];
expect(result.status).toEqual('passed');
});
it('passes the spec if the custom equality matcher passes for types nested inside asymmetric equality testers', function(done) {
it('passes the spec if the custom equality matcher passes for types nested inside asymmetric equality testers', async function() {
env.it('spec using custom equality matcher', function() {
const customEqualityFn = function(a, b) {
// All "foo*" strings match each other.
@@ -99,15 +98,16 @@ describe('Custom Matchers (Integration)', function() {
.toEqual(jasmineUnderTest.arrayWithExactContents(['fooBar']));
});
const specExpectations = function(result) {
expect(result.status).toEqual('passed');
};
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
env.addReporter(reporter);
await env.execute();
env.addReporter({ specDone: specExpectations });
env.execute(null, done);
expect(reporter.specDone).toHaveBeenCalledTimes(1);
const result = reporter.specDone.calls.argsFor(0)[0];
expect(result.status).toEqual('passed');
});
it('displays an appropriate failure message if a custom equality matcher fails', function(done) {
it('displays an appropriate failure message if a custom equality matcher fails', async function() {
env.it('spec using custom equality matcher', function() {
const customEqualityFn = function(a, b) {
// "foo" is not equal to anything
@@ -120,18 +120,19 @@ describe('Custom Matchers (Integration)', function() {
env.expect({ foo: 'foo' }).toEqual({ foo: 'foo' });
});
const specExpectations = function(result) {
expect(result.status).toEqual('failed');
expect(result.failedExpectations[0].message).toEqual(
"Expected $.foo = 'foo' to equal 'foo'."
);
};
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
env.addReporter(reporter);
await env.execute();
env.addReporter({ specDone: specExpectations });
env.execute(null, done);
expect(reporter.specDone).toHaveBeenCalledTimes(1);
const result = reporter.specDone.calls.argsFor(0)[0];
expect(result.status).toEqual('failed');
expect(result.failedExpectations[0].message).toEqual(
"Expected $.foo = 'foo' to equal 'foo'."
);
});
it('uses the negative compare function for a negative comparison, if provided', function(done) {
it('uses the negative compare function for a negative comparison, if provided', async function() {
env.it('spec with custom negative comparison matcher', function() {
env.addMatchers({
toBeReal: function() {
@@ -149,15 +150,16 @@ describe('Custom Matchers (Integration)', function() {
env.expect(true).not.toBeReal();
});
const specExpectations = function(result) {
expect(result.status).toEqual('passed');
};
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
env.addReporter(reporter);
await env.execute();
env.addReporter({ specDone: specExpectations });
env.execute(null, done);
expect(reporter.specDone).toHaveBeenCalledTimes(1);
const result = reporter.specDone.calls.argsFor(0)[0];
expect(result.status).toEqual('passed');
});
it('generates messages with the same rules as built in matchers absent a custom message', function(done) {
it('generates messages with the same rules as built in matchers absent a custom message', async function() {
env.it('spec with an expectation', function() {
env.addMatchers({
toBeReal: function() {
@@ -172,17 +174,18 @@ describe('Custom Matchers (Integration)', function() {
env.expect('a').toBeReal();
});
const specExpectations = function(result) {
expect(result.failedExpectations[0].message).toEqual(
"Expected 'a' to be real."
);
};
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
env.addReporter(reporter);
await env.execute();
env.addReporter({ specDone: specExpectations });
env.execute(null, done);
expect(reporter.specDone).toHaveBeenCalledTimes(1);
const result = reporter.specDone.calls.argsFor(0)[0];
expect(result.failedExpectations[0].message).toEqual(
"Expected 'a' to be real."
);
});
it('passes the expected and actual arguments to the comparison function', function(done) {
it('passes the expected and actual arguments to the comparison function', async function() {
const argumentSpy = jasmine
.createSpy('argument spy')
.and.returnValue({ pass: true });
@@ -199,17 +202,13 @@ describe('Custom Matchers (Integration)', function() {
env.expect(true).toBeReal('arg1', 'arg2');
});
const specExpectations = function() {
expect(argumentSpy).toHaveBeenCalledWith(true);
expect(argumentSpy).toHaveBeenCalledWith(true, 'arg');
expect(argumentSpy).toHaveBeenCalledWith(true, 'arg1', 'arg2');
};
env.addReporter({ specDone: specExpectations });
env.execute(null, done);
await env.execute();
expect(argumentSpy).toHaveBeenCalledWith(true);
expect(argumentSpy).toHaveBeenCalledWith(true, 'arg');
expect(argumentSpy).toHaveBeenCalledWith(true, 'arg1', 'arg2');
});
it('passes the jasmine utility to the matcher factory', function(done) {
it('passes the jasmine utility to the matcher factory', async function() {
const matcherFactory = function() {
return {
compare: function() {
@@ -229,17 +228,13 @@ describe('Custom Matchers (Integration)', function() {
env.expect(true).toBeReal();
});
const specExpectations = function() {
expect(matcherFactorySpy).toHaveBeenCalledWith(
jasmine.any(jasmineUnderTest.MatchersUtil)
);
};
env.addReporter({ specDone: specExpectations });
env.execute(null, done);
await env.execute();
expect(matcherFactorySpy).toHaveBeenCalledWith(
jasmine.any(jasmineUnderTest.MatchersUtil)
);
});
it('provides custom equality testers to the matcher factory via matchersUtil', function(done) {
it('provides custom equality testers to the matcher factory via matchersUtil', async function() {
const matcherFactory = function(matchersUtil) {
return {
compare: function(actual, expected) {
@@ -262,12 +257,13 @@ describe('Custom Matchers (Integration)', function() {
env.expect([1, 2]).toBeArrayWithFirstElement('1');
});
const specExpectations = function(result) {
expect(customEqualityFn).toHaveBeenCalledWith(1, '1');
expect(result.failedExpectations).toEqual([]);
};
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
env.addReporter(reporter);
await env.execute();
env.addReporter({ specDone: specExpectations });
env.execute(null, done);
expect(reporter.specDone).toHaveBeenCalledTimes(1);
const result = reporter.specDone.calls.argsFor(0)[0];
expect(customEqualityFn).toHaveBeenCalledWith(1, '1');
expect(result.failedExpectations).toEqual([]);
});
});

View File

@@ -6,7 +6,7 @@ describe('Custom object formatters', function() {
env.configure({ random: false });
});
it('scopes custom object formatters to a spec', function(done) {
it('scopes custom object formatters to a spec', async function() {
env.it('a spec with custom pretty-printer', function() {
env.addCustomObjectFormatter(function(obj) {
return 'custom(' + obj + ')';
@@ -22,21 +22,19 @@ describe('Custom object formatters', function() {
const specDone = function(result) {
specResults.push(result);
};
const expectations = function() {
expect(specResults[0].failedExpectations[0].message).toEqual(
'Expected custom(42) to be undefined.'
);
expect(specResults[1].failedExpectations[0].message).toEqual(
'Expected 42 to be undefined.'
);
done();
};
env.addReporter({ specDone: specDone });
env.execute(null, expectations);
await env.execute();
expect(specResults[0].failedExpectations[0].message).toEqual(
'Expected custom(42) to be undefined.'
);
expect(specResults[1].failedExpectations[0].message).toEqual(
'Expected 42 to be undefined.'
);
});
it('scopes custom object formatters to a suite', function(done) {
it('scopes custom object formatters to a suite', async function() {
env.it('a spec without custom pretty-printer', function() {
env.expect(42).toBeUndefined();
});
@@ -57,18 +55,16 @@ describe('Custom object formatters', function() {
const specDone = function(result) {
specResults.push(result);
};
const expectations = function() {
expect(specResults[0].failedExpectations[0].message).toEqual(
'Expected 42 to be undefined.'
);
expect(specResults[1].failedExpectations[0].message).toEqual(
'Expected custom(42) to be undefined.'
);
done();
};
env.addReporter({ specDone: specDone });
env.execute(null, expectations);
await env.execute();
expect(specResults[0].failedExpectations[0].message).toEqual(
'Expected 42 to be undefined.'
);
expect(specResults[1].failedExpectations[0].message).toEqual(
'Expected custom(42) to be undefined.'
);
});
it('throws an exception if you try to add a custom object formatter outside a runable', function() {

View File

@@ -10,7 +10,7 @@ describe('Deprecation (integration)', function() {
env.cleanup_();
});
it('reports a deprecation on the top suite', function(done) {
it('reports a deprecation on the top suite', async function() {
const reporter = jasmine.createSpyObj('reporter', ['jasmineDone']);
env.addReporter(reporter);
spyOn(console, 'error');
@@ -20,24 +20,23 @@ describe('Deprecation (integration)', function() {
});
env.it('a spec', function() {});
env.execute(null, function() {
expect(reporter.jasmineDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
jasmine.objectContaining({
message: jasmine.stringMatching(/^the message/)
})
]
})
);
expect(console.error).toHaveBeenCalledWith(
jasmine.stringMatching(/^DEPRECATION: the message/)
);
done();
});
await env.execute();
expect(reporter.jasmineDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
jasmine.objectContaining({
message: jasmine.stringMatching(/^the message/)
})
]
})
);
expect(console.error).toHaveBeenCalledWith(
jasmine.stringMatching(/^DEPRECATION: the message/)
);
});
it('reports a deprecation on a descendent suite', function(done) {
it('reports a deprecation on a descendent suite', async function() {
const reporter = jasmine.createSpyObj('reporter', ['suiteDone']);
env.addReporter(reporter);
spyOn(console, 'error');
@@ -49,26 +48,23 @@ describe('Deprecation (integration)', function() {
env.it('a spec', function() {});
});
env.execute(null, function() {
expect(reporter.suiteDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
jasmine.objectContaining({
message: jasmine.stringMatching(/^the message/)
})
]
})
);
expect(console.error).toHaveBeenCalledWith(
jasmine.stringMatching(
/^DEPRECATION: the message \(in suite: a suite\)/
)
);
done();
});
await env.execute();
expect(reporter.suiteDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
jasmine.objectContaining({
message: jasmine.stringMatching(/^the message/)
})
]
})
);
expect(console.error).toHaveBeenCalledWith(
jasmine.stringMatching(/^DEPRECATION: the message \(in suite: a suite\)/)
);
});
it('reports a deprecation on a spec', function(done) {
it('reports a deprecation on a spec', async function() {
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
env.addReporter(reporter);
spyOn(console, 'error');
@@ -79,26 +75,25 @@ describe('Deprecation (integration)', function() {
});
});
env.execute(null, function() {
expect(reporter.specDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
jasmine.objectContaining({
message: jasmine.stringMatching(/^the message/)
})
]
})
);
expect(console.error).toHaveBeenCalledWith(
jasmine.stringMatching(
/^DEPRECATION: the message \(in spec: a suite a spec\)/
)
);
done();
});
await env.execute();
expect(reporter.specDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
jasmine.objectContaining({
message: jasmine.stringMatching(/^the message/)
})
]
})
);
expect(console.error).toHaveBeenCalledWith(
jasmine.stringMatching(
/^DEPRECATION: the message \(in spec: a suite a spec\)/
)
);
});
it('omits the suite or spec context when ignoreRunnable is true', function(done) {
it('omits the suite or spec context when ignoreRunnable is true', async function() {
const reporter = jasmine.createSpyObj('reporter', ['jasmineDone']);
env.addReporter(reporter);
spyOn(console, 'error');
@@ -107,27 +102,26 @@ describe('Deprecation (integration)', function() {
env.deprecated('the message', { ignoreRunnable: true });
});
env.execute(null, function() {
expect(reporter.jasmineDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
jasmine.objectContaining({
message: jasmine.stringMatching(/^the message/)
})
]
})
);
expect(console.error).toHaveBeenCalledWith(
jasmine.stringMatching(/the message/)
);
expect(console.error).not.toHaveBeenCalledWith(
jasmine.stringMatching(/a spec/)
);
done();
});
await env.execute();
expect(reporter.jasmineDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
jasmine.objectContaining({
message: jasmine.stringMatching(/^the message/)
})
]
})
);
expect(console.error).toHaveBeenCalledWith(
jasmine.stringMatching(/the message/)
);
expect(console.error).not.toHaveBeenCalledWith(
jasmine.stringMatching(/a spec/)
);
});
it('includes the stack trace', function(done) {
it('includes the stack trace', async function() {
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
env.addReporter(reporter);
spyOn(console, 'error');
@@ -138,25 +132,24 @@ describe('Deprecation (integration)', function() {
});
});
env.execute(null, function() {
expect(reporter.specDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
jasmine.objectContaining({
stack: jasmine.stringMatching(/DeprecationSpec.js/)
})
]
})
);
expect(console.error).toHaveBeenCalled();
expect(console.error.calls.argsFor(0)[0].replace(/\n/g, 'NL')).toMatch(
/^DEPRECATION: the message \(in spec: a suite a spec\)NL.*DeprecationSpec.js/
);
done();
});
await env.execute();
expect(reporter.specDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
jasmine.objectContaining({
stack: jasmine.stringMatching(/DeprecationSpec.js/)
})
]
})
);
expect(console.error).toHaveBeenCalled();
expect(console.error.calls.argsFor(0)[0].replace(/\n/g, 'NL')).toMatch(
/^DEPRECATION: the message \(in spec: a suite a spec\)NL.*DeprecationSpec.js/
);
});
it('excludes the stack trace when omitStackTrace is true', function(done) {
it('excludes the stack trace when omitStackTrace is true', async function() {
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
env.addReporter(reporter);
spyOn(console, 'error');
@@ -167,25 +160,24 @@ describe('Deprecation (integration)', function() {
});
});
env.execute(null, function() {
expect(reporter.specDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
jasmine.objectContaining({
stack: jasmine.falsy()
})
]
})
);
expect(console.error).toHaveBeenCalled();
expect(console.error).not.toHaveBeenCalledWith(
jasmine.stringMatching(/DeprecationSpec.js/)
);
done();
});
await env.execute();
expect(reporter.specDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
jasmine.objectContaining({
stack: jasmine.falsy()
})
]
})
);
expect(console.error).toHaveBeenCalled();
expect(console.error).not.toHaveBeenCalledWith(
jasmine.stringMatching(/DeprecationSpec.js/)
);
});
it('emits a given deprecation only once', function(done) {
it('emits a given deprecation only once', async function() {
const reporter = jasmine.createSpyObj('reporter', [
'specDone',
'suiteDone'
@@ -205,43 +197,40 @@ describe('Deprecation (integration)', function() {
});
});
env.execute(null, function() {
expect(reporter.suiteDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
// only one
jasmine.objectContaining({
message: jasmine.stringMatching(/^the message/)
})
]
})
);
expect(reporter.specDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
// only the other one
jasmine.objectContaining({
message: jasmine.stringMatching(/^a different message/)
})
]
})
);
expect(console.error).toHaveBeenCalledTimes(2);
expect(console.error).toHaveBeenCalledWith(
jasmine.stringMatching(
/^DEPRECATION: the message \(in suite: a suite\)/
)
);
expect(console.error).toHaveBeenCalledWith(
jasmine.stringMatching(
/^DEPRECATION: a different message \(in spec: a suite a spec\)/
)
);
done();
});
await env.execute();
expect(reporter.suiteDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
// only one
jasmine.objectContaining({
message: jasmine.stringMatching(/^the message/)
})
]
})
);
expect(reporter.specDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
// only the other one
jasmine.objectContaining({
message: jasmine.stringMatching(/^a different message/)
})
]
})
);
expect(console.error).toHaveBeenCalledTimes(2);
expect(console.error).toHaveBeenCalledWith(
jasmine.stringMatching(/^DEPRECATION: the message \(in suite: a suite\)/)
);
expect(console.error).toHaveBeenCalledWith(
jasmine.stringMatching(
/^DEPRECATION: a different message \(in spec: a suite a spec\)/
)
);
});
it('emits a given deprecation each time when config.verboseDeprecations is true', function(done) {
it('emits a given deprecation each time when config.verboseDeprecations is true', async function() {
const reporter = jasmine.createSpyObj('reporter', [
'specDone',
'suiteDone'
@@ -262,46 +251,45 @@ describe('Deprecation (integration)', function() {
});
});
env.execute(null, function() {
expect(reporter.suiteDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
jasmine.objectContaining({
message: jasmine.stringMatching(/^the message/)
}),
jasmine.objectContaining({
message: jasmine.stringMatching(/^the message/)
})
]
})
);
expect(reporter.specDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
jasmine.objectContaining({
message: jasmine.stringMatching(/^the message/)
})
]
})
);
expect(console.error).toHaveBeenCalledTimes(3);
expect(console.error.calls.argsFor(0)[0]).toMatch(
/^DEPRECATION: the message \(in suite: a suite\)/
);
expect(console.error.calls.argsFor(1)[0]).toMatch(
/^DEPRECATION: the message \(in suite: a suite\)/
);
expect(console.error.calls.argsFor(2)[0]).toMatch(
/^DEPRECATION: the message \(in spec: a suite a spec\)/
);
expect(console.error.calls.argsFor(2)[0]).toMatch(
/^DEPRECATION: the message \(in spec: a suite a spec\)/
);
done();
});
await env.execute();
expect(reporter.suiteDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
jasmine.objectContaining({
message: jasmine.stringMatching(/^the message/)
}),
jasmine.objectContaining({
message: jasmine.stringMatching(/^the message/)
})
]
})
);
expect(reporter.specDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
jasmine.objectContaining({
message: jasmine.stringMatching(/^the message/)
})
]
})
);
expect(console.error).toHaveBeenCalledTimes(3);
expect(console.error.calls.argsFor(0)[0]).toMatch(
/^DEPRECATION: the message \(in suite: a suite\)/
);
expect(console.error.calls.argsFor(1)[0]).toMatch(
/^DEPRECATION: the message \(in suite: a suite\)/
);
expect(console.error.calls.argsFor(2)[0]).toMatch(
/^DEPRECATION: the message \(in spec: a suite a spec\)/
);
expect(console.error.calls.argsFor(2)[0]).toMatch(
/^DEPRECATION: the message \(in spec: a suite a spec\)/
);
});
it('handles deprecations that occur before execute() is called', function(done) {
it('handles deprecations that occur before execute() is called', async function() {
const reporter = jasmine.createSpyObj('reporter', ['jasmineDone']);
env.addReporter(reporter);
spyOn(console, 'error');
@@ -309,20 +297,19 @@ describe('Deprecation (integration)', function() {
env.deprecated('the message');
env.it('a spec', function() {});
env.execute(null, function() {
expect(reporter.jasmineDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
jasmine.objectContaining({
message: jasmine.stringMatching(/^the message/)
})
]
})
);
expect(console.error).toHaveBeenCalledWith(
jasmine.stringMatching(/^DEPRECATION: the message/)
);
done();
});
await env.execute();
expect(reporter.jasmineDone).toHaveBeenCalledWith(
jasmine.objectContaining({
deprecationWarnings: [
jasmine.objectContaining({
message: jasmine.stringMatching(/^the message/)
})
]
})
);
expect(console.error).toHaveBeenCalledWith(
jasmine.stringMatching(/^DEPRECATION: the message/)
);
});
});

View File

@@ -454,55 +454,319 @@ describe('Env integration', function() {
env.execute(null, assertions);
});
it('copes with async failures after done has been called', function(done) {
const global = {
setTimeout: function(fn, delay) {
return setTimeout(fn, delay);
},
clearTimeout: function(fn, delay) {
clearTimeout(fn, delay);
}
};
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
env.cleanup_();
env = new jasmineUnderTest.Env();
const reporter = jasmine.createSpyObj('fakeReporter', [
'specDone',
'suiteDone'
]);
describe('Handling async errors', function() {
it('routes async errors to a running spec', async function() {
const global = {
setTimeout: function(fn, delay) {
return setTimeout(fn, delay);
},
clearTimeout: function(fn, delay) {
clearTimeout(fn, delay);
}
};
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
env.cleanup_();
env = new jasmineUnderTest.Env();
const reporter = jasmine.createSpyObj('fakeReporter', [
'specDone',
'suiteDone'
]);
const assertions = function() {
expect(reporter.specDone).not.toHaveFailedExpectationsForRunnable(
env.addReporter(reporter);
env.describe('A suite', function() {
env.it('fails', function(specDone) {
setTimeout(function() {
global.onerror('fail');
specDone();
});
});
});
await env.execute();
expect(reporter.specDone).toHaveFailedExpectationsForRunnable(
'A suite fails',
['fail thrown']
);
expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable(
'A suite',
['fail thrown']
);
done();
};
});
env.addReporter(reporter);
describe('When the running spec has reported specDone', function() {
it('routes async errors to an ancestor suite', async function() {
const global = {
setTimeout: function(fn, delay) {
return setTimeout(fn, delay);
},
clearTimeout: function(fn) {
clearTimeout(fn);
}
};
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
env.fdescribe('A suite', function() {
env.it('fails', function(specDone) {
setTimeout(function() {
specDone();
const realClearStack = jasmineUnderTest.getClearStack(global);
const clearStackCallbacks = {};
let clearStackCallCount = 0;
spyOn(jasmineUnderTest, 'getClearStack').and.returnValue(function(fn) {
clearStackCallCount++;
if (clearStackCallbacks[clearStackCallCount]) {
clearStackCallbacks[clearStackCallCount]();
}
realClearStack(fn);
});
env.cleanup_();
env = new jasmineUnderTest.Env();
let suiteErrors = [];
env.addReporter({
suiteDone: function(result) {
const messages = result.failedExpectations.map(e => e.message);
suiteErrors = suiteErrors.concat(messages);
},
specDone: function() {
clearStackCallbacks[clearStackCallCount + 1] = function() {
global.onerror('fail at the end of the reporter queue');
};
clearStackCallbacks[clearStackCallCount + 2] = function() {
global.onerror('fail at the end of the spec queue');
};
}
});
env.describe('A suite', function() {
env.it('is finishing when the failure occurs', function() {});
});
await env.execute();
expect(suiteErrors).toEqual([
'fail at the end of the reporter queue thrown',
'fail at the end of the spec queue thrown'
]);
});
});
it('routes async errors to a running suite', function(done) {
const global = {
setTimeout: function(fn, delay) {
return setTimeout(fn, delay);
},
clearTimeout: function(fn, delay) {
clearTimeout(fn, delay);
}
};
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
env.cleanup_();
env = new jasmineUnderTest.Env();
const reporter = jasmine.createSpyObj('fakeReporter', [
'specDone',
'suiteDone'
]);
const assertions = function() {
expect(reporter.specDone).not.toHaveFailedExpectationsForRunnable(
'A suite fails',
['fail thrown']
);
expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable(
'A suite',
['fail thrown']
);
done();
};
env.addReporter(reporter);
env.fdescribe('A suite', function() {
env.it('fails', function(specDone) {
setTimeout(function() {
specDone();
setTimeout(function() {
global.onerror('fail');
setTimeout(function() {
global.onerror('fail');
});
});
});
});
});
env.describe('Ignored', function() {
env.it('is not run', function() {});
});
env.execute(null, assertions);
});
env.describe('Ignored', function() {
env.it('is not run', function() {});
describe('When the running suite has reported suiteDone', function() {
it('routes async errors to an ancestor suite', async function() {
const global = {
setTimeout: function(fn, delay) {
return setTimeout(fn, delay);
},
clearTimeout: function(fn, delay) {
clearTimeout(fn, delay);
}
};
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
const realClearStack = jasmineUnderTest.getClearStack(global);
const clearStackCallbacks = {};
let clearStackCallCount = 0;
spyOn(jasmineUnderTest, 'getClearStack').and.returnValue(function(fn) {
clearStackCallCount++;
if (clearStackCallbacks[clearStackCallCount]) {
clearStackCallbacks[clearStackCallCount]();
}
realClearStack(fn);
});
env.cleanup_();
env = new jasmineUnderTest.Env();
let suiteErrors = [];
env.addReporter({
suiteDone: function(result) {
const messages = result.failedExpectations.map(e => e.message);
suiteErrors = suiteErrors.concat(messages);
if (result.description === 'A nested suite') {
clearStackCallbacks[clearStackCallCount + 1] = function() {
global.onerror('fail at the end of the reporter queue');
};
clearStackCallbacks[clearStackCallCount + 2] = function() {
global.onerror('fail at the end of the suite queue');
};
}
}
});
env.describe('A suite', function() {
env.describe('A nested suite', function() {
env.it('a spec', function() {});
});
});
await env.execute();
expect(suiteErrors).toEqual([
'fail at the end of the reporter queue thrown',
'fail at the end of the suite queue thrown'
]);
});
});
env.execute(null, assertions);
describe('When the env has started reporting jasmineDone', function() {
it('logs the error to the console', async function() {
const global = {
setTimeout: function(fn, delay) {
return setTimeout(fn, delay);
},
clearTimeout: function(fn, delay) {
clearTimeout(fn, delay);
}
};
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
env.cleanup_();
env = new jasmineUnderTest.Env();
spyOn(console, 'error');
env.addReporter({
jasmineDone: function() {
global.onerror('a very late error');
}
});
env.it('a spec', function() {});
await env.execute();
/* eslint-disable-next-line no-console */
expect(console.error).toHaveBeenCalledWith(
'Jasmine received a result after the suite finished:'
);
/* eslint-disable-next-line no-console */
expect(console.error).toHaveBeenCalledWith(
jasmine.objectContaining({
message: 'a very late error thrown',
globalErrorType: 'afterAll'
})
);
});
});
it('routes all errors that occur during stack clearing somewhere', async function() {
const global = {
setTimeout: function(fn, delay) {
return setTimeout(fn, delay);
},
clearTimeout: function(fn) {
clearTimeout(fn);
}
};
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
const realClearStack = jasmineUnderTest.getClearStack(global);
let clearStackCallCount = 0;
let jasmineDone = false;
const expectedErrors = [];
const expectedErrorsAfterJasmineDone = [];
spyOn(jasmineUnderTest, 'getClearStack').and.returnValue(function(fn) {
clearStackCallCount++;
const msg = `Error in clearStack #${clearStackCallCount}`;
if (jasmineDone) {
expectedErrorsAfterJasmineDone.push(`${msg} thrown`);
} else {
expectedErrors.push(`${msg} thrown`);
}
global.onerror(msg);
realClearStack(fn);
});
spyOn(console, 'error');
env.cleanup_();
env = new jasmineUnderTest.Env();
const receivedErrors = [];
function logErrors(event) {
for (const failure of event.failedExpectations) {
receivedErrors.push(failure.message);
}
}
env.addReporter({
specDone: logErrors,
suiteDone: logErrors,
jasmineDone: function(event) {
jasmineDone = true;
logErrors(event);
}
});
env.describe('A suite', function() {
env.it('is finishing when the failure occurs', function() {});
});
await env.execute();
expect(receivedErrors.length).toEqual(expectedErrors.length);
for (const e of expectedErrors) {
expect(receivedErrors).toContain(e);
}
for (const message of expectedErrorsAfterJasmineDone) {
/* eslint-disable-next-line no-console */
expect(console.error).toHaveBeenCalledWith(
jasmine.objectContaining({ message })
);
}
});
});
it('reports multiple calls to done in the top suite as errors', function(done) {
@@ -539,11 +803,18 @@ describe('Env integration', function() {
});
});
it('reports multiple calls to done in a non-top suite as errors', function(done) {
const reporter = jasmine.createSpyObj('fakeReporter', ['jasmineDone']);
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() {
@@ -555,31 +826,50 @@ describe('Env integration', function() {
env.afterAll(function(innerDone) {
innerDone();
innerDone();
lateDone = innerDone;
});
});
env.execute(null, function() {
expect(reporter.jasmineDone).toHaveBeenCalled();
const errors = reporter.jasmineDone.calls.argsFor(0)[0]
.failedExpectations;
expect(errors.length).toEqual(2);
expect(errors[0].message)
.withContext('suite beforeAll')
.toContain(message);
expect(errors[0].globalErrorType).toEqual('lateError');
expect(errors[1].message)
.withContext('suite afterAll')
.toContain(message);
expect(errors[1].globalErrorType).toEqual('lateError');
done();
});
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', function(done) {
const reporter = jasmine.createSpyObj('fakeReporter', ['jasmineDone']);
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() {
@@ -594,28 +884,39 @@ describe('Env integration', function() {
env.afterEach(function(innerDone) {
innerDone();
innerDone();
lateDone = innerDone;
});
});
env.execute(null, function() {
expect(reporter.jasmineDone).toHaveBeenCalled();
const errors = reporter.jasmineDone.calls.argsFor(0)[0]
.failedExpectations;
expect(errors.length).toEqual(3);
expect(errors[0].message)
.withContext('error caused by beforeEach')
.toContain(message);
expect(errors[0].globalErrorType).toEqual('lateError');
expect(errors[1].message)
.withContext('error caused by it')
.toContain(message);
expect(errors[1].globalErrorType).toEqual('lateError');
expect(errors[2].message)
.withContext('error caused by afterEach')
.toContain(message);
expect(errors[2].globalErrorType).toEqual('lateError');
done();
});
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', function(done) {
@@ -1320,7 +1621,7 @@ describe('Env integration', function() {
});
env.addReporter(reporter);
jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = 5;
jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = 500;
env.beforeAll(function() {
clock.install();
@@ -1331,7 +1632,7 @@ describe('Env integration', function() {
});
env.it('spec that should not time out', function(innerDone) {
clock.tick(6);
clock.tick(1000);
expect(true).toEqual(true);
jasmine.debugLog('Calling realSetTimeout in spec');
realSetTimeout(function() {

View File

@@ -10,156 +10,158 @@ describe('Matchers (Integration)', function() {
});
function verifyPasses(expectations) {
it('passes', function(done) {
it('passes', async function() {
env.it('a spec', function() {
expectations(env);
});
const specExpectations = function(result) {
expect(result.status).toEqual('passed');
expect(result.passedExpectations.length)
.withContext('Number of passed expectations')
.toEqual(1);
expect(result.failedExpectations.length)
.withContext('Number of failed expectations')
.toEqual(0);
expect(
result.failedExpectations[0] && result.failedExpectations[0].message
)
.withContext('Failure message')
.toBeUndefined();
};
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
env.addReporter(reporter);
await env.execute();
env.addReporter({ specDone: specExpectations });
env.execute(null, done);
expect(reporter.specDone).toHaveBeenCalledTimes(1);
const result = reporter.specDone.calls.argsFor(0)[0];
expect(result.status).toEqual('passed');
expect(result.passedExpectations.length)
.withContext('Number of passed expectations')
.toEqual(1);
expect(result.failedExpectations.length)
.withContext('Number of failed expectations')
.toEqual(0);
expect(
result.failedExpectations[0] && result.failedExpectations[0].message
)
.withContext('Failure message')
.toBeUndefined();
});
}
function verifyFails(expectations) {
it('fails', function(done) {
it('fails', async function() {
env.it('a spec', function() {
expectations(env);
});
const specExpectations = function(result) {
expect(result.status).toEqual('failed');
expect(result.failedExpectations.length)
.withContext('Number of failed expectations')
.toEqual(1);
expect(result.failedExpectations[0].message)
.withContext(
'Failed with a thrown error rather than a matcher failure'
)
.not.toMatch(/^Error: /);
expect(result.failedExpectations[0].message)
.withContext(
'Failed with a thrown type error rather than a matcher failure'
)
.not.toMatch(/^TypeError: /);
expect(result.failedExpectations[0].matcherName)
.withContext('Matcher name')
.not.toEqual('');
};
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
env.addReporter(reporter);
await env.execute();
env.addReporter({ specDone: specExpectations });
env.execute(null, done);
expect(reporter.specDone).toHaveBeenCalledTimes(1);
const result = reporter.specDone.calls.argsFor(0)[0];
expect(result.status).toEqual('failed');
expect(result.failedExpectations.length)
.withContext('Number of failed expectations')
.toEqual(1);
expect(result.failedExpectations[0].message)
.withContext('Failed with a thrown error rather than a matcher failure')
.not.toMatch(/^Error: /);
expect(result.failedExpectations[0].message)
.withContext(
'Failed with a thrown type error rather than a matcher failure'
)
.not.toMatch(/^TypeError: /);
expect(result.failedExpectations[0].matcherName)
.withContext('Matcher name')
.not.toEqual('');
});
}
function verifyFailsWithCustomObjectFormatters(config) {
it('uses custom object formatters', function(done) {
it('uses custom object formatters', async function() {
env.it('a spec', function() {
env.addCustomObjectFormatter(config.formatter);
config.expectations(env);
});
const specExpectations = function(result) {
expect(result.status).toEqual('failed');
expect(result.failedExpectations.length)
.withContext('Number of failed expectations')
.toEqual(1);
expect(result.failedExpectations[0].message).toEqual(
config.expectedMessage
);
};
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
env.addReporter(reporter);
await env.execute();
env.addReporter({ specDone: specExpectations });
env.execute(null, done);
expect(reporter.specDone).toHaveBeenCalledTimes(1);
const result = reporter.specDone.calls.argsFor(0)[0];
expect(result.status).toEqual('failed');
expect(result.failedExpectations.length)
.withContext('Number of failed expectations')
.toEqual(1);
expect(result.failedExpectations[0].message).toEqual(
config.expectedMessage
);
});
}
function verifyPassesAsync(expectations) {
it('passes', function(done) {
it('passes', async function() {
env.it('a spec', function() {
return expectations(env);
});
const specExpectations = function(result) {
expect(result.status).toEqual('passed');
expect(result.passedExpectations.length)
.withContext('Number of passed expectations')
.toEqual(1);
expect(result.failedExpectations.length)
.withContext('Number of failed expectations')
.toEqual(0);
expect(
result.failedExpectations[0] && result.failedExpectations[0].message
)
.withContext('Failure message')
.toBeUndefined();
};
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
env.addReporter(reporter);
await env.execute();
env.addReporter({ specDone: specExpectations });
env.execute(null, done);
expect(reporter.specDone).toHaveBeenCalledTimes(1);
const result = reporter.specDone.calls.argsFor(0)[0];
expect(result.status).toEqual('passed');
expect(result.passedExpectations.length)
.withContext('Number of passed expectations')
.toEqual(1);
expect(result.failedExpectations.length)
.withContext('Number of failed expectations')
.toEqual(0);
expect(
result.failedExpectations[0] && result.failedExpectations[0].message
)
.withContext('Failure message')
.toBeUndefined();
});
}
function verifyFailsAsync(expectations) {
it('fails', function(done) {
it('fails', async function() {
env.it('a spec', function() {
return expectations(env);
});
const specExpectations = function(result) {
expect(result.status).toEqual('failed');
expect(result.failedExpectations.length)
.withContext('Number of failed expectations')
.toEqual(1);
expect(result.failedExpectations[0].message)
.withContext(
'Failed with a thrown error rather than a matcher failure'
)
.not.toMatch(/^Error: /);
expect(result.failedExpectations[0].matcherName)
.withContext('Matcher name')
.not.toEqual('');
};
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
env.addReporter(reporter);
await env.execute();
env.addReporter({ specDone: specExpectations });
env.execute(null, done);
expect(reporter.specDone).toHaveBeenCalledTimes(1);
const result = reporter.specDone.calls.argsFor(0)[0];
expect(result.status).toEqual('failed');
expect(result.failedExpectations.length)
.withContext('Number of failed expectations')
.toEqual(1);
expect(result.failedExpectations[0].message)
.withContext('Failed with a thrown error rather than a matcher failure')
.not.toMatch(/^Error: /);
expect(result.failedExpectations[0].matcherName)
.withContext('Matcher name')
.not.toEqual('');
});
}
function verifyFailsWithCustomObjectFormattersAsync(config) {
it('uses custom object formatters', function(done) {
it('uses custom object formatters', async function() {
const env = new jasmineUnderTest.Env();
env.it('a spec', function() {
env.addCustomObjectFormatter(config.formatter);
return config.expectations(env);
});
const specExpectations = function(result) {
expect(result.status).toEqual('failed');
expect(result.failedExpectations.length)
.withContext('Number of failed expectations')
.toEqual(1);
expect(result.failedExpectations[0].message).toEqual(
config.expectedMessage
);
};
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
env.addReporter(reporter);
await env.execute();
env.addReporter({ specDone: specExpectations });
env.execute(null, done);
expect(reporter.specDone).toHaveBeenCalledTimes(1);
const result = reporter.specDone.calls.argsFor(0)[0];
expect(result.status).toEqual('failed');
expect(result.failedExpectations.length)
.withContext('Number of failed expectations')
.toEqual(1);
expect(result.failedExpectations[0].message).toEqual(
config.expectedMessage
);
});
}
@@ -753,76 +755,79 @@ describe('Matchers (Integration)', function() {
});
describe('When an async matcher is used with .already()', function() {
it('propagates the matcher result when the promise is resolved', function(done) {
it('propagates the matcher result when the promise is resolved', async function() {
env.it('a spec', function() {
return env.expectAsync(Promise.resolve()).already.toBeRejected();
});
const specExpectations = function(result) {
expect(result.status).toEqual('failed');
expect(result.failedExpectations.length)
.withContext('Number of failed expectations')
.toEqual(1);
expect(result.failedExpectations[0].message).toEqual(
'Expected [object Promise] to be rejected.'
);
expect(result.failedExpectations[0].matcherName)
.withContext('Matcher name')
.not.toEqual('');
};
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
env.addReporter(reporter);
await env.execute();
env.addReporter({ specDone: specExpectations });
env.execute(null, done);
expect(reporter.specDone).toHaveBeenCalledTimes(1);
const result = reporter.specDone.calls.argsFor(0)[0];
expect(result.status).toEqual('failed');
expect(result.failedExpectations.length)
.withContext('Number of failed expectations')
.toEqual(1);
expect(result.failedExpectations[0].message).toEqual(
'Expected [object Promise] to be rejected.'
);
expect(result.failedExpectations[0].matcherName)
.withContext('Matcher name')
.not.toEqual('');
});
it('propagates the matcher result when the promise is rejected', function(done) {
it('propagates the matcher result when the promise is rejected', async function() {
env.it('a spec', function() {
return env
.expectAsync(Promise.reject(new Error('nope')))
.already.toBeResolved();
});
const specExpectations = function(result) {
expect(result.status).toEqual('failed');
expect(result.failedExpectations.length)
.withContext('Number of failed expectations')
.toEqual(1);
expect(result.failedExpectations[0].message).toEqual(
'Expected a promise to be resolved but it was ' +
'rejected with Error: nope.'
);
expect(result.failedExpectations[0].matcherName)
.withContext('Matcher name')
.not.toEqual('');
};
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
env.addReporter(reporter);
await env.execute();
env.addReporter({ specDone: specExpectations });
env.execute(null, done);
expect(reporter.specDone).toHaveBeenCalledTimes(1);
const result = reporter.specDone.calls.argsFor(0)[0];
expect(result.status).toEqual('failed');
expect(result.failedExpectations.length)
.withContext('Number of failed expectations')
.toEqual(1);
expect(result.failedExpectations[0].message).toEqual(
'Expected a promise to be resolved but it was ' +
'rejected with Error: nope.'
);
expect(result.failedExpectations[0].matcherName)
.withContext('Matcher name')
.not.toEqual('');
});
it('fails when the promise is pending', function(done) {
it('fails when the promise is pending', async function() {
const promise = new Promise(function() {});
env.it('a spec', function() {
return env.expectAsync(promise).already.toBeResolved();
});
const specExpectations = function(result) {
expect(result.status).toEqual('failed');
expect(result.failedExpectations.length)
.withContext('Number of failed expectations')
.toEqual(1);
expect(result.failedExpectations[0].message).toEqual(
'Expected a promise to be settled ' +
'(via expectAsync(...).already) but it was pending.'
);
expect(result.failedExpectations[0].matcherName)
.withContext('Matcher name')
.not.toEqual('');
};
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
env.addReporter(reporter);
await env.execute();
env.addReporter({ specDone: specExpectations });
env.execute(null, done);
expect(reporter.specDone).toHaveBeenCalledTimes(1);
const result = reporter.specDone.calls.argsFor(0)[0];
expect(result.status).toEqual('failed');
expect(result.failedExpectations.length)
.withContext('Number of failed expectations')
.toEqual(1);
expect(result.failedExpectations[0].message).toEqual(
'Expected a promise to be settled ' +
'(via expectAsync(...).already) but it was pending.'
);
expect(result.failedExpectations[0].matcherName)
.withContext('Matcher name')
.not.toEqual('');
});
});
});

View File

@@ -1,6 +1,6 @@
describe('DiffBuilder', function() {
it('records the actual and expected objects', function() {
const diffBuilder = jasmineUnderTest.DiffBuilder();
const diffBuilder = new jasmineUnderTest.DiffBuilder();
diffBuilder.setRoots({ x: 'actual' }, { x: 'expected' });
diffBuilder.recordMismatch();
@@ -10,7 +10,7 @@ describe('DiffBuilder', function() {
});
it('prints the path at which the difference was found', function() {
const diffBuilder = jasmineUnderTest.DiffBuilder();
const diffBuilder = new jasmineUnderTest.DiffBuilder();
diffBuilder.setRoots({ foo: { x: 'actual' } }, { foo: { x: 'expected' } });
diffBuilder.withPath('foo', function() {
@@ -23,7 +23,7 @@ describe('DiffBuilder', function() {
});
it('prints multiple messages, separated by newlines', function() {
const diffBuilder = jasmineUnderTest.DiffBuilder();
const diffBuilder = new jasmineUnderTest.DiffBuilder();
diffBuilder.setRoots({ foo: 1, bar: 3 }, { foo: 2, bar: 4 });
diffBuilder.withPath('foo', function() {
@@ -40,7 +40,7 @@ describe('DiffBuilder', function() {
});
it('allows customization of the message', function() {
const diffBuilder = jasmineUnderTest.DiffBuilder();
const diffBuilder = new jasmineUnderTest.DiffBuilder();
diffBuilder.setRoots({ x: 'bar' }, { x: 'foo' });
function darthVaderFormatter(actual, expected, path) {
@@ -68,7 +68,7 @@ describe('DiffBuilder', function() {
const prettyPrinter = function(val) {
return '|' + val + '|';
},
diffBuilder = jasmineUnderTest.DiffBuilder({
diffBuilder = new jasmineUnderTest.DiffBuilder({
prettyPrinter: prettyPrinter
});
prettyPrinter.customFormat_ = function() {};
@@ -86,7 +86,7 @@ describe('DiffBuilder', function() {
it('passes the injected pretty-printer to the diff formatter', function() {
const diffFormatter = jasmine.createSpy('diffFormatter'),
prettyPrinter = function() {},
diffBuilder = jasmineUnderTest.DiffBuilder({
diffBuilder = new jasmineUnderTest.DiffBuilder({
prettyPrinter: prettyPrinter
});
prettyPrinter.customFormat_ = function() {};

View File

@@ -104,7 +104,9 @@ describe('toBeInstanceOf', function() {
});
it('passes for an async function', function() {
const fn = eval("(async function fn() { return 'foo'; })");
async function fn() {
return 'foo';
}
const matcher = jasmineUnderTest.matchers.toBeInstanceOf();
const result = matcher.compare(fn, Function);

View File

@@ -24,11 +24,10 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) {
) {
var f;
if (typeof funcToCall === 'string') {
/* jshint evil: true */
f = function() {
// eslint-disable-next-line no-eval
return eval(funcToCall);
};
/* jshint evil: false */
} else {
f = funcToCall;
}

View File

@@ -329,7 +329,7 @@ getJasmineRequireObj().Env = function(j$) {
}
};
var expectationFactory = function(actual, spec) {
const expectationFactory = function(actual, spec) {
return j$.Expectation.factory({
matchersUtil: makeMatchersUtil(),
customMatchers: runnableResources[spec.id].customMatchers,
@@ -342,16 +342,21 @@ getJasmineRequireObj().Env = function(j$) {
}
};
// TODO: Unify recordLateError with recordLateExpectation? The extra
// diagnostic info added by the latter is probably useful in most cases.
function recordLateError(error) {
const result = expectationResultFactory({
error,
passed: false,
matcherName: '',
expected: '',
actual: ''
});
result.globalErrorType = 'lateError';
topSuite.result.failedExpectations.push(result);
const isExpectationResult =
error.matcherName !== undefined && error.passed !== undefined;
const result = isExpectationResult
? error
: j$.buildExpectationResult({
error,
passed: false,
matcherName: '',
expected: '',
actual: ''
});
routeLateFailure(result);
}
function recordLateExpectation(runable, runableType, result) {
@@ -382,7 +387,27 @@ getJasmineRequireObj().Env = function(j$) {
topSuite.result.failedExpectations.push(delayedExpectationResult);
}
var asyncExpectationFactory = function(actual, spec, runableType) {
function routeLateFailure(expectationResult) {
// Report the result on the nearest ancestor suite that hasn't already
// been reported done.
for (let r = currentRunnable(); r; r = r.parentSuite) {
if (!r.reportedDone) {
if (r === topSuite) {
expectationResult.globalErrorType = 'lateError';
}
r.result.failedExpectations.push(expectationResult);
return;
}
}
// If we get here, all results have been reported and there's nothing we
// can do except log the result and hope the user sees it.
console.error('Jasmine received a result after the suite finished:');
console.error(expectationResult);
}
const asyncExpectationFactory = function(actual, spec, runableType) {
return j$.Expectation.asyncFactory({
matchersUtil: makeMatchersUtil(),
customAsyncMatchers: runnableResources[spec.id].customAsyncMatchers,
@@ -397,11 +422,11 @@ getJasmineRequireObj().Env = function(j$) {
return spec.addExpectationResult(passed, result);
}
};
var suiteAsyncExpectationFactory = function(actual, suite) {
const suiteAsyncExpectationFactory = function(actual, suite) {
return asyncExpectationFactory(actual, suite, 'Suite');
};
var specAsyncExpectationFactory = function(actual, suite) {
const specAsyncExpectationFactory = function(actual, suite) {
return asyncExpectationFactory(actual, suite, 'Spec');
};
@@ -474,16 +499,6 @@ getJasmineRequireObj().Env = function(j$) {
return fullName.join(' ');
};
// TODO: we may just be able to pass in the fn instead of wrapping here
var buildExpectationResult = j$.buildExpectationResult,
exceptionFormatter = new j$.ExceptionFormatter(),
expectationResultFactory = function(attrs) {
attrs.messageFormatter = exceptionFormatter.message;
attrs.stackFormatter = exceptionFormatter.stack;
return buildExpectationResult(attrs);
};
/**
* Causes a deprecation warning to be logged to the console and reported to
* reporters.
@@ -537,7 +552,7 @@ getJasmineRequireObj().Env = function(j$) {
options.onException =
options.onException ||
function(e) {
(currentRunnable() || topSuite).onException(e);
(currentRunnable() || topSuite).handleException(e);
};
options.deprecated = self.deprecated;
@@ -549,7 +564,6 @@ getJasmineRequireObj().Env = function(j$) {
description: 'Jasmine__TopLevel__Suite',
expectationFactory: expectationFactory,
asyncExpectationFactory: suiteAsyncExpectationFactory,
expectationResultFactory: expectationResultFactory,
autoCleanClosures: config.autoCleanClosures,
onLateError: recordLateError
});
@@ -722,10 +736,10 @@ getJasmineRequireObj().Env = function(j$) {
if (suite.hadBeforeAllFailure) {
reportChildrenOfBeforeAllFailure(suite).then(function() {
reporter.suiteDone(result, next);
reportSuiteDone(suite, result, next);
});
} else {
reporter.suiteDone(result, next);
reportSuiteDone(suite, result, next);
}
},
orderChildren: function(node) {
@@ -815,6 +829,7 @@ getJasmineRequireObj().Env = function(j$) {
failedExpectations: topSuite.result.failedExpectations,
deprecationWarnings: topSuite.result.deprecationWarnings
};
topSuite.reportedDone = true;
reporter.jasmineDone(jasmineDoneInfo, function() {
done(jasmineDoneInfo);
});
@@ -859,7 +874,7 @@ getJasmineRequireObj().Env = function(j$) {
child.result.status = 'failed';
await new Promise(function(resolve) {
reporter.specDone(child.result, resolve);
reportSpecDone(child, child.result, resolve);
});
}
}
@@ -1007,7 +1022,6 @@ getJasmineRequireObj().Env = function(j$) {
timer: new j$.Timer(),
expectationFactory: expectationFactory,
asyncExpectationFactory: suiteAsyncExpectationFactory,
expectationResultFactory: expectationResultFactory,
throwOnExpectationFailure: config.stopSpecOnExpectationFailure,
autoCleanClosures: config.autoCleanClosures,
onLateError: recordLateError
@@ -1073,7 +1087,7 @@ getJasmineRequireObj().Env = function(j$) {
}
if (declarationError) {
suite.onException(declarationError);
suite.handleException(declarationError);
}
currentDeclarationSuite = parentSuite;
@@ -1116,7 +1130,6 @@ getJasmineRequireObj().Env = function(j$) {
},
onStart: specStarted,
description: description,
expectationResultFactory: expectationResultFactory,
queueRunnerFactory: queueRunnerFactory,
userContext: function() {
return suite.clonedSharedUserContext();
@@ -1139,7 +1152,7 @@ getJasmineRequireObj().Env = function(j$) {
hasFailures = true;
}
reporter.specDone(result, next);
reportSpecDone(spec, result, next);
}
function specStarted(spec, next) {
@@ -1149,6 +1162,16 @@ getJasmineRequireObj().Env = function(j$) {
}
};
function reportSpecDone(spec, result, next) {
spec.reportedDone = true;
reporter.specDone(result, next);
}
function reportSuiteDone(suite, result, next) {
suite.reportedDone = true;
reporter.suiteDone(result, next);
}
this.it_ = function(description, fn, timeout) {
ensureIsNotNested('it');
// it() sometimes doesn't have a fn argument, so only check the type if

View File

@@ -1,5 +1,5 @@
getJasmineRequireObj().ExceptionFormatter = function(j$) {
var ignoredProperties = [
const ignoredProperties = [
'name',
'message',
'stack',
@@ -13,9 +13,10 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) {
];
function ExceptionFormatter(options) {
var jasmineFile = (options && options.jasmineFile) || j$.util.jasmineFile();
const jasmineFile =
(options && options.jasmineFile) || j$.util.jasmineFile();
this.message = function(error) {
var message = '';
let message = '';
if (error.jasmineMessage) {
message += error.jasmineMessage;
@@ -43,9 +44,9 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) {
return null;
}
var stackTrace = new j$.StackTrace(error);
var lines = filterJasmine(stackTrace);
var result = '';
const stackTrace = new j$.StackTrace(error);
const lines = filterJasmine(stackTrace);
let result = '';
if (stackTrace.message && !omitMessage) {
lines.unshift(stackTrace.message);
@@ -58,9 +59,9 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) {
};
function filterJasmine(stackTrace) {
var result = [],
jasmineMarker =
stackTrace.style === 'webkit' ? '<Jasmine>' : ' at <Jasmine>';
const result = [];
const jasmineMarker =
stackTrace.style === 'webkit' ? '<Jasmine>' : ' at <Jasmine>';
stackTrace.frames.forEach(function(frame) {
if (frame.file !== jasmineFile) {
@@ -78,10 +79,10 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) {
return;
}
var result = {};
var empty = true;
const result = {};
let empty = true;
for (var prop in error) {
for (const prop in error) {
if (j$.util.arrayContains(ignoredProperties, prop)) {
continue;
}

View File

@@ -6,8 +6,8 @@ getJasmineRequireObj().Expectation = function(j$) {
function Expectation(options) {
this.expector = new j$.Expector(options);
var customMatchers = options.customMatchers || {};
for (var matcherName in customMatchers) {
const customMatchers = options.customMatchers || {};
for (const matcherName in customMatchers) {
this[matcherName] = wrapSyncCompare(
matcherName,
customMatchers[matcherName]
@@ -77,8 +77,8 @@ getJasmineRequireObj().Expectation = function(j$) {
function AsyncExpectation(options) {
this.expector = new j$.Expector(options);
var customAsyncMatchers = options.customAsyncMatchers || {};
for (var matcherName in customAsyncMatchers) {
const customAsyncMatchers = options.customAsyncMatchers || {};
for (const matcherName in customAsyncMatchers) {
this[matcherName] = wrapAsyncCompare(
matcherName,
customAsyncMatchers[matcherName]
@@ -134,36 +134,34 @@ getJasmineRequireObj().Expectation = function(j$) {
function wrapSyncCompare(name, matcherFactory) {
return function() {
var result = this.expector.compare(name, matcherFactory, arguments);
const result = this.expector.compare(name, matcherFactory, arguments);
this.expector.processResult(result);
};
}
function wrapAsyncCompare(name, matcherFactory) {
return function() {
var self = this;
// Capture the call stack here, before we go async, so that it will contain
// frames that are relevant to the user instead of just parts of Jasmine.
var errorForStack = j$.util.errorWithStack();
const errorForStack = j$.util.errorWithStack();
return this.expector
.compare(name, matcherFactory, arguments)
.then(function(result) {
self.expector.processResult(result, errorForStack);
.then(result => {
this.expector.processResult(result, errorForStack);
});
};
}
function addCoreMatchers(prototype, matchers, wrapper) {
for (var matcherName in matchers) {
var matcher = matchers[matcherName];
for (const matcherName in matchers) {
const matcher = matchers[matcherName];
prototype[matcherName] = wrapper(matcherName, matcher);
}
}
function addFilter(source, filter) {
var result = Object.create(source);
const result = Object.create(source);
result.expector = source.expector.addFilter(filter);
return result;
}
@@ -188,7 +186,7 @@ getJasmineRequireObj().Expectation = function(j$) {
return result;
}
var syncNegatingFilter = {
const syncNegatingFilter = {
selectComparisonFunc: function(matcher) {
function defaultNegativeCompare() {
return negate(matcher.compare.apply(null, arguments));
@@ -199,7 +197,7 @@ getJasmineRequireObj().Expectation = function(j$) {
buildFailureMessage: negatedFailureMessage
};
var asyncNegatingFilter = {
const asyncNegatingFilter = {
selectComparisonFunc: function(matcher) {
function defaultNegativeCompare() {
return matcher.compare.apply(this, arguments).then(negate);
@@ -210,10 +208,10 @@ getJasmineRequireObj().Expectation = function(j$) {
buildFailureMessage: negatedFailureMessage
};
var expectSettledPromiseFilter = {
const expectSettledPromiseFilter = {
selectComparisonFunc: function(matcher) {
return function(actual) {
var matcherArgs = arguments;
const matcherArgs = arguments;
return j$.isPending_(actual).then(function(isPending) {
if (isPending) {
@@ -236,9 +234,7 @@ getJasmineRequireObj().Expectation = function(j$) {
}
ContextAddingFilter.prototype.modifyFailureMessage = function(msg) {
var nl = msg.indexOf('\n');
if (nl === -1) {
if (msg.indexOf('\n') === -1) {
return this.message + ': ' + msg;
} else {
return this.message + ':\n' + indent(msg);

View File

@@ -1,5 +1,3 @@
/*jshint bitwise: false*/
getJasmineRequireObj().Order = function() {
function Order(options) {
this.random = 'random' in options ? options.random : true;

View File

@@ -1,11 +1,298 @@
getJasmineRequireObj().makePrettyPrinter = function(j$) {
function SinglePrettyPrintRun(customObjectFormatters, pp) {
this.customObjectFormatters_ = customObjectFormatters;
this.ppNestLevel_ = 0;
this.seen = [];
this.length = 0;
this.stringParts = [];
this.pp_ = pp;
class SinglePrettyPrintRun {
constructor(customObjectFormatters, pp) {
this.customObjectFormatters_ = customObjectFormatters;
this.ppNestLevel_ = 0;
this.seen = [];
this.length = 0;
this.stringParts = [];
this.pp_ = pp;
}
format(value) {
this.ppNestLevel_++;
try {
const customFormatResult = this.applyCustomFormatters_(value);
if (customFormatResult) {
this.emitScalar(customFormatResult);
} else if (j$.util.isUndefined(value)) {
this.emitScalar('undefined');
} else if (value === null) {
this.emitScalar('null');
} else if (value === 0 && 1 / value === -Infinity) {
this.emitScalar('-0');
} else if (value === j$.getGlobal()) {
this.emitScalar('<global>');
} else if (value.jasmineToString) {
this.emitScalar(value.jasmineToString(this.pp_));
} else if (j$.isString_(value)) {
this.emitString(value);
} else if (j$.isSpy(value)) {
this.emitScalar('spy on ' + value.and.identity);
} else if (j$.isSpy(value.toString)) {
this.emitScalar('spy on ' + value.toString.and.identity);
} else if (value instanceof RegExp) {
this.emitScalar(value.toString());
} else if (typeof value === 'function') {
this.emitScalar('Function');
} else if (j$.isDomNode(value)) {
if (value.tagName) {
this.emitDomElement(value);
} else {
this.emitScalar('HTMLNode');
}
} else if (value instanceof Date) {
this.emitScalar('Date(' + value + ')');
} else if (j$.isSet(value)) {
this.emitSet(value);
} else if (j$.isMap(value)) {
this.emitMap(value);
} else if (j$.isTypedArray_(value)) {
this.emitTypedArray(value);
} else if (
value.toString &&
typeof value === 'object' &&
!j$.isArray_(value) &&
hasCustomToString(value)
) {
try {
this.emitScalar(value.toString());
} catch (e) {
this.emitScalar('has-invalid-toString-method');
}
} else if (j$.util.arrayContains(this.seen, value)) {
this.emitScalar(
'<circular reference: ' +
(j$.isArray_(value) ? 'Array' : 'Object') +
'>'
);
} else if (j$.isArray_(value) || j$.isA_('Object', value)) {
this.seen.push(value);
if (j$.isArray_(value)) {
this.emitArray(value);
} else {
this.emitObject(value);
}
this.seen.pop();
} else {
this.emitScalar(value.toString());
}
} catch (e) {
if (this.ppNestLevel_ > 1 || !(e instanceof MaxCharsReachedError)) {
throw e;
}
} finally {
this.ppNestLevel_--;
}
}
applyCustomFormatters_(value) {
return customFormat(value, this.customObjectFormatters_);
}
iterateObject(obj, fn) {
const objKeys = j$.MatchersUtil.keys(obj, j$.isArray_(obj));
const length = Math.min(objKeys.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
for (let i = 0; i < length; i++) {
fn(objKeys[i]);
}
return objKeys.length > length;
}
emitScalar(value) {
this.append(value);
}
emitString(value) {
this.append("'" + value + "'");
}
emitArray(array) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Array');
return;
}
const length = Math.min(array.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
this.append('[ ');
for (let i = 0; i < length; i++) {
if (i > 0) {
this.append(', ');
}
this.format(array[i]);
}
if (array.length > length) {
this.append(', ...');
}
let first = array.length === 0;
const wasTruncated = this.iterateObject(array, property => {
if (first) {
first = false;
} else {
this.append(', ');
}
this.formatProperty(array, property);
});
if (wasTruncated) {
this.append(', ...');
}
this.append(' ]');
}
emitSet(set) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Set');
return;
}
this.append('Set( ');
const size = Math.min(set.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
let i = 0;
set.forEach(function(value, key) {
if (i >= size) {
return;
}
if (i > 0) {
this.append(', ');
}
this.format(value);
i++;
}, this);
if (set.size > size) {
this.append(', ...');
}
this.append(' )');
}
emitMap(map) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Map');
return;
}
this.append('Map( ');
const size = Math.min(map.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
let i = 0;
map.forEach(function(value, key) {
if (i >= size) {
return;
}
if (i > 0) {
this.append(', ');
}
this.format([key, value]);
i++;
}, this);
if (map.size > size) {
this.append(', ...');
}
this.append(' )');
}
emitObject(obj) {
const ctor = obj.constructor;
const constructorName =
typeof ctor === 'function' && obj instanceof ctor
? j$.fnNameFor(obj.constructor)
: 'null';
this.append(constructorName);
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
return;
}
this.append('({ ');
let first = true;
const wasTruncated = this.iterateObject(obj, property => {
if (first) {
first = false;
} else {
this.append(', ');
}
this.formatProperty(obj, property);
});
if (wasTruncated) {
this.append(', ...');
}
this.append(' })');
}
emitTypedArray(arr) {
const constructorName = j$.fnNameFor(arr.constructor);
const limitedArray = Array.prototype.slice.call(
arr,
0,
j$.MAX_PRETTY_PRINT_ARRAY_LENGTH
);
let itemsString = Array.prototype.join.call(limitedArray, ', ');
if (limitedArray.length !== arr.length) {
itemsString += ', ...';
}
this.append(constructorName + ' [ ' + itemsString + ' ]');
}
emitDomElement(el) {
const tagName = el.tagName.toLowerCase();
let out = '<' + tagName;
for (const attr of el.attributes) {
out += ' ' + attr.name;
if (attr.value !== '') {
out += '="' + attr.value + '"';
}
}
out += '>';
if (el.childElementCount !== 0 || el.textContent !== '') {
out += '...</' + tagName + '>';
}
this.append(out);
}
formatProperty(obj, property) {
if (typeof property === 'symbol') {
this.append(property.toString());
} else {
this.append(property);
}
this.append(': ');
this.format(obj[property]);
}
append(value) {
// This check protects us from the rare case where an object has overriden
// `toString()` with an invalid implementation (returning a non-string).
if (typeof value !== 'string') {
value = Object.prototype.toString.call(value);
}
const result = truncate(value, j$.MAX_PRETTY_PRINT_CHARS - this.length);
this.length += result.value.length;
this.stringParts.push(result.value);
if (result.truncated) {
throw new MaxCharsReachedError();
}
}
}
function hasCustomToString(value) {
@@ -23,315 +310,6 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
}
}
SinglePrettyPrintRun.prototype.format = function(value) {
this.ppNestLevel_++;
try {
var customFormatResult = this.applyCustomFormatters_(value);
if (customFormatResult) {
this.emitScalar(customFormatResult);
} else if (j$.util.isUndefined(value)) {
this.emitScalar('undefined');
} else if (value === null) {
this.emitScalar('null');
} else if (value === 0 && 1 / value === -Infinity) {
this.emitScalar('-0');
} else if (value === j$.getGlobal()) {
this.emitScalar('<global>');
} else if (value.jasmineToString) {
this.emitScalar(value.jasmineToString(this.pp_));
} else if (j$.isString_(value)) {
this.emitString(value);
} else if (j$.isSpy(value)) {
this.emitScalar('spy on ' + value.and.identity);
} else if (j$.isSpy(value.toString)) {
this.emitScalar('spy on ' + value.toString.and.identity);
} else if (value instanceof RegExp) {
this.emitScalar(value.toString());
} else if (typeof value === 'function') {
this.emitScalar('Function');
} else if (j$.isDomNode(value)) {
if (value.tagName) {
this.emitDomElement(value);
} else {
this.emitScalar('HTMLNode');
}
} else if (value instanceof Date) {
this.emitScalar('Date(' + value + ')');
} else if (j$.isSet(value)) {
this.emitSet(value);
} else if (j$.isMap(value)) {
this.emitMap(value);
} else if (j$.isTypedArray_(value)) {
this.emitTypedArray(value);
} else if (
value.toString &&
typeof value === 'object' &&
!j$.isArray_(value) &&
hasCustomToString(value)
) {
try {
this.emitScalar(value.toString());
} catch (e) {
this.emitScalar('has-invalid-toString-method');
}
} else if (j$.util.arrayContains(this.seen, value)) {
this.emitScalar(
'<circular reference: ' +
(j$.isArray_(value) ? 'Array' : 'Object') +
'>'
);
} else if (j$.isArray_(value) || j$.isA_('Object', value)) {
this.seen.push(value);
if (j$.isArray_(value)) {
this.emitArray(value);
} else {
this.emitObject(value);
}
this.seen.pop();
} else {
this.emitScalar(value.toString());
}
} catch (e) {
if (this.ppNestLevel_ > 1 || !(e instanceof MaxCharsReachedError)) {
throw e;
}
} finally {
this.ppNestLevel_--;
}
};
SinglePrettyPrintRun.prototype.applyCustomFormatters_ = function(value) {
return customFormat(value, this.customObjectFormatters_);
};
SinglePrettyPrintRun.prototype.iterateObject = function(obj, fn) {
var objKeys = j$.MatchersUtil.keys(obj, j$.isArray_(obj));
var isGetter = function isGetter(prop) {};
if (obj.__lookupGetter__) {
isGetter = function isGetter(prop) {
var getter = obj.__lookupGetter__(prop);
return !j$.util.isUndefined(getter) && getter !== null;
};
}
var length = Math.min(objKeys.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
for (var i = 0; i < length; i++) {
var property = objKeys[i];
fn(property, isGetter(property));
}
return objKeys.length > length;
};
SinglePrettyPrintRun.prototype.emitScalar = function(value) {
this.append(value);
};
SinglePrettyPrintRun.prototype.emitString = function(value) {
this.append("'" + value + "'");
};
SinglePrettyPrintRun.prototype.emitArray = function(array) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Array');
return;
}
var length = Math.min(array.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
this.append('[ ');
for (var i = 0; i < length; i++) {
if (i > 0) {
this.append(', ');
}
this.format(array[i]);
}
if (array.length > length) {
this.append(', ...');
}
var self = this;
var first = array.length === 0;
var truncated = this.iterateObject(array, function(property, isGetter) {
if (first) {
first = false;
} else {
self.append(', ');
}
self.formatProperty(array, property, isGetter);
});
if (truncated) {
this.append(', ...');
}
this.append(' ]');
};
SinglePrettyPrintRun.prototype.emitSet = function(set) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Set');
return;
}
this.append('Set( ');
var size = Math.min(set.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
var i = 0;
set.forEach(function(value, key) {
if (i >= size) {
return;
}
if (i > 0) {
this.append(', ');
}
this.format(value);
i++;
}, this);
if (set.size > size) {
this.append(', ...');
}
this.append(' )');
};
SinglePrettyPrintRun.prototype.emitMap = function(map) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Map');
return;
}
this.append('Map( ');
var size = Math.min(map.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
var i = 0;
map.forEach(function(value, key) {
if (i >= size) {
return;
}
if (i > 0) {
this.append(', ');
}
this.format([key, value]);
i++;
}, this);
if (map.size > size) {
this.append(', ...');
}
this.append(' )');
};
SinglePrettyPrintRun.prototype.emitObject = function(obj) {
var ctor = obj.constructor,
constructorName;
constructorName =
typeof ctor === 'function' && obj instanceof ctor
? j$.fnNameFor(obj.constructor)
: 'null';
this.append(constructorName);
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
return;
}
var self = this;
this.append('({ ');
var first = true;
var truncated = this.iterateObject(obj, function(property, isGetter) {
if (first) {
first = false;
} else {
self.append(', ');
}
self.formatProperty(obj, property, isGetter);
});
if (truncated) {
this.append(', ...');
}
this.append(' })');
};
SinglePrettyPrintRun.prototype.emitTypedArray = function(arr) {
var constructorName = j$.fnNameFor(arr.constructor),
limitedArray = Array.prototype.slice.call(
arr,
0,
j$.MAX_PRETTY_PRINT_ARRAY_LENGTH
),
itemsString = Array.prototype.join.call(limitedArray, ', ');
if (limitedArray.length !== arr.length) {
itemsString += ', ...';
}
this.append(constructorName + ' [ ' + itemsString + ' ]');
};
SinglePrettyPrintRun.prototype.emitDomElement = function(el) {
var tagName = el.tagName.toLowerCase(),
attrs = el.attributes,
i,
len = attrs.length,
out = '<' + tagName,
attr;
for (i = 0; i < len; i++) {
attr = attrs[i];
out += ' ' + attr.name;
if (attr.value !== '') {
out += '="' + attr.value + '"';
}
}
out += '>';
if (el.childElementCount !== 0 || el.textContent !== '') {
out += '...</' + tagName + '>';
}
this.append(out);
};
SinglePrettyPrintRun.prototype.formatProperty = function(
obj,
property,
isGetter
) {
if (typeof property === 'symbol') {
this.append(property.toString());
} else {
this.append(property);
}
this.append(': ');
if (isGetter) {
this.append('<getter>');
} else {
this.format(obj[property]);
}
};
SinglePrettyPrintRun.prototype.append = function(value) {
// This check protects us from the rare case where an object has overriden
// `toString()` with an invalid implementation (returning a non-string).
if (typeof value !== 'string') {
value = Object.prototype.toString.call(value);
}
var result = truncate(value, j$.MAX_PRETTY_PRINT_CHARS - this.length);
this.length += result.value.length;
this.stringParts.push(result.value);
if (result.truncated) {
throw new MaxCharsReachedError();
}
};
function truncate(s, maxlen) {
if (s.length <= maxlen) {
return { value: s, truncated: false };
@@ -351,10 +329,8 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
MaxCharsReachedError.prototype = new Error();
function customFormat(value, customObjectFormatters) {
var i, result;
for (i = 0; i < customObjectFormatters.length; i++) {
result = customObjectFormatters[i](value);
for (const formatter of customObjectFormatters) {
const result = formatter(value);
if (result !== undefined) {
return result;
@@ -365,8 +341,11 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
return function(customObjectFormatters) {
customObjectFormatters = customObjectFormatters || [];
var pp = function(value) {
var prettyPrinter = new SinglePrettyPrintRun(customObjectFormatters, pp);
const pp = function(value) {
const prettyPrinter = new SinglePrettyPrintRun(
customObjectFormatters,
pp
);
prettyPrinter.format(value);
return prettyPrinter.stringParts.join('');
};

View File

@@ -253,8 +253,6 @@ getJasmineRequireObj().QueueRunner = function(j$) {
};
QueueRunner.prototype.diagnoseConflictingAsync_ = function(fn, retval) {
var msg;
if (retval && j$.isFunction_(retval.then)) {
// Issue a warning that matches the user's code.
// Omit the stack trace because there's almost certainly no user code
@@ -274,8 +272,6 @@ getJasmineRequireObj().QueueRunner = function(j$) {
'function to not return a promise.'
);
}
this.deprecated(msg, { omitStackTrace: true });
}
};

View File

@@ -1,28 +1,9 @@
getJasmineRequireObj().Spec = function(j$) {
/**
* @interface Spec
* @see Configuration#specFilter
* @since 2.0.0
*/
function Spec(attrs) {
this.expectationFactory = attrs.expectationFactory;
this.asyncExpectationFactory = attrs.asyncExpectationFactory;
this.resultCallback = attrs.resultCallback || function() {};
/**
* The unique ID of this spec.
* @name Spec#id
* @readonly
* @type {string}
* @since 2.0.0
*/
this.id = attrs.id;
/**
* The description passed to the {@link it} that created this spec.
* @name Spec#description
* @readonly
* @type {string}
* @since 2.0.0
*/
this.description = attrs.description || '';
this.queueableFn = attrs.queueableFn;
this.beforeAndAfterFns =
@@ -43,8 +24,6 @@ getJasmineRequireObj().Spec = function(j$) {
function() {
return '';
};
this.expectationResultFactory =
attrs.expectationResultFactory || function() {};
this.onLateError = attrs.onLateError || function() {};
this.queueRunnerFactory = attrs.queueRunnerFactory || function() {};
this.catchingExceptions =
@@ -86,14 +65,20 @@ getJasmineRequireObj().Spec = function(j$) {
properties: null,
debugLogs: null
};
this.reportedDone = false;
}
Spec.prototype.addExpectationResult = function(passed, data, isError) {
var expectationResult = this.expectationResultFactory(data);
const expectationResult = j$.buildExpectationResult(data);
if (passed) {
this.result.passedExpectations.push(expectationResult);
} else {
this.result.failedExpectations.push(expectationResult);
if (this.reportedDone) {
this.onLateError(expectationResult);
} else {
this.result.failedExpectations.push(expectationResult);
}
if (this.throwOnExpectationFailure && !isError) {
throw new j$.errors.ExpectationFailed();
@@ -147,7 +132,7 @@ getJasmineRequireObj().Spec = function(j$) {
isLeaf: true,
queueableFns: [...fns.befores, this.queueableFn, ...fns.afters],
onException: function() {
self.onException.apply(self, arguments);
self.handleException.apply(self, arguments);
},
onMultipleDone: function() {
// Issue a deprecation. Include the context ourselves and pass
@@ -197,9 +182,10 @@ getJasmineRequireObj().Spec = function(j$) {
debugLogs: null
};
this.markedPending = this.markedExcluding;
this.reportedDone = false;
};
Spec.prototype.onException = function onException(e) {
Spec.prototype.handleException = function handleException(e) {
if (Spec.isPendingSpecException(e)) {
this.pend(extractCustomPendingMessage(e));
return;
@@ -273,13 +259,6 @@ getJasmineRequireObj().Spec = function(j$) {
return 'passed';
};
/**
* The full description including all ancestors of this spec.
* @name Spec#getFullName
* @function
* @returns {string}
* @since 2.0.0
*/
Spec.prototype.getFullName = function() {
return this.getSpecName(this);
};
@@ -289,7 +268,7 @@ getJasmineRequireObj().Spec = function(j$) {
deprecation = { message: deprecation };
}
this.result.deprecationWarnings.push(
this.expectationResultFactory(deprecation)
j$.buildExpectationResult(deprecation)
);
};
@@ -332,6 +311,7 @@ getJasmineRequireObj().Spec = function(j$) {
/**
* @interface Spec
* @see Configuration#specFilter
* @since 2.0.0
*/
Object.defineProperty(Spec.prototype, 'metadata', {
get: function() {
@@ -342,6 +322,7 @@ getJasmineRequireObj().Spec = function(j$) {
* @name Spec#id
* @readonly
* @type {string}
* @since 2.0.0
*/
id: this.id,
@@ -350,6 +331,7 @@ getJasmineRequireObj().Spec = function(j$) {
* @name Spec#description
* @readonly
* @type {string}
* @since 2.0.0
*/
description: this.description,
@@ -358,6 +340,7 @@ getJasmineRequireObj().Spec = function(j$) {
* @name Spec#getFullName
* @function
* @returns {string}
* @since 2.0.0
*/
getFullName: this.getFullName.bind(this)
};

View File

@@ -1,48 +1,21 @@
getJasmineRequireObj().Suite = function(j$) {
/**
* @interface Suite
* @see Env#topSuite
* @since 2.0.0
*/
function Suite(attrs) {
this.env = attrs.env;
/**
* The unique ID of this suite.
* @name Suite#id
* @readonly
* @type {string}
* @since 2.0.0
*/
this.id = attrs.id;
this.parentSuite = attrs.parentSuite;
/**
* The description passed to the {@link describe} that created this suite.
* @name Suite#description
* @readonly
* @type {string}
* @since 2.0.0
*/
this.description = attrs.description;
this.expectationFactory = attrs.expectationFactory;
this.asyncExpectationFactory = attrs.asyncExpectationFactory;
this.expectationResultFactory = attrs.expectationResultFactory;
this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure;
this.autoCleanClosures =
attrs.autoCleanClosures === undefined ? true : !!attrs.autoCleanClosures;
this.onLateError = attrs.onLateError;
this.onLateError = attrs.onLateError || function() {};
this.beforeFns = [];
this.afterFns = [];
this.beforeAllFns = [];
this.afterAllFns = [];
this.timer = attrs.timer || new j$.Timer();
/**
* The suite's children.
* @name Suite#children
* @type {Array.<(Spec|Suite)>}
* @since 2.0.0
*/
this.children = [];
this.reset();
@@ -61,13 +34,6 @@ getJasmineRequireObj().Suite = function(j$) {
return this.asyncExpectationFactory(actual, this);
};
/**
* The full description including all ancestors of this suite.
* @name Suite#getFullName
* @function
* @returns {string}
* @since 2.0.0
*/
Suite.prototype.getFullName = function() {
var fullName = [];
for (
@@ -163,6 +129,7 @@ getJasmineRequireObj().Suite = function(j$) {
this.children.forEach(function(child) {
child.reset();
});
this.reportedDone = false;
};
Suite.prototype.addChild = function(child) {
@@ -204,25 +171,29 @@ getJasmineRequireObj().Suite = function(j$) {
return j$.UserContext.fromExisting(this.sharedUserContext());
};
Suite.prototype.onException = function() {
Suite.prototype.handleException = function() {
if (arguments[0] instanceof j$.errors.ExpectationFailed) {
return;
}
var data = {
const data = {
matcherName: '',
passed: false,
expected: '',
actual: '',
error: arguments[0]
};
var failedExpectation = this.expectationResultFactory(data);
const failedExpectation = j$.buildExpectationResult(data);
if (!this.parentSuite) {
failedExpectation.globalErrorType = 'afterAll';
}
this.result.failedExpectations.push(failedExpectation);
if (this.reportedDone) {
this.onLateError(failedExpectation);
} else {
this.result.failedExpectations.push(failedExpectation);
}
};
Suite.prototype.onMultipleDone = function() {
@@ -249,8 +220,15 @@ getJasmineRequireObj().Suite = function(j$) {
Suite.prototype.addExpectationResult = function() {
if (isFailure(arguments)) {
var data = arguments[1];
this.result.failedExpectations.push(this.expectationResultFactory(data));
const data = arguments[1];
const expectationResult = j$.buildExpectationResult(data);
if (this.reportedDone) {
this.onLateError(expectationResult);
} else {
this.result.failedExpectations.push(expectationResult);
}
if (this.throwOnExpectationFailure) {
throw new j$.errors.ExpectationFailed();
}
@@ -262,7 +240,7 @@ getJasmineRequireObj().Suite = function(j$) {
deprecation = { message: deprecation };
}
this.result.deprecationWarnings.push(
this.expectationResultFactory(deprecation)
j$.buildExpectationResult(deprecation)
);
};
@@ -279,6 +257,7 @@ getJasmineRequireObj().Suite = function(j$) {
/**
* @interface Suite
* @see Env#topSuite
* @since 2.0.0
*/
function SuiteMetadata(suite) {
this.suite_ = suite;
@@ -287,6 +266,7 @@ getJasmineRequireObj().Suite = function(j$) {
* @name Suite#id
* @readonly
* @type {string}
* @since 2.0.0
*/
this.id = suite.id;
@@ -303,6 +283,7 @@ getJasmineRequireObj().Suite = function(j$) {
* @name Suite#description
* @readonly
* @type {string}
* @since 2.0.0
*/
this.description = suite.description;
}
@@ -312,6 +293,7 @@ getJasmineRequireObj().Suite = function(j$) {
* @name Suite#getFullName
* @function
* @returns {string}
* @since 2.0.0
*/
SuiteMetadata.prototype.getFullName = function() {
return this.suite_.getFullName();
@@ -321,6 +303,7 @@ getJasmineRequireObj().Suite = function(j$) {
* The suite's children.
* @name Suite#children
* @type {Array.<(Spec|Suite)>}
* @since 2.0.0
*/
Object.defineProperty(SuiteMetadata.prototype, 'children', {
get: function() {

View File

@@ -42,7 +42,7 @@ getJasmineRequireObj().TreeProcessor = function() {
queueableFns: childFns,
userContext: tree.sharedUserContext(),
onException: function() {
tree.onException.apply(tree, arguments);
tree.handleException.apply(tree, arguments);
},
onComplete: done,
onMultipleDone: tree.onMultipleDone
@@ -218,7 +218,7 @@ getJasmineRequireObj().TreeProcessor = function() {
queueableFns: [onStart].concat(wrapChildren(node, segmentNumber)),
userContext: node.sharedUserContext(),
onException: function() {
node.onException.apply(node, arguments);
node.handleException.apply(node, arguments);
},
onMultipleDone: node.onMultipleDone
? node.onMultipleDone.bind(node)

View File

@@ -30,12 +30,9 @@ getJasmineRequireObj().Any = function(j$) {
return typeof other == 'boolean';
}
/* jshint -W122 */
/* global Symbol */
if (typeof Symbol != 'undefined' && this.expectedObject == Symbol) {
return typeof other == 'symbol';
}
/* jshint +W122 */
return other instanceof this.expectedObject;
};

View File

@@ -0,0 +1,17 @@
getJasmineRequireObj().Is = function(j$) {
class Is {
constructor(expected) {
this.expected_ = expected;
}
asymmetricMatch(actual) {
return actual === this.expected_;
}
jasmineToString(pp) {
return `<jasmine.is(${pp(this.expected_)})>`;
}
}
return Is;
};

View File

@@ -283,6 +283,18 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
return new j$.Empty();
};
/**
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher}
* that passes if the actual value is the same as the sample as determined
* by the `===` operator.
* @name jasmine.is
* @function
* @param {Object} sample - The value to compare the actual to.
*/
j$.is = function(sample) {
return new j$.Is(sample);
};
/**
* Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* that will succeed if the actual value being compared is not empty.

View File

@@ -1,8 +1,7 @@
//TODO: expectation result may make more sense as a presentation of an expectation.
getJasmineRequireObj().buildExpectationResult = function(j$) {
function buildExpectationResult(options) {
var messageFormatter = options.messageFormatter || function() {},
stackFormatter = options.stackFormatter || function() {};
const exceptionFormatter = new j$.ExceptionFormatter();
/**
* @typedef Expectation
@@ -16,7 +15,7 @@ getJasmineRequireObj().buildExpectationResult = function(j$) {
* is reported on the top suite. Valid values are undefined, "afterAll",
* "load", "lateExpectation", and "lateError".
*/
var result = {
const result = {
matcherName: options.matcherName,
message: message(),
stack: options.omitStackTrace ? '' : stack(),
@@ -52,7 +51,7 @@ getJasmineRequireObj().buildExpectationResult = function(j$) {
} else if (options.message) {
return options.message;
} else if (options.error) {
return messageFormatter(options.error);
return exceptionFormatter.message(options.error);
}
return '';
}
@@ -62,7 +61,8 @@ getJasmineRequireObj().buildExpectationResult = function(j$) {
return '';
}
var error = options.error;
let error = options.error;
if (!error) {
if (options.errorForStack) {
error = options.errorForStack;
@@ -78,7 +78,7 @@ getJasmineRequireObj().buildExpectationResult = function(j$) {
}
// Omit the message from the stack trace because it will be
// included elsewhere.
return stackFormatter(error, { omitMessage: true });
return exceptionFormatter.stack(error, { omitMessage: true });
}
}

View File

@@ -1,118 +1,112 @@
getJasmineRequireObj().DiffBuilder = function(j$) {
return function DiffBuilder(config) {
var prettyPrinter = (config || {}).prettyPrinter || j$.makePrettyPrinter(),
mismatches = new j$.MismatchTree(),
path = new j$.ObjectPath(),
actualRoot = undefined,
expectedRoot = undefined;
class DiffBuilder {
constructor(config) {
this.prettyPrinter_ =
(config || {}).prettyPrinter || j$.makePrettyPrinter();
this.mismatches_ = new j$.MismatchTree();
this.path_ = new j$.ObjectPath();
this.actualRoot_ = undefined;
this.expectedRoot_ = undefined;
}
return {
setRoots: function(actual, expected) {
actualRoot = actual;
expectedRoot = expected;
},
setRoots(actual, expected) {
this.actualRoot_ = actual;
this.expectedRoot_ = expected;
}
recordMismatch: function(formatter) {
mismatches.add(path, formatter);
},
recordMismatch(formatter) {
this.mismatches_.add(this.path_, formatter);
}
getMessage: function() {
var messages = [];
getMessage() {
const messages = [];
mismatches.traverse(function(path, isLeaf, formatter) {
var actualCustom,
expectedCustom,
useCustom,
derefResult = dereferencePath(
path,
actualRoot,
expectedRoot,
prettyPrinter
),
actual = derefResult.actual,
expected = derefResult.expected;
if (formatter) {
messages.push(formatter(actual, expected, path, prettyPrinter));
return true;
}
actualCustom = prettyPrinter.customFormat_(actual);
expectedCustom = prettyPrinter.customFormat_(expected);
useCustom = !(
j$.util.isUndefined(actualCustom) &&
j$.util.isUndefined(expectedCustom)
);
if (useCustom) {
messages.push(
wrapPrettyPrinted(actualCustom, expectedCustom, path)
);
return false; // don't recurse further
}
if (isLeaf) {
messages.push(
defaultFormatter(actual, expected, path, prettyPrinter)
);
}
this.mismatches_.traverse((path, isLeaf, formatter) => {
const { actual, expected } = this.dereferencePath_(path);
if (formatter) {
messages.push(formatter(actual, expected, path, this.prettyPrinter_));
return true;
});
}
return messages.join('\n');
},
const actualCustom = this.prettyPrinter_.customFormat_(actual);
const expectedCustom = this.prettyPrinter_.customFormat_(expected);
const useCustom = !(
j$.util.isUndefined(actualCustom) &&
j$.util.isUndefined(expectedCustom)
);
withPath: function(pathComponent, block) {
var oldPath = path;
path = path.add(pathComponent);
block();
path = oldPath;
if (useCustom) {
messages.push(wrapPrettyPrinted(actualCustom, expectedCustom, path));
return false; // don't recurse further
}
if (isLeaf) {
messages.push(this.defaultFormatter_(actual, expected, path));
}
return true;
});
return messages.join('\n');
}
withPath(pathComponent, block) {
const oldPath = this.path_;
this.path_ = this.path_.add(pathComponent);
block();
this.path_ = oldPath;
}
dereferencePath_(objectPath) {
let actual = this.actualRoot_;
let expected = this.expectedRoot_;
const handleAsymmetricExpected = () => {
if (
j$.isAsymmetricEqualityTester_(expected) &&
j$.isFunction_(expected.valuesForDiff_)
) {
const asymmetricResult = expected.valuesForDiff_(
actual,
this.prettyPrinter_
);
expected = asymmetricResult.self;
actual = asymmetricResult.other;
}
};
handleAsymmetricExpected();
for (const pc of objectPath.components) {
actual = actual[pc];
expected = expected[pc];
handleAsymmetricExpected();
}
};
function defaultFormatter(actual, expected, path, prettyPrinter) {
return { actual: actual, expected: expected };
}
defaultFormatter_(actual, expected, path) {
return wrapPrettyPrinted(
prettyPrinter(actual),
prettyPrinter(expected),
this.prettyPrinter_(actual),
this.prettyPrinter_(expected),
path
);
}
function wrapPrettyPrinted(actual, expected, path) {
return (
'Expected ' +
path +
(path.depth() ? ' = ' : '') +
actual +
' to equal ' +
expected +
'.'
);
}
};
function dereferencePath(objectPath, actual, expected, pp) {
function handleAsymmetricExpected() {
if (
j$.isAsymmetricEqualityTester_(expected) &&
j$.isFunction_(expected.valuesForDiff_)
) {
var asymmetricResult = expected.valuesForDiff_(actual, pp);
expected = asymmetricResult.self;
actual = asymmetricResult.other;
}
}
var i;
handleAsymmetricExpected();
for (i = 0; i < objectPath.components.length; i++) {
actual = actual[objectPath.components[i]];
expected = expected[objectPath.components[i]];
handleAsymmetricExpected();
}
return { actual: actual, expected: expected };
}
function wrapPrettyPrinted(actual, expected, path) {
return (
'Expected ' +
path +
(path.depth() ? ' = ' : '') +
actual +
' to equal ' +
expected +
'.'
);
}
return DiffBuilder;
};

View File

@@ -6,56 +6,51 @@ getJasmineRequireObj().MismatchTree = function(j$) {
the expected and actual object graphs. MismatchTree maintains that context
and provides it via the traverse method.
*/
function MismatchTree(path) {
this.path = path || new j$.ObjectPath([]);
this.formatter = undefined;
this.children = [];
this.isMismatch = false;
}
MismatchTree.prototype.add = function(path, formatter) {
var key, child;
if (path.depth() === 0) {
this.formatter = formatter;
this.isMismatch = true;
} else {
key = path.components[0];
path = path.shift();
child = this.child(key);
if (!child) {
child = new MismatchTree(this.path.add(key));
this.children.push(child);
}
child.add(path, formatter);
class MismatchTree {
constructor(path) {
this.path = path || new j$.ObjectPath([]);
this.formatter = undefined;
this.children = [];
this.isMismatch = false;
}
};
MismatchTree.prototype.traverse = function(visit) {
var i,
hasChildren = this.children.length > 0;
add(path, formatter) {
if (path.depth() === 0) {
this.formatter = formatter;
this.isMismatch = true;
} else {
const key = path.components[0];
path = path.shift();
let child = this.child(key);
if (this.isMismatch || hasChildren) {
if (visit(this.path, !hasChildren, this.formatter)) {
for (i = 0; i < this.children.length; i++) {
this.children[i].traverse(visit);
if (!child) {
child = new MismatchTree(this.path.add(key));
this.children.push(child);
}
child.add(path, formatter);
}
}
traverse(visit) {
const hasChildren = this.children.length > 0;
if (this.isMismatch || hasChildren) {
if (visit(this.path, !hasChildren, this.formatter)) {
for (const child of this.children) {
child.traverse(visit);
}
}
}
}
};
MismatchTree.prototype.child = function(key) {
var i, pathEls;
for (i = 0; i < this.children.length; i++) {
pathEls = this.children[i].path.components;
if (pathEls[pathEls.length - 1] === key) {
return this.children[i];
}
child(key) {
return this.children.find(child => {
const pathEls = child.path.components;
return pathEls[pathEls.length - 1] === key;
});
}
};
}
return MismatchTree;
};

View File

@@ -1,27 +1,29 @@
getJasmineRequireObj().ObjectPath = function(j$) {
function ObjectPath(components) {
this.components = components || [];
}
ObjectPath.prototype.toString = function() {
if (this.components.length) {
return '$' + map(this.components, formatPropertyAccess).join('');
} else {
return '';
class ObjectPath {
constructor(components) {
this.components = components || [];
}
};
ObjectPath.prototype.add = function(component) {
return new ObjectPath(this.components.concat([component]));
};
toString() {
if (this.components.length) {
return '$' + this.components.map(formatPropertyAccess).join('');
} else {
return '';
}
}
ObjectPath.prototype.shift = function() {
return new ObjectPath(this.components.slice(1));
};
add(component) {
return new ObjectPath(this.components.concat([component]));
}
ObjectPath.prototype.depth = function() {
return this.components.length;
};
shift() {
return new ObjectPath(this.components.slice(1));
}
depth() {
return this.components.length;
}
}
function formatPropertyAccess(prop) {
if (typeof prop === 'number' || typeof prop === 'symbol') {
@@ -32,15 +34,7 @@ getJasmineRequireObj().ObjectPath = function(j$) {
return '.' + prop;
}
return "['" + prop + "']";
}
function map(array, fn) {
var results = [];
for (var i = 0; i < array.length; i++) {
results.push(fn(array[i]));
}
return results;
return `['${prop}']`;
}
function isValidIdentifier(string) {

View File

@@ -14,7 +14,7 @@ getJasmineRequireObj().toEqual = function(j$) {
var result = {
pass: false
},
diffBuilder = j$.DiffBuilder({ prettyPrinter: matchersUtil.pp });
diffBuilder = new j$.DiffBuilder({ prettyPrinter: matchersUtil.pp });
result.pass = matchersUtil.equals(actual, expected, diffBuilder);

View File

@@ -91,6 +91,7 @@ var getJasmineRequireObj = (function(jasmineGlobal) {
j$.Falsy = jRequire.Falsy(j$);
j$.Empty = jRequire.Empty(j$);
j$.NotEmpty = jRequire.NotEmpty(j$);
j$.Is = jRequire.Is(j$);
j$.matchers = jRequire.requireMatchers(jRequire, j$);
j$.asyncMatchers = jRequire.requireAsyncMatchers(jRequire, j$);