File size: 7,391 Bytes
ce4bc73 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
"""Tests for position details component and modal."""
import pytest
from dash import html
from src.folio.components.position_details import create_position_details
from src.folio.data_model import OptionPosition, PortfolioGroup, StockPosition
class TestPositionDetails:
"""Tests for position details component."""
def test_create_position_details(self):
"""Test that position details can be created correctly."""
# Create test positions
stock_position = StockPosition(
ticker="AAPL",
quantity=100,
market_exposure=15000.0,
beta=1.2,
beta_adjusted_exposure=18000.0,
)
option_position = OptionPosition(
ticker="AAPL",
position_type="option",
quantity=10,
market_exposure=1500.0,
beta=1.2,
beta_adjusted_exposure=1800.0,
strike=150.0,
expiry="2023-01-01",
option_type="CALL",
delta=0.7,
delta_exposure=1050.0,
notional_value=15000.0,
underlying_beta=1.2,
)
# Create portfolio group
portfolio_group = PortfolioGroup(
ticker="AAPL",
stock_position=stock_position,
option_positions=[option_position],
net_exposure=16500.0,
beta=1.2,
beta_adjusted_exposure=19800.0,
total_delta_exposure=1050.0,
options_delta_exposure=1050.0,
)
# Create position details
details = create_position_details(portfolio_group)
# Verify that details is a Dash component
assert isinstance(details, html.Div)
# Verify that the ticker is in the title
assert "AAPL" in details.children[0].children
# Verify that there are sections for stock, options, and combined metrics
assert len(details.children[1].children) == 3
def test_create_position_details_no_stock(self):
"""Test that position details can be created correctly without a stock position."""
# Create test positions
option_position = OptionPosition(
ticker="AAPL",
position_type="option",
quantity=10,
market_exposure=1500.0,
beta=1.2,
beta_adjusted_exposure=1800.0,
strike=150.0,
expiry="2023-01-01",
option_type="CALL",
delta=0.7,
delta_exposure=1050.0,
notional_value=15000.0,
underlying_beta=1.2,
)
# Create portfolio group
portfolio_group = PortfolioGroup(
ticker="AAPL",
stock_position=None,
option_positions=[option_position],
net_exposure=1500.0,
beta=1.2,
beta_adjusted_exposure=1800.0,
total_delta_exposure=1050.0,
options_delta_exposure=1050.0,
)
# Create position details
details = create_position_details(portfolio_group)
# Verify that details is a Dash component
assert isinstance(details, html.Div)
# Verify that the ticker is in the title
assert "AAPL" in details.children[0].children
# Verify that there are sections for options and combined metrics (no stock)
assert len(details.children[1].children) == 2
def test_create_position_details_no_options(self):
"""Test that position details can be created correctly without option positions."""
# Create test positions
stock_position = StockPosition(
ticker="AAPL",
quantity=100,
market_exposure=15000.0,
beta=1.2,
beta_adjusted_exposure=18000.0,
)
# Create portfolio group
portfolio_group = PortfolioGroup(
ticker="AAPL",
stock_position=stock_position,
option_positions=[],
net_exposure=15000.0,
beta=1.2,
beta_adjusted_exposure=18000.0,
total_delta_exposure=0.0,
options_delta_exposure=0.0,
)
# Create position details
details = create_position_details(portfolio_group)
# Verify that details is a Dash component
assert isinstance(details, html.Div)
# Verify that the ticker is in the title
assert "AAPL" in details.children[0].children
# Verify that there are sections for stock and combined metrics (no options)
assert len(details.children[1].children) == 2
def test_position_modal_integration(self):
"""Test the full position details modal flow as it would work in the UI.
This test simulates what happens when a user clicks the 'details' button on a position.
It tests the entire flow from position data to displaying the modal, ensuring that
the modal can be created and displayed correctly regardless of the internal implementation.
"""
# Create position data as it would be stored in the UI
position_data = {
"ticker": "AAPL",
"stock_position": {
"ticker": "AAPL",
"quantity": 100,
"market_exposure": 15000.0,
"beta": 1.2,
"beta_adjusted_exposure": 18000.0,
"position_type": "stock", # This field comes from to_dict() serialization
},
"option_positions": [],
"net_exposure": 15000.0,
"beta": 1.2,
"beta_adjusted_exposure": 18000.0,
"total_delta_exposure": 0.0,
"options_delta_exposure": 0.0,
}
try:
# Create a StockPosition from the position data
stock_position_data = position_data["stock_position"].copy()
# The position_type field should now be accepted by StockPosition
# No need to remove it
stock_position = StockPosition(**stock_position_data)
# Create a PortfolioGroup manually
group = PortfolioGroup(
ticker=position_data["ticker"],
stock_position=stock_position,
option_positions=[],
net_exposure=position_data["net_exposure"],
beta=position_data["beta"],
beta_adjusted_exposure=position_data["beta_adjusted_exposure"],
total_delta_exposure=position_data["total_delta_exposure"],
options_delta_exposure=position_data["options_delta_exposure"],
)
# Now create the position details component
details = create_position_details(group)
# Verify that the details component is created correctly
assert details is not None
# Verify that the ticker is in the title
assert "AAPL" in details.children[0].children
# Verify that the details has the expected sections
assert len(details.children[1].children) == 2 # Stock and combined metrics
# Verify that the position_type field is properly stored and returned
assert stock_position.position_type == "stock"
assert stock_position.to_dict()["position_type"] == "stock"
except Exception as e:
pytest.fail(f"Position modal failed to load: {e}")
|