implement test specifier configuration#64
Conversation
| if (!contents.includes("node:test")) { | ||
| this.deleteFileTests(uri.toString()); | ||
| return; | ||
| } |
There was a problem hiding this comment.
Unfortunately, this is no longer a good cheap relevancy test - but if you'd like, I'd be happy to update it to be:
"If your test specifiers only reference packages, and not relative imports - then we can construct a cheap relevancy test for those packages".
There was a problem hiding this comment.
We could match the extensionless basename of any TestFunctionSpecifierConfig.name. Less specific but still cheaper than parsing the AST unnecessarily.
src/controller.ts
Outdated
| } | ||
|
|
||
| const tree = parseSource(contents); | ||
| const tree = parseSource(contents, folder, uri, this.testSpecifiers); |
There was a problem hiding this comment.
Kind of a gross API, but I wanted to keep the code structure as similar as possible without getting your feedback. Making these parameters optional meant most of the tests didn't need change.
| watcher.onDidCreate((uri) => this.includeTest(uri.fsPath) && this._syncFile(uri)); | ||
| watcher.onDidChange((uri) => this.includeTest(uri.fsPath) && this._syncFile(uri)); | ||
| watcher.onDidCreate((uri) => this.syncFile(uri)); | ||
| watcher.onDidChange((uri) => this.syncFile(uri)); |
There was a problem hiding this comment.
I believe this is what syncFile was doing anyway.
| */ | ||
| export interface TestFunctionSpecifierConfig { | ||
| /** The names of the functions that should be included in the test runner view */ | ||
| name: string[] | string; |
There was a problem hiding this comment.
Maybe this should always be an array - I didn't realize the JSON schema in the package.json was going to be awkward to express this union type.
connor4312
left a comment
There was a problem hiding this comment.
Looks generally sane, some comments!
| }, | ||
| ]); | ||
|
|
||
| const testSpecifiers = new ConfigValue("testSpecifiers", defaultTestFunctionSpecifiers); |
There was a problem hiding this comment.
Make sure to register an onChange listener for this down below, like we do for includePatterns
src/controller.ts
Outdated
| include: string[], | ||
| exclude: string[], | ||
| extensionConfigs: ExtensionConfig[], | ||
| testSpecifiers: TestFunctionSpecifierConfig[], |
There was a problem hiding this comment.
| testSpecifiers: TestFunctionSpecifierConfig[], | |
| private readonly testSpecifiers: TestFunctionSpecifierConfig[], |
There was a problem hiding this comment.
Oh interesting, I didn't know about this little syntactic sugar.
src/controller.ts
Outdated
| * @param contents the file contents of uri - to be used as an optimization | ||
| */ | ||
| private async _syncFile(uri: vscode.Uri, contents?: string) { | ||
| const folder = vscode.workspace.getWorkspaceFolder(uri); |
There was a problem hiding this comment.
The Controller is already rooted at a particular workspace folder. We shouldn't have any URIs passed here that aren't in that workspace folder (if so that's a bug)
There was a problem hiding this comment.
ok, perfect - I'll update.
| if (!contents.includes("node:test")) { | ||
| this.deleteFileTests(uri.toString()); | ||
| return; | ||
| } |
There was a problem hiding this comment.
We could match the extensionless basename of any TestFunctionSpecifierConfig.name. Less specific but still cheaper than parsing the AST unnecessarily.
src/parsing.ts
Outdated
|
|
||
| let importValue = node.source.value; | ||
| if (node.source.value.startsWith("./") || node.source.value.startsWith("../")) { | ||
| if (!folder || !fileUri) { |
There was a problem hiding this comment.
I think neither of these should ever be undefined here. We only parse from Controllers rooted in a workspace folder, and only parse files once saved on disk.
There was a problem hiding this comment.
That is correct - but since I left them optional, I was just making Typescript happy until I had your feedback on what to do for this API. I'll make them required and remove these superfluous checks.
src/parsing.ts
Outdated
| Path.resolve(Path.dirname(fileUri.fsPath), node.source.value), | ||
| ); | ||
|
|
||
| importValue = `./${importRelativeToRoot}`; |
There was a problem hiding this comment.
We need to normalize to forward slashes on Windows
There was a problem hiding this comment.
Good catch, but hmm. I think the issue here is that I am moving from a URI "path" (which would be the same on all platforms) to a filesystem path.
If the logic stayed as a URI, then I don't think we'd need to worry about that. Let me see if I can re-work this logic and avoid switching to filesystem paths, so we can avoid the cross platform issues.
| for (const spec of node.specifiers) { | ||
| const specType = spec.type; | ||
| if (specType === C.ImportDefaultSpecifier || specType === C.ImportNamespaceSpecifier) { | ||
| if (validNames.has("default")) { |
There was a problem hiding this comment.
The filter shouldn't happen at this level. This covers cases like import * as t from 'node:test'. We should then match validNames on accesses like t.test or t.suite (where the lower branch covers the cases like import { test } from 'node:test)
The unit tests in parsing.test.ts can help you. Run with npx vitest
There was a problem hiding this comment.
I think I didn't understand this comment fully until now. But I believe this is solved now.
src/parsing.ts
Outdated
| text: string, | ||
| folder?: vscode.WorkspaceFolder, | ||
| fileUri?: vscode.Uri, | ||
| testFunctions?: TestFunctionSpecifierConfig[], |
There was a problem hiding this comment.
This should always by defined, the ConfigValue will provide your default value. Just update unit tests :)
|
@connor4312 thank you for the review - quite a few of your comment were related to some of the API choices I had to make because I was struggling to get the unit tests working. Let me see if I can elaborate a bit more to explain the situation, and see if you happen to know a solution. Firstly: I am able to run the existing unit tests just fine. No issues at all. When I was trying to write new unit tests - which I do need a lot of - I hit a snag... I need the tests to pass a Alternatively
I'm off for the weekend, but will pick this back up next week Monday. |
Yea, this is something that's injected in the vscode extension host but not Node unit tests. I would just stub out the relevant bits. I think the only complex part is URIs, and for that you can add Or you can just pass in the |
|
OK perfect - I'll make that change and significantly beef up the parsing unit tests, and fix the inevitable issues that arise. Have a great weekend! |
This allows unit test to be written and run without VS code.
skabbes
left a comment
There was a problem hiding this comment.
OK, I believe I have made all of the requested changes.
A few notes...
I checked vscode-uri, and noticed that they were just essentially using node:path/posix so used that instead, and stopped using fsPath completely with the URIs.
I implemented the cheap "might have tests" check in exactly the way you suggested (see fileMightHaveTests).
|
Nice! I think the last thing is that |
|
Thanks! I'll add a negative test for that and update now. |
|
Thank you for all the help, and for merging, if you could cut a new release at your convenience - I'd be very grateful! |
|
Published in 1.7.0, thanks for the PR! |

Original Discussion here:
#63