webdriverio-community / wdio-vscode-service

A service to test VSCode extensions from end to end using WebdriverIO
https://webdriverio-community.github.io/wdio-vscode-service/
MIT License
29 stars 23 forks source link

Bug: EditorView#getActiveTab() fails #100

Closed seanpoulter closed 5 months ago

seanpoulter commented 6 months ago

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 Promise.all when this.tab$$.map<T> should return a ChainablePromiseArray as a Promise<Array<T>>, not an Array<Promise<T>>. The code is here: https://github.com/webdriverio-community/wdio-vscode-service/blob/c25410fd6c8a339378724ef95dfa2d8bdbfc036d/src/pageobjects/editor/EditorView.ts#L303-L305

Discussion

christian-bromann commented 6 months ago
  • Let me know if you'd like a PR with a failing test and a fix

Yes! Any contributions would be much appreciated!

seanpoulter commented 6 months ago

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! :tada:

Edit: A PR would unblock test development at work. :blush:

christian-bromann commented 5 months ago

Awesome, looking forward!

rrousselGit commented 5 months ago

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.

christian-bromann commented 5 months ago

@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.

seanpoulter commented 5 months ago

Would the end goal be to support Promise.all(elem$$) from the shim?

christian-bromann commented 5 months ago

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.

seanpoulter commented 5 months ago

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.
christian-bromann commented 5 months ago

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'))
rrousselGit commented 5 months ago

Note that doing Promise.all(Array.from(buttons.map(...))) works.