tests/testthat/test-bid_validate.R

test_that("bid_validate works with valid inputs", {
  anticipate_result <- bid_anticipate(
    bid_structure(
      bid_interpret(
        bid_notice(
          problem = "Complex interface",
          theory = "Cognitive Load Theory",
          evidence = "User complaints"
        ),
        central_question = "How to simplify?",
        data_story = list(
          hook = "Users are confused",
          context = "Dashboard has evolved over time"
        )
      ),

      concepts = c("Principle of Proximity", "Default Effect")
    ),
    bias_mitigations = list(
      anchoring = "Provide reference points",
      framing = "Use consistent positive framing"
    )
  )

  result <- bid_validate(
    previous_stage = anticipate_result,
    summary_panel = "Dashboard simplified for quicker insights",
    collaboration = "Added team annotation features"
  )

  expect_s3_class(result, "tbl_df")
  expect_equal(result$stage, "Validate")
  expect_equal(
    result$summary_panel,
    "Dashboard simplified for quicker insights"
  )
  expect_equal(result$collaboration, "Added team annotation features")
  expect_match(result$previous_bias, "anchoring: Provide reference points")
  expect_true(!is.na(result$suggestions))
})

test_that("bid_validate fails with missing previous_stage", {
  expect_error(
    bid_validate(summary_panel = "Test", collaboration = "Test"),
    "argument \"previous_stage\" is missing, with no default"
  )
})

test_that("bid_validate allows optional parameters", {
  anticipate_result <- bid_anticipate(
    bid_structure(
      bid_interpret(
        bid_notice(
          problem = "Complex interface",
          theory = "Cognitive Load Theory",
          evidence = "User complaints"
        ),
        central_question = "How to simplify?",
        data_story = list(
          hook = "Users are confused",
          context = "Dashboard has evolved over time"
        )
      ),

      concepts = c("Principle of Proximity", "Default Effect")
    ),
    bias_mitigations = list(
      anchoring = "Provide reference points",
      framing = "Use consistent positive framing"
    )
  )

  # Should not error when only summary_panel is provided
  expect_no_error(
    bid_validate(
      previous_stage = anticipate_result,
      summary_panel = "Test"
    )
  )

  # Should not error when only collaboration is provided
  expect_no_error(
    bid_validate(
      previous_stage = anticipate_result,
      collaboration = "Test"
    )
  )
})

test_that("bid_validate validates boolean parameters", {
  anticipate_result <- bid_anticipate(
    bid_structure(
      bid_interpret(
        bid_notice(
          problem = "Complex interface",
          theory = "Cognitive Load Theory",
          evidence = "User complaints"
        ),
        central_question = "How to simplify?",
        data_story = list(
          hook = "Users are confused",
          context = "Dashboard has evolved over time"
        )
      )
    ),
    bias_mitigations = list(anchoring = "Provide reference points")
  )

  # Test invalid include_exp_design
  expect_error(
    bid_validate(
      previous_stage = anticipate_result,
      include_exp_design = "not_logical"
    ),
    "Parameter 'include_exp_design' must be a single logical value \\(TRUE/FALSE\\)"
  )

  # Test invalid include_telemetry
  expect_error(
    bid_validate(
      previous_stage = anticipate_result,
      include_telemetry = c(TRUE, FALSE)
    ),
    "Parameter 'include_telemetry' must be a single logical value \\(TRUE/FALSE\\)"
  )

  # Test invalid include_empower_tools
  expect_error(
    bid_validate(
      previous_stage = anticipate_result,
      include_empower_tools = 1
    ),
    "Parameter 'include_empower_tools' must be a single logical value \\(TRUE/FALSE\\)"
  )

  # Test valid boolean values work
  expect_no_error(
    bid_validate(
      previous_stage = anticipate_result,
      include_exp_design = FALSE,
      include_telemetry = TRUE,
      include_empower_tools = FALSE
    )
  )
})

test_that("bid_validate provides contextual suggestions", {
  anticipate_result <- bid_anticipate(
    bid_structure(
      bid_interpret(
        bid_notice(
          problem = "Complex interface",
          theory = "Cognitive Load Theory",
          evidence = "User complaints"
        ),
        central_question = "How to simplify?",
        data_story = list(
          hook = "Users are confused",
          context = "Dashboard has evolved over time"
        )
      ),

      concepts = c("Principle of Proximity", "Default Effect")
    ),
    bias_mitigations = list(
      anchoring = "Provide reference points",
      framing = "Use consistent positive framing"
    )
  )

  result <- bid_validate(
    previous_stage = anticipate_result,
    summary_panel = "Dashboard improved",
    collaboration = "Added team features"
  )

  # Check that suggestions are contextual (not specific patterns)
  expect_true(nchar(result$suggestions) > 0)
  expect_type(result$suggestions, "character")
})

test_that("bid_validate auto-suggests summary_panel when NULL", {
  anticipate_result <- bid_anticipate(
    bid_structure(
      bid_interpret(
        bid_notice(
          problem = "Complex interface",
          theory = "Cognitive Load Theory",
          evidence = "User complaints"
        ),
        central_question = "How to simplify?",
        data_story = list(
          hook = "Users are confused",
          context = "Dashboard has evolved over time"
        )
      ),

      concepts = c("Principle of Proximity", "Default Effect")
    ),
    bias_mitigations = list(
      anchoring = "Provide reference points",
      framing = "Use consistent positive framing"
    )
  )

  suppressMessages(
    result <- bid_validate(
      previous_stage = anticipate_result,
      summary_panel = NULL,
      collaboration = "Added team annotation features"
    )
  )

  expect_s3_class(result, "tbl_df")
  expect_false(is.na(result$summary_panel[1]))
  expect_true(nchar(result$summary_panel[1]) > 0)
  # Auto-suggested summary should be meaningful
  expect_true(nchar(result$summary_panel[1]) > 10)
})

test_that("bid_validate auto-suggests collaboration when NULL", {
  anticipate_result <- bid_anticipate(
    bid_structure(
      bid_interpret(
        bid_notice(
          problem = "Complex interface",
          theory = "Cognitive Load Theory",
          evidence = "User complaints"
        ),
        central_question = "How to simplify?",
        data_story = list(
          hook = "Users are confused",
          context = "Dashboard has evolved over time"
        )
      ),

      concepts = c("Principle of Proximity", "Default Effect")
    ),
    bias_mitigations = list(
      anchoring = "Provide reference points",
      framing = "Use consistent positive framing"
    ),
    interaction_principles = list(
      hover = "Show details on hover",
      feedback = "Visual feedback for selected items"
    )
  )

  suppressMessages(
    result <- bid_validate(
      previous_stage = anticipate_result,
      summary_panel = "Test summary",
      collaboration = NULL
    )
  )

  expect_s3_class(result, "tbl_df")
  expect_false(is.na(result$collaboration[1]))
  expect_true(nchar(result$collaboration[1]) > 0)
  # Auto-suggested collaboration should be meaningful
  expect_true(nchar(result$collaboration[1]) > 10)
})

test_that("bid_validate auto-suggests next_steps when NULL", {
  anticipate_result <- bid_anticipate(
    bid_structure(
      bid_interpret(
        bid_notice(
          problem = "Complex interface",
          theory = "Cognitive Load Theory",
          evidence = "User complaints"
        ),
        central_question = "How to simplify?",
        data_story = list(
          hook = "Users are confused",
          context = "Dashboard has evolved over time"
        )
      ),

      concepts = c("Principle of Proximity", "Default Effect")
    ),
    bias_mitigations = list(
      anchoring = "Provide reference points",
      framing = "Use consistent positive framing"
    )
  )

  suppressMessages(
    result <- bid_validate(
      previous_stage = anticipate_result,
      summary_panel = "Test summary",
      collaboration = "Test collaboration",
      next_steps = NULL
    )
  )

  expect_s3_class(result, "tbl_df")
  expect_false(is.na(result$next_steps[1]))
  expect_true(nchar(result$next_steps[1]) > 0)
  # Should contain multiple steps (semicolon-separated)
  expect_gt(stringr::str_count(result$next_steps[1], ";"), 0)
})

test_that("bid_validate handles NA values in previous_stage fields", {
  anticipate_result <- tibble(
    stage = "Anticipate",
    bias_mitigations = NA_character_,
    interaction_principles = NA_character_,
    previous_layout = NA_character_,
    previous_concepts = NA_character_,
    previous_accessibility = NA_character_,
    timestamp = Sys.time()
  )

  suppressMessages(
    result <- bid_validate(
      previous_stage = anticipate_result,
      summary_panel = "Test summary",
      collaboration = "Test collaboration"
    )
  )

  expect_s3_class(result, "tbl_df")
  expect_true(is.na(result$previous_bias[1]))
  # previous_interaction was removed, no longer testing it
  expect_true(is.na(result$previous_layout[1]))
  expect_true(is.na(result$previous_concepts[1]))
  expect_true(is.na(result$previous_accessibility[1]))

  expect_false(is.na(result$summary_panel[1]))
  expect_false(is.na(result$collaboration[1]))
  expect_false(is.na(result$suggestions[1]))
})

test_that("bid_validate handles next_steps edge cases", {
  anticipate_result <- tibble(
    stage = "Anticipate",
    bias_mitigations = "test: value",
    timestamp = Sys.time()
  )

  # Test with short steps - should work without warning
  result <- bid_validate(
    previous_stage = anticipate_result,
    summary_panel = "Test summary",
    collaboration = "Test collaboration",
    next_steps = c("OK", "Good", "Review dashboard", "Implement changes")
  )

  expect_s3_class(result, "tbl_df")
  expect_false(is.na(result$next_steps[1]))

  # Test with long steps - should work without warning
  long_step <- paste(
    rep(
      "This is a very long next step description that goes into excessive detail. ",
      5
    ),
    collapse = ""
  )

  result <- bid_validate(
    previous_stage = anticipate_result,
    summary_panel = "Test summary",
    collaboration = "Test collaboration",
    next_steps = c("Step 1", long_step, "Step 3")
  )

  expect_s3_class(result, "tbl_df")
  expect_false(is.na(result$next_steps[1]))

  # Test with empty steps - should auto-suggest
  suppressMessages(
    result <- bid_validate(
      previous_stage = anticipate_result,
      summary_panel = "Test summary",
      collaboration = "Test collaboration",
      next_steps = c("", "  ", "")
    )
  )

  expect_s3_class(result, "tbl_df")
  expect_false(is.na(result$next_steps[1]))
  expect_true(nchar(result$next_steps[1]) > 0)
})

test_that("bid_validate handles summary_panel and collaboration variations", {
  anticipate_result <- tibble(
    stage = "Anticipate",
    bias_mitigations = "test: value",
    timestamp = Sys.time()
  )

  # Test with short summary - should still work
  result <- bid_validate(
    previous_stage = anticipate_result,
    summary_panel = "Too short",
    collaboration = "Test collaboration"
  )

  expect_s3_class(result, "tbl_df")
  expect_equal(result$summary_panel, "Too short")
  expect_true(nchar(result$suggestions) > 0)

  # Test with long summary - should still work
  long_summary <- paste(
    rep(
      "This is a very detailed summary that contains excessive information about the dashboard. ",
      10
    ),
    collapse = ""
  )

  result <- bid_validate(
    previous_stage = anticipate_result,
    summary_panel = long_summary,
    collaboration = "Test collaboration"
  )

  expect_s3_class(result, "tbl_df")
  expect_equal(result$summary_panel, long_summary)
  expect_true(nchar(result$suggestions) > 0)

  # Test with basic collaboration
  result <- bid_validate(
    previous_stage = anticipate_result,
    summary_panel = "Test summary",
    collaboration = "Basic features only"
  )

  expect_s3_class(result, "tbl_df")
  expect_equal(result$collaboration, "Basic features only")
  expect_true(nchar(result$suggestions) > 0)
})

test_that("bid_validate properly handles interaction_principles JSON", {
  anticipate_result <- tibble(
    stage = "Anticipate",
    bias_mitigations = "anchoring: Test",
    interaction_principles = "{\"hover\":\"Show on hover\",\"selection\":\"Highlight selected\"}",
    timestamp = Sys.time()
  )

  result <- bid_validate(
    previous_stage = anticipate_result,
    summary_panel = "Test summary",
    collaboration = "Test collaboration"
  )

  expect_s3_class(result, "tbl_df")
  # previous_interaction was removed in refactor, no longer testing it
  expect_type(result$suggestions, "character")
})

test_that("bid_validate tailors collaboration by audience and empower flag", {
  # Executive audience with empower tools (default TRUE)
  prev_exec <- tibble::tibble(
    stage = "Interpret",
    audience = "Executive managers",
    central_question = "How to compare regions?",
    timestamp = Sys.time()
  )

  suppressMessages({
    res_exec <- bid_validate(
      previous_stage = prev_exec,
      summary_panel = "Summary",
      collaboration = NULL
    )
  })
  expect_true(grepl(
    "Executive-focused collaboration",
    res_exec$collaboration,
    ignore.case = TRUE
  ))
  expect_true(
    grepl(
      "decision tracking|empowerment",
      res_exec$suggestions,
      ignore.case = TRUE
    ) ||
      grepl("Executive", res_exec$collaboration, ignore.case = TRUE)
  )

  # Analyst audience without empower tools
  prev_analyst <- tibble::tibble(
    stage = "Interpret",
    audience = "Data analysts",
    central_question = "How to compare models?",
    timestamp = Sys.time()
  )

  suppressMessages({
    res_analyst <- bid_validate(
      previous_stage = prev_analyst,
      summary_panel = "Summary",
      collaboration = NULL,
      include_empower_tools = FALSE
    )
  })
  expect_true(grepl(
    "Advanced collaboration tools",
    res_analyst$collaboration,
    ignore.case = TRUE
  ))
  # ensure empower phrasing is not forced when flag is FALSE
  expect_false(grepl("empower", res_analyst$collaboration, ignore.case = TRUE))
})

test_that("bid_validate adds exp design and telemetry suggestions when missing", {
  prev <- tibble::tibble(
    stage = "Anticipate",
    bias_mitigations = "anchoring: Provide reference points",
    timestamp = Sys.time()
  )

  res <- bid_validate(
    previous_stage = prev,
    summary_panel = "Brief summary",
    collaboration = "Basic sharing",
    next_steps = c("Document decisions"), # no 'test'/'experiment'/'telemetry' terms
    include_exp_design = TRUE,
    include_telemetry = TRUE
  )

  expect_s3_class(res, "tbl_df")
  expect_true(grepl(
    "experimental design|A/B",
    res$suggestions,
    ignore.case = TRUE
  ))
  expect_true(grepl("telemetry|monitor", res$suggestions, ignore.case = TRUE))
})

test_that("bid_validate auto-summary handles compare/trend and problem/find/mobile/theory branches", {
  # central_question contains 'compare'
  prev_compare <- tibble::tibble(
    stage = "Interpret",
    central_question = "How do we compare A vs B?",
    timestamp = Sys.time()
  )
  suppressMessages({
    r1 <- bid_validate(
      previous_stage = prev_compare,
      summary_panel = NULL,
      collaboration = "x"
    )
  })
  expect_true(grepl(
    "Comparative summary",
    r1$summary_panel,
    ignore.case = TRUE
  ))

  # central_question contains 'trend'
  prev_trend <- tibble::tibble(
    stage = "Interpret",
    central_question = "What trend over time should we watch?",
    timestamp = Sys.time()
  )
  suppressMessages({
    r2 <- bid_validate(
      previous_stage = prev_trend,
      summary_panel = NULL,
      collaboration = "x"
    )
  })
  expect_true(grepl("Time-based summary", r2$summary_panel, ignore.case = TRUE))

  # problem contains 'find/search' and 'mobile'
  prev_problem <- tibble::tibble(
    stage = "Notice",
    problem = "Hard to find information on mobile",
    timestamp = Sys.time()
  )
  suppressMessages({
    r3 <- bid_validate(
      previous_stage = prev_problem,
      summary_panel = NULL,
      collaboration = "x"
    )
  })
  expect_true(grepl(
    "navigation paths|Mobile-optimized",
    r3$summary_panel,
    ignore.case = TRUE
  ))

  # theory contains 'visual'
  prev_theory <- tibble::tibble(
    stage = "Notice",
    theory = "Visual Hierarchy",
    timestamp = Sys.time()
  )
  suppressMessages({
    r4 <- bid_validate(
      previous_stage = prev_theory,
      summary_panel = NULL,
      collaboration = "x"
    )
  })
  expect_true(grepl(
    "Visually hierarchical summary",
    r4$summary_panel,
    ignore.case = TRUE
  ))
})

test_that("bid_validate extracts previous info for Structure and cooperation concept path", {
  prev_structure <- tibble::tibble(
    stage = "Structure",
    layout = "grid",
    concepts = "Cooperation",
    accessibility = "Color contrast AA",
    previous_central_question = "How to simplify?",
    timestamp = Sys.time()
  )

  suppressMessages({
    res <- bid_validate(
      previous_stage = prev_structure,
      summary_panel = "S",
      collaboration = NULL
    ) # triggers concept-based collab path
  })
  expect_equal(res$previous_layout, "grid")
  expect_true(grepl(
    "Structured collaboration workflows",
    res$collaboration,
    ignore.case = TRUE
  ))
  expect_match(res$previous_concepts, "Cooperation")
  expect_match(res$previous_accessibility, "Color contrast AA")
})

Try the bidux package in your browser

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

bidux documentation built on Aug. 30, 2025, 1:12 a.m.