webdriverio-community / wdio-vscode-service

A service to test VSCode extensions from end to end using WebdriverIO

Home Page:https://webdriverio-community.github.io/wdio-vscode-service/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

executeCommand() runs the first matching command, not the command itself

jeffb-sfdc opened this issue · comments

The extension I work on is pretty complicated, and has many commands. I'm attempting to automate running one of the commands but I'm finding that when the text of the command is passed to executeCommand(), a "fuzzy match" is performed and the first matching command runs, not the command I specified.

Steps to reproduce:

  1. Let's say an extension has the following commands:
    Create and Set Up Project
    Create Project
    Create Project with Boilerplate Example

  2. Type SHIFT-CMD-P and open the command palette

  3. Type, Create Project
    -> Notice how VS Code filters the commands, and how that the commands that appear are the same that are listed in step 1, and appear in the same order

  4. Now write some e2e test code, and add the following:

const workbench = await browser.getWorkbench();
const command = 'Create Project';
// await workbench.executeCommand(command);
const prompt = await workbench.openCommandPrompt();
await prompt.setText(`>${command}`);
await prompt.confirm();
  1. And now run this test and execute this code

Result:
await workbench.openCommandPrompt() opens the command palette
...and prompt.setText() sets the text to ">Create Project"
...however, this filters the list and displays all matching commands. The first command listed is "Create and Set Up Project", and when prompt.confirm() executes, the first command listed runs, which in this case is "Create and Set Up Project", not "Create Project"

The implementation for executeCommand() is:

    async executeCommand (command: string): Promise<void> {
        const prompt = await this.openCommandPrompt()
        await prompt.setText(`>${command}`)
        await prompt.confirm()
    }

A possible fix for this would be to change executeCommand() to:

    async executeCommand (command: string): Promise<void> {
        const prompt = await this.openCommandPrompt()
        await prompt.setText(`>${command}`)
        const quickPicks = await prompt.getQuickPicks()
        for (const quickPick of quickPicks) {
            const label = await quickPick.getLabel()
            if (label === command) {
                await quickPick.select()
                return
            }
        }

        throw new Error('Command not found')
    }

Or maybe call out the fuzziness and spilt executeCommand() in to:

    async executeFuzzyCommand (command: string): Promise<void> {
        const prompt = await this.openCommandPrompt()
        await prompt.setText(`>${command}`)
        await prompt.confirm()
    }

    async executeExactCommand (command: string): Promise<void> {
        const prompt = await this.openCommandPrompt()
        await prompt.setText(`>${command}`)
        const quickPicks = await prompt.getQuickPicks()
        for (const quickPick of quickPicks) {
            const label = await quickPick.getLabel()
            if (label === command) {
                await quickPick.select()
                return
            }
        }

        throw new Error('Command not found')
    }

@christian-bromann your thoughts?

How about this interface:

  • async executeCommand (command: string): Promise<void>: basically what we have right now
  • async executeQuickPick (label: RegExp): Promise<void>: runs the command matching the quick pick label, if no label matches, throw an error

?

I posted #49 to address this issue.

Let's continue convo in #49