Skip to content
This repository was archived by the owner on Oct 17, 2025. It is now read-only.

Commit acaec8b

Browse files
committed
feat(index): add jasmine2.0 support
1 parent ad24dc7 commit acaec8b

9 files changed

Lines changed: 326 additions & 226 deletions

File tree

README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Features
1616
Installation
1717
------------
1818
```
19-
npm install jasminewd
19+
npm install jasminewd2
2020
```
2121

2222
Usage
@@ -26,15 +26,17 @@ Assumes selenium-webdriver as a peer dependency.
2626

2727
```js
2828
// In your setup.
29-
var minijn = require('minijasminenode');
30-
require('jasminewd');
29+
var JasmineRunner = require('jasmine');
30+
var jrunner = new JasmineRunner();
31+
require('jasminewd2');
3132

3233
global.driver = new webdriver.Builder().
3334
usingServer('http://localhost:4444/wd/hub').
3435
withCapabilities({browserName: 'chrome'}).
3536
build();
3637

37-
minijn.executeSpecs(/* ... */);
38+
jrunner.projectBaseDir = '';
39+
jrunner.execute(['**/*_spec.js']);
3840

3941
// In your tests
4042

index.js

Lines changed: 94 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -72,47 +72,44 @@ function wrapInControlFlow(globalFn, fnName) {
7272
var driverError = new Error();
7373
driverError.stack = driverError.stack.replace(/ +at.+jasminewd.+\n/, '');
7474

75-
function asyncTestFn(fn, desc) {
75+
function asyncTestFn(fn) {
7676
return function(done) {
77-
var desc_ = 'Asynchronous test function: ' + fnName + '(';
78-
if (desc) {
79-
desc_ += '"' + desc + '"';
80-
}
81-
desc_ += ')';
82-
8377
// deferred object for signaling completion of asychronous function within globalFn
84-
var asyncFnDone = webdriver.promise.defer();
78+
var asyncFnDone = webdriver.promise.defer(),
79+
originalFail = jasmine.getEnv().fail;
8580

8681
if (fn.length === 0) {
8782
// function with globalFn not asychronous
8883
asyncFnDone.fulfill();
8984
} else if (fn.length > 1) {
9085
throw Error('Invalid # arguments (' + fn.length + ') within function "' + fnName +'"');
86+
} else {
87+
// Add fail method to async done callback and override env fail to
88+
// reject async done promise
89+
jasmine.getEnv().fail = asyncFnDone.fulfill.fail = function(userError) {
90+
asyncFnDone.reject(new Error(userError));
91+
};
9192
}
9293

9394
var flowFinished = flow.execute(function() {
94-
fn.call(jasmine.getEnv().currentSpec, function(userError) {
95-
if (userError) {
96-
asyncFnDone.reject(new Error(userError));
97-
} else {
98-
asyncFnDone.fulfill();
99-
}
100-
});
101-
}, desc_);
95+
fn.call(jasmine.getEnv(), asyncFnDone.fulfill);
96+
});
10297

10398
webdriver.promise.all([asyncFnDone, flowFinished]).then(function() {
99+
jasmine.getEnv().fail = originalFail;
104100
seal(done)();
105101
}, function(e) {
106-
e.stack = e.stack + '==== async task ====\n' + driverError.stack;
107-
done(e);
102+
jasmine.getEnv().fail = originalFail;
103+
e.stack = e.stack + '\n==== async task ====\n' + driverError.stack;
104+
done.fail(e);
108105
});
109106
};
110107
}
111108

112109
var description, func, timeout;
113110
switch (fnName) {
114111
case 'it':
115-
case 'iit':
112+
case 'fit':
116113
description = validateString(arguments[0]);
117114
func = validateFunction(arguments[1]);
118115
if (!arguments[2]) {
@@ -124,6 +121,8 @@ function wrapInControlFlow(globalFn, fnName) {
124121
break;
125122
case 'beforeEach':
126123
case 'afterEach':
124+
case 'beforeAll':
125+
case 'afterAll':
127126
func = validateFunction(arguments[0]);
128127
if (!arguments[1]) {
129128
globalFn(asyncTestFn(func));
@@ -139,117 +138,99 @@ function wrapInControlFlow(globalFn, fnName) {
139138
}
140139

141140
global.it = wrapInControlFlow(global.it, 'it');
142-
global.iit = wrapInControlFlow(global.iit, 'iit');
141+
global.fit = wrapInControlFlow(global.fit, 'fit');
143142
global.beforeEach = wrapInControlFlow(global.beforeEach, 'beforeEach');
144143
global.afterEach = wrapInControlFlow(global.afterEach, 'afterEach');
144+
global.beforeAll = wrapInControlFlow(global.beforeAll, 'beforeAll');
145+
global.afterAll = wrapInControlFlow(global.afterAll, 'afterAll');
145146

147+
var originalExpect = global.expect;
148+
global.expect = function(actual) {
149+
if (actual instanceof webdriver.WebElement) {
150+
throw 'expect called with WebElement argument, expected a Promise. ' +
151+
'Did you mean to use .getText()?';
152+
}
153+
return originalExpect(actual);
154+
};
146155

147156
/**
148-
* Wrap a Jasmine matcher function so that it can take webdriverJS promises.
149-
* @param {!Function} matcher The matcher function to wrap.
150-
* @param {webdriver.promise.Promise} actualPromise The promise which will
151-
* resolve to the actual value being tested.
152-
* @param {boolean} not Whether this is being called with 'not' active.
157+
* Creates a matcher wrapper that resolves any promises given for actual and
158+
* expected values, as well as the `pass` property of the result.
153159
*/
154-
function wrapMatcher(matcher, actualPromise, not) {
160+
jasmine.Expectation.prototype.wrapCompare = function(name, matcherFactory) {
155161
return function() {
156-
var originalArgs = arguments;
157-
var matchError = new Error("Failed expectation");
158-
matchError.stack = matchError.stack.replace(/ +at.+jasminewd.+\n/, '');
159-
actualPromise.then(function(actual) {
160-
var expected = originalArgs[0];
162+
var expected = Array.prototype.slice.call(arguments, 0),
163+
expectation = this,
164+
matchError = new Error("Failed expectation");
161165

162-
var expectation = originalExpect(actual);
163-
if (not) {
164-
expectation = expectation.not;
165-
}
166-
var originalAddMatcherResult = expectation.spec.addMatcherResult;
167-
var error = matchError;
168-
expectation.spec.addMatcherResult = function(result) {
169-
result.trace = error;
170-
jasmine.Spec.prototype.addMatcherResult.call(this, result);
171-
};
166+
matchError.stack = matchError.stack.replace(/ +at.+jasminewd.+\n/, '');
172167

173-
if (webdriver.promise.isPromise(expected)) {
174-
if (originalArgs.length > 1) {
175-
throw error('Multi-argument matchers with promises are not ' +
176-
'supported.');
177-
}
178-
expected.then(function(exp) {
179-
expectation[matcher].apply(expectation, [exp]);
180-
expectation.spec.addMatcherResult = originalAddMatcherResult;
168+
flow.execute(function() {
169+
return webdriver.promise.when(expectation.actual).then(function(actual) {
170+
return webdriver.promise.all(expected).then(function(expected) {
171+
return compare(actual, expected);
181172
});
182-
} else {
183-
expectation.spec.addMatcherResult = function(result) {
184-
result.trace = error;
185-
originalAddMatcherResult.call(this, result);
186-
};
187-
expectation[matcher].apply(expectation, originalArgs);
188-
expectation.spec.addMatcherResult = originalAddMatcherResult;
189-
}
173+
});
190174
});
191-
};
192-
}
193175

194-
/**
195-
* Return a chained set of matcher functions which will be evaluated
196-
* after actualPromise is resolved.
197-
* @param {webdriver.promise.Promise} actualPromise The promise which will
198-
* resolve to the actual value being tested.
199-
*/
200-
function promiseMatchers(actualPromise) {
201-
var promises = {not: {}};
202-
var env = jasmine.getEnv();
203-
var matchersClass = env.currentSpec.matchersClass || env.matchersClass;
176+
function compare(actual, expected) {
177+
var args = expected.slice(0);
178+
args.unshift(actual);
204179

205-
for (var matcher in matchersClass.prototype) {
206-
promises[matcher] = wrapMatcher(matcher, actualPromise, false);
207-
promises.not[matcher] = wrapMatcher(matcher, actualPromise, true);
208-
}
180+
var matcher = matcherFactory(expectation.util, expectation.customEqualityTesters);
181+
var matcherCompare = matcher.compare;
209182

210-
return promises;
211-
}
183+
if (expectation.isNot) {
184+
matcherCompare = matcher.negativeCompare || defaultNegativeCompare;
185+
}
212186

213-
var originalExpect = global.expect;
187+
var result = matcherCompare.apply(null, args);
214188

215-
global.expect = function(actual) {
216-
if (actual instanceof webdriver.WebElement) {
217-
throw 'expect called with WebElement argument, expected a Promise. ' +
218-
'Did you mean to use .getText()?';
219-
}
220-
if (webdriver.promise.isPromise(actual)) {
221-
return promiseMatchers(actual);
222-
} else {
223-
return originalExpect(actual);
224-
}
225-
};
189+
return webdriver.promise.when(result.pass).then(function(pass) {
190+
var message = "";
226191

227-
// Wrap internal Jasmine function to allow custom matchers
228-
// to return promises that resolve to truthy or falsy values
229-
var originalMatcherFn = jasmine.Matchers.matcherFn_;
230-
jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) {
231-
var matcherFnThis = this;
232-
var matcherFnArgs = jasmine.util.argsToArray(arguments);
233-
return function() {
234-
var matcherThis = this;
235-
var matcherArgs = jasmine.util.argsToArray(arguments);
236-
var result = matcherFunction.apply(this, arguments);
192+
if (!pass) {
193+
if (!result.message) {
194+
args.unshift(expectation.isNot);
195+
args.unshift(name);
196+
message = expectation.util.buildFailureMessage.apply(null, args);
197+
} else {
198+
message = result.message;
199+
}
200+
}
237201

238-
if (webdriver.promise.isPromise(result)) {
239-
result.then(function(resolution) {
240-
matcherFnArgs[1] = function() {
241-
return resolution;
202+
if (expected.length == 1) {
203+
expected = expected[0];
204+
}
205+
var res = {
206+
matcherName: name,
207+
passed: pass,
208+
message: message,
209+
actual: actual,
210+
expected: expected,
211+
error: matchError
242212
};
243-
originalMatcherFn.apply(matcherFnThis, matcherFnArgs).
244-
apply(matcherThis, matcherArgs);
213+
expectation.addExpectationResult(pass, res);
245214
});
246-
} else {
247-
originalMatcherFn.apply(matcherFnThis, matcherFnArgs).
248-
apply(matcherThis, matcherArgs);
215+
216+
function defaultNegativeCompare() {
217+
var result = matcher.compare.apply(null, args);
218+
if (webdriver.promise.isPromise(result.pass)) {
219+
result.pass = result.pass.then(function(pass) {
220+
return !pass;
221+
});
222+
} else {
223+
result.pass = !result.pass;
224+
}
225+
return result;
226+
}
249227
}
250228
};
251229
};
252230

231+
// Re-add core matchers so they are wrapped.
232+
jasmine.Expectation.addCoreMatchers(jasmine.matchers);
233+
253234
/**
254235
* A Jasmine reporter which does nothing but execute the input function
255236
* on a timeout failure.
@@ -258,30 +239,17 @@ var OnTimeoutReporter = function(fn) {
258239
this.callback = fn;
259240
};
260241

261-
OnTimeoutReporter.prototype.reportRunnerStarting = function() {};
262-
OnTimeoutReporter.prototype.reportRunnerResults = function() {};
263-
OnTimeoutReporter.prototype.reportSuiteResults = function() {};
264-
OnTimeoutReporter.prototype.reportSpecStarting = function() {};
265-
OnTimeoutReporter.prototype.reportSpecResults = function(spec) {
266-
if (!spec.results().passed()) {
267-
var result = spec.results();
268-
var failureItem = null;
242+
OnTimeoutReporter.prototype.specDone = function(result) {
243+
if (result.status === 'failed') {
244+
for (var i = 0; i < result.failedExpectations.length; i++) {
245+
var failureMessage = result.failedExpectations[i].message;
269246

270-
var items_length = result.getItems().length;
271-
for (var i = 0; i < items_length; i++) {
272-
if (result.getItems()[i].passed_ === false) {
273-
failureItem = result.getItems()[i];
274-
275-
var jasmineTimeoutRegexp =
276-
/timed out after \d+ msec waiting for spec to complete/;
277-
if (failureItem.toString().match(jasmineTimeoutRegexp)) {
278-
this.callback();
279-
}
247+
if (failureMessage.match(/Timeout/)) {
248+
this.callback();
280249
}
281250
}
282251
}
283252
};
284-
OnTimeoutReporter.prototype.log = function() {};
285253

286254
// On timeout, the flow should be reset. This will prevent webdriver tasks
287255
// from overflowing into the next test and causing it to fail or timeout
@@ -292,7 +260,7 @@ jasmine.getEnv().addReporter(new OnTimeoutReporter(function() {
292260
console.warn('A Jasmine spec timed out. Resetting the WebDriver Control Flow.');
293261
console.warn('The last active task was: ');
294262
console.warn(
295-
(flow.activeFrame_ && flow.activeFrame_.getPendingTask() ?
263+
(flow.activeFrame_ && flow.activeFrame_.getPendingTask() ?
296264
flow.activeFrame_.getPendingTask().toString() :
297265
'unknown'));
298266
flow.reset();

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"name": "jasminewd",
3-
"description": "WebDriverJS adapter for Jasmine.",
2+
"name": "jasminewd2",
3+
"description": "WebDriverJS adapter for Jasmine2.",
44
"homepage": "https://github.com/angular/jasminewd",
55
"keywords": [
66
"test",
@@ -13,7 +13,7 @@
1313
"author": "Julie Ralph <ju.ralph@gmail.com>",
1414
"devDependencies": {
1515
"jshint": "2.5.0",
16-
"minijasminenode": "1.1.1",
16+
"jasmine": "2.1.1",
1717
"selenium-webdriver": "2.43.4"
1818
},
1919
"repository": {
@@ -23,8 +23,8 @@
2323
"main": "index.js",
2424
"scripts": {
2525
"pretest": "node_modules/.bin/jshint index.js spec",
26-
"test": "node node_modules/.bin/minijasminenode spec/adapterSpec.js"
26+
"test": "scripts/test.sh"
2727
},
2828
"license": "MIT",
29-
"version": "1.1.0"
29+
"version": "0.0.2"
3030
}

scripts/test.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
PASSING_SPECS="spec/support/passing_specs.json"
2+
FAILING_SPECS="spec/support/failing_specs.json"
3+
CMD_BASE="node node_modules/.bin/jasmine JASMINE_CONFIG_PATH="
4+
5+
echo "### running passing specs"
6+
CMD=$CMD_BASE$PASSING_SPECS
7+
$CMD
8+
[ "$?" -eq 0 ] || exit 1
9+
echo
10+
11+
EXPECTED_RESULTS="13 specs, 12 failures"
12+
echo "### running failing specs (expecting $EXPECTED_RESULTS)"
13+
CMD=$CMD_BASE$FAILING_SPECS
14+
res=`$CMD 2>/dev/null`
15+
results_line=`echo "$res" | tail -2 | head -1`
16+
echo "result: $results_line"
17+
[ "$results_line" = "$EXPECTED_RESULTS" ] || exit 1
18+
19+
echo "all pass"

0 commit comments

Comments
 (0)