Skip to content
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

Convert to native test API #90

Open
wants to merge 111 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 95 commits
Commits
Show all changes
111 commits
Select commit Hold shift + click to select a range
ad4371e
Add new test loader that uses the native Test API
Tabby Feb 16, 2022
966a878
Change dependencies for new API
Tabby Feb 16, 2022
235ca4b
Convert base test runner class to new API
Tabby Feb 17, 2022
fde28f2
Finish converting the test runners
Tabby Feb 18, 2022
c11b7cc
Add missing newlines to ends of files
Tabby Feb 18, 2022
b91d118
Launch debugger when debugging & delete adapter.ts
Tabby Feb 18, 2022
c801e0b
Fix lint error in tsconfig.json
Tabby Feb 18, 2022
b802ce5
Fix things enough to be able to see the UI populated with tests
Tabby Feb 18, 2022
7a63668
Install jsmock and clean up source a bit in preparation for testing
Tabby Feb 18, 2022
d9c573d
Clean up tests, add unit test suite, and ensure all suites run
Tabby Feb 19, 2022
19a5074
Remove leading _ from variables
Tabby Feb 19, 2022
6128f8c
More refactoring, a few more unit tests, get rspec loading tests to pass
Tabby Feb 21, 2022
d3283aa
Update launch profiles
Tabby Feb 23, 2022
98d932d
Get Rspec success test passing
Tabby Feb 23, 2022
df5aef0
Fix usage of cancellation token and typo
Tabby Feb 23, 2022
dc08baa
Tweak logging calls in test loader
Tabby Feb 23, 2022
2c17716
Fix path handling and get unit tests green again
Tabby Feb 23, 2022
3e9afef
Get first two rspec integration tests back to green
Tabby Feb 23, 2022
35179a6
Test all calls to runContext.passed in rspec success test
Tabby Feb 24, 2022
ec5471d
Convert remaining rspec tests, and refactor them a bit
Tabby Feb 24, 2022
a6703a9
Get rspec tests all green \o/
Tabby Feb 24, 2022
245d96d
Tidy logging, fix minor issue with subfolders
Tabby Feb 24, 2022
e4ac041
Change test loading to be more lazy and fill suite with files quickly…
Tabby Feb 25, 2022
ffc699b
Fully implement lazy test loading for rspec
Tabby Feb 28, 2022
9f806b7
Get everything sort of working in a quick and dirty way
Tabby Mar 2, 2022
e73d7fc
Merge remote-tracking branch 'upstream/main' into convert-to-native-t…
Tabby Aug 8, 2022
5686bbe
Update TS test stubs of vscode Test API interfaces to match upstream …
Tabby Nov 8, 2022
cab32d9
Allow VSCode to run automatic npm tasks
Tabby Nov 8, 2022
7adf9d0
Add .bundle folders to .gitignore
Tabby Nov 8, 2022
60cbd42
Add .nvmrc set to use LTS version of node
Tabby Nov 8, 2022
c02bc91
Fix failing unit tests
Tabby Nov 8, 2022
481fa3b
Start trying to fix rspec test failures
Tabby Nov 8, 2022
998caef
Cleanup and refactor TestSuite and start unit testing it
Tabby Nov 8, 2022
3beb215
Add .editorconfig file
Tabby Nov 8, 2022
9cbf25b
Add some TestLoader test and fix up some parsing bugs
Tabby Nov 9, 2022
028feee
Change Config.getTestDirectory() to getRelativeTestDirectory() and ad…
Tabby Nov 9, 2022
0f2719f
Fix getAbsoluteTestFolder
Tabby Nov 12, 2022
72b5b03
Fix normaliseTestId to also strip root test folder
Tabby Nov 12, 2022
7df3b9b
Get RSpec test suite passing
Tabby Nov 12, 2022
2fc6539
Get minitest working (Kind of hacky for now)
Tabby Nov 27, 2022
bfeffb5
Fix RSpec status parsing for errored tests
Tabby Dec 2, 2022
679aa29
Fix discoverAllFilesInWorkspace and use it in loadAllTests tests
Tabby Dec 2, 2022
a4730fc
Remove a lot of debug output
Tabby Dec 2, 2022
b5b2c10
Update Github workflow and add unit tests to it
Tabby Dec 2, 2022
5b1dde4
Clean up some comments/TODOs
Tabby Dec 2, 2022
ca1ab9c
Change TestRunner.initTests to a method rather than a property
Tabby Dec 27, 2022
754d821
Remove tests from collections if not in test runner output
Tabby Dec 27, 2022
ff42615
Tidy up handling of child processes and extract function to get comma…
Tabby Dec 30, 2022
0e5b0fa
WIP: Fix status handling and test information parsing to work correct…
Tabby Dec 31, 2022
3fb967e
Rearrange RSpec test suite some more
Tabby Dec 31, 2022
13930e7
Finish merging status handling into TestRunner and fix behaviour
Tabby Jan 2, 2023
f510125
WIP: redoing child process handling and testRunner structure
Tabby Jan 3, 2023
97074d4
Finally get rid of initTests and start using a TestRunProfile instead
Tabby Jan 3, 2023
57657b5
Get everything more-or-less working again
Tabby Jan 5, 2023
8b1347b
Simplify TestRunner, fix removeMissingTests logic & bugs
Tabby Jan 6, 2023
e61f57e
Tidy test logger and construction of TestRunner & TestLoader
Tabby Jan 6, 2023
ba218d1
Rename TestSuite to TestSuiteManager
Tabby Jan 6, 2023
5489b4d
Stop interpolating strings in log messages, and other log tidying
Tabby Jan 6, 2023
1bab95e
Move definition of ParsedTest to TestRunner where it's used
Tabby Jan 6, 2023
2430066
Fix imports after renaming TestSuite
Tabby Jan 6, 2023
5871243
Split out parsed test types in TestRunner
Tabby Jan 6, 2023
bf0881c
Add queue for loading tests
Tabby Jan 9, 2023
6dbcf18
Ensure disposables are all handled correctly & tidy debug session han…
Tabby Jan 9, 2023
53edadd
Combine test runners and begin to unify test output format
Tabby Jan 10, 2023
575ff55
Wire up status events and fix bugs introduced by refactor
Tabby Jan 11, 2023
36dbe49
Disable GPU acceleration in vscode test instance
Tabby Jan 11, 2023
13bd8db
Merge remote-tracking branch 'upstream/main' into convert-to-native-t…
Tabby Jan 11, 2023
abeefd6
Update vsce dependency to @vscode/vsce-2.16.0
Tabby Jan 12, 2023
24b2c12
Add RSpec deeply nested contexts spec and update label expectations f…
Tabby Jan 12, 2023
72b9edf
Fix parent ID handling for RSpec contexts
Tabby Jan 12, 2023
dc62d9f
Fix more small issues
Tabby Jan 13, 2023
26a80c9
Make test resolution actually lazy
Tabby Jan 13, 2023
c09a7ad
Change queue from an array to a set
Tabby Jan 13, 2023
f68262b
Fix log issues
Tabby Jan 13, 2023
f50a876
Finally fix tests being loaded twice >_<
Tabby Jan 13, 2023
d38c774
Mark items as busy when loading them
Tabby Jan 13, 2023
d12e9a3
Don't mark tests as passed during test loading
Tabby Jan 13, 2023
985d72a
Remove commented out method for sorting tests
Tabby Jan 13, 2023
d0e84f1
Use VSC stdout logger in tests, delete stub logger and some unused mocks
Tabby Jan 14, 2023
c26f9fe
Refactor TestRunContext into TestStatusListener to simplify things
Tabby Jan 14, 2023
6abc51d
Delete stub implementations used in tests
Tabby Jan 15, 2023
94577b5
Forgot to rename the test status listener file after renaming the class
Tabby Jan 15, 2023
2ba2915
delete TODO file
Tabby Jan 15, 2023
84006f1
Update README.md
Tabby Jan 15, 2023
f98b2a4
Add architecture doc
Tabby Jan 15, 2023
d098e88
Add changelog entry
Tabby Jan 15, 2023
0480f79
Add ability to run all test suites in one go, for convenince
Tabby Jan 15, 2023
9ce2492
Revert unnecessary change to ruby/Rakefile used to test changes in cu…
Tabby Jan 16, 2023
c2aa46d
Revert unnecessary change to ruby/rspecs, also used to test changes i…
Tabby Jan 16, 2023
08d46f3
Change rake_task_test assertions to not be dependent on order
Tabby Jan 16, 2023
25b31db
Log test statuses and unrecognised stdout messages at info level
Tabby Jan 16, 2023
fcc2185
Improve logging of child process output for when things don't work
Tabby Jan 16, 2023
524a040
Ensure exit codes other than 0 are actually treated as errors
Tabby Jan 16, 2023
2764bcf
Add extra debug logging around disposing/cancellation
Tabby Jan 16, 2023
954965e
Update expectations in rake_task_test
Tabby Jan 16, 2023
3f1a74c
Apply @naveg's fix for ID segment splitting causing high CPU usage
Tabby Jan 17, 2023
1058978
Attempt to fix repeated loading of children
Tabby Jan 17, 2023
0ca7e55
Fix error in custom_formatter.rb if exception.backtrace_locations is nil
Tabby Jan 17, 2023
012b603
Don't report error/failure statuses until the end of the run
Tabby Jan 17, 2023
8bafc72
Change log level when logLevel config setting is changed
Tabby Jan 17, 2023
78b6f50
Don't run whole file when only RSpec context should be run (also fix …
Tabby Jan 17, 2023
f235b5d
Improve error logging if test process fails to start
Tabby Jan 17, 2023
96bbefe
Add tests for FrameworkProcess output and exit code handling
Tabby Jan 18, 2023
82d080c
Apply RSpec pattern symlink fix from #115
Tabby Jan 18, 2023
06eca34
Update test for symlink pattern fix
Tabby Jan 18, 2023
e150bbc
Tidy up command and argument handling
Tabby Jan 18, 2023
764477d
Merge remote-tracking branch 'upstream/main' into convert-to-native-t…
Tabby Jan 18, 2023
edf2916
Update dependencies with `npm audit fix`
Tabby Apr 24, 2023
235ad1d
Stop using TestRunProfile for loading tests
Tabby Apr 24, 2023
7a0982c
Fix markdown lint warning in README.md
Tabby Apr 24, 2023
2b4fde9
Use file pattern when running all tests with rspec
Tabby Apr 24, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
root = true

[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
7 changes: 5 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,15 @@ jobs:
run: |
npm run build
npm run package
- name: Run unit tests
run: |
xvfb-run -a node ./out/test/runFrameworkTests.js unitTests
- name: Run minitest tests
run: |
xvfb-run -a node ./out/test/runMinitestTests.js
xvfb-run -a node ./out/test/runFrameworkTests.js minitest
- name: Run rspec tests
run: |
xvfb-run -a node ./out/test/runRspecTests.js
xvfb-run -a node ./out/test/runFrameworkTests.js rspec
- name: Run Ruby test
run: |
cd ruby && bundle exec rake
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ out/
ruby/Gemfile.lock
/.vscode-test
*.vsix
.rbenv-gemsets
.ruby-version
**/.bundle/
2 changes: 2 additions & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
lts/*

23 changes: 19 additions & 4 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionTestsPath=${workspaceFolder}/out/test/suite/frameworks/minitest/index",
"--extensionTestsPath=${workspaceFolder}/out/test/suite",
"${workspaceFolder}/test/fixtures/minitest"
],
"outFiles": ["${workspaceFolder}/out/test/**/*.js"]
"outFiles": ["${workspaceFolder}/out/test/**/*.js"],
"env": { "TEST_SUITE": "minitest" }
},
{
"name": "Run tests for RSpec",
Expand All @@ -32,10 +33,24 @@
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionTestsPath=${workspaceFolder}/out/test/suite/frameworks/rspec/index",
"--extensionTestsPath=${workspaceFolder}/out/test/suite",
"${workspaceFolder}/test/fixtures/rspec"
],
"outFiles": ["${workspaceFolder}/out/test/**/**/*.js"]
"outFiles": ["${workspaceFolder}/out/test/**/*.js"],
"env": { "TEST_SUITE": "rspec" }
},
{
"name": "Run unit tests",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionTestsPath=${workspaceFolder}/out/test/suite",
"${workspaceFolder}/test/fixtures/unitTests"
],
"outFiles": ["${workspaceFolder}/out/test/**/*.js"],
"env": { "TEST_SUITE": "unitTests" }
}
]
}
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@
"ruby.format": false,
"ruby.lint": {
"rubocop": false
}
},
"task.allowAutomaticTasks": "on"
}
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## [Unreleased]
### Changed
- Rewrite extension to use the native [VSCode testing API](https://code.visualstudio.com/api/extension-guides/testing) instead of the older one provided by the [Test Explorer UI](https://marketplace.visualstudio.com/items?itemName=hbenl.vscode-test-explorer) extension.
- Allows for partial test tree updates, lazy loading of tests, much more responsive UI, filtering of tests, as well as greater efficiency by interacting directly with VSCode instead of going through another extension, and much more.

## [0.9.1] - 2022-08-04
### Fixed
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ Property | Description
---------------------------------------|---------------------------------------------------------------
`rubyTestExplorer.logpanel` | Whether to write diagnotic logs to an output panel.
`rubyTestExplorer.logfile` | Write diagnostic logs to the given file.
`rubyTestExplorer.logLevel` | The level of information to log. One of `off` (no logs), `error`, `warn`, `info` (default), `debug`, or `trace` (all logs). Note: `debug` and `trace` are very noisy and are not reccomended for daily use.
`rubyTestExplorer.testFramework` | `none`, `auto`, `rspec`, or `minitest`. `auto` by default, which automatically detects the test framework based on the gems listed by Bundler. Can disable the extension functionality with `none` or set the test framework explicitly, if auto-detect isn't working properly.
`rubyTestExplorer.filePattern` | Define the pattern to match test files by, for example `["*_test.rb", "test_*.rb", "*_spec.rb"]`.
`rubyTestExplorer.debuggerHost` | Define the host to connect the debugger to, for example `127.0.0.1`.
Expand Down Expand Up @@ -92,7 +93,7 @@ There are two groups of tests included in the repository.

- Tests for Ruby scripts to collect test information and run tests. Run with `bundle exec rake` in `ruby` directory.
- Tests for VS Code extension which invokes the Ruby scripts. Run from VS Code's debug panel with the "Run tests for" configurations.
- There are separate debug configurations for each supported test framework.
- There are separate debug configurations for each supported test framework, as well as unit tests for the extension itself.
- Note that you'll need to run `npm run build && npm run package` before you'll be able to successfully run the extension tests. You'll also need to re-run these every time you make changes to the extension code or your tests.

You can see `.github/workflows/test.yml` for CI configurations.
Expand Down
1 change: 1 addition & 0 deletions bin/setup
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ npm install
bundle install --gemfile=ruby/Gemfile
bundle install --gemfile=test/fixtures/rspec/Gemfile
bundle install --gemfile=test/fixtures/minitest/Gemfile
bundle install --gemfile=test/fixtures/rspec/Gemfile
136 changes: 136 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
# Architecture

This extension is essentially comprised of 4 main parts:

- [Configuration and setup](#configuration-and-setup)
- [Management of the test tree state](#management-of-the-test-tree-state)
- [Discovering tests](#discovering-tests)
- [1. File changes](#1-file-changes)
- [2. Resolve handler](#2-resolve-handler)
- [Loading queue](#loading-queue)
- [Running tests](#running-tests)

As much as possible, anything that might need to be cleaned up or cancelled extends the [Disposable](https://code.visualstudio.com/api/references/vscode-api#Disposable) interface, so that it provides a clear, uniform way for other classes to do so.

## Configuration and setup

These parts of the extension are the most straightforward:

- `Config`
- Abstract base class for test framework configuration.
- Ensures that the rest of the extension does not need to care which test framework is being used when building commands to run, or getting file patterns, etc.
- `RspecConfig` & `MinitestConfig`
- Framework-specific subclasses of `Config`.
- Implement the abstract functions from `Config` as well as any other configuration/processing needed to supply the extension with the relevant data to interact correctly with their respective frameworks.
- `TestFactory`
- Creates the `TestLoader` and `TestRunner` instances used by the extension.
- Disposes of the `TestLoader` and `TestRunner` if necessary when the configuration changes, so that they clean up and terminate any running processes and can be recreated for the new configuration.
- `main.ts`
- Extension entry point - called by VSCode to intialize the extension
- Creates the logger, `TestController` (see [Management of the test tree state](#management-of-the-test-tree-state)), `TestFactory`, and `Config` instances
- Creates the three [TestRunProfile](https://code.visualstudio.com/api/references/vscode-api#TestRunProfile) instances used by the extension (see [Running tests](#running-tests))
- Creates the debug configuration used by the `Debug` profile
- Registers the controller, factory and profiles with VSCode to be disposed of when the extension is unloaded
- Registers a `resolveHandler` with the controller and initializes the `TestLoader` (see [Discovering tests](#discovering-tests))

## Management of the test tree state

There are only two classes that deal with this:

- [TestController](https://code.visualstudio.com/api/references/vscode-api#TestController)
- Part of the VSCode API, and is the link between VSCode and this extension
- `TestSuiteManager`
- Provides functions for the rest of the extension to use to update and access the test tree.

The [TestController](https://code.visualstudio.com/api/references/vscode-api#TestController) instance is the heart of the VSCode testing API:

- It is used to create [TestRunProfiles](https://code.visualstudio.com/api/references/vscode-api#TestRunProfile), which make it easy for tests to be run in different ways
- It is used to create [TestItems](https://code.visualstudio.com/api/references/vscode-api#TestItem) which represent the various folders, files, describes/contexts/groups, and tests
- It holds the list of known tests allowing them to be displayed in the UI, and run/discovered via the handler functions registered on the controller or the profiles created with it.
- It is used to create [TestRuns](https://code.visualstudio.com/api/references/vscode-api#TestRun) from [TestRunRequests](https://code.visualstudio.com/api/references/vscode-api#TestRunRequest), which are used for reporting the statuses of tests that are run, as well as grouping results.

The classes and functions provided by the VSCode API for managing the state of the test tree are, by necessity, very basic as they cannot predict what will be appropriate for any particular test provider. For example, the [TestItemCollection](https://code.visualstudio.com/api/references/vscode-api#TestItemCollection) used by the controller to hold the known tests cannot retrieve [TestItems](https://code.visualstudio.com/api/references/vscode-api#TestItem) that are children of the top-level items.

Because of this, as well as other constraints we must satisfy when using the testing API, and to make things easier in the rest of the extension, we have the `TestSuiteManager` class which keeps all the logic for managing a hierarchy of tests in a single place. It takes care of the following:

- Creating [TestItem](https://code.visualstudio.com/api/references/vscode-api#TestItem) instances to ensure that all the following constraints are always satisfied:
- Test IDs must all be unique. We use the relative path to the test from the test folder root, and its location, e.g. for the second RSpec test in `./spec/foo/bar_spec.rb`, the ID would be `foo/bar_spec.rb[1:2]`.
- Test item URIs are optional, but we want them to always be set with both the absolute file path and [Range](https://code.visualstudio.com/api/references/vscode-api#TestItem).
- `canResolveChildren` should be `true` for all items that can have children which is non-trivial to determine.
- Folders, files and some test groups don't get included in test framework output, so we need to ensure that all parent items are also created when an item needs creating.
- Retrieving [TestItems](https://code.visualstudio.com/api/references/vscode-api#TestItem)
- For the same reason that we need to create parents when creating items, we also have to walk the test tree to find a test item when needed.
- Deleting [TestItems](https://code.visualstudio.com/api/references/vscode-api#TestItem)
- To delete an item we also have to walk the tree to find the collection that contains it.
- Normalising IDs
- Because we use the relative path to a test file as part of the ID, it's helpful to allow other classes to not have to worry about things like stripping leading `/`s, `./`s, etc

## Discovering tests

([VS Code API docs](https://code.visualstudio.com/api/extension-guides/testing#discovering-tests))

Discovering tests is done by the `TestLoader` class in two main ways:

### 1. File changes

When the `TestLoader` is created, or when the configuration that affects finding test files is changed, a set of [FileSystemWatchers](https://code.visualstudio.com/api/references/vscode-api#FileSystemWatcher) are created using the configured file patterns.

1. When a file is created:
A [TestItem](https://code.visualstudio.com/api/references/vscode-api#TestItem) is created for the new file and added to the tree.
2. When a file is changed:
The [TestItem](https://code.visualstudio.com/api/references/vscode-api#TestItem) for the changed file is retrieved from the tree, and enqueued to be loaded by the test framework to get new/updated information about the tests within it.
3. When a file is deleted:
The [TestItem](https://code.visualstudio.com/api/references/vscode-api#TestItem) for the deleted file is removed from the [TestItemCollection](https://code.visualstudio.com/api/references/vscode-api#TestItemCollection) that contains it, along with all its children.

### 2. Resolve handler

When the extension is initialized, a `resolveHandler` function is registered with the [TestController](https://code.visualstudio.com/api/references/vscode-api#TestController).

This function is called called whenever an item that may contain children is expanded in the test sidebar by clicking on the arrow icon, and is passed the relevant [TestItem](https://code.visualstudio.com/api/references/vscode-api#TestItem) from the tree as a parameter. This item is then enqueued to be loaded by the test framework.

This function It may also be called with no arguments to resolve all tests if a request to reload the entire tree is made, in which case the test framework is run immediately to load all tests.

### Loading queue

As mentioned, the `TestLoader` makes use of a queue for loading tests. The main reason for this is that the [FileSystemWatchers](https://code.visualstudio.com/api/references/vscode-api#FileSystemWatcher) only report changes one file at a time, and on large repositories this can easily result in hundreds of test processes being spawned in a short amount of time which will easily grind even powerful computers to a halt.

To avoid this, tests are added to a queue to be loaded, which behaves as follows:

- An async worker function checks the queue for [TestItems](https://code.visualstudio.com/api/references/vscode-api#TestItem) to run
- If any are found, it:
- Drains the queue, so that [TestItems](https://code.visualstudio.com/api/references/vscode-api#TestItem) enqueued while it is running don't get missed
- Sets the `busy` flag on all the [TestItems](https://code.visualstudio.com/api/references/vscode-api#TestItem) - this causes a spinner to be displayed in the UI for those items.
- Creates a [TestRunRequest](https://code.visualstudio.com/api/references/vscode-api#TestItem) containing the items to be loaded, using the `ResolveTests` profile and runs it with the profile's `runHandler` (see below) to load all the tests that were in the queue.
- Once this is completed, it unsets the `busy` flag on the [TestItems](https://code.visualstudio.com/api/references/vscode-api#TestItem) and checks the queue for more items.
- If the queue is empty, it creates a promise and waits for it to be resolved. Once resolved, it checks the queue again.
- When a test is added to the queue, if the async worker is waiting for items, the resolve function for the promise it is waiting on is resolved to notify it that items have been added.

This ensures that only one test process at a time is running to load tests.

## Running tests

([VS Code API docs](https://code.visualstudio.com/api/extension-guides/testing#running-tests))

When the extension is initialized (see [Configuration and setup](#configuration-and-setup)), three [TestRunProfiles](https://code.visualstudio.com/api/references/vscode-api#TestRunProfile) are registered with the controller:

- The `Run` profile, used for running tests (default profile for the `Run` [profile kind](https://code.visualstudio.com/api/references/vscode-api#TestRunProfileKind))
- The `Debug` profile, used for debugging tests (default profile for the `Debug` [profile kind](https://code.visualstudio.com/api/references/vscode-api#TestRunProfileKind))
- The `ResolveTests` profile, used for loading tests (using the `Run` [profile kind](https://code.visualstudio.com/api/references/vscode-api#TestRunProfileKind))
- This profile can only be used internally by the extension, and is used by the `TestLoader` for loading tests

Note: There is a third possible profile kind, `Profile`, intended to be used for profiling tests that is not currently used by this extension.

When a user runs/debugs one or more tests from the UI, the `runHandler` function associated with the default profile for that [profile kind](https://code.visualstudio.com/api/references/vscode-api#TestRunProfileKind) is called. For all three profiles, this is `TestRunner.runHandler`.

The `runHandler` does the following:

- Creates a [TestRun](https://code.visualstudio.com/api/references/vscode-api#TestRun) from the [TestRunRequest](https://code.visualstudio.com/api/references/vscode-api#TestRunRequest) passed in as a parameter
- If the profile in the request is a `Debug` profile, it starts a debugging session and continues
- Marks all the [TestItems](https://code.visualstudio.com/api/references/vscode-api#TestItem) in the request as enqueued.
- Builds the command to run the requested tests (obtained from the `RspecConfig`/`MinitestConfig` classes, as appropriate)
- If the profile in the request is the `ResolveTests` profile, it builds a dry-run (RSpec)/list tests (Minitest) command
- Creates a `FrameworkProcess` instance, passing in the command to be run
- `FrameworkProcess` is a wrapper around the `child_process` in which the test framework runs. It parses the output, and emits status events based on it, and handles the lifetime of the child process, terminating it early if needed.
- Registers a `TestStatusListener` with the `FrameworkProcess` to call the [TestRun](https://code.visualstudio.com/api/references/vscode-api#TestRun) with information about the test results as they are received.
- Tells the `FrameworkProcess` instance to spawn the child process and waits for it to finish
- Calls `end` on the [TestRun](https://code.visualstudio.com/api/references/vscode-api#TestRun) to let VSCode know the test run is finished.
Loading