Coverage for src/tests/api/v1/club/members/test_presenters.py: 100%

69 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2024-01-01 00:00 +0000

1"""Module for testing the member JSON:API resource.""" 

2 

3import json 

4 

5from typing import Any, AsyncGenerator 

6 

7import pytest 

8 

9from deepdiff import DeepDiff 

10from kwai_api.v1.club.members.presenters import ( 

11 JsonApiContactPresenter, 

12 JsonApiMemberPresenter, 

13 JsonApiPersonPresenter, 

14 JsonApiUploadMemberPresenter, 

15) 

16from kwai_bc_club.domain.contact import ContactEntity, ContactIdentifier 

17from kwai_bc_club.domain.country import CountryEntity 

18from kwai_bc_club.domain.file_upload import FileUploadEntity 

19from kwai_bc_club.domain.member import MemberEntity, MemberIdentifier 

20from kwai_bc_club.domain.person import PersonEntity, PersonIdentifier 

21from kwai_bc_club.domain.value_objects import Address, Birthdate, Gender, License 

22from kwai_bc_club.import_members import MemberImportResult, OkMemberImportResult 

23from kwai_core.domain.presenter import IterableResult 

24from kwai_core.domain.value_objects.date import Date 

25from kwai_core.domain.value_objects.email_address import EmailAddress 

26from kwai_core.domain.value_objects.identifier import IntIdentifier 

27from kwai_core.domain.value_objects.name import Name 

28from kwai_core.domain.value_objects.owner import Owner 

29from kwai_core.domain.value_objects.unique_id import UniqueId 

30 

31 

32@pytest.fixture 

33def contact(country: CountryEntity) -> ContactEntity: 

34 """A fixture for a contact entity.""" 

35 return ContactEntity( 

36 id=ContactIdentifier(1), 

37 emails=(EmailAddress("jigoro.kano@kwai.com"),), 

38 address=Address( 

39 address="", 

40 postal_code="", 

41 city="Tokyo", 

42 county="", 

43 country=country, 

44 ), 

45 ) 

46 

47 

48@pytest.fixture 

49def expected_contact_json( 

50 contact: ContactEntity, expected_country_json: dict[str, Any] 

51) -> dict[str, Any]: 

52 """A fixture for a JSON:API resource of a contact.""" 

53 return { 

54 "data": { 

55 "id": "1", 

56 "type": "contacts", 

57 "attributes": { 

58 "emails": ["jigoro.kano@kwai.com"], 

59 "address": "", 

60 "postal_code": "", 

61 "city": "Tokyo", 

62 "county": "", 

63 "mobile": "", 

64 "tel": "", 

65 "remark": "", 

66 }, 

67 "meta": { 

68 "created_at": str(contact.traceable_time.created_at), 

69 "updated_at": str(contact.traceable_time.updated_at), 

70 }, 

71 "relationships": { 

72 "country": { 

73 "data": { 

74 "id": expected_country_json["data"]["id"], 

75 "type": expected_country_json["data"]["type"], 

76 } 

77 } 

78 }, 

79 }, 

80 "included": [ 

81 expected_country_json["data"], 

82 ], 

83 } 

84 

85 

86@pytest.fixture 

87def person(contact: ContactEntity, country: CountryEntity) -> PersonEntity: 

88 """A fixture for a person entity.""" 

89 return PersonEntity( 

90 id=PersonIdentifier(1), 

91 name=Name(first_name="Jigoro", last_name="Kano"), 

92 gender=Gender.MALE, 

93 birthdate=Birthdate(Date.create(year=1860, month=10, day=28)), 

94 contact=contact, 

95 nationality=country, 

96 ) 

97 

98 

99@pytest.fixture 

100def expected_person_json( 

101 person: PersonEntity, 

102 expected_contact_json: dict[str, Any], 

103 expected_country_json: dict[str, Any], 

104) -> dict[str, Any]: 

105 """A fixture for a JSON:API resource of a person.""" 

106 return { 

107 "data": { 

108 "id": "1", 

109 "type": "persons", 

110 "attributes": { 

111 "first_name": "Jigoro", 

112 "last_name": "Kano", 

113 "gender": 1, 

114 "birthdate": "1860-10-28", 

115 "remark": "", 

116 }, 

117 "meta": { 

118 "created_at": str(person.traceable_time.created_at), 

119 "updated_at": str(person.traceable_time.updated_at), 

120 }, 

121 "relationships": { 

122 "nationality": { 

123 "data": { 

124 "id": expected_country_json["data"]["id"], 

125 "type": expected_country_json["data"]["type"], 

126 } 

127 }, 

128 "contact": { 

129 "data": { 

130 "id": expected_contact_json["data"]["id"], 

131 "type": expected_contact_json["data"]["type"], 

132 } 

133 }, 

134 }, 

135 }, 

136 "included": [expected_contact_json["data"], expected_country_json["data"]], 

137 } 

138 

139 

140def test_create_contact_document( 

141 contact: ContactEntity, expected_contact_json: dict[str, Any] 

142): 

143 """Test the creation of a contact document.""" 

144 contact_document = JsonApiContactPresenter().present(contact).get_document() 

145 json_resource = json.loads(contact_document.model_dump_json()) 

146 

147 diff = DeepDiff(json_resource, expected_contact_json, ignore_order=True) 

148 assert not diff, f"JSON structure is not as expected: {diff}" 

149 

150 

151@pytest.fixture 

152def member(person: PersonEntity) -> MemberEntity: 

153 """A fixture for a member entity.""" 

154 return MemberEntity( 

155 id=MemberIdentifier(1), 

156 license=License(number="1234567890", end_date=Date.today().add(years=1)), 

157 person=person, 

158 ) 

159 

160 

161def test_create_person_document( 

162 person: PersonEntity, expected_person_json: dict[str, Any] 

163): 

164 """Test the creation of a person document.""" 

165 person_document = JsonApiPersonPresenter().present(person).get_document() 

166 json_resource = json.loads(person_document.model_dump_json()) 

167 

168 diff = DeepDiff(json_resource, expected_person_json, ignore_order=True) 

169 assert not diff, f"JSON structure is not as expected: {diff}" 

170 

171 

172@pytest.fixture 

173def expected_member_json( 

174 member: MemberEntity, expected_person_json: dict[str, Any] 

175) -> dict[str, Any]: 

176 """A fixture for a JSON:API resource of a member.""" 

177 return { 

178 "data": { 

179 "id": str(member.uuid), 

180 "type": "members", 

181 "attributes": { 

182 "license_number": "1234567890", 

183 "license_end_date": str(member.license.end_date), 

184 "remark": "", 

185 "active": True, 

186 "competition": False, 

187 }, 

188 "meta": { 

189 "created_at": str(member.traceable_time.created_at), 

190 "updated_at": str(member.traceable_time.updated_at), 

191 }, 

192 "relationships": { 

193 "person": { 

194 "data": { 

195 "id": expected_person_json["data"]["id"], 

196 "type": expected_person_json["data"]["type"], 

197 } 

198 } 

199 }, 

200 }, 

201 "included": [expected_person_json["data"], *expected_person_json["included"]], 

202 } 

203 

204 

205def test_create_member_document( 

206 member: MemberEntity, expected_member_json: dict[str, Any] 

207): 

208 """Test the creation of a JSON:API document for a Member resource.""" 

209 member_document = JsonApiMemberPresenter().present(member).get_document() 

210 json_resource = json.loads(member_document.model_dump_json()) 

211 diff = DeepDiff(json_resource, expected_member_json, ignore_order=True) 

212 assert not diff, f"JSON structure is not expected: {diff}" 

213 

214 

215@pytest.fixture 

216def make_member_import(make_member): 

217 """Fixture factory for creating a member import result.""" 

218 

219 def _make_member_import(): 

220 return OkMemberImportResult( 

221 file_upload=FileUploadEntity( 

222 filename="test.csv", 

223 owner=Owner( 

224 id=IntIdentifier(1), 

225 uuid=UniqueId.generate(), 

226 name=Name(first_name="Jigoro", last_name="Kano"), 

227 ), 

228 ), 

229 row=1, 

230 member=make_member(), 

231 ) 

232 

233 return _make_member_import 

234 

235 

236async def member_import_generator( 

237 make_member_import, 

238) -> AsyncGenerator[MemberImportResult, None]: 

239 """A generator for member import.""" 

240 yield make_member_import() 

241 

242 

243@pytest.fixture 

244def iterable_result(make_member_import) -> IterableResult[MemberImportResult]: 

245 """A fixture that creates a IterableResult for an upload member result.""" 

246 return IterableResult[MemberImportResult]( 

247 count=0, iterator=member_import_generator(make_member_import) 

248 ) 

249 

250 

251async def test_jsonapi_member_upload_presenter(iterable_result): 

252 """Test a presenter for an iterable result containing uploaded members.""" 

253 presenter = JsonApiUploadMemberPresenter() 

254 await presenter.present(iterable_result) 

255 document = presenter.get_document() 

256 assert document is not None, "The presenter should contain a document." 

257 assert len(document.data.relationships.members.data) == 1, ( 

258 "There should be 1 member in the members relationship" 

259 ) 

260 assert document.data.relationships.members.data[0].id != "0", ( 

261 "The member should have an id" 

262 )