tests/testthat/test-kpiwidget.R

test_that("Standard mode returns an htmlwidget with correct data", {
  sd <- crosstalk::SharedData$new(mtcars)
  res <- kpiwidget(sd,
    kpi = "mean", column = "mpg", decimals = 1,
    prefix = "", suffix = " mpg"
  )

  # Check that the returned object is an htmlwidget
  expect_s3_class(res, "htmlwidget")

  # Check that the data sent to JS equals the 'mpg' column from mtcars
  expect_equal(res$x$data, mtcars[["mpg"]])

  # Check settings: kpi should be "mean" and no comparison mode
  expect_equal(res$x$settings$kpi, "mean")
  expect_null(res$x$settings$comparison)
})

test_that("Comparison mode (share) returns an htmlwidget with proper filters", {
  sd <- crosstalk::SharedData$new(mtcars)
  res <- kpiwidget(sd,
    kpi = "sum", comparison = "share", column = "mpg",
    group1 = ~ cyl == 4
  )

  expect_s3_class(res, "htmlwidget")
  expect_equal(res$x$settings$comparison, "share")
  expect_equal(res$x$settings$kpi, "sum")

  # group1_filter should be a logical vector of length equal to number of rows
  expect_true(is.logical(res$x$group1_filter))
  expect_equal(length(res$x$group1_filter), nrow(mtcars))

  # In share mode, if group2 is not provided, group2_filter should be all TRUE.
  expect_equal(res$x$group2_filter, rep(TRUE, nrow(mtcars)))
})

test_that("Comparison mode (ratio) returns an htmlwidget with proper filters", {
  sd <- crosstalk::SharedData$new(mtcars)
  res <- kpiwidget(sd,
    kpi = "sum", comparison = "ratio", column = "mpg",
    group1 = ~ cyl == 4
  )

  expect_s3_class(res, "htmlwidget")
  expect_equal(res$x$settings$comparison, "ratio")
  expect_equal(res$x$settings$kpi, "sum")

  # Check that group1_filter and group2_filter are logical and have correct length
  expect_true(is.logical(res$x$group1_filter))
  expect_true(is.logical(res$x$group2_filter))
  expect_equal(length(res$x$group1_filter), nrow(mtcars))
  expect_equal(length(res$x$group2_filter), nrow(mtcars))

  # In ratio mode, default group2_filter should be the complement of group1_filter.
  expect_equal(res$x$group2_filter, !res$x$group1_filter)
})

test_that("Non-SharedData input returns NULL with warning", {
  expect_warning(
    res <- kpiwidget(mtcars,
      kpi = "mean", column = "mpg", decimals = 1,
      prefix = "", suffix = " mpg"
    ),
    "kpiWidget can be used only with a Crosstalk SharedData object!"
  )
  expect_null(res)
})

test_that("Nonexistent column returns NULL with warning", {
  sd <- crosstalk::SharedData$new(mtcars)
  expect_warning(
    res <- kpiwidget(sd,
      kpi = "mean", column = "nonexistent", decimals = 1,
      prefix = "", suffix = " mpg"
    ),
    "No 'nonexistent' column in data."
  )
  expect_null(res)
})


test_that("Nonexistent column returns NULL with warning in comparison mode", {
  sd <- crosstalk::SharedData$new(mtcars)
  expect_warning(
    res <- kpiwidget(sd,
      kpi = "mean", column = "nonexistent", decimals = 1,
      comparison = "share", group1 = ~ cyl == 4
    ),
    "No 'nonexistent' column in data."
  )
  expect_null(res)
})

test_that("Missing group1 in comparison mode returns NULL with warning", {
  sd <- crosstalk::SharedData$new(mtcars)
  expect_warning(
    res <- kpiwidget(sd, kpi = "sum", comparison = "share", column = "mpg"),
    "group1 filter must be provided in comparison mode."
  )
  expect_null(res)
})

test_that("Selection filter works correctly", {
  sd <- crosstalk::SharedData$new(mtcars)
  res <- kpiwidget(sd,
    kpi = "mean", column = "mpg",
    selection = ~ mpg > 20, decimals = 1
  )

  expect_s3_class(res, "htmlwidget")

  # Manually filter mtcars by mpg > 20.
  filtered <- mtcars[mtcars$mpg > 20, , drop = FALSE]
  expect_equal(res$x$data, filtered[["mpg"]])
})

test_that("Missing column returns NULL with warning", {
  sd <- crosstalk::SharedData$new(mtcars)
  expect_warning(
    res <- kpiwidget(sd, kpi = "sum"),
    "Column must be provided for standard KPI calculation."
  )
  expect_null(res)
})

test_that("Selection must be one-sided formula", {
  sd <- crosstalk::SharedData$new(mtcars)
  expect_warning(
    res <- kpiwidget(sd, kpi = "sum", column = "mpg", selection = mpg ~ mpg > 20),
    "Unexpected two-sided formula in selection: mpg ~ mpg > 20"
  )
  expect_null(res)
})

test_that("group1 wrong format", {
  sd <- crosstalk::SharedData$new(mtcars)
  expect_warning(
    res <- kpiwidget(sd,
      kpi = "sum", column = "mpg", comparison = "ratio",
      group1 = "~ cyl > 4"
    ),
    "group1 must be a one-sided formula. Remove single/double quotes if you used them."
  )
  expect_null(res)
})

test_that("group1 must be one-sided formula", {
  sd <- crosstalk::SharedData$new(mtcars)
  expect_warning(
    res <- kpiwidget(sd,
      kpi = "sum", column = "mpg", comparison = "ratio",
      group1 = cyl ~ cyl > 4
    ),
    "Unexpected two-sided formula in group2: cyl ~ cyl > 4"
  )
  expect_null(res)
})

test_that("group2 wrong format", {
  sd <- crosstalk::SharedData$new(mtcars)
  expect_warning(
    res <- kpiwidget(sd,
      kpi = "sum", column = "mpg", comparison = "ratio",
      group1 = ~ cyl > 4, group2 = "~ cyl == 4"
    ),
    "group2 must be a one-sided formula or remain blank. Remove single/double quotes if you used them."
  )
  expect_null(res)
})

test_that("group2 must be one-sided formula", {
  sd <- crosstalk::SharedData$new(mtcars)
  expect_warning(
    res <- kpiwidget(sd,
      kpi = "sum", column = "mpg", comparison = "ratio",
      group1 = ~ cyl > 4, group2 = cyl ~ cyl == 4
    ),
    "Unexpected two-sided formula in group2: cyl ~ cyl == 4"
  )
  expect_null(res)
})


test_that("Comparison mode (ratio), group2 is one-sided formula, returns an htmlwidget with proper filters", {
  sd <- crosstalk::SharedData$new(mtcars)

  res <- kpiwidget(sd,
    kpi = "sum", column = "mpg", comparison = "ratio",
    group1 = ~ cyl > 4, group2 = ~ cyl == 4
  )

  expect_s3_class(res, "htmlwidget")
  expect_equal(res$x$settings$comparison, "ratio")
  expect_equal(res$x$settings$kpi, "sum")

  # Check that group1_filter and group2_filter are logical and have correct length
  expect_true(is.logical(res$x$group1_filter))
  expect_true(is.logical(res$x$group2_filter))
  expect_equal(length(res$x$group1_filter), nrow(mtcars))
  expect_equal(length(res$x$group2_filter), nrow(mtcars))
})


test_that("Comparison mode (ratio) without specified column will return count by default (each row has value == 1). No error is thrown", {
  sd <- crosstalk::SharedData$new(mtcars)

  res <- kpiwidget(sd,
    kpi = "sum", comparison = "ratio",
    group1 = ~ cyl > 4, group2 = ~ cyl == 4
  )

  expect_s3_class(res, "htmlwidget")
  expect_equal(res$x$settings$comparison, "ratio")
  expect_equal(res$x$settings$kpi, "sum")

  # Check that group1_filter and group2_filter are logical and have correct length
  expect_true(is.logical(res$x$group1_filter))
  expect_true(is.logical(res$x$group2_filter))
  expect_equal(length(res$x$group1_filter), nrow(mtcars))
  expect_equal(length(res$x$group2_filter), nrow(mtcars))
})

Try the kpiwidget package in your browser

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

kpiwidget documentation built on April 4, 2025, 2:31 a.m.