Skip to content

Commit

Permalink
jest-cli@12
Browse files Browse the repository at this point in the history
  • Loading branch information
aaronabramov committed May 14, 2016
1 parent 74cce27 commit c09899d
Show file tree
Hide file tree
Showing 61 changed files with 922 additions and 696 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@
"scriptPreprocessor": "scripts/jest/preprocessor.js",
"setupEnvScriptFile": "scripts/jest/environment.js",
"setupTestFrameworkScriptFile": "scripts/jest/test-framework-setup.js",
"testRunner": "jasmine1",
"testFileExtensions": [
"coffee",
"js",
Expand Down
1 change: 1 addition & 0 deletions scripts/jest/jest.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ declare function xit(name: string, fn: any): void;
interface Expect {
not: Expect
toThrow(message?: string): void
toThrowError(message?: string): void
toBe(value: any): void
toEqual(value: any): void
toBeFalsy(): void
Expand Down
246 changes: 225 additions & 21 deletions scripts/jest/test-framework-setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,238 @@

var env = jasmine.getEnv();

var callCount = 0;
var oldError = console.error;
var newError = function() {
callCount++;
oldError.apply(this, arguments);
var spec = env.currentSpec;
if (spec) {
var expectationResult = new jasmine.ExpectationResult({
passed: false,
message:
'Expected test not to warn. If the warning is expected, mock it ' +
'out using spyOn(console, \'error\'); and test that the warning ' +
'occurs.',
});
spec.addMatcherResult(expectationResult);
}
};

console.error = newError;

// Make sure console.error is set back at the end of each test, or else the
// above logic won't work
afterEach(function() {
// TODO: Catch test cases that call spyOn() but don't inspect the mock
// properly.
env.beforeEach(() => {
callCount = 0;
jasmine.addMatchers({
toBeReset() {
return {
compare(actual) {
// TODO: Catch test cases that call spyOn() but don't inspect the mock
// properly.
if (actual !== newError && !jasmine.isSpy(actual)) {
return {
pass: false,
message: 'Test did not tear down console.error mock properly.',
};
}
return {pass: true};
},
};
},
toNotHaveBeenCalled() {
return {
compare(actual) {
return {
pass: callCount === 0,
message:
'Expected test not to warn. If the warning is expected, mock ' +
'it out using spyOn(console, \'error\'); and test that the ' +
'warning occurs.',
};
},
};
},
});
});
env.afterEach(() => {
expect(console.error).toBeReset();
expect(console.error).toNotHaveBeenCalled();
});


// MetaMatchers

class MetaMatcherReporter {
constructor() {
this._testResults = [];
this._currentSuites = [];
}

specDone(result) {
this._testResults.push(
this._extractSpecResults(result, this._currentSuites.slice(0))
);
}

suiteStarted(suite) {
this._currentSuites.push(suite.description);
}

suiteDone() {
this._currentSuites.pop();
}

getResults() {
return this._testResults;
}

if (console.error !== newError && !console.error.isSpy) {
var expectationResult = new jasmine.ExpectationResult({
passed: false,
message: 'Test did not tear down console.error mock properly.',
_extractSpecResults(specResult, currentSuites) {
const results = {
title: 'it ' + specResult.description,
ancestorTitles: currentSuites,
failureMessages: [],
numPassingAsserts: 0, // Jasmine2 only returns an array of failed asserts.
};

// specResult.failedExpectations.forEach(failed => {
// let message;
// if (!failed.matcherName) {
// message = this._formatter.formatException(failed.stack);
// } else {
// message = this._formatter.formatMatchFailure(failed);
// }
// results.failureMessages.push(message);
// });
results.failedExpectations = specResult.failedExpectations;

return results;
}

getResultsSummary() {
let numFailingTests = 0;
let numPassingTests = 0;
const testResults = this._testResults;
testResults.forEach(testResult => {
if (testResult.failureMessages.length > 0) {
numFailingTests++;
} else {
numPassingTests++;
}
});
env.currentSpec.addMatcherResult(expectationResult);
return {
numTests: numFailingTests + numPassingTests,
numFailingTests,
numPassingTests,
testResults,
};
}
}

function getRunnerWithResults(describeFunction) {
if (describeFunction._cachedRunner) {
// Cached result of execution. This is a convenience way to test against
// the same authoritative function multiple times.
return describeFunction._cachedRunner;
}

var myEnv = new jasmine.Env();

var matcherReporter = new MetaMatcherReporter();
myEnv.addReporter(matcherReporter);

myEnv.describe('', describeFunction);
myEnv.execute();
console.error('f');
var results = matcherReporter.getResultsSummary();
// console.error(results);
console.error(describeFunction.toString());

describeFunction._cachedRunner = results;
return results;
}

function compareSpec(actual, expected) {
if (actual.numTests !== expected.numTests) {
return (
'Expected ' + expected.numTests + ' expects, ' +
'but got ' + actual.numTests + ':' +
actual.title
);
}
return null;
}

function includesDescription(specs, description, startIndex) {
for (var i = startIndex; i < specs.length; i++) {
if (specs[i].title === description) {
return true;
}
}
return false;
}

function compareSpecs(actualSpecs, expectedSpecs) {
for (var i = 0; i < actualSpecs.length && i < expectedSpecs.length; i++) {
var actual = actualSpecs[i];
var expected = expectedSpecs[i];
if (actual.title === expected.title) {
var errorMessage = compareSpec(actual, expected);
if (errorMessage) {
return errorMessage;
}
continue;
} else if (includesDescription(actualSpecs, expected.title, i)) {
return 'Did not expect the spec:' + actualSpecs[i].title;
} else {
return 'Expected an equivalent to:' + expectedSpecs[i].gtitle;
}
}
if (i < actualSpecs.length) {
return 'Did not expect the spec:' + actualSpecs[i].title;
}
if (i < expectedSpecs.length) {
return 'Expected an equivalent to:' + expectedSpecs[i].title;
}
return null;
}

function compareDescription(a, b) {
if (a.title === b.title) {
return 0;
}
return a.title < b.title ? -1 : 1;
}

function compareRunners(actual, expected) {
return compareSpecs(
actual.testResults.sort(compareDescription),
expected.testResults.sort(compareDescription)
);
}

// env.addReporter();

env.beforeEach(() => {
jasmine.addMatchers({
toEqualSpecsIn(/* util, customEqualityMatcher*/) {
return {
compare(actualDescribeFunction, expectedDescribeFunction) {
if (typeof actualDescribeFunction !== 'function') {
throw Error('toEqualSpecsIn() should be used on a describe function');
}
if (typeof expectedDescribeFunction !== 'function') {
throw Error('toEqualSpecsIn() should be passed a describe function');
}
var actual = getRunnerWithResults(actualDescribeFunction);
var expected = getRunnerWithResults(expectedDescribeFunction);
var errorMessage = compareRunners(actual, expected);
// var errorMessage = null;

console.error(actual);
console.error(expected);
console.error('----')

if (errorMessage) {
return {
pass: false,
message: errorMessage + 'The specs are equal. Expected them to be different.',
}
};

return {
pass: true,
};
},
};
},
});
});
22 changes: 11 additions & 11 deletions src/addons/__tests__/ReactFragment-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ describe('ReactFragment', function() {
};
var element = <div>{[children]}</div>;
var container = document.createElement('div');
expect(() => ReactDOM.render(element, container)).toThrow(
expect(() => ReactDOM.render(element, container)).toThrowError(
'Objects are not valid as a React child (found: object with keys ' +
'{x, y, z}). If you meant to render a collection of children, use an ' +
'array instead or wrap the object using createFragment(object) from ' +
Expand All @@ -51,7 +51,7 @@ describe('ReactFragment', function() {
}
}
var container = document.createElement('div');
expect(() => ReactDOM.render(<Foo />, container)).toThrow(
expect(() => ReactDOM.render(<Foo />, container)).toThrowError(
'Objects are not valid as a React child (found: object with keys ' +
'{a, b, c}). If you meant to render a collection of children, use an ' +
'array instead or wrap the object using createFragment(object) from ' +
Expand All @@ -62,7 +62,7 @@ describe('ReactFragment', function() {
it('should throw if a plain object looks like an old element', function() {
var oldEl = {_isReactElement: true, type: 'span', props: {}};
var container = document.createElement('div');
expect(() => ReactDOM.render(<div>{oldEl}</div>, container)).toThrow(
expect(() => ReactDOM.render(<div>{oldEl}</div>, container)).toThrowError(
'Objects are not valid as a React child (found: object with keys ' +
'{_isReactElement, type, props}). It looks like you\'re using an ' +
'element created by a different version of React. Make sure to use ' +
Expand All @@ -75,35 +75,35 @@ describe('ReactFragment', function() {

ReactFragment.create({1: <span />, 2: <span />});

expect(console.error.argsForCall.length).toBe(1);
expect(console.error.argsForCall[0][0]).toContain(
expect(console.error.calls.count()).toBe(1);
expect(console.error.calls.argsFor(0)[0]).toContain(
'Child objects should have non-numeric keys so ordering is preserved.'
);
});

it('should warn if passing null to createFragment', function() {
spyOn(console, 'error');
ReactFragment.create(null);
expect(console.error.calls.length).toBe(1);
expect(console.error.argsForCall[0][0]).toContain(
expect(console.error.calls.count()).toBe(1);
expect(console.error.calls.argsFor(0)[0]).toContain(
'React.addons.createFragment only accepts a single object.'
);
});

it('should warn if passing an array to createFragment', function() {
spyOn(console, 'error');
ReactFragment.create([]);
expect(console.error.calls.length).toBe(1);
expect(console.error.argsForCall[0][0]).toContain(
expect(console.error.calls.count()).toBe(1);
expect(console.error.calls.argsFor(0)[0]).toContain(
'React.addons.createFragment only accepts a single object.'
);
});

it('should warn if passing a ReactElement to createFragment', function() {
spyOn(console, 'error');
ReactFragment.create(<div />);
expect(console.error.calls.length).toBe(1);
expect(console.error.argsForCall[0][0]).toContain(
expect(console.error.calls.count()).toBe(1);
expect(console.error.calls.argsFor(0)[0]).toContain(
'React.addons.createFragment does not accept a ReactElement without a ' +
'wrapper object.'
);
Expand Down
2 changes: 1 addition & 1 deletion src/addons/__tests__/renderSubtreeIntoContainer-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ describe('renderSubtreeIntoContainer', function() {
componentDidMount: function() {
expect(function() {
renderSubtreeIntoContainer(<Parent />, <Component />, portal);
}).toThrow('parentComponentmust be a valid React Component');
}).toThrowError('parentComponentmust be a valid React Component');
},
});
});
Expand Down
Loading

0 comments on commit c09899d

Please sign in to comment.