Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
80635 views
1
/**
2
* Copyright (c) 2014, Facebook, Inc. All rights reserved.
3
*
4
* This source code is licensed under the BSD-style license found in the
5
* LICENSE file in the root directory of this source tree. An additional grant
6
* of patent rights can be found in the PATENTS file in the same directory.
7
*/
8
'use strict';
9
10
var fs = require('graceful-fs');
11
var jasminePit = require('jasmine-pit');
12
var JasmineReporter = require('./JasmineReporter');
13
var path = require('path');
14
var utils = require('../lib/utils');
15
16
var JASMINE_PATH = require.resolve('../../vendor/jasmine/jasmine-1.3.0');
17
var jasmineFileContent =
18
fs.readFileSync(require.resolve(JASMINE_PATH), 'utf8');
19
20
var JASMINE_ONLY_ROOT = path.dirname(require.resolve('jasmine-only'));
21
var POTENTIALLY_PRECOMPILED_FILE = path.join(
22
JASMINE_ONLY_ROOT,
23
'app',
24
'js',
25
'jasmine_only.js'
26
);
27
var COFFEE_SCRIPT_FILE = path.join(
28
JASMINE_ONLY_ROOT,
29
'app',
30
'js',
31
'jasmine_only.coffee'
32
);
33
34
var jasmineOnlyContent =
35
fs.existsSync(POTENTIALLY_PRECOMPILED_FILE)
36
? fs.readFileSync(POTENTIALLY_PRECOMPILED_FILE, 'utf8')
37
: require('coffee-script').compile(
38
fs.readFileSync(COFFEE_SCRIPT_FILE, 'utf8')
39
);
40
41
function jasmineTestRunner(config, environment, moduleLoader, testPath) {
42
// Jasmine does stuff with timers that affect running the tests. However, we
43
// also mock out all the timer APIs (to make them test-controllable).
44
//
45
// To account for this conflict, we set up jasmine in an environment with real
46
// timers (instead of mock timers).
47
environment.fakeTimers.runWithRealTimers(function() {
48
// Execute jasmine's main code
49
environment.runSourceText(jasmineFileContent, JASMINE_PATH);
50
51
// Install jasmine-pit -- because it's amazing
52
jasminePit.install(environment.global);
53
54
// Install jasmine-only
55
environment.runSourceText(jasmineOnlyContent);
56
57
// Node must have been run with --harmony in order for WeakMap to be
58
// available prior to version 0.12
59
if (typeof WeakMap !== 'function') {
60
throw new Error(
61
'Please run node with the --harmony flag! jest requires WeakMap ' +
62
'which is only available with the --harmony flag in node < v0.12'
63
);
64
}
65
66
// Mainline Jasmine sets __Jasmine_been_here_before__ on each object to
67
// detect cycles, but that doesn't work on frozen objects so we use a
68
// WeakMap instead.
69
var _comparedObjects = new WeakMap();
70
environment.global.jasmine.Env.prototype.compareObjects_ =
71
function(a, b, mismatchKeys, mismatchValues) {
72
if (_comparedObjects.get(a) === b && _comparedObjects.get(b) === a) {
73
return true;
74
}
75
var areArrays =
76
environment.global.jasmine.isArray_(a)
77
&& environment.global.jasmine.isArray_(b);
78
79
_comparedObjects.set(a, b);
80
_comparedObjects.set(b, a);
81
82
var hasKey = function(obj, keyName) {
83
return (
84
obj !== null
85
&& obj !== undefined
86
&& obj[keyName] !== environment.global.jasmine.undefined
87
);
88
};
89
90
for (var property in b) {
91
if (areArrays && typeof b[property] === 'function') {
92
continue;
93
}
94
if (!hasKey(a, property) && hasKey(b, property)) {
95
mismatchKeys.push(
96
'expected has key \'' + property + '\', but missing from actual.'
97
);
98
}
99
}
100
for (property in a) {
101
if (areArrays && typeof a[property] === 'function') {
102
continue;
103
}
104
if (!hasKey(b, property) && hasKey(a, property)) {
105
mismatchKeys.push(
106
'expected missing key \'' + property + '\', but present in ' +
107
'actual.'
108
);
109
}
110
}
111
for (property in b) {
112
// The only different implementation from the original jasmine
113
if (areArrays &&
114
(typeof a[property] === 'function' ||
115
typeof b[property] === 'function')) {
116
continue;
117
}
118
var areEqual = this.equals_(
119
a[property],
120
b[property],
121
mismatchKeys,
122
mismatchValues
123
);
124
if (!areEqual) {
125
var aprop;
126
var bprop;
127
if (!a[property]) {
128
aprop = a[property];
129
} else if (a[property].toString) {
130
aprop = environment.global.jasmine.util.htmlEscape(
131
a[property].toString()
132
);
133
} else {
134
aprop = Object.prototype.toString.call(a[property]);
135
}
136
137
if (!b[property]) {
138
bprop = b[property];
139
} else if (b[property].toString) {
140
bprop = environment.global.jasmine.util.htmlEscape(
141
b[property].toString()
142
);
143
} else {
144
bprop = Object.prototype.toString.call(b[property]);
145
}
146
147
mismatchValues.push(
148
'\'' + property + '\' was \'' + bprop +
149
'\' in expected, but was \'' + aprop +
150
'\' in actual.'
151
);
152
}
153
}
154
155
if (areArrays && a.length !== b.length) {
156
mismatchValues.push('arrays were not the same length');
157
}
158
159
_comparedObjects.delete(a);
160
_comparedObjects.delete(b);
161
return (mismatchKeys.length === 0 && mismatchValues.length === 0);
162
};
163
164
if (config.setupTestFrameworkScriptFile) {
165
var setupScriptContent = utils.readAndPreprocessFileContent(
166
config.setupTestFrameworkScriptFile,
167
config
168
);
169
170
utils.runContentWithLocalBindings(
171
environment.runSourceText.bind(environment),
172
setupScriptContent,
173
config.setupTestFrameworkScriptFile,
174
{
175
__dirname: path.dirname(config.setupTestFrameworkScriptFile),
176
__filename: config.setupTestFrameworkScriptFile,
177
require: moduleLoader.constructBoundRequire(
178
config.setupTestFrameworkScriptFile
179
),
180
jest: moduleLoader.getJestRuntime(config.setupTestFrameworkScriptFile)
181
}
182
);
183
}
184
});
185
186
var jasmine = environment.global.jasmine;
187
188
jasmine.getEnv().beforeEach(function() {
189
this.addMatchers({
190
toBeCalled: function() {
191
if (this.actual.mock === undefined) {
192
throw Error('toBeCalled() should be used on a mock function');
193
}
194
return this.actual.mock.calls.length !== 0;
195
},
196
197
lastCalledWith: function() {
198
if (this.actual.mock === undefined) {
199
throw Error('lastCalledWith() should be used on a mock function');
200
}
201
var calls = this.actual.mock.calls;
202
var args = Array.prototype.slice.call(arguments);
203
this.env.currentSpec.expect(calls[calls.length - 1]).toEqual(args);
204
return true;
205
},
206
207
toBeCalledWith: function() {
208
if (this.actual.mock === undefined) {
209
throw Error('toBeCalledWith() should be used on a mock function');
210
}
211
var calls = this.actual.mock.calls;
212
var args = Array.prototype.slice.call(arguments);
213
214
// Often toBeCalledWith is called on a mock that only has one call, so
215
// we can give a better error message in this case.
216
if (calls.length === 1) {
217
var expect = this.env.currentSpec.expect(calls[0]);
218
if (this.isNot) {
219
expect = expect.not;
220
}
221
expect.toEqual(args);
222
return !this.isNot;
223
}
224
225
return calls.some(function(call) {
226
return this.env.equals_(call, args);
227
}, this);
228
}
229
});
230
231
if (!config.persistModuleRegistryBetweenSpecs) {
232
moduleLoader.requireModule(
233
__filename,
234
'jest-runtime'
235
).resetModuleRegistry();
236
}
237
});
238
239
var jasmineReporter = new JasmineReporter({
240
noHighlight: config.noHighlight,
241
});
242
jasmine.getEnv().addReporter(jasmineReporter);
243
244
// Run the test by require()ing it
245
moduleLoader.requireModule(testPath, './' + path.basename(testPath));
246
247
jasmine.getEnv().execute();
248
return jasmineReporter.getResults();
249
}
250
251
module.exports = jasmineTestRunner;
252
253