Coverage for tests/test_customers.py: 100%

105 statements  

« prev     ^ index     » next       coverage.py v7.14.1, created at 2026-06-09 19:37 +0200

1"""Tests du sous-client customers (synchrone et asynchrone).""" 

2 

3from __future__ import annotations 

4 

5from typing import Any 

6 

7from unittest.mock import AsyncMock, MagicMock 

8 

9import pytest # type: ignore[import] # pylint: disable=W0611 

10 

11from henrri_connect.connect import ( 

12 AsyncHenrriClient, SyncHenrriClient, # type: ignore[import] 

13) 

14from henrri_connect.models import Contact, Customer, CustomerRequest 

15from henrri_connect.models.base import CustomerType 

16from tests.conftest import CUSTOMER_JSON, PAGED_META, make_response 

17 

18 

19def _paged(elements: list[Any]) -> dict[str, Any]: 

20 return {"elements": elements, "meta": PAGED_META} 

21 

22 

23class TestSyncCustomers: 

24 """Tests du sous-client customers (synchrone).""" 

25 def test_list_retourne_clients( 

26 self, sync_client: SyncHenrriClient, mock_http: MagicMock 

27 ) -> None: 

28 """Test de la méthode list_customers().""" 

29 mock_http.request.return_value = make_response(_paged([CUSTOMER_JSON])) 

30 

31 result = sync_client.customers.list_customers( 

32 request=CustomerRequest( 

33 page=1, 

34 limit=50, 

35 search="", 

36 from_date="2020-01-01", 

37 to_date="2027-01-01", 

38 ), 

39 with_selected_fields=False, 

40 ) 

41 

42 assert len(result.elements or []) == 1 

43 assert (result.elements[0].name if result.elements else None) == "Acme Corp" 

44 assert (result.meta.total_count if result.meta else 0) == 1 

45 

46 def test_list_passe_les_filtres( 

47 self, sync_client: SyncHenrriClient, mock_http: MagicMock 

48 ) -> None: 

49 """Test de la méthode list_customers().""" 

50 mock_http.request.return_value = make_response(_paged([])) 

51 

52 sync_client.customers.list_customers( 

53 request=CustomerRequest(search="acme", page=2, limit=10, from_date="", to_date=""), 

54 with_selected_fields=False, 

55 ) 

56 

57 _, kwargs = mock_http.request.call_args 

58 params = kwargs["params"] 

59 assert params["search"] == "acme" 

60 assert params["page"] == 2 

61 assert params["limit"] == 10 

62 

63 def test_list_exclut_params_none( 

64 self, sync_client: SyncHenrriClient, mock_http: MagicMock 

65 ) -> None: 

66 """Test de la méthode list_customers().""" 

67 mock_http.request.return_value = make_response(_paged([])) 

68 

69 sync_client.customers.list_customers( 

70 request=CustomerRequest(search="", from_date="", to_date=""), 

71 with_selected_fields=False, 

72 ) 

73 

74 _, kwargs = mock_http.request.call_args 

75 params = kwargs["params"] 

76 # ``search`` is required on CustomerRequest in current models; 

77 # it will be present as empty string 

78 assert params["search"] == "" 

79 assert "sortBy" not in params 

80 

81 def test_add_cree_client( 

82 self, sync_client: SyncHenrriClient, mock_http: MagicMock 

83 ) -> None: 

84 """Test de la méthode add_customer().""" 

85 mock_http.request.return_value = make_response({**CUSTOMER_JSON, "id": 99}) 

86 customer = Customer(name="Nouveau", type=CustomerType.COMPANY) 

87 

88 result = sync_client.customers.add(customer) 

89 

90 assert result.id == 99 

91 args = mock_http.request.call_args 

92 assert args.args[0] == "POST" 

93 

94 def test_get_retourne_client( 

95 self, sync_client: SyncHenrriClient, mock_http: MagicMock 

96 ) -> None: 

97 """Test de la méthode get_customer().""" 

98 mock_http.request.return_value = make_response(CUSTOMER_JSON) 

99 

100 result = sync_client.customers.get(1) 

101 

102 assert result.id == 1 

103 assert "/v1/customers/1" in mock_http.request.call_args.args[1] 

104 

105 def test_modify_met_a_jour( 

106 self, sync_client: SyncHenrriClient, mock_http: MagicMock 

107 ) -> None: 

108 """Test de la méthode modify_customer().""" 

109 updated = {**CUSTOMER_JSON, "name": "Acme Updated"} 

110 mock_http.request.return_value = make_response(updated) 

111 customer = Customer(name="Acme Updated", type=CustomerType.COMPANY) 

112 

113 result = sync_client.customers.modify(1, customer) 

114 

115 assert result.name == "Acme Updated" 

116 assert mock_http.request.call_args.args[0] == "PUT" 

117 

118 def test_delete_envoie_delete( 

119 self, sync_client: SyncHenrriClient, mock_http: MagicMock 

120 ) -> None: 

121 """Test de la méthode delete_customer().""" 

122 mock_http.request.return_value = make_response({}) 

123 

124 sync_client.customers.delete(1) 

125 

126 assert mock_http.request.call_args.args[0] == "DELETE" 

127 assert "/v1/customers/1" in mock_http.request.call_args.args[1] 

128 

129 def test_get_best_sales( 

130 self, sync_client: SyncHenrriClient, mock_http: MagicMock 

131 ) -> None: 

132 """Test de la méthode get_best_sales().""" 

133 mock_http.request.return_value = make_response(_paged([CUSTOMER_JSON])) 

134 

135 result = sync_client.customers.get_best_sales(year=2025) 

136 

137 assert len(result.elements or []) == 1 

138 assert "/customers/best-sales" in mock_http.request.call_args.args[1] 

139 

140 def test_get_address( 

141 self, sync_client: SyncHenrriClient, mock_http: MagicMock 

142 ) -> None: 

143 """Test de la méthode get_address().""" 

144 mock_http.request.return_value = make_response( 

145 {"id": 5, "city": "Paris", "isPostCodeShared": False} 

146 ) 

147 

148 address = sync_client.customers.get_address(1) 

149 

150 assert address.city == "Paris" 

151 assert "/v1/customers/1/address" in mock_http.request.call_args.args[1] 

152 

153 def test_list_contacts( 

154 self, sync_client: SyncHenrriClient, mock_http: MagicMock 

155 ) -> None: 

156 """Test de la méthode list_contacts().""" 

157 contact_json = {"id": 1, "firstName": "Alice", "isPrimary": True, "showOnDocument": False} 

158 mock_http.request.return_value = make_response([contact_json]) 

159 

160 contacts = sync_client.customers.list_contacts(1) 

161 

162 assert len(contacts) == 1 

163 assert contacts[0].first_name == "Alice" 

164 

165 def test_add_contact( 

166 self, sync_client: SyncHenrriClient, mock_http: MagicMock 

167 ) -> None: 

168 """Test de la méthode add_contact().""" 

169 contact_json = {"id": 2, "firstName": "Bob", "isPrimary": False, "showOnDocument": False} 

170 mock_http.request.return_value = make_response(contact_json) 

171 contact = Contact() 

172 

173 result = sync_client.customers.add_contact(1, contact) 

174 

175 assert result.id == 2 

176 assert mock_http.request.call_args.args[0] == "POST" 

177 

178 def test_delete_contact( 

179 self, sync_client: SyncHenrriClient, mock_http: MagicMock 

180 ) -> None: 

181 """Test de la méthode delete_contact().""" 

182 mock_http.request.return_value = make_response({}) 

183 

184 sync_client.customers.delete_contact(1, 2) 

185 

186 assert mock_http.request.call_args.args[0] == "DELETE" 

187 assert "/contacts/2" in mock_http.request.call_args.args[1] 

188 

189 

190class TestAsyncCustomers: 

191 """Test de la classe AsyncCustomers.""" 

192 async def test_list_retourne_clients( 

193 self, async_client: AsyncHenrriClient, mock_async_http: AsyncMock 

194 ) -> None: 

195 """Test de la méthode list_customers().""" 

196 mock_async_http.request.return_value = make_response(_paged([CUSTOMER_JSON])) 

197 

198 result = await async_client.customers.list_customers( 

199 request=CustomerRequest(search="", from_date="", to_date=""), 

200 with_selected_fields=False, 

201 ) 

202 assert result is not None 

203 assert result.elements is not None 

204 assert len(result.elements) == 1 

205 assert result.elements[0].name == "Acme Corp" 

206 

207 async def test_get_retourne_client( 

208 self, async_client: AsyncHenrriClient, mock_async_http: AsyncMock 

209 ) -> None: 

210 """Test de la méthode get_customer().""" 

211 mock_async_http.request.return_value = make_response(CUSTOMER_JSON) 

212 

213 result = await async_client.customers.get(1) 

214 

215 assert result.id == 1 

216 

217 async def test_add_cree_client( 

218 self, async_client: AsyncHenrriClient, mock_async_http: AsyncMock 

219 ) -> None: 

220 """Test de la méthode add_customer().""" 

221 mock_async_http.request.return_value = make_response({**CUSTOMER_JSON, "id": 88}) 

222 customer = Customer(name="Async Corp", type=CustomerType.COMPANY) 

223 

224 result = await async_client.customers.add(customer) 

225 

226 assert result.id == 88 

227 

228 async def test_delete_envoie_delete( 

229 self, async_client: AsyncHenrriClient, mock_async_http: AsyncMock 

230 ) -> None: 

231 """Test de la méthode delete_customer().""" 

232 mock_async_http.request.return_value = make_response({}) 

233 

234 await async_client.customers.delete(1) 

235 

236 assert mock_async_http.request.call_args.args[0] == "DELETE"