Bug: EditorView#getActiveTab() fails
seanpoulter opened this issue · comments
Context
When I do something to make a Webview open in a new Editor Tab
Then I want to wait for it to appear
And I create a new PageObject with it
Problem
When I run:
const workbench = await browser.getWorkbench();
const editorView = await workbench.getEditorView();
const activeTab = await editorView.getActiveTab();
I see:
TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator)
at EditorGroup.getOpenTabs
because we're using . The code is here:Promise.all
when this.tab$$.map<T>
should return a ChainablePromiseArray
as a Promise<Array<T>>
, not an Array<Promise<T>>
wdio-vscode-service/src/pageobjects/editor/EditorView.ts
Lines 303 to 305 in c25410f
Discussion
- Let me know if you'd like a PR with a failing test and a fix
- Is there a better way to wait for the webview? It seems like I should probably be able to
new MyWebview().wait()
?
- Let me know if you'd like a PR with a failing test and a fix
Yes! Any contributions would be much appreciated!
I can open a PR with an alternative implementation that avoids the bug but I don't understand the root cause (yet). Even with the Node.js debug tools I haven't found the problem. I'm going to try reproducing the problem unit testing shim.ts* from wdio-utils
. That's lovely code BTW! 🎉
Edit: A PR would unblock test development at work. 😊
Awesome, looking forward!
It seems like the issue is with all elem$$
when passed to an API that expects an array
Because elem$$
does not return an array, but something array-looking.
This happens in a few places. It's probably worth doing a global $$
search to make sure they aren't passed to APIs that expect arrays.
@rrousselGit these page objects have been adopted from a different project and rewritten for WebdriverIO. Chances are that there are more locations where this happens. I will go ahead and close this one as it has been resolved. I hope to be able to update the package later this week.
Would the end goal be to support Promise.all(elem$$)
from the shim?
Would the end goal be to support
Promise.all(elem$$)
from the shim?
That would be a nice feature. I was under the assumption that this already works already since internally we create an Array and just extend the prototype object to allow async array methods, like map
, filter
etc.
I'm poking at cb/driver-setup-update and tsc
is flagging this:
> wdio-vscode-service@5.2.3 build:ts
> tsc -b .
src/pageobjects/dialog/ModalDialog.ts:47:42 - error TS2769: No overload matches this call.
Overload 1 of 2, '(values: readonly unknown[] | []): Promise<[] | unknown[]>', gave the following error.
Argument of type 'Promise<string[]>' is not assignable to parameter of type 'readonly unknown[] | []'.
Overload 2 of 2, '(values: Iterable<unknown>): Promise<unknown[]>', gave the following error.
Argument of type 'Promise<string[]>' is not assignable to parameter of type 'Iterable<unknown>'.
Property '[Symbol.iterator]' is missing in type 'Promise<string[]>' but required in type 'Iterable<unknown>'.
47 const titles = await Promise.all(buttons.map(async (btn) => btn.getAttribute('title')))
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/pageobjects/dialog/ModalDialog.ts:47:42
47 const titles = await Promise.all(buttons.map(async (btn) => btn.getAttribute('title')))
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Did you forget to use 'await'?
node_modules/typescript/lib/lib.es2015.iterable.d.ts:49:5
49 [Symbol.iterator](): Iterator<T>;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'[Symbol.iterator]' is declared here.
src/pageobjects/dialog/ModalDialog.ts:47:42
47 const titles = await Promise.all(buttons.map(async (btn) => btn.getAttribute('title')))
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Did you forget to use 'await'?
Found 1 error.
ERROR: "build:ts" exited with 1.
All these Promise.all
calls are no necessary at all. We can update them like so:
- const titles = await Promise.all(buttons.map(async (btn) => btn.getAttribute('title')))
+ const titles = await buttons.map(async (btn) => btn.getAttribute('title'))
Note that doing Promise.all(Array.from(buttons.map(...)))
works.