Skip to content

Commit e9ef598

Browse files
sjelincnishina
authored andcommitted
chore(promises): Wait for promises explicitly (#70)
See #68 for details
1 parent 90ec028 commit e9ef598

File tree

5 files changed

+81
-25
lines changed

5 files changed

+81
-25
lines changed

.jshintignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
spec/asyncAwaitSpec.js
1+
./spec/asyncAwaitSpec.js

index.js

+38-23
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,6 @@
66

77
var webdriver = require('selenium-webdriver');
88

9-
/**
10-
* Wraps a function so that all passed arguments are ignored.
11-
* @param {!Function} fn The function to wrap.
12-
* @return {!Function} The wrapped function.
13-
*/
14-
function seal(fn) {
15-
return function() {
16-
fn();
17-
};
18-
}
19-
209
/**
2110
* Validates that the parameter is a function.
2211
* @param {Object} functionToValidate The function to validate.
@@ -59,10 +48,28 @@ function validateString(stringtoValidate) {
5948
}
6049
}
6150

51+
/**
52+
* Calls a function once the control flow is idle
53+
* @param {webdriver.promise.ControlFlow} flow The Web Driver control flow
54+
* @param {!Function} fn The function to call
55+
*/
56+
function callWhenIdle(flow, fn) {
57+
if (flow.isIdle()) {
58+
fn();
59+
} else {
60+
flow.once(webdriver.promise.ControlFlow.EventType.IDLE, function() {
61+
fn();
62+
});
63+
}
64+
}
65+
66+
6267
/**
6368
* Wraps a function so it runs inside a webdriver.promise.ControlFlow and
6469
* waits for the flow to complete before continuing.
70+
* @param {!webdriver.promise.ControlFlow} flow The WebDriver control flow.
6571
* @param {!Function} globalFn The function to wrap.
72+
* @param {!string} fnName The name of the function being wrapped (e.g. `'it'`).
6673
* @return {!Function} The new function.
6774
*/
6875
function wrapInControlFlow(flow, globalFn, fnName) {
@@ -78,30 +85,38 @@ function wrapInControlFlow(flow, globalFn, fnName) {
7885

7986
flow.execute(function controlFlowExecute() {
8087
return new webdriver.promise.Promise(function(fulfill, reject) {
88+
function wrappedReject(err) {
89+
var wrappedErr = new Error(err);
90+
reject(wrappedErr);
91+
}
8192
if (async) {
8293
// If testFn is async (it expects a done callback), resolve the promise of this
8394
// test whenever that callback says to. Any promises returned from testFn are
8495
// ignored.
8596
var proxyDone = fulfill;
86-
proxyDone.fail = function(err) {
87-
var wrappedErr = new Error(err);
88-
reject(wrappedErr);
89-
};
97+
proxyDone.fail = wrappedReject;
9098
testFn(proxyDone);
9199
} else {
92100
// Without a callback, testFn can return a promise, or it will
93101
// be assumed to have completed synchronously.
94-
fulfill(testFn());
102+
var ret = testFn();
103+
if (webdriver.promise.isPromise(ret)) {
104+
ret.then(fulfill, wrappedReject);
105+
} else {
106+
fulfill(ret);
107+
}
95108
}
96109
}, flow);
97-
}, 'Run ' + fnName + description + ' in control flow').then(seal(done), function(err) {
98-
if (!err) {
99-
err = new Error('Unknown Error');
100-
err.stack = '';
110+
}, 'Run ' + fnName + description + ' in control flow').then(
111+
callWhenIdle.bind(null, flow, done), function(err) {
112+
if (!err) {
113+
err = new Error('Unknown Error');
114+
err.stack = '';
115+
}
116+
err.stack = err.stack + '\nFrom asynchronous test: \n' + driverError.stack;
117+
callWhenIdle(flow, done.fail.bind(done, err));
101118
}
102-
err.stack = err.stack + '\nFrom asynchronous test: \n' + driverError.stack;
103-
done.fail(err);
104-
});
119+
);
105120
};
106121
}
107122

scripts/test.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ $CMD
99
[ "$?" -eq 0 ] || exit 1
1010
echo
1111

12-
EXPECTED_RESULTS="16 specs, 15 failures"
12+
EXPECTED_RESULTS="18 specs, 16 failures"
1313
echo "### running failing specs (expecting $EXPECTED_RESULTS)"
1414
CMD=$CMD_BASE$FAILING_SPECS
1515
echo "### $CMD"

spec/adapterSpec.js

+21
Original file line numberDiff line numberDiff line change
@@ -242,4 +242,25 @@ describe('webdriverJS Jasmine adapter', function() {
242242
expect(spec3.description).toBe('test3');
243243
});
244244
});
245+
246+
describe('native promises', function() {
247+
var currentTest = null;
248+
249+
it('should wait for webdriver events sent from native promise', function() {
250+
currentTest = 'A';
251+
return new Promise(function(resolve) {
252+
setTimeout(function() {
253+
fakeDriver.sleep(100).then(function() {
254+
expect(currentTest).toBe('A');
255+
});
256+
resolve();
257+
}, 100);
258+
});
259+
});
260+
261+
it('should not start a test before another finishes', function(done) {
262+
currentTest = 'B';
263+
setTimeout(done, 200);
264+
});
265+
});
245266
});

spec/errorSpec.js

+20
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,24 @@ describe('things that should fail', function() {
102102
expect(fakeDriver.getDecimalNumber()).toBeCloseTo(3.1);
103103
expect(fakeDriver.getDecimalNumber()).not.toBeCloseTo(3.14);
104104
});
105+
106+
describe('native promises', function() {
107+
var testADone = false;
108+
109+
it('should handle rejection from native promise', function() {
110+
return new Promise(function(resolve, reject) {
111+
setTimeout(function() {
112+
fakeDriver.sleep(100).then(function() {
113+
testADone = true;
114+
});
115+
reject('Rejected promise');
116+
}, 100);
117+
});
118+
});
119+
120+
it('should not start a test before another finishes', function(done) {
121+
expect(testADone).toBe(true); // this test actually passes
122+
setTimeout(done, 200);
123+
});
124+
});
105125
});

0 commit comments

Comments
 (0)