Skip to content

Commit a657d34

Browse files
authored
Merge pull request #10 from franccesco/fix/position-name-optional
fix(models): make Position.name optional to handle null API responses
2 parents a06fa4f + d5ee719 commit a657d34

2 files changed

Lines changed: 58 additions & 1 deletion

File tree

src/bloomy/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class Position(BloomyBaseModel):
3232
"""Model for position information."""
3333

3434
id: int
35-
name: str
35+
name: str | None = None
3636

3737

3838
class UserDetails(BloomyBaseModel):

tests/test_users.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,40 @@ def test_details_with_all(
9393
assert len(result.positions) == 1
9494
assert result.positions[0].name == "Manager"
9595

96+
def test_details_with_positions_null_name(
97+
self, mock_http_client: Mock, sample_user_data: dict[str, Any]
98+
) -> None:
99+
"""Test getting user details with positions including null names."""
100+
# Mock responses
101+
user_response = Mock()
102+
user_response.json.return_value = sample_user_data
103+
104+
reports_response = Mock()
105+
reports_response.json.return_value = []
106+
107+
positions_response = Mock()
108+
positions_response.json.return_value = [
109+
{"Group": {"Position": {"Id": 789, "Name": "Manager"}}},
110+
{"Group": {"Position": {"Id": 790, "Name": None}}},
111+
]
112+
113+
mock_http_client.get.side_effect = [
114+
user_response,
115+
reports_response,
116+
positions_response,
117+
]
118+
119+
user_ops = UserOperations(mock_http_client)
120+
result = user_ops.details(user_id=123, all=True)
121+
122+
assert result.direct_reports is not None
123+
assert result.positions is not None
124+
assert len(result.positions) == 2
125+
assert result.positions[0].id == 789
126+
assert result.positions[0].name == "Manager"
127+
assert result.positions[1].id == 790
128+
assert result.positions[1].name is None
129+
96130
def test_direct_reports(self, mock_http_client: Mock) -> None:
97131
"""Test getting direct reports."""
98132
mock_response = Mock()
@@ -139,6 +173,29 @@ def test_positions(self, mock_http_client: Mock) -> None:
139173

140174
mock_http_client.get.assert_called_once_with("users/123/seats")
141175

176+
def test_positions_with_null_name(self, mock_http_client: Mock) -> None:
177+
"""Test getting user positions when name is null."""
178+
mock_response = Mock()
179+
mock_response.json.return_value = [
180+
{"Group": {"Position": {"Id": 101, "Name": None}}},
181+
{"Group": {"Position": {"Id": 102, "Name": "Team Lead"}}},
182+
{"Group": {"Position": {"Id": 103, "Name": None}}},
183+
]
184+
mock_http_client.get.return_value = mock_response
185+
186+
user_ops = UserOperations(mock_http_client)
187+
result = user_ops.positions(user_id=123)
188+
189+
assert len(result) == 3
190+
assert result[0].id == 101
191+
assert result[0].name is None
192+
assert result[1].id == 102
193+
assert result[1].name == "Team Lead"
194+
assert result[2].id == 103
195+
assert result[2].name is None
196+
197+
mock_http_client.get.assert_called_once_with("users/123/seats")
198+
142199
def test_search(self, mock_http_client: Mock) -> None:
143200
"""Test searching users."""
144201
mock_response = Mock()

0 commit comments

Comments
 (0)