Open jeffb-sfdc opened 2 years ago
executeCommand
is how you tell VS Code to run a command. The issue you referenced is designed behavior of canonical URIs in VS Code and is not related to the command system.A more complete example would probably better live in https://github.com/microsoft/vscode-extension-samples
@connor4312
re. 1: I don't want to derail the issue that I posted and get off topic, but if curious, this is why calling vscode.commands.executeCommand()
directly is different from invoking the command via VS Code's UI:
In extension.ts, change the HelloWorld callback function to:
let disposable = vscode.commands.registerCommand('helloworld.helloWorld', (firstArg: any, secondArg: any, thirdArg: any) => {
debugger;
// The code you place here will be executed every time your command is executed
// Display a message box to the user
vscode.window.showInformationMessage('Hello World from HelloWorld!');
});
Next, in package.json, add the command to the explorer context:
.
.
.
"contributes": {
"commands": [
{
"command": "helloworld.helloWorld",
"title": "Hello World"
}
],
"menus": {
"explorer/context": [
{
"command": "helloworld.helloWorld"
}
]
}
},
.
.
.
Next, in extension.test.ts, change Sample test
to:
test('Sample test', async () => {
debugger;
await vscode.commands.executeCommand(
'helloworld.helloWorld',
{
foo: 'myFoo',
bar: 'my-bar'
},
'foo-bar-baz'
);
assert.strictEqual(-1, [1, 2, 3].indexOf(5));
assert.strictEqual(-1, [1, 2, 3].indexOf(0));
});
After compiling...
The debugger should break into the callback for the helloWorld
command, and if you audit the parameters passed in to the callback, firstArg is a URI of the first selected file, and secondArg is an array of URIs of all selected files
Sample test
debugger
in the helloWorld callbackIn this case, the arguments being passed to the command are being constructed in the test itself, not in VS Code, thus hiding any bugs that might come up.
re. 2: Thanks! I'll check out vscode-extension-tester
re. residing in https://github.com/microsoft/vscode-extension-samples: Maybe... it looks like https://github.com/microsoft/vscode-test/tree/main/sample/test/suite ...is pretty much exactly the same as: https://github.com/microsoft/vscode-extension-samples/tree/main/helloworld-test-sample/src/test/suite ...so it kinda seems like this repo is redundant then.
Well, regardless, I think adding some "real world"-like examples either here or to vscode-extension-samples (and the boilerplate code that gets generated when running yo generator-code
) would be better. The repo already has suite
and suite2
(https://github.com/microsoft/vscode-test/tree/main/sample/test), perhaps more suites cold be added there.
In steps 1-4, the command is being triggered from the context menu in the explorer view. When called in this way, certain arguments are being passed to a command. However, commands can be called from anywhere, even multiple places in the VS Code UI (depending on its package contributions) or other extensions (if they use executeCommand.) If called from other places, they can receive different arguments. Commands are "public functions" and VS Code doesn't enforce a single schema for any given command's arguments.
While the sample integration test does a great job of demonstrating how to set up the downloading of VS Code and setting up running the tests within VS Code, the integration test (
https://github.com/microsoft/vscode-test/blob/main/sample/test/suite/extension.test.ts
) which tests the sample extension (https://github.com/microsoft/vscode-test/blob/main/sample/src/extension.ts
) doesn't have much substance to it - it validates thatarray.indexOf()
returns -1, which doesn't really have much to do with validating the extension, and doesn't demonstrate how to drive the UI, and check & validate the state/contents of the UI after the test finished.It would be very helpful if there were examples demonstrating how to implement integration tests (end-to-end/integration tests, not unit tests), and show how to drive the UI, and test/validate the UI for expected results.
Now, one might say, "it's easy, just..." 1) Add
vscode.commands.executeCommand('helloworld.helloWorld')
to the test 2) and then write a spy to verify thatvscode.window.showInformationMessage()
is called, and that it's called with "Hello World!"This has some shortcomings:
Directly calling
executeCommand()
and passing mocked data (the "rest" parameter) which we mock ourselves is not adequate. We recently found a bug where VS Code passes bad data to commands. (see https://github.com/microsoft/vscode/issues/152993). Microsoft says it's not a bug, but it is for us - when we're passed an incorrect file path, a library we depend on fails, so we wrote code to get around this and we need to write tests which automate this end to end. For this reason, we want to issue an instruction to VS Code itself, and tell VS Code to "run the "ABC" command", and not directly callexecuteCommand()
We need to be able to drive the UI, and the driving needs to be performed at a high level - as if the user was typing themselves, and not programmatically by calling APIs or functions directly. Suppose our extension presents the user with a text prompt when the extension's command is invoked, and the user is prompted to enter in a string. We need to be able to write a test which waits for the text input prompt to appear, and then enter/input some text. Now suppose that when the command is invoked, that the user is prompted for input several times (to input several different values). We don't want to stub functions - we have a goal to make our integration tests be end-to-end, and be as if the user was inputing the data themselves, so this means no mocks/stubs.
What we want to do might not be aligned with how you intended integration tests to work, but...
Thanks,
Jeff