@@ -247,6 +247,56 @@ class FormbricksViewModelInstrumentedTest {
247247
248248 // endregion
249249
250+ // region matchedSurvey null tests (surveys=null forces matchedSurvey to null)
251+
252+ @Test
253+ fun testGetJson_noMatchedSurvey_clickOutsideFallsBackToProject () {
254+ val json = invokeGetJsonWithNoSurveys(
255+ projectClickOutsideClose = true ,
256+ projectOverlay = SurveyOverlay .NONE
257+ )
258+ assertTrue(json.contains(" \" clickOutside\" :true" ))
259+ }
260+
261+ @Test
262+ fun testGetJson_noMatchedSurvey_clickOutsideProjectNull_returnsFalse () {
263+ val json = invokeGetJsonWithNoSurveys(
264+ projectClickOutsideClose = null ,
265+ projectOverlay = SurveyOverlay .NONE
266+ )
267+ assertTrue(json.contains(" \" clickOutside\" :false" ))
268+ }
269+
270+ @Test
271+ fun testGetJson_noMatchedSurvey_overlayFallsBackToProject () {
272+ val json = invokeGetJsonWithNoSurveys(
273+ projectClickOutsideClose = null ,
274+ projectOverlay = SurveyOverlay .DARK
275+ )
276+ assertTrue(json.contains(" \" overlay\" :\" dark\" " ))
277+ }
278+
279+ @Test
280+ fun testGetJson_noMatchedSurvey_overlayProjectNull_returnsNone () {
281+ val json = invokeGetJsonWithNoSurveys(
282+ projectClickOutsideClose = null ,
283+ projectOverlay = null
284+ )
285+ assertTrue(json.contains(" \" overlay\" :\" none\" " ))
286+ }
287+
288+ @Test
289+ fun testGetJson_noMatchedSurvey_bothFallBackToProject () {
290+ val json = invokeGetJsonWithNoSurveys(
291+ projectClickOutsideClose = true ,
292+ projectOverlay = SurveyOverlay .LIGHT
293+ )
294+ assertTrue(json.contains(" \" clickOutside\" :true" ))
295+ assertTrue(json.contains(" \" overlay\" :\" light\" " ))
296+ }
297+
298+ // endregion
299+
250300 // region helpers
251301
252302 private fun invokeGetJson (
@@ -291,6 +341,44 @@ class FormbricksViewModelInstrumentedTest {
291341 data = envResponseData,
292342 originalResponseMap = mapOf ()
293343 )
344+ return callGetJson(envHolder, surveyId)
345+ }
346+
347+ /* *
348+ * Creates an environment with surveys=null so that matchedSurvey resolves to null.
349+ * This forces clickOutside and overlay to fall through entirely to project-level values,
350+ * covering the bytecode branches where matchedSurvey is null.
351+ */
352+ private fun invokeGetJsonWithNoSurveys (
353+ projectClickOutsideClose : Boolean? = null,
354+ projectOverlay : SurveyOverlay ? = null
355+ ): String {
356+ val project = Project (
357+ id = " proj1" ,
358+ recontactDays = null ,
359+ clickOutsideClose = projectClickOutsideClose,
360+ overlay = projectOverlay,
361+ placement = null ,
362+ inAppSurveyBranding = null ,
363+ styling = null
364+ )
365+ val envData = EnvironmentData (
366+ surveys = null ,
367+ actionClasses = null ,
368+ project = project
369+ )
370+ val envResponseData = EnvironmentResponseData (
371+ data = envData,
372+ expiresAt = null
373+ )
374+ val envHolder = EnvironmentDataHolder (
375+ data = envResponseData,
376+ originalResponseMap = mapOf ()
377+ )
378+ return callGetJson(envHolder, " any-survey-id" )
379+ }
380+
381+ private fun callGetJson (envHolder : EnvironmentDataHolder , surveyId : String ): String {
294382 val viewModel = FormbricksViewModel ()
295383 return viewModel.javaClass.getDeclaredMethod(
296384 " getJson" ,
0 commit comments