Error: menu() cannot be used non-interactively while using devtools::check()

While testing a function when I use devtools::check() to build and check the package it throws an error Error: menu() cannot be used non-interactively

Error: `{ ... }` threw an unexpected error.
Message: menu() cannot be used non-interactively
Class:   simpleError/error/condition

[ FAIL 1 | WARN 0 | SKIP 0 | PASS 47 ]
Error: Test failures
Execution halted

Is there any way to overcome this issue or just I've to skip the test case using skip_if_not(interactive()).

Welcome @Piyush_Kumar! Depending on what your test is testing, you could

Note that in this I was assuming the call to menu() happens in your code.

The major issue is still the to see the menu() in the R console so that the user can interact.
I posted this question on StackOverflow.

cli::test_that_cli(configs = "plain", "function_name() works", {
    skip_if_not(interactive())
    mockr::with_mock(function_name = function() {
        set.seed(5165)
    })
    expect_snapshot(
        expect_type(function_name(), "list")
        expect_error(function_name(), "Do it and then return please.")
    )
})

Previously, I was testing which shows the menu in the R console but the during::check() it gets failed.

local({
    with_mock(function_name, function_name())
    cli::test_that_cli(configs = "plain", "function_name() works", {
        skip_if_not(interactive())
        expect_snapshot(
            expect_type(function_name, "list")
        )
    })
})

I'm not sure I'm mocking my function correctly.

I'm not sure I follow your function exactly.

I've made an example package GitHub - maelle/menutests: What the Package Does (One Line, Title Case) with tests for one of the versions of the functions. Note that it's a stupid function as one probably never wants to reveal secrets. :slight_smile:

reveal_secret <- function(secret, ok = ask()) {
  if (is.null(ok)) {
    stop("A value is needed for `ok` see ?reveal_secret")
  }
  if (ok) {
    message(secret)
  } else {
    message("Nothing done.")
  }
}

ask <- function() {
  switch(
    utils::menu(c("yes", "no"), title = "Ok to print secret?"),
    TRUE, FALSE
  )
}

(NULL is the case where the user types 0 instead of using one of the menu choices).

The function has an argument whose default value comes from using the menu function.

In the tests I can either

  • use a value for that argument
test_that("reveal_secret works", {
  expect_message(reveal_secret("top-secret", ok = TRUE), "top-secret")
  expect_message(reveal_secret("top-secret", ok = FALSE), "Nothing")
})
  • or use mocking. with mockery one cannot mock base R functions but I can mock ask().
test_that("reveal_secret works, mocking", {
  mockery::stub(where = reveal_secret, what = "ask", how = TRUE)
  expect_message(reveal_secret("top-secret"), "top-secret")
})

test_that("reveal_secret works, mocking 2", {
  mockery::stub(where = reveal_secret, what = "ask", how = FALSE)
  expect_message(reveal_secret("top-secret"), "Nothing")
})

test_that("reveal_secret works, mocking 3", {
  mockery::stub(where = reveal_secret, what = "ask", how = NULL)
  expect_error(reveal_secret("top-secret"), "needed")
})

I hope this helps a bit?

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.