@@ -115,3 +115,82 @@ def test_identify_with_traits_serializer__transient__identity_and_traits_not_per
115115 # Then
116116 assert not Identity .objects .filter (identifier = identity_identifier ).exists ()
117117 assert not Trait .objects .filter (identity__identifier = identity_identifier ).exists ()
118+
119+
120+ def test_identify_with_traits_serializer_validate_traits_returns_empty_list_when_persistence_not_allowed (
121+ mocker : MockerFixture ,
122+ environment : Environment ,
123+ ) -> None :
124+ # Given
125+ data = {
126+ "identifier" : "test_user" ,
127+ "traits" : [
128+ {"trait_key" : "key1" , "trait_value" : "value1" },
129+ {"trait_key" : "key2" , "trait_value" : "value2" },
130+ ],
131+ }
132+
133+ environment .allow_client_traits = False
134+ environment .save ()
135+
136+ mock_request = mocker .MagicMock ()
137+ mock_request .environment = environment
138+
139+ serializer = IdentifyWithTraitsSerializer (
140+ data = data , context = {"environment" : environment , "request" : mock_request }
141+ )
142+
143+ # When
144+ assert serializer .is_valid ()
145+ validated_traits = serializer .validated_data .get ("traits" )
146+
147+ serializer .save () # type: ignore[no-untyped-call]
148+ # Then
149+ assert validated_traits == []
150+
151+ assert Identity .objects .filter (identifier = "test_user" ).exists ()
152+ assert not Trait .objects .filter (identity__identifier = "test_user" ).exists ()
153+
154+
155+ def test_identify_with_traits_serializer_does_not_erase_existing_traits_when_persistence_not_allowed (
156+ mocker : MockerFixture ,
157+ environment : Environment ,
158+ ) -> None :
159+ # Given
160+ identity = Identity .objects .create (environment = environment , identifier = "new_user" )
161+ Trait .objects .create (
162+ identity = identity ,
163+ trait_key = "existing_key" ,
164+ string_value = "existing_value" ,
165+ value_type = "string" ,
166+ )
167+
168+ environment .allow_client_traits = False
169+ environment .save ()
170+
171+ data = {
172+ "identifier" : "new_user" ,
173+ "traits" : [
174+ {"trait_key" : "new_key" , "trait_value" : "new_value" },
175+ {"trait_key" : "new_second_key" , "trait_value" : "new_second_value" },
176+ ],
177+ }
178+
179+ mock_request = mocker .MagicMock ()
180+ mock_request .environment = environment
181+
182+ serializer = IdentifyWithTraitsSerializer (
183+ data = data , context = {"environment" : environment , "request" : mock_request }
184+ )
185+
186+ # When
187+ assert serializer .is_valid ()
188+ serializer .save () # type: ignore[no-untyped-call]
189+
190+ # Then
191+ identity .refresh_from_db ()
192+ traits = Trait .objects .filter (identity = identity )
193+
194+ assert traits .count () == 1
195+ assert traits [0 ].trait_key == "existing_key"
196+ assert traits [0 ].string_value == "existing_value"
0 commit comments