test_that("complex promise chains with mixed success/failure", { counter <- 0 promise_resolve(1) |> then(\(x) { counter <<- counter + 1 stop("error1") }) |> catch(\(err) { counter <<- counter + 1 "recovered" }) |> then(\(x) { counter <<- counter + 1 x }) |> catch(\(err) { counter <<- counter + 1 "should not reach" }) |> then(\(x) { counter <<- counter + 1 expect_equal(x, "recovered") }) |> wait_for_it() expect_equal(counter, 4) }) test_that("then() handles NULL callbacks correctly", { # NULL onFulfilled should pass through value expect_assertions(1) promise_resolve(42) |> then(NULL, \(err) "error") |> extract() |> expect_equal(42) }) test_that("catch() handles NULL callbacks correctly", { # NULL onRejected should pass through error expect_assertions(1) promise_resolve(stop("boom")) |> then(\(x) x, NULL) |> catch(\(err) expect_match(err$message, "boom")) |> wait_for_it() }) test_that("then() validates arguments properly", { expect_error( then(promise_resolve(1), onFulfilled = "not a function"), "function" ) expect_error( catch(promise_resolve(1), "not a function"), "function" ) }) test_that("tee types are handled correctly", { expect_silent({ p <- promise_resolve(1) |> then(tee = TRUE) p2 <- promise_resolve(1) |> catch(\(err) {}, tee = TRUE) }) expect_snapshot( then(promise_resolve(1), tee = 4), error = TRUE ) expect_snapshot( promise_resolve(1) |> catch(\(err) {}, tee = "4"), error = TRUE ) }) test_that("then(tee = FALSE) functions are normalized", { counter <- 0 promise_resolve(1) |> then( \() { counter <<- counter + 1 2 } ) |> then( \(value) { expect_equal(value, 2) counter <<- counter + 1 invisible(3) } ) |> then( \(value, .visible) { expect_equal(value, 3) expect_false(.visible) counter <<- counter + 1 stop("boom") } ) |> then( onRejected = \() { counter <<- counter + 1 stop("blast") } ) |> then( onRejected = \(err) { expect_true(grepl("blast", err$message)) counter <<- counter + 1 } ) wait_for_it() expect_equal(counter, 5) }) test_that("catch(tee = FALSE) functions are normalized", { counter <- 0 promise_resolve(stop("boom")) |> catch( \() { counter <<- counter + 1 stop("blast") } ) |> catch( \(err) { expect_true(grepl("blast", err$message)) counter <<- counter + 1 } ) |> catch(\(err) {}) wait_for_it() expect_equal(counter, 2) }) test_that("then(tee=TRUE) functions are normalized", { then_counter <- 0 error_counter <- 0 promise_resolve(1) |> then( tee = TRUE, \() { then_counter <<- then_counter + 1 } ) |> then( tee = TRUE, \(value) { expect_equal(value, 1) then_counter <<- then_counter + 1 3 } ) |> then( tee = TRUE, \(value, .visible) { expect_equal(value, 1) expect_true(.visible) then_counter <<- then_counter + 1 stop("boom") } ) |> then( tee = TRUE, onRejected = \() { error_counter <<- error_counter + 1 } ) |> then( tee = TRUE, onRejected = \(err) { expect_true(grepl("boom", err$message)) error_counter <<- error_counter + 1 } ) |> then(onRejected = \(err) { expect_true(grepl("boom", err$message)) error_counter <<- error_counter + 1 }) |> wait_for_it() expect_equal(then_counter, 3) expect_equal(error_counter, 3) }) test_that("catch(tee=TRUE) functions are normalized", { error_counter <- 0 promise_resolve(stop("boom")) |> catch( tee = TRUE, \() { error_counter <<- error_counter + 1 } ) |> catch( tee = TRUE, \(err) { expect_true(grepl("boom", err$message)) error_counter <<- error_counter + 1 } ) |> catch(\() { error_counter <<- error_counter + 1 }) |> wait_for_it() expect_equal(error_counter, 3) })