Skip to content

Treat test_that() tests as document symbols #856

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

Merged
merged 2 commits into from
Jul 21, 2025
Merged

Conversation

lionel-
Copy link
Contributor

@lionel- lionel- commented Jun 26, 2025

Addresses posit-dev/positron#1428.

test_that() blocks are now recorded as document symbols. This enables the following features:

  • Hierarchical outline
  • Breadcrumbs
  • Document symbol search (@ prefix in the command palette)

The tests are registered with "Test: " prefix, followed by the test title.

I've purposely not made them workspace symbols, so you can't search for tests across files with a workspace symbol search (# prefix in the command palette). The markdown extension does that for markdown sections and I find it gets in the way a lot when searching for variables and functions.

QA Notes

I've added backend side tests.

On the frontend with:

test_that("foo", {
    # section ----
    bar <- function() {
        1
    }
    1
})

You should see Test: foo:

  • in the outline (and be able to interact with it)
  • in breadcrumbs (and be able to interact with them)
  • in document symbols
Screenshot 2025-06-26 at 16 47 52
Screen.Recording.2025-06-26.at.16.40.37.mov

@lionel- lionel- changed the base branch from main to bugfix/section-symbols June 26, 2025 14:58
Copy link
Member

@jennybc jennybc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be interesting to add a test where there are comments that basically section the tests into different blocks. Like this:

https://github.com/tidyverse/forcats/blob/main/tests/testthat/test-lvls.R

Also just a side note: the test explorer (which is a positron-r matter) needs to gain a way to register test_that()-like functions, i.e. if a user or an R package creates a wrapper that basically quacks like test_that() and should be treated accordingly by machinery like this. Whenever that happens, we'd probably want to try to make breadcrumbs also work. posit-dev/positron#7213

@lionel-
Copy link
Contributor Author

lionel- commented Jun 27, 2025

Also just a side note: the test explorer (which is a positron-r matter) needs to gain a way to register test_that()-like functions, i.e. if a user or an R package creates a wrapper that basically quacks like test_that() and should be treated accordingly by machinery like this. Whenever that happens, we'd probably want to try to make breadcrumbs also work. posit-dev/positron#7213

I was thinking the same! Almost implemented it as a TS query as queries would probably be the way to make it generic.

It'd be nice to share the same configurability for document symbols and the test infra.

@lionel-
Copy link
Contributor Author

lionel- commented Jun 27, 2025

I think it would be interesting to add a test where there are comments that basically section the tests into different blocks.

I've now expanded the test with a second section.

@lionel- lionel- force-pushed the feature/testthat-symbols branch from 68df2ed to 1b58bb0 Compare June 30, 2025 08:42
@lionel- lionel- force-pushed the bugfix/section-symbols branch from 74dbe94 to a5b9485 Compare June 30, 2025 08:42
@jennybc
Copy link
Member

jennybc commented Jul 1, 2025

I took this for a little test drive in gargle. I'm wondering if we might just want to stop at the top-level test_that() calls, in terms of document symbols. At least in this example, I feel like the lower-level symbols are a net negative and somewhat overwhelming. I haven't thought deeply about this problem ... are there cases where digging into each test_that() for symbols is super useful?

I guess having them in the outline view is fine, because they can be collapsed. The problem of overabundance seems to hurt more in when using the command palette to search for a symbol.

Screen.Recording.2025-07-01.at.4.53.52.PM.mov

@lionel-
Copy link
Contributor Author

lionel- commented Jul 3, 2025

@jennybc I think we want to recurse to support things like sections inside test_that() (even if it's not good practice to have very large test blocks, you still see them in the wild).

But regarding how busy the outline currently feels I think this will be mostly solved by this: posit-dev/positron#8330

@@ -156,6 +156,10 @@ fn collect_symbols(
collect_sections(node, contents, current_level, symbols)?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely agree with our plans to remove local variables from outline, way too noisy

Image

Comment on lines +294 to +308
let Some(first_argument) = arguments.child(1).and_then(|n| n.child(0)) else {
return Ok(());
};
if !first_argument.is_string() {
return Ok(());
}

let Some(string) = first_argument.child_by_field_name("content") else {
return Ok(());
};

// Recurse in arguments. We could skip the first one if we wanted.
let mut children = Vec::new();
let mut cursor = arguments.walk();
for child in arguments.children_by_field_name("argument", &mut cursor) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be a little nicer if you pull out arguments.children_by_field_name("argument", &mut cursor) into a variable and:

  • Use the first child for the first_argument bits
  • Use the second child for collect_symbols()
  • Ignore any other children

I feel like that would make our assumption of "test_that is a 2 argument function call where the first is a string and the second is the test" more explicit and clear to see in the code

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll try and do something along these lines. In one the PRs I sent we gain some nicer iterators over arguments that should help a lot for this sort of things.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll just come back to this once the iterators are merged.

Base automatically changed from bugfix/section-symbols to main July 21, 2025 08:02
@lionel- lionel- merged commit 3c6437a into main Jul 21, 2025
6 checks passed
@lionel- lionel- deleted the feature/testthat-symbols branch July 21, 2025 08:14
@github-actions github-actions bot locked and limited conversation to collaborators Jul 21, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants