-
Notifications
You must be signed in to change notification settings - Fork 11
implement test specifier configuration #64
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
implement test specifier configuration #64
Conversation
| if (!contents.includes("node:test")) { | ||
| this.deleteFileTests(uri.toString()); | ||
| return; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks generally sane, some comments!
| }, | ||
| ]); | ||
|
|
||
| const testSpecifiers = new ConfigValue("testSpecifiers", defaultTestFunctionSpecifiers); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make sure to register an onChange listener for this down below, like we do for includePatterns
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you!
src/controller.ts
Outdated
| include: string[], | ||
| exclude: string[], | ||
| extensionConfigs: ExtensionConfig[], | ||
| testSpecifiers: TestFunctionSpecifierConfig[], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| testSpecifiers: TestFunctionSpecifierConfig[], | |
| private readonly testSpecifiers: TestFunctionSpecifierConfig[], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, perfect - I'll update.
| if (!contents.includes("node:test")) { | ||
| this.deleteFileTests(uri.toString()); | ||
| return; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to normalize to forward slashes on Windows
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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