@@ -141,3 +141,179 @@ resource "posthog_survey" "test" {
141141}
142142` , name )
143143}
144+
145+ // TestSurvey_ClearNumericLimits verifies that removing the nullable numeric
146+ // attributes from config sends an explicit JSON null on PATCH, which PostHog
147+ // interprets as "clear this column", and that the resulting state reflects the
148+ // cleared values. Without the drop-omitempty fix, step 2 would still observe
149+ // the values from step 1 because the omitempty pointer would never be sent.
150+ func TestSurvey_ClearNumericLimits (t * testing.T ) {
151+ skipIfNotAcceptance (t )
152+
153+ rName := acctest .RandomWithPrefix ("tf-survey" )
154+
155+ resource .Test (t , resource.TestCase {
156+ PreCheck : func () { testAccPreCheck (t ) },
157+ ProtoV6ProviderFactories : testAccProtoV6ProviderFactories ,
158+ CheckDestroy : testAccCheckSurveyDestroy ,
159+ Steps : []resource.TestStep {
160+ // Step 1: create with every nullable numeric field set so we have a
161+ // non-trivial baseline to clear from.
162+ {
163+ Config : testAccSurveyAllNumericLimits (rName ),
164+ Check : resource .ComposeAggregateTestCheckFunc (
165+ resource .TestCheckResourceAttr (testSurveyResourceName , "schedule" , "recurring" ),
166+ resource .TestCheckResourceAttr (testSurveyResourceName , "responses_limit" , "100" ),
167+ resource .TestCheckResourceAttr (testSurveyResourceName , "iteration_count" , "3" ),
168+ resource .TestCheckResourceAttr (testSurveyResourceName , "iteration_frequency_days" , "7" ),
169+ resource .TestCheckResourceAttr (testSurveyResourceName , "response_sampling_interval_type" , "week" ),
170+ resource .TestCheckResourceAttr (testSurveyResourceName , "response_sampling_interval" , "2" ),
171+ resource .TestCheckResourceAttr (testSurveyResourceName , "response_sampling_limit" , "50" ),
172+ ),
173+ },
174+ // Step 2: drop every nullable numeric field. State must show them as
175+ // unset, which only happens if PostHog actually cleared the columns —
176+ // MapResponseToModel reads them straight from the GET response.
177+ {
178+ Config : testAccSurveyNoNumericLimits (rName ),
179+ Check : resource .ComposeAggregateTestCheckFunc (
180+ resource .TestCheckNoResourceAttr (testSurveyResourceName , "responses_limit" ),
181+ resource .TestCheckNoResourceAttr (testSurveyResourceName , "iteration_count" ),
182+ resource .TestCheckNoResourceAttr (testSurveyResourceName , "iteration_frequency_days" ),
183+ resource .TestCheckNoResourceAttr (testSurveyResourceName , "response_sampling_interval" ),
184+ resource .TestCheckNoResourceAttr (testSurveyResourceName , "response_sampling_limit" ),
185+ ),
186+ },
187+ },
188+ })
189+ }
190+
191+ // TestSurvey_LinkAndUnlinkFlag is the most user-visible drop-omitempty case:
192+ // linking a feature flag, then removing the linked_flag_id and confirming the
193+ // survey is actually unlinked server-side (the API response no longer
194+ // includes a linked_flag, so int64ValueFromMapOrNull surfaces null).
195+ func TestSurvey_LinkAndUnlinkFlag (t * testing.T ) {
196+ skipIfNotAcceptance (t )
197+
198+ rName := acctest .RandomWithPrefix ("tf-survey" )
199+
200+ resource .Test (t , resource.TestCase {
201+ PreCheck : func () { testAccPreCheck (t ) },
202+ ProtoV6ProviderFactories : testAccProtoV6ProviderFactories ,
203+ CheckDestroy : testAccCheckSurveyDestroy ,
204+ Steps : []resource.TestStep {
205+ // Step 1: survey linked to a fresh feature flag.
206+ {
207+ Config : testAccSurveyWithLinkedFlag (rName ),
208+ Check : resource .ComposeAggregateTestCheckFunc (
209+ resource .TestCheckResourceAttrPair (
210+ testSurveyResourceName , "linked_flag_id" ,
211+ "posthog_feature_flag.test" , "id" ,
212+ ),
213+ ),
214+ },
215+ // Step 2: remove linked_flag_id from the survey while keeping the
216+ // flag resource around. The survey should report no linked flag.
217+ {
218+ Config : testAccSurveyWithoutLinkedFlag (rName ),
219+ Check : resource .ComposeAggregateTestCheckFunc (
220+ resource .TestCheckNoResourceAttr (testSurveyResourceName , "linked_flag_id" ),
221+ ),
222+ },
223+ },
224+ })
225+ }
226+
227+ func testAccSurveyAllNumericLimits (name string ) string {
228+ return fmt .Sprintf (`
229+ provider "posthog" {}
230+
231+ resource "posthog_survey" "test" {
232+ name = %q
233+ type = "popover"
234+ schedule = "recurring"
235+ responses_limit = 100
236+ iteration_count = 3
237+ iteration_frequency_days = 7
238+ response_sampling_interval_type = "week"
239+ response_sampling_interval = 2
240+ response_sampling_limit = 50
241+
242+ questions_json = jsonencode([
243+ {
244+ type = "open"
245+ question = "How satisfied are you?"
246+ }
247+ ])
248+ }
249+ ` , name )
250+ }
251+
252+ func testAccSurveyNoNumericLimits (name string ) string {
253+ return fmt .Sprintf (`
254+ provider "posthog" {}
255+
256+ resource "posthog_survey" "test" {
257+ name = %q
258+ type = "popover"
259+
260+ questions_json = jsonencode([
261+ {
262+ type = "open"
263+ question = "How satisfied are you?"
264+ }
265+ ])
266+ }
267+ ` , name )
268+ }
269+
270+ func testAccSurveyWithLinkedFlag (name string ) string {
271+ return fmt .Sprintf (`
272+ provider "posthog" {}
273+
274+ resource "posthog_feature_flag" "test" {
275+ key = %[1]q
276+ name = "Test flag for survey link"
277+ active = true
278+ rollout_percentage = 100
279+ }
280+
281+ resource "posthog_survey" "test" {
282+ name = %[1]q
283+ type = "popover"
284+ linked_flag_id = posthog_feature_flag.test.id
285+
286+ questions_json = jsonencode([
287+ {
288+ type = "open"
289+ question = "How satisfied are you?"
290+ }
291+ ])
292+ }
293+ ` , name )
294+ }
295+
296+ func testAccSurveyWithoutLinkedFlag (name string ) string {
297+ return fmt .Sprintf (`
298+ provider "posthog" {}
299+
300+ resource "posthog_feature_flag" "test" {
301+ key = %[1]q
302+ name = "Test flag for survey link"
303+ active = true
304+ rollout_percentage = 100
305+ }
306+
307+ resource "posthog_survey" "test" {
308+ name = %[1]q
309+ type = "popover"
310+
311+ questions_json = jsonencode([
312+ {
313+ type = "open"
314+ question = "How satisfied are you?"
315+ }
316+ ])
317+ }
318+ ` , name )
319+ }
0 commit comments