fix: premature resolution of wait conditions when using scopedBy page objects#326
fix: premature resolution of wait conditions when using scopedBy page objects#326epfremmer wants to merge 2 commits into
Conversation
|
Travis CI has been really bad lately. It's not picking up new builds. |
|
Is this because this is on a fork? Did a force push and seems to have picked it up that time |
1bf8a3c to
c5f670a
Compare
|
@kellyselden finally got this to behave 🎉 |
| try { | ||
| return await this._browser.waitUntil(async () => await this.isExisting()); | ||
| } catch (e) { | ||
| // if the waitUntil condition fails fall through to the original non-scoped |
There was a problem hiding this comment.
This will unfortunately double the waiting time of failing tests, right? 30 secs to 60 secs.
There was a problem hiding this comment.
I think the default timeout is still 30 seconds. I tested this by commenting out all of the timeout overrides in one of the tests and allowing it to fail, which it did after 30 seconds
|
|
||
| await this.open('index.html'); | ||
|
|
||
| this.page._browser._browser.options.waitforTimeout = 10000; |
There was a problem hiding this comment.
The browser is global, this will leak across the whole test suite.
There was a problem hiding this comment.
Added a timeout value reset in afterEach hook
| element.disabled = false; | ||
|
|
||
| document.body.appendChild(element); | ||
| }, 100); |
There was a problem hiding this comment.
This has a race condition. If the assertion runs before this, the test will fail.
There was a problem hiding this comment.
This is intentional I want scopeBy to start running and respond to the element changing state in order to test that the wait condition is working.
|
|
||
| async waitForInsert() { | ||
| await handleError.call(this, async () => { | ||
| if (typeof this._selector === 'function') { |
There was a problem hiding this comment.
These can go in a reusable function, kinda like handleError so they both can use it.
There was a problem hiding this comment.
What do you want it called?
| await handleError.call(this, async () => { | ||
| if (typeof this._selector === 'function') { | ||
| try { | ||
| return await this._browser.waitUntil(async () => await this.isExisting()); |
There was a problem hiding this comment.
Should this go in the browser's waitForExist implementation?
There was a problem hiding this comment.
I tried that first and ran into so many issues because of all of the areas in which waitForExists impacts. Opted to hoist it up to here for simplicity sake.
| } | ||
|
|
||
| async waitForEnabled() { | ||
| await this.waitForInsert(); |
There was a problem hiding this comment.
I don't think these are necessary. The existing assumption is that you are already dealing with an existing element when you call these methods. You are waiting for an element to go from disabled to enabled. If you're element is missing to begin with, the consumer should be tasked with calling waitForInsert first.
There was a problem hiding this comment.
I feel like it is better developer ergonomics for consumers to not have to be concerned with that, as well as, fewer wait condition lines in tests.
I'll remove this, but I think we should consider putting it back in to make for a smoother testing experience.
c5f670a to
0e77136
Compare
When using a function style selector wait conditions fail early if the scoped selector does not yield any results. Instead we should continue to wait/check until the wait condition times out. Additionally in order to retain custom friendly error messages that include the selector that an exception occurred on we fallback to the original wait behavior which includes the custom errors.
before waiting on other conditions like enabled/visible
0e77136 to
d68f9aa
Compare
|
|
||
| async waitForInsert() { | ||
| await handleError.call(this, async () => { | ||
| if (typeof this._selector === 'function') { |
| if (this.browser && this.browser.options) { | ||
| // some of the tests need to validate wait conditions and modify the wait | ||
| // timeout so this needs to be reset to avoid leaking context between tests | ||
| this.browser.options.waitforTimeout = 0; |
There was a problem hiding this comment.
You should check out isExisting. It would be better to not assume any hard coded numbers here.
| await this.writeFixture('index.html', ` | ||
| <input class="foo"> | ||
| `); | ||
| describe(Element.prototype.waitForEnabled, function() { |
There was a problem hiding this comment.
Since the waiting in these methods was removed, I don't think any of these extra tests are needed anymore.
| await handleError.call(this, async () => { | ||
| if (typeof this._selector === 'function') { | ||
| try { | ||
| return await this._browser.waitUntil(async () => !(await this.isExisting())); |
There was a problem hiding this comment.
return value is not used in this method.
|
|
||
| await this.open('index.html'); | ||
|
|
||
| this.page._browser._browser.options.waitforTimeout = 10000; |
There was a problem hiding this comment.
do you think 1 second is enough?
There was a problem hiding this comment.
yep, I'm proposing switching to 1000, and also asking if that would be enough.
| .to.eventually.be.fulfilled; | ||
| }); | ||
|
|
||
| it('waits for scoped element to be inserted', async function() { |
There was a problem hiding this comment.
maybe putting these in their own describe block would be better? not sure, but then you could set the new timeout in the beforeEach.
When using things like
await this.users.scopeByName('some name').waitForVisible();the promise immediately rejects because the scoped selector cannot be found.Example error: