Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(SELENIUM_PROMISE_MANAGER): Support SELENIUM_PROMISE_MANAGER=0 #72

Merged
merged 1 commit into from
Jan 13, 2017

Conversation

sjelin
Copy link
Contributor

@sjelin sjelin commented Dec 17, 2016

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

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 #69

@sjelin sjelin changed the title feat(SELENIUM_PROMISE_MANAGER=0): Improve support for SELENIUM_PROMIS… feat(SELENIUM_PROMISE_MANAGER=0): Improve support for SELENIUM_PROMISE_MANAGER=0 Dec 17, 2016
@sjelin
Copy link
Contributor Author

sjelin commented Dec 28, 2016

This PR is so lonely 😢 @juliemr @cnishina @mgiambalvo

@juliemr juliemr self-assigned this Jan 3, 2017
@sjelin
Copy link
Contributor Author

sjelin commented Jan 3, 2017

Probably needs tests. I'll probably just do adapterSpec.js again but with async await.

Copy link
Member

@juliemr juliemr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, please add some tests :)

return webdriver.promise.all(expected).then(function(expected) {
return compare(actual, expected);
});
expectation.actual = extractPromiseFromDeferred(expectation.actual);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused here. Before, expectation.actual could potentially be a regular value or a promise. Being a deferred wasn't on the table - why is this a concern now? (Commit message says it's "needed for selenium 3", but why?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I was referencing another commit from the beta branch: 70c9f62

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the record: we looked into this offline, and we can't figure out why that change was originally made. As far as we can tell, there's no reason anyone should do expect(foo)... where foo is a deferred, not a promise.

In selenium-webdriver@2, all deferred objects were promises. That's changed with version 3, and is a breaking change, but we don't expect this to affect very many users at all (and it will be released in a major version).

So we're going to remove the special logic to handle deferreds,

* is directly returned. Otherwise, a promise (generated by the .then
* functions in vals) resolving to the callback's return value is returned.
*/
function maybePromises(vals, callback) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should have a test for this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. I'll spin it out into a helper file to make unit testing easy

@sjelin sjelin changed the title feat(SELENIUM_PROMISE_MANAGER=0): Improve support for SELENIUM_PROMISE_MANAGER=0 feat(SELENIUM_PROMISE_MANAGER=0): Support SELENIUM_PROMISE_MANAGER=0 Jan 11, 2017
@sjelin sjelin changed the title feat(SELENIUM_PROMISE_MANAGER=0): Support SELENIUM_PROMISE_MANAGER=0 feat(SELENIUM_PROMISE_MANAGER=0): Support SELENIUM_PROMISE_MANAGER=0 Jan 11, 2017
@sjelin sjelin changed the title feat(SELENIUM_PROMISE_MANAGER=0): Support SELENIUM_PROMISE_MANAGER=0 feat(SELENIUM_PROMISE_MANAGER): Support SELENIUM_PROMISE_MANAGER=0 Jan 11, 2017
@sjelin
Copy link
Contributor Author

sjelin commented Jan 11, 2017

@juliemr after a solid week of getting side tracked, I finally returned to this PR and did everything you told me to do!

It turns out originally this was only supposed to be a step towards support, which is why there weren't tests. Now this PR is the full thing, which is why it is so much longer than it was before. I've also updated the PR/commit title/description to reflect that change

@@ -0,0 +1,58 @@
/**
* This file implements jasminewd's peculiar alternatives to Promise.resolve()
* and Promise.all(). Do not use the code from this file as pollyfill for
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: polyfill

@@ -1,110 +1,110 @@
var webdriver = require('selenium-webdriver');
import {promise as wdpromise, WebElement} from 'selenium-webdriver';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a compelling reason to move this to TS?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was important back when I was using noImplicitAny, and will be important again in #79. Removed from this PR and transferred over

@@ -104,6 +104,10 @@ describe('things that should fail', function() {
});

describe('native promises', function() {
it('should have done argument override return returned promise', function(done) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the description string here needs clarification - maybe:

it should time out if done argument is never called, even if promise is returned

?

@@ -0,0 +1,14 @@
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be cleaner for ts to output files to a folder, maybe spec/built, so that if we add more ts files later we don't need to special case every one in the .ignore files.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went with built_spec/ instead because keeping the files in the same location relative to index.js is important.

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 angular#69
@sjelin
Copy link
Contributor Author

sjelin commented Jan 12, 2017

@juliemr All comments addressed

@juliemr
Copy link
Member

juliemr commented Jan 13, 2017

LGTM

@sjelin sjelin merged commit 27b4850 into angular:jasminewd2 Jan 13, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support SELENIUM_PROMISE_MANAGER=0
2 participants