Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

jasminewd2

Package Overview
Dependencies
Maintainers
3
Versions
17
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

jasminewd2 - npm Package Compare versions

Comparing version 0.1.1 to 2.0.0

maybePromise.js

88

CHANGELOG.md
# Changelog for jasminewd2
# 2.0.0
(Skipping 1.x because `0.0.1` was originally accidently published as `1.0.0`.)
## Breaking changes
- ([fae803c](https://github.com/angular/protractor/commit/fae803cd294e5413523d37bdaa282a9f96cd65a1))
pass webdriver instance into `init()` instead of using `require()` (#83)
So where as before you would write:
```js
require('jasminewd').init(webdriver.promise.controlFlow());
```
Now you will write:
```js
require('jasminewd').init(webdriver.promise.controlFlow(), webdriver);
```
This removes the dependency on `selenium-webdriver` and protects jasminewd from having a
different webdriver instance than Protractor, which could be a huge problem if they had different
control flow settings.
This is a breaking change because it changes the API for the `init` function.
I also removed the dependency on jasmine, which didn't do anything anyway. Maybe it should have
been a peerDependency but those are deprecated.
## Features
- ([171cbde](https://github.com/angular/protractor/commit/171cbde22f307bd3cc35c4c1785f171392dca8da))
Added types (though you'll have to wait for `@types/jasminewd2` to use them) (#79)
- ([27b4850](https://github.com/angular/protractor/commit/27b485019589cd662ee69e7920893ffa50774b97))
Support `SELENIUM_PROMISE_MANAGER=0` (#72)
There are three major ways this was done in this change:
* In `callWhenIdle`, if `flow.isIdle` is not defined, we assume we are working with a
`SimpleScheduler` instance, and so the flow is effectively idle.
* In `initJasmineWd`, if `flow.reset` is not defined, we assume we are working with a
`SimpleScheduler` instance, and so don't bother resetting the flow.
* In `wrapInControlFlow`, we use `flow.promise` to create a new promise if possible. Since
`new webdriver.promise.Promise()` would have always made a `ManagedPromise`, but `flow.promise`
will do the right thing.
* In `wrapCompare`, we avoid the webdriver library entirely, and never instance any extra
promises. Using `webdriver.promise.when` and `webdriver.promise.all` could have been a problem
if our instance of `webdriver` had the control flow turned on, but another instance somewhere
did not (or even the same instance, but just at a different point in time). Instead we use the
new `maybePromise` tool, which is a mess but is also exactly what we want.
* In `specs/*`, we replace `webdriver.promise.fulfilled` with `webdriver.promise.when`.
* In `specs/*`, a new version of `adapterSpec.js` and `errorSpec.js` are created:
`asyncAwaitAdapterSpec.ts` and `asyncAwaitErrorSpec.ts`.
I also also fixed a minor bug where we weren't correctly checking for promises inside an array of
expected results. Before we had:
```js
expected = Array.prototype.slice.call(arguments, 0);
...
webdriver.promise.isPromise(expected);
```
I thought about it for a little while, and there's no way that's correct. `expected` is an
`Array<any>`, there's no way it has a `.then` function.
Closes https://github.com/angular/jasminewd/issues/69
## Bug Fixes
- ([369a249](https://github.com/angular/protractor/commit/369a2499189fbcdc541f354cfede49dba9335e6b))
Don't rely on `webdriver.promise` functions (#82)
While we support `SELENIUM_PROMISE_MANAGER=0` already, we rely on `SimpleScheduler` and some other
utility functions which will be going away after the control flow has been fully deprecated. This
commit allows jasminewd to work without those utility functions, and even allows people to pass
jasminewd their own custom scheduler implementation.
This does not fix our tests, which will also break when those utility functions go away. See
https://github.com/angular/jasminewd/issues/81
Closes https://github.com/angular/jasminewd/issues/80
# 0.1.1

@@ -4,0 +92,0 @@

167

index.js

@@ -7,3 +7,5 @@ /**

var webdriver = require('selenium-webdriver');
var WebElement; // Equal to webdriver.WebElement
var idleEventName = 'idle'; // Equal to webdriver.promise.ControlFlow.EventType.IDLE
var maybePromise = require('./maybePromise');

@@ -53,13 +55,13 @@ /**

/**
* Calls a function once the control flow is idle
* @param {webdriver.promise.ControlFlow} flow The Web Driver control flow
* @param {!Function} fn The function to call
* Calls a function once the scheduler is idle. If the scheduler does not support the idle API,
* calls the function immediately. See scheduler.md#idle-api for details.
*
* @param {Object} scheduler The scheduler to wait for.
* @param {!Function} fn The function to call.
*/
function callWhenIdle(flow, fn) {
if (flow.isIdle()) {
function callWhenIdle(scheduler, fn) {
if (!scheduler.once || !scheduler.isIdle || scheduler.isIdle()) {
fn();
} else {
flow.once(webdriver.promise.ControlFlow.EventType.IDLE, function() {
fn();
});
scheduler.once(idleEventName, function() { fn(); });
}

@@ -70,5 +72,11 @@ }

/**
* Wraps a function so it runs inside a webdriver.promise.ControlFlow and
* waits for the flow to complete before continuing.
* @param {!webdriver.promise.ControlFlow} flow The WebDriver control flow.
* Wraps a function so it runs inside a scheduler's `execute()` block.
*
* In the most common case, this means wrapping in a `webdriver.promise.ControlFlow` instance
* to wait for the control flow to complete one task before starting the next. See scheduler.md
* for details.
*
* @param {!Object} scheduler See scheduler.md for details.
* @param {!Function} newPromise Makes a new promise using whatever implementation the scheduler
* prefers.
* @param {!Function} globalFn The function to wrap.

@@ -78,3 +86,3 @@ * @param {!string} fnName The name of the function being wrapped (e.g. `'it'`).

*/
function wrapInControlFlow(flow, globalFn, fnName) {
function wrapInScheduler(scheduler, newPromise, globalFn, fnName) {
return function() {

@@ -90,4 +98,4 @@ var driverError = new Error();

flow.execute(function controlFlowExecute() {
return new webdriver.promise.Promise(function(fulfill, reject) {
scheduler.execute(function schedulerExecute() {
return newPromise(function(fulfill, reject) {
function wrappedReject(err) {

@@ -108,3 +116,3 @@ var wrappedErr = new Error(err);

var ret = testFn();
if (webdriver.promise.isPromise(ret)) {
if (maybePromise.isPromise(ret)) {
ret.then(fulfill, wrappedReject);

@@ -115,5 +123,5 @@ } else {

}
}, flow);
});
}, 'Run ' + fnName + description + ' in control flow').then(
callWhenIdle.bind(null, flow, done), function(err) {
callWhenIdle.bind(null, scheduler, done), function(err) {
if (!err) {

@@ -124,3 +132,3 @@ err = new Error('Unknown Error');

err.stack = err.stack + '\nFrom asynchronous test: \n' + driverError.stack;
callWhenIdle(flow, done.fail.bind(done, err));
callWhenIdle(scheduler, done.fail.bind(done, err));
}

@@ -166,8 +174,13 @@ );

/**
* Initialize the JasmineWd adapter with a particlar webdriver instance. We
* pass webdriver here instead of using require() in order to ensure Protractor
* and Jasminews are using the same webdriver instance.
* @param {Object} flow. The ControlFlow to wrap tests in.
* Initialize the JasmineWd adapter with a particlar scheduler, generally a webdriver control flow.
*
* @param {Object=} scheduler The scheduler to wrap tests in. See scheduler.md for details.
* Defaults to a mock scheduler that calls functions immediately.
* @param {Object=} webdriver The result of `require('selenium-webdriver')`. Passed in here rather
* than required by jasminewd directly so that jasminewd can't end up up with a different version
* of `selenium-webdriver` than your tests use. If not specified, jasminewd will still work, but
* it won't check for `WebElement` instances in expect() statements and could cause control flow
* problems if your tests are using an old version of `selenium-webdriver` (e.g. version 2.53.0).
*/
function initJasmineWd(flow) {
function initJasmineWd(scheduler, webdriver) {
if (jasmine.JasmineWdInitialized) {

@@ -178,18 +191,57 @@ throw Error('JasmineWd already initialized when init() was called');

global.it = wrapInControlFlow(flow, global.it, 'it');
global.fit = wrapInControlFlow(flow, global.fit, 'fit');
global.beforeEach = wrapInControlFlow(flow, global.beforeEach, 'beforeEach');
global.afterEach = wrapInControlFlow(flow, global.afterEach, 'afterEach');
global.beforeAll = wrapInControlFlow(flow, global.beforeAll, 'beforeAll');
global.afterAll = wrapInControlFlow(flow, global.afterAll, 'afterAll');
// On timeout, the flow should be reset. This will prevent webdriver tasks
// from overflowing into the next test and causing it to fail or timeout
// as well. This is done in the reporter instead of an afterEach block
// to ensure that it runs after any afterEach() blocks with webdriver tasks
// get to complete first.
jasmine.getEnv().addReporter(new OnTimeoutReporter(function() {
console.warn('A Jasmine spec timed out. Resetting the WebDriver Control Flow.');
flow.reset();
}));
// Pull information from webdriver instance
if (webdriver) {
WebElement = webdriver.WebElement || WebElement;
idleEventName = (
webdriver.promise &&
webdriver.promise.ControlFlow &&
webdriver.promise.ControlFlow.EventType &&
webdriver.promise.ControlFlow.EventType.IDLE
) || idleEventname;
}
// Default to mock scheduler
if (!scheduler) {
scheduler = { execute: function(fn) {
return Promise.resolve().then(fn);
} };
}
// Figure out how we're getting new promises
var newPromise;
if (typeof scheduler.promise == 'function') {
newPromise = scheduler.promise.bind(scheduler);
} else if (webdriver && webdriver.promise && webdriver.promise.ControlFlow &&
(scheduler instanceof webdriver.promise.ControlFlow) &&
(webdriver.promise.USE_PROMISE_MANAGER !== false)) {
newPromise = function(resolver) {
return new webdriver.promise.Promise(resolver, scheduler);
};
} else {
newPromise = function(resolver) {
return new Promise(resolver);
};
}
// Wrap functions
global.it = wrapInScheduler(scheduler, newPromise, global.it, 'it');
global.fit = wrapInScheduler(scheduler, newPromise, global.fit, 'fit');
global.beforeEach = wrapInScheduler(scheduler, newPromise, global.beforeEach, 'beforeEach');
global.afterEach = wrapInScheduler(scheduler, newPromise, global.afterEach, 'afterEach');
global.beforeAll = wrapInScheduler(scheduler, newPromise, global.beforeAll, 'beforeAll');
global.afterAll = wrapInScheduler(scheduler, newPromise, global.afterAll, 'afterAll');
// Reset API
if (scheduler.reset) {
// On timeout, the flow should be reset. This will prevent webdriver tasks
// from overflowing into the next test and causing it to fail or timeout
// as well. This is done in the reporter instead of an afterEach block
// to ensure that it runs after any afterEach() blocks with webdriver tasks
// get to complete first.
jasmine.getEnv().addReporter(new OnTimeoutReporter(function() {
console.warn('A Jasmine spec timed out. Resetting the WebDriver Control Flow.');
scheduler.reset();
}));
}
}

@@ -199,3 +251,3 @@

global.expect = function(actual) {
if (actual instanceof webdriver.WebElement) {
if (WebElement && (actual instanceof WebElement)) {
throw Error('expect called with WebElement argument, expected a Promise. ' +

@@ -210,2 +262,6 @@ 'Did you mean to use .getText()?');

* expected values, as well as the `pass` property of the result.
*
* Wrapped matchers will return either `undefined` or a promise which resolves
* when the matcher is complete, depending on if the matcher had to resolve any
* promises.
*/

@@ -220,12 +276,8 @@ jasmine.Expectation.prototype.wrapCompare = function(name, matcherFactory) {

if (!webdriver.promise.isPromise(expectation.actual) &&
!webdriver.promise.isPromise(expected)) {
compare(expectation.actual, expected);
} else {
webdriver.promise.when(expectation.actual).then(function(actual) {
return webdriver.promise.all(expected).then(function(expected) {
return compare(actual, expected);
});
// Return either undefined or a promise of undefined
return maybePromise(expectation.actual, function(actual) {
return maybePromise.all(expected, function(expected) {
return compare(actual, expected);
});
}
});

@@ -245,8 +297,5 @@ function compare(actual, expected) {

if (webdriver.promise.isPromise(result.pass)) {
return webdriver.promise.when(result.pass).then(compareDone);
} else {
return compareDone(result.pass);
}
return maybePromise(result.pass, compareDone);
// compareDone always returns undefined
function compareDone(pass) {

@@ -285,9 +334,5 @@ var message = '';

var result = matcher.compare.apply(null, args);
if (webdriver.promise.isPromise(result.pass)) {
result.pass = result.pass.then(function(pass) {
return !pass;
});
} else {
result.pass = !result.pass;
}
result.pass = maybePromise(result.pass, function(pass) {
return !pass;
});
return result;

@@ -294,0 +339,0 @@ }

@@ -14,9 +14,13 @@ {

"author": "Julie Ralph <ju.ralph@gmail.com>",
"dependencies": {
"devDependencies": {
"@types/jasmine": "^2.5.40",
"@types/node": "^6.0.56",
"@types/selenium-webdriver": "^2.53.38",
"jasmine": "2.4.1",
"selenium-webdriver": "3.0.1"
},
"devDependencies": {
"jshint": "^2.9.4",
"typescript": "^2.0.10"
"selenium-webdriver": "3.0.1",
"tslint": "^4.2.0",
"tslint-eslint-rules": "^3.2.3",
"typescript": "^2.0.10",
"vrsource-tslint-rules": "^4.0.0"
},

@@ -30,4 +34,6 @@ "repository": {

"jshint": "jshint index.js spec",
"tsc": "tsc -t ES2015 spec/asyncAwaitSpec.ts",
"pretest": "npm run jshint && npm run tsc",
"tslint": "tslint spec/*.ts",
"lint": "npm run jshint && npm run tslint",
"tsc": "tsc; cp spec/*.js built_spec",
"pretest": "npm run lint && npm run tsc",
"test": "scripts/test.sh"

@@ -39,3 +45,3 @@ },

},
"version": "0.1.1"
"version": "2.0.0"
}

@@ -31,9 +31,8 @@ jasminewd [![Build Status](https://travis-ci.org/angular/jasminewd.svg?branch=master)](https://travis-ci.org/angular/jasminewd)

Assumes selenium-webdriver as a peer dependency.
In your setup:
```js
// In your setup.
var JasmineRunner = require('jasmine');
var jrunner = new JasmineRunner();
require('jasminewd2');
var webdriver = require('selenium-webdriver');

@@ -45,7 +44,11 @@ global.driver = new webdriver.Builder().

require('jasminewd2').init(driver.controlFlow(), webdriver);
jrunner.projectBaseDir = '';
jrunner.execute(['**/*_spec.js']);
```
// In your tests
In your tests:
```js
describe('tests with webdriver', function() {

@@ -66,2 +69,20 @@ it('will wait until webdriver is done', function() {

TypeScript
----------
For the typings related to the changes in the global jasmine variables (e.g.
allowing `it()` blocks to return a promise), we publish the package
`@types/jasminewd2`. If you are writing tests using jasminewd (including
Protractor tests), be sure to include `@types/jasminewd2` in your
`devDependencies`, as these global type modifications are ***not*** bundled with
the `jasminewd2` npm module.
jasminewd also exports one function directly: `init`. Unfortunately, we do not
publish typings for this function. If you call this function directly (e.g. you
are a Protractor dev), you should simply do:
```ts
require('jasminewd2').init(controlFlow, webdriver);
```
`async` functions / `await`

@@ -75,2 +96,3 @@ ---------------------------

still use them, but if you do then you will have to use `await`/Promises for
almost all your synchronization. See `spec/asyncAwaitSpec.ts` for details.
almost all your synchronization. See `spec/asyncAwaitAdapterSpec.ts` and
`spec/asyncAwaitErrorSpec.ts` for examples.
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc