Add Meta Matchers for Testing Tests
This adds a matcher called toEqualSpecsIn which executes two test suites, without reporting the result. It then compares the specs and the number of expects executed by each spec. This will be used to ensure that tests written in other languages test the same thing as the base line, ES6 classes. Sets up CoffeeScript equivalence test.
Sebastian Markbage committed
Jan 26, 2015 at 15:50 UTC
3bbf6ce1a53358d2a3030050c88901b06e507460
3 files changed
+213
src/modern/class/__tests__/ReactClassEquivalence-test.js
new
+27
@@ -0,0 +1,27 @@
1
+/**
2
+ * Copyright 2015, Facebook, Inc.
3
+ * All rights reserved.
4
+ *
5
+ * This source code is licensed under the BSD-style license found in the
6
+ * LICENSE file in the root directory of this source tree. An additional grant
7
+ * of patent rights can be found in the PATENTS file in the same directory.
8
+ *
9
+ * @emails react-core
10
+ */
11
+
12
+var MetaMatchers = require('MetaMatchers');
13
+
14
+describe('ReactClassEquivalence', function() {
15
+
16
+ beforeEach(function() {
17
+ this.addMatchers(MetaMatchers);
18
+ });
19
+
20
+ var es6 = () => require('./ReactES6Class-test.js');
21
+ var coffee = () => require('./ReactCoffeeScriptClass-test.coffee');
22
+
23
+ it('tests the same thing for es6 classes and coffee script', function() {
24
+ expect(coffee).toEqualSpecsIn(es6);
25
+ });
26
+
27
+});
src/test/MetaMatchers.js
new
+126
@@ -0,0 +1,126 @@
1
+/**
2
+ * Copyright 2015, Facebook, Inc.
3
+ * All rights reserved.
4
+ *
5
+ * This source code is licensed under the BSD-style license found in the
6
+ * LICENSE file in the root directory of this source tree. An additional grant
7
+ * of patent rights can be found in the PATENTS file in the same directory.
8
+ *
9
+ * @providesModule MetaMatchers
10
+ */
11
+
12
+'use strict';
13
+
14
+/**
15
+ * This modules adds a jasmine matcher toEqualSpecsIn that can be used to
16
+ * compare the specs in two different "describe" functions and their result.
17
+ * It can be used to test a test.
18
+ */
19
+
20
+function getRunnerWithResults(describeFunction) {
21
+ if (describeFunction._cachedRunner) {
22
+ // Cached result of execution. This is a convenience way to test against
23
+ // the same authorative function multiple times.
24
+ return describeFunction._cachedRunner;
25
+ }
26
+ // Patch the current global environment.
27
+ var env = new jasmine.Env();
28
+ // Execute the tests synchronously.
29
+ env.updateInterval = 0;
30
+ var outerGetEnv = jasmine.getEnv;
31
+ jasmine.getEnv = function() { return env; };
32
+ // TODO: Bring over matchers from the existing environment.
33
+ var runner = env.currentRunner();
34
+ try {
35
+ env.describe('', describeFunction);
36
+ env.execute();
37
+ } finally {
38
+ // Restore the environment.
39
+ jasmine.getEnv = outerGetEnv;
40
+ }
41
+ describeFunction._cachedRunner = runner;
42
+ return runner;
43
+}
44
+
45
+function compareSpec(actual, expected) {
46
+ if (actual.results().totalCount !== expected.results().totalCount) {
47
+ return (
48
+ 'Expected ' + expected.results().totalCount + ' expects, ' +
49
+ 'but got ' + actual.results().totalCount + ':' +
50
+ actual.getFullName()
51
+ );
52
+ }
53
+ return null;
54
+}
55
+
56
+function includesDescription(specs, description, startIndex) {
57
+ for (var i = startIndex; i < specs.length; i++) {
58
+ if (specs[i].description === description) {
59
+ return true;
60
+ }
61
+ }
62
+ return false;
63
+}
64
+
65
+function compareSpecs(actualSpecs, expectedSpecs) {
66
+ for (var i = 0; i < actualSpecs.length && i < expectedSpecs.length; i++) {
67
+ var actual = actualSpecs[i];
68
+ var expected = expectedSpecs[i];
69
+ if (actual.description === expected.description) {
70
+ var errorMessage = compareSpec(actual, expected);
71
+ if (errorMessage) {
72
+ return errorMessage;
73
+ }
74
+ continue;
75
+ } else if (includesDescription(actualSpecs, expected.description, i)) {
76
+ return 'Did not expect the spec:' + actualSpecs[i].getFullName();
77
+ } else {
78
+ return 'Expected an equivalent to:' + expectedSpecs[i].getFullName();
79
+ }
80
+ }
81
+ if (i < actualSpecs.length) {
82
+ return 'Did not expect the spec:' + actualSpecs[i].getFullName();
83
+ }
84
+ if (i < expectedSpecs.length) {
85
+ return 'Expected an equivalent to:' + expectedSpecs[i].getFullName();
86
+ }
87
+ return null;
88
+}
89
+
90
+function compareDescription(a, b) {
91
+ if (a.description === b.description) {
92
+ return 0;
93
+ }
94
+ return a.description < b.description ? -1 : 1;
95
+}
96
+
97
+function compareRunners(actual, expected) {
98
+ return compareSpecs(
99
+ actual.specs().sort(compareDescription),
100
+ expected.specs().sort(compareDescription)
101
+ );
102
+}
103
+
104
+var MetaMatchers = {
105
+ toEqualSpecsIn: function(expectedDescribeFunction) {
106
+ var actualDescribeFunction = this.actual;
107
+ if (typeof actualDescribeFunction !== 'function') {
108
+ throw Error('toEqualSpecsIn() should be used on a describe function');
109
+ }
110
+ if (typeof expectedDescribeFunction !== 'function') {
111
+ throw Error('toEqualSpecsIn() should be passed a describe function');
112
+ }
113
+ var actual = getRunnerWithResults(actualDescribeFunction);
114
+ var expected = getRunnerWithResults(expectedDescribeFunction);
115
+ var errorMessage = compareRunners(actual, expected);
116
+ this.message = function() {
117
+ return [
118
+ errorMessage,
119
+ 'The specs are equal. Expected them to be different.'
120
+ ];
121
+ };
122
+ return !errorMessage;
123
+ }
124
+};
125
+
126
+module.exports = MetaMatchers;
src/test/__tests__/MetaMatchers-test.js
new
+60
@@ -0,0 +1,60 @@
1
+/**
2
+ * Copyright 2015, Facebook, Inc.
3
+ * All rights reserved.
4
+ *
5
+ * This source code is licensed under the BSD-style license found in the
6
+ * LICENSE file in the root directory of this source tree. An additional grant
7
+ * of patent rights can be found in the PATENTS file in the same directory.
8
+ *
9
+ * @emails react-core
10
+ */
11
+
12
+var MetaMatchers = require('MetaMatchers');
13
+
14
+describe('meta-matchers', function() {
15
+
16
+ beforeEach(function() {
17
+ this.addMatchers(MetaMatchers);
18
+ });
19
+
20
+ function a() {
21
+ it('should add 1 and 2', function() {
22
+ expect(1 + 2).toBe(3);
23
+ });
24
+ }
25
+
26
+ function b() {
27
+ it('should add 1 and 2', function() {
28
+ expect(1 + 2).toBe(3);
29
+ });
30
+ }
31
+
32
+ function c() {
33
+ it('should add 1 and 2', function() {
34
+ expect(1 + 2).toBe(3);
35
+ });
36
+ it('should mutiply 1 and 2', function() {
37
+ expect(1 * 2).toBe(2);
38
+ });
39
+ }
40
+
41
+ function d() {
42
+ it('should add 1 and 2', function() {
43
+ expect(1 + 2).toBe(3);
44
+ });
45
+ it('should mutiply 1 and 2', function() {
46
+ expect(1 * 2).toBe(2);
47
+ expect(2 * 1).toBe(2);
48
+ });
49
+ }
50
+
51
+ it('tests equality of specs', function() {
52
+ expect(a).toEqualSpecsIn(b);
53
+ });
54
+
55
+ it('tests inequality of specs and expects', function() {
56
+ expect(b).not.toEqualSpecsIn(c);
57
+ expect(c).not.toEqualSpecsIn(d);
58
+ });
59
+
60
+});