`expect_snapshot()` of an image in a temporary directory/file

I've a method generating an image in R markdown or Quarto (e.g. [![](path_to_file)](link)). The method generates image as .pdf or .svg depending on the output format of the rendered document.

I previously used expect_match() to test that method, which worked well for simple cases. I now need to find a better alternative to perform more tests that produce slightly different outputs. expect_snapshot() seems to be the best option. My only issue is that using expect_snapshot(my_function()) generates paths from the root directory of my local machine (e.g. /User/my_user_name/.../file.svg), which I don't want.

I've messed around with withr::with_tempdir() and withr::local_tempfile() but I'm struggling to make the snapshot test work. One of the difficulty is that the function picks the right image format automatically on rendering, meaning that I've to use expect_snapshot() together with rmarkdown::render().

My question is how could I use expect_snapshot() so that it uses a temporary directory in this case?

Here's one of the things I've tried, without success:

render <- purrr::partial(rmarkdown::render, clean = FALSE, quiet = TRUE)

read_rendered_md <- function() {
  readr::read_file(list.files(pattern = "\\.md$"))

  tmp_file <- withr::local_tempfile(lines = dedent("
    ```{r echo = FALSE, results = 'asis'}
    aut <- Plume$new(basic_df())
    cat(aut$get_orcids(), sep = '\n\n')
  "), fileext = ".Rmd", tmpdir = getwd())

  render(tmp_file, output_format = "rtf_document")

  render(tmp_file, output_format = "html_document")

I've also read about expect_snapshot_file() but couldn't really figure out if that's what I need and how to make it work in my case.

Can you show an example that we can run? E.g. a link to a repository if it is public?

I made a (simplified) copy of the repo here.

I want to test $get_orcids() that produces these kinds of outputs:

In markdown, the output for the .pdf version of the icon is as follows:


aut <- Plume$new(encyclopedists)
#> Denis Diderot[\hspace{3pt}![](/Library/Frameworks/R.framework/Versions/4.2/Resources/library/plume/icons/orcid.pdf){height=16px}\hspace{3pt}](https://orcid.org/0000-0000-0000-0001)<https://orcid.org/0000-0000-0000-0001>
#> Jean-Jacques Rousseau[\hspace{3pt}![](/Library/Frameworks/R.framework/Versions/4.2/Resources/library/plume/icons/orcid.pdf){height=16px}\hspace{3pt}](https://orcid.org/0000-0000-0000-0002)<https://orcid.org/0000-0000-0000-0002>
#> Jean Le Rond d'Alembert[\hspace{3pt}![](/Library/Frameworks/R.framework/Versions/4.2/Resources/library/plume/icons/orcid.pdf){height=16px}\hspace{3pt}](https://orcid.org/0000-0000-0000-0003)<https://orcid.org/0000-0000-0000-0003>

I guess the easiest solution here is to have a snapshot of the strings returned by the method. The only issue is the path displayed when creating the snapshot.

I was thinking to test the .svg icon as well but I already tested it here. I can probably skip the rendering part for $get_orcids(), although I'd still be curious to know how to snapshot a rendered file. It's a bit messy, I've 2 methods for different purposes generating the same icon and I'm not sure how to organise those tests… :sweat_smile:

I've just tried again and the code chunk in the first post now properly returns snapshots of the rendered files. The only issue really is the path which is /User/my_user_name/.../orcid.pdf instead of /Library/Frameworks/R.framework/Versions/4.2/Resources/library/plume/icons/orcid.pdf.

You can use expect_snapshot()'s transform argument to post-process the output. I would run a simple sub() or gsub() to remove or change the path, so the snapshot is always the same.

This is actually not that simple, because paths look different on different platforms (e.g. Windows), but it should work eventually.


Thanks for the suggestion.

I guess I'll give expect_snapshot_file() another try. I saw a few examples on how to use this function in the tibble package. It seems like it's better suited in this case because I'll get a snapshot of the actual rendered document, so no need to bother with the path. It will only work for the .svg icon but since I use a helper to generate icon metadata, I can test the helper for the other options. That will fix my not well organized icon tests issue at the same time :slight_smile:

A relevant issue to watch: Provide a set of default transformers for snapshot tests? · Issue #1822 · r-lib/testthat · GitHub

Thanks for the link.

Sadly, expect_snapshot_file() doesn't suit either because it won't use the right image path to print the icon in the .md document.

I find the expect_snapshot() + transform solution too difficult/tedious for my use case. I'll simply use expect_match() again but only to test one case and use a snapshot to get the icon metadata from the helper function for all other cases. I guess that's a decent solution for now.

So I'm about to rewrite the tests and on a second thought, I might choose the expect_snapshot() + transform solution but instead of trying to tweak the file path, I'll simply replace it with the file name.

I'm not sure how to use the transform parameter though, except that its argument must be a function, and I can't find examples of it.

Fixed, I used orcid\\.pdf in the regex for the svg version of the icon haha :man_facepalming:
We can consider the issue solved. Thanks again for your help :slight_smile:


Considering that



Denis Diderot[\hspace{3pt}![](/Library/Frameworks/R.framework/Versions/4.2/Resources/library/plume/icons/orcid.pdf){height=16px}\hspace{3pt}](https://orcid.org/0000-0000-0000-0001)<https://orcid.org/0000-0000-0000-0001>

How should I use transform to get the following?

# full path replaced with the file name `orcid.pdf`
Denis Diderot[\hspace{3pt}![](orcid.pdf){height=16px}\hspace{3pt}](https://orcid.org/0000-0000-0000-0001)<https://orcid.org/0000-0000-0000-0001>

Here's what I've tried, without success:

expect_snapshot(cat(read_rendered_md()), transform = \(x) {
  gsub("(?<=\\()\\/.+\\/(?=orcid\\.pdf\\))", "", x, perl = TRUE)

The "Should take a character vector of lines as input" part in the documentation bugs me.

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.