tests/testthat/test-utils.R

# validate_duration() -----------------------------------------------------

test_that("validate_duration() accepts a non-negative numeric scalar", {
  expect_no_error(validate_duration(1000))
  expect_no_error(validate_duration(0.5))
  expect_no_error(validate_duration(0))
})

test_that("validate_duration() rejects invalid input", {
  expect_snapshot(error = TRUE, validate_duration("fast"))
  expect_snapshot(error = TRUE, validate_duration(TRUE))
  expect_snapshot(error = TRUE, validate_duration(NULL))
  expect_snapshot(error = TRUE, validate_duration(-1))
  expect_snapshot(error = TRUE, validate_duration(c(100, 200)))
  expect_snapshot(error = TRUE, validate_duration("x", arg = "delay"))
})

# to_js_props() -- plain scalar -------------------------------------------

test_that("to_js_props() passes through a plain numeric scalar unchanged", {
  result <- to_js_props(list(opacity = 1))
  expect_equal(result$opacity, 1)
})

test_that("to_js_props() passes through a plain character scalar unchanged", {
  result <- to_js_props(list(fill = "#ff0000"))
  expect_equal(result$fill, "#ff0000")
})

# to_js_props() -- length-2 numeric vector treated as from/to -------------

test_that("to_js_props() converts a length-2 numeric vector to a from/to list", {
  result <- to_js_props(list(opacity = c(0, 1)))
  expect_type(result$opacity, "list")
  expect_equal(result$opacity$from, 0)
  expect_equal(result$opacity$to, 1)
})

test_that("to_js_props() handles multiple properties simultaneously", {
  result <- to_js_props(list(opacity = c(0, 1), translateY = c(-20, 0)))
  expect_equal(result$opacity$from, 0)
  expect_equal(result$opacity$to, 1)
  expect_equal(result$translateY$from, -20)
  expect_equal(result$translateY$to, 0)
})

# to_js_props() -- nested easing serialisation ----------------------------

test_that("to_js_props() serialises anime_easing objects inside keyframes", {
  kf <- anime_keyframes(
    list(to = 1, ease = anime_easing_spring()),
    list(to = 0, ease = "outQuad")
  )
  result <- to_js_props(list(opacity = kf))
  expect_identical(
    result$opacity[[1]]$ease,
    list(type = "spring", bounce = 0.5, duration = 628)
  )
  expect_identical(result$opacity[[2]]$ease, "outQuad")
})

test_that("to_js_props() serialises the per-property ease of anime_from_to", {
  ft <- anime_from_to(0, 1, ease = anime_easing_bezier(0.4, 0, 0.2, 1))
  result <- to_js_props(list(opacity = ft))
  expect_identical(result$opacity$from, 0)
  expect_identical(result$opacity$to, 1)
  expect_identical(
    result$opacity$ease,
    list(type = "cubicBezier", args = list(0.4, 0, 0.2, 1))
  )
})

# timeline_to_json_config() -----------------------------------------------

test_that("timeline_to_json_config() tags the config kind", {
  config <- timeline_to_json_config(anime_timeline())
  expect_identical(config$kind, "timeline")
})

test_that("timeline_to_json_config() preserves defaults", {
  tl <- anime_timeline(duration = 800, ease = "outElastic", delay = 0)
  result <- timeline_to_json_config(tl)
  expect_equal(result$defaults$duration, 800)
  expect_equal(result$defaults$ease, "outElastic")
})

test_that("timeline_to_json_config() serialises easing objects in defaults", {
  tl <- anime_timeline(ease = anime_easing_spring())
  result <- timeline_to_json_config(tl)
  expect_identical(
    result$defaults$ease,
    list(type = "spring", bounce = 0.5, duration = 628)
  )
})

test_that("timeline_to_json_config() preserves loop", {
  tl <- anime_timeline(loop = TRUE)
  result <- timeline_to_json_config(tl)
  expect_true(result$loop)
})

test_that("timeline_to_json_config() round-trips through JSON without data loss", {
  skip_if_not_installed("jsonlite")

  tl <- anime_timeline(duration = 1000, ease = "linear", delay = 0) |>
    anime_add(selector = ".dot", props = list(opacity = c(0, 1)))
  config <- timeline_to_json_config(tl)
  json <- jsonlite::toJSON(config, auto_unbox = TRUE)
  round_trip <- jsonlite::fromJSON(json, simplifyVector = FALSE)

  expect_equal(round_trip$kind, "timeline")
  expect_equal(round_trip$defaults$duration, 1000)
  expect_equal(round_trip$segments[[1]]$selector, ".dot")
  expect_equal(round_trip$segments[[1]]$props$opacity$from, 0)
  expect_equal(round_trip$segments[[1]]$props$opacity$to, 1)
})

test_that("timeline_to_json_config() includes optional playback fields when present", {
  tl <- anime_timeline() |>
    anime_playback(autoplay = FALSE, controls = TRUE, alternate = TRUE)
  result <- timeline_to_json_config(tl)
  expect_false(result$autoplay)
  expect_true(result$controls)
  expect_true(result$alternate)
})

Try the animejs package in your browser

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

animejs documentation built on Aug. 21, 2026, 5:17 p.m.