tests/testthat/test-extras.R

library(testthat)

test_that("ig_get_options filters option-like positions from mock_response", {
  # Mock response mimicking the API structure for /positions endpoint
  mock <- list(
    positions = list(
      list(
        position = list(
          contractSize = 100,
          createdDate = "2025/10/01 12:00:00",
          dealId = "D1",
          dealSize = 1,
          direction = "BUY",
          limitLevel = 150,
          openLevel = 145,
          currency = "USD",
          controlledRisk = FALSE,
          stopLevel = 140,
          trailingStep = NULL,
          trailingStopDistance = NULL,
          limitedRiskPremium = NULL
        ),
        market = list(
          instrumentName = "Call A",
          expiry = "DEC-25",
          epic = "OP.CALLA.DEC25.IP",
          instrumentType = "OPTION",
          lotSize = 1,
          high = 150,
          low = 140,
          percentageChange = 2.5,
          netChange = 5,
          bid = 145,
          offer = 146,
          updateTime = "2025/10/01 12:00:00",
          delayTime = 0,
          streamingPricesAvailable = TRUE,
          marketStatus = "TRADEABLE",
          scalingFactor = 1
        )
      ),
      list(
        position = list(
          contractSize = 200,
          createdDate = "2025/10/01 12:00:00",
          dealId = "D2",
          dealSize = 2,
          direction = "SELL",
          limitLevel = 1.2000,
          openLevel = 1.1950,
          currency = "USD",
          controlledRisk = FALSE,
          stopLevel = 1.2050,
          trailingStep = NULL,
          trailingStopDistance = NULL,
          limitedRiskPremium = NULL
        ),
        market = list(
          instrumentName = "Spot EURUSD",
          expiry = "-",
          epic = "CS.D.EURUSD.MINI.IP",
          instrumentType = "SPOT",
          lotSize = 1,
          high = 1.2100,
          low = 1.1900,
          percentageChange = -0.5,
          netChange = -0.0050,
          bid = 1.1950,
          offer = 1.1960,
          updateTime = "2025/10/01 12:00:00",
          delayTime = 0,
          streamingPricesAvailable = TRUE,
          marketStatus = "TRADEABLE",
          scalingFactor = 1
        )
      ),
      list(
        position = list(
          contractSize = 300,
          createdDate = "2025/10/01 12:00:00",
          dealId = "D3",
          dealSize = 3,
          direction = "BUY",
          limitLevel = 200,
          openLevel = 195,
          currency = "USD",
          controlledRisk = FALSE,
          stopLevel = 190,
          trailingStep = NULL,
          trailingStopDistance = NULL,
          limitedRiskPremium = NULL
        ),
        market = list(
          instrumentName = "Put B",
          expiry = "DEC-25",
          epic = "OP.PUTB.DEC25.IP",
          instrumentType = "OPTION",
          lotSize = 1,
          high = 200,
          low = 190,
          percentageChange = 1.5,
          netChange = 3,
          bid = 195,
          offer = 196,
          updateTime = "2025/10/01 12:00:00",
          delayTime = 0,
          streamingPricesAvailable = TRUE,
          marketStatus = "TRADEABLE",
          scalingFactor = 1
        )
      )
    )
  )
  
  res <- ig_get_options(
    auth = list(base_url = "https://demo-api.ig.com", cst = "x", security = "y", api_key = "k"),
    mock_response = mock
  )
  expect_s3_class(res, "tbl_df")
  # Should only contain rows where instrumentType indicates OPTION
  expect_true(all(res$instrumentType %in% c("OPTION", "DERIVATIVE", "OPTION_CONTRACT")))
  expect_equal(nrow(res), 2)
  expect_true(all(c("dealId", "instrumentName", "size") %in% names(res)))
  expect_equal(res$dealId, c("D1", "D3"))
  expect_equal(res$instrumentName, c("Call A", "Put B"))
})

test_that("ig_get_options handles empty positions", {
  mock <- list(positions = list())
  res <- ig_get_options(auth = list(base_url = "https://demo-api.ig.com", cst = "x", security = "y", api_key = "k"), mock_response = mock)
  expect_s3_class(res, "tbl_df")
  expect_equal(nrow(res), 0)
  expect_true(all(c("dealId", "instrumentName", "size", "instrumentType") %in% names(res)))
})

test_that("ig_get_options handles missing positions", {
  mock <- list(otherField = "invalid")
  res <- ig_get_options(auth = list(base_url = "https://demo-api.ig.com", cst = "x", security = "y", api_key = "k"), mock_response = mock)
  expect_s3_class(res, "tbl_df")
  expect_equal(nrow(res), 0)
  expect_true(all(c("dealId", "instrumentName", "size", "instrumentType") %in% names(res)))
})

# Mock ig_get_markets_by_epic with correct instrument structure
mock_ig_get_markets_by_epic <- function(epic, auth, detailed = FALSE) {
  if (epic == "CS.D.USDCHF.MINI.IP") {
    return(list(
      instrument = list(  # Single list, not a list of lists
        epic = "CS.D.USDCHF.MINI.IP",
        expiry = "-",
        currencies = list(list(code = "CHF")),
        marketStatus = "TRADEABLE"
      ),
      snapshot = list(
        bid = 0.795,
        offer = 0.795,
        scalingFactor = 10000
      )
    ))
  }
  stop("Invalid epic")
}
assignInNamespace("ig_get_markets_by_epic", mock_ig_get_markets_by_epic, ns = "igfetchr")


test_that("ig_execute_trade fails with invalid epic", {
  mock_auth <- list(
    base_url = "https://demo-api.ig.com",
    api_key = "mock_api_key",
    cst = "mock_cst",
    security = "mock_security_token",
    acc_number = "mock_account"
  )
  
  expect_error(
    ig_execute_trade(
      epic = "",
      direction = "BUY",
      size = 1.0,
      auth = mock_auth,
      currency_code = "CHF",
      order_type = "MARKET",
      time_in_force = "FILL_OR_KILL"
    ),
    regexp = "is.character\\(epic\\) && nchar\\(epic\\) > 0 is not TRUE"
  )
})

test_that("ig_execute_trade fails with invalid direction", {
  mock_auth <- list(
    base_url = "https://demo-api.ig.com",
    api_key = "mock_api_key",
    cst = "mock_cst",
    security = "mock_security_token",
    acc_number = "mock_account"
  )
  
  expect_error(
    ig_execute_trade(
      epic = "CS.D.USDCHF.MINI.IP",
      direction = "INVALID",
      size = 1.0,
      auth = mock_auth,
      currency_code = "CHF",
      order_type = "MARKET",
      time_in_force = "FILL_OR_KILL"
    ),
    regexp = "is.character\\(direction\\) && direction %in% c\\(\"BUY\", \"SELL\"\\) is not TRUE"
  )
})

test_that("ig_execute_trade fails with invalid size", {
  mock_auth <- list(
    base_url = "https://demo-api.ig.com",
    api_key = "mock_api_key",
    cst = "mock_cst",
    security = "mock_security_token",
    acc_number = "mock_account"
  )
  
  expect_error(
    ig_execute_trade(
      epic = "CS.D.USDCHF.MINI.IP",
      direction = "BUY",
      size = -1,
      auth = mock_auth,
      currency_code = "CHF",
      order_type = "MARKET",
      time_in_force = "FILL_OR_KILL"
    ),
    regexp = "is.numeric\\(size\\) && size > 0 is not TRUE"
  )
})

test_that("ig_execute_trade fails with invalid auth", {
  expect_error(
    ig_execute_trade(
      epic = "CS.D.USDCHF.MINI.IP",
      direction = "BUY",
      size = 1.0,
      auth = NULL,
      currency_code = "CHF",
      order_type = "MARKET",
      time_in_force = "FILL_OR_KILL"
    ),
    regexp = "`auth` must be a list from ig_auth\\(\\)"
  )
})

test_that("ig_execute_trade fails with invalid deal_reference", {
  mock_auth <- list(
    base_url = "https://demo-api.ig.com",
    api_key = "mock_api_key",
    cst = "mock_cst",
    security = "mock_security_token",
    acc_number = "mock_account"
  )
  
  expect_error(
    ig_execute_trade(
      epic = "CS.D.USDCHF.MINI.IP",
      direction = "BUY",
      size = 1.0,
      auth = mock_auth,
      currency_code = "CHF",
      order_type = "MARKET",
      time_in_force = "FILL_OR_KILL",
      deal_reference = "INVALID@REFERENCE"
    ),
    regexp = "is.null\\(deal_reference\\) \\|\\| \\(is.character\\(deal_reference\\) && grepl.* is not TRUE"
  )
})


test_that("ig_close_session works in testing mode and ig_logout returns TRUE", {
  Sys.setenv(IGFETCHR_TESTING = "true")
  on.exit(Sys.unsetenv("IGFETCHR_TESTING"))

  expect_true(isTRUE(ig_close_session(list(base_url = "https://demo-api.ig.com", cst = "x", security = "y"))))
  expect_true(isTRUE(ig_logout(list(base_url = "https://demo-api.ig.com", cst = "x", security = "y"))))
})

Try the igfetchr package in your browser

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

igfetchr documentation built on Nov. 21, 2025, 5:07 p.m.