tests/testthat/test-api-mocked.R

# Mocked API tests using httptest2
# Fixtures are pre-recorded v3 API responses

# Helper to create mock responses inline
mock_json_response <- function(values, next_url = NULL) {
  body <- list(values = values)
  if (!is.null(next_url)) body$next_url <- next_url
  jsonlite::toJSON(body, auto_unbox = TRUE)
}

test_that("get_kpi() returns tibble from mocked response", {
  local_mocked_bindings(
    req_perform = function(req, ...) {
      structure(list(
        status_code = 200L,
        body = charToRaw(mock_json_response(
          data.frame(
            id = c("N00001", "N00002"),
            title = c("KPI One", "KPI Two"),
            description = c("Desc 1", "Desc 2"),
            auspice = c("X", "E"),
            has_ou_data = c(0, 1),
            is_divided_by_gender = c(FALSE, TRUE),
            municipality_type = c("K", "K"),
            operating_area = c("Area 1", "Area 2"),
            publication_date = c("2020-01-01", "2020-01-01"),
            publ_period = c("2020", "2020"),
            stringsAsFactors = FALSE
          )
        ))
      ), class = "httr2_response")
    },
    resp_body_string = function(resp, ...) {
      rawToChar(resp$body)
    },
    .package = "httr2"
  )

  result <- get_kpi(max_results = 2)
  expect_s3_class(result, "tbl_df")
  expect_equal(nrow(result), 2)
  expect_true("id" %in% names(result))
  expect_true("title" %in% names(result))
  expect_true("auspice" %in% names(result))
})

test_that("get_municipality() returns tibble from mocked response", {
  local_mocked_bindings(
    req_perform = function(req, ...) {
      structure(list(
        status_code = 200L,
        body = charToRaw(mock_json_response(
          data.frame(
            id = c("0180", "1480"),
            title = c("Stockholm", "Gothenburg"),
            type = c("K", "K"),
            stringsAsFactors = FALSE
          )
        ))
      ), class = "httr2_response")
    },
    resp_body_string = function(resp, ...) {
      rawToChar(resp$body)
    },
    .package = "httr2"
  )

  result <- get_municipality(max_results = 2)
  expect_s3_class(result, "tbl_df")
  expect_equal(nrow(result), 2)
  expect_true("type" %in% names(result))
})

test_that("get_metadata() handles connection errors gracefully", {
  local_mocked_bindings(
    req_perform = function(req, ...) {
      stop("Connection refused")
    },
    .package = "httr2"
  )

  expect_warning(
    result <- get_metadata("kpi", max_results = 1),
    "Could not connect"
  )
  expect_null(result)
})

test_that("get_metadata() handles malformed JSON gracefully", {
  local_mocked_bindings(
    req_perform = function(req, ...) {
      structure(list(
        status_code = 200L,
        body = charToRaw("not valid json{{{")
      ), class = "httr2_response")
    },
    resp_body_string = function(resp, ...) {
      rawToChar(resp$body)
    },
    .package = "httr2"
  )

  expect_warning(
    result <- get_metadata("kpi", max_results = 1),
    "malformatted"
  )
  expect_null(result)
})

test_that("get_values() chunks >25 KPIs into separate requests", {
  call_count <- 0L

  local_mocked_bindings(
    req_perform = function(req, ...) {
      call_count <<- call_count + 1L
      # Return a minimal valid response for each chunk
      kpi_id <- if (call_count == 1L) "N00001" else "N00026"
      body <- jsonlite::toJSON(list(
        values = data.frame(
          kpi = kpi_id,
          municipality = "0180",
          period = 2020L,
          values = I(list(data.frame(
            gender = "T", status = "", value = call_count
          ))),
          stringsAsFactors = FALSE
        )
      ), auto_unbox = TRUE)
      structure(list(
        status_code = 200L,
        body = charToRaw(body)
      ), class = "httr2_response")
    },
    resp_body_string = function(resp, ...) rawToChar(resp$body),
    .package = "httr2"
  )

  kpis <- paste0("N", sprintf("%05d", 1:30))
  result <- get_values(kpi = kpis, municipality = "0180", simplify = FALSE)

  expect_s3_class(result, "tbl_df")
  # Two chunks: 25 + 5 = 2 API calls
  expect_equal(call_count, 2L)
  expect_equal(nrow(result), 2)
})

test_that("get_metadata() chunks >25 IDs into separate requests", {
  call_count <- 0L

  local_mocked_bindings(
    req_perform = function(req, ...) {
      call_count <<- call_count + 1L
      body <- jsonlite::toJSON(list(
        values = data.frame(
          id = paste0("N", sprintf("%05d", call_count)),
          title = paste("KPI", call_count),
          stringsAsFactors = FALSE
        )
      ), auto_unbox = TRUE)
      structure(list(
        status_code = 200L,
        body = charToRaw(body)
      ), class = "httr2_response")
    },
    resp_body_string = function(resp, ...) rawToChar(resp$body),
    .package = "httr2"
  )

  ids <- paste0("N", sprintf("%05d", 1:30))
  result <- get_metadata("kpi", id = ids)

  expect_s3_class(result, "tbl_df")
  expect_equal(call_count, 2L)
  expect_equal(nrow(result), 2)
})

test_that("get_values() does not chunk when <=25 params", {
  call_count <- 0L

  local_mocked_bindings(
    req_perform = function(req, ...) {
      call_count <<- call_count + 1L
      body <- jsonlite::toJSON(list(
        values = data.frame(
          kpi = "N00001",
          municipality = "0180",
          period = 2020L,
          values = I(list(data.frame(
            gender = "T", status = "", value = 1
          ))),
          stringsAsFactors = FALSE
        )
      ), auto_unbox = TRUE)
      structure(list(
        status_code = 200L,
        body = charToRaw(body)
      ), class = "httr2_response")
    },
    resp_body_string = function(resp, ...) rawToChar(resp$body),
    .package = "httr2"
  )

  kpis <- paste0("N", sprintf("%05d", 1:25))
  result <- get_values(kpi = kpis, municipality = "0180", simplify = FALSE)

  expect_s3_class(result, "tbl_df")
  expect_equal(call_count, 1L)
})

test_that("get_values() handles empty results gracefully", {
  local_mocked_bindings(
    req_perform = function(req, ...) {
      structure(list(
        status_code = 200L,
        body = charToRaw(jsonlite::toJSON(list(values = list()), auto_unbox = TRUE))
      ), class = "httr2_response")
    },
    resp_body_string = function(resp, ...) {
      rawToChar(resp$body)
    },
    .package = "httr2"
  )

  expect_warning(
    result <- get_values(kpi = "N00001", municipality = "0180"),
    "zero hits"
  )
  expect_null(result)
})

Try the rKolada package in your browser

Any scripts or data that you put into this service are public.

rKolada documentation built on March 4, 2026, 5:06 p.m.