Skip to content

Commit 6429be9

Browse files
committed
fix: improve survey bundle size
1 parent 9b9c658 commit 6429be9

File tree

5 files changed

+156
-187
lines changed

5 files changed

+156
-187
lines changed

src/__tests__/surveys.test.ts

+49-52
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,27 @@
11
/// <reference lib="dom" />
22

3-
import { PostHogSurveys } from '../posthog-surveys'
4-
import {
5-
SurveyType,
6-
SurveyQuestionType,
7-
Survey,
8-
MultipleSurveyQuestion,
9-
SurveyQuestionBranchingType,
10-
SurveyQuestion,
11-
RatingSurveyQuestion,
12-
} from '../posthog-surveys-types'
3+
import { generateSurveys, getNextSurveyStep } from '../extensions/surveys'
134
import {
145
canActivateRepeatedly,
156
getDisplayOrderChoices,
167
getDisplayOrderQuestions,
178
} from '../extensions/surveys/surveys-utils'
18-
import { PostHogPersistence } from '../posthog-persistence'
199
import { PostHog } from '../posthog-core'
10+
import { PostHogPersistence } from '../posthog-persistence'
11+
import { PostHogSurveys } from '../posthog-surveys'
12+
import {
13+
MultipleSurveyQuestion,
14+
RatingSurveyQuestion,
15+
Survey,
16+
SurveyQuestion,
17+
SurveyQuestionBranchingType,
18+
SurveyQuestionType,
19+
SurveyType,
20+
} from '../posthog-surveys-types'
2021
import { DecideResponse, PostHogConfig, Properties } from '../types'
21-
import { window } from '../utils/globals'
22-
import { RequestRouter } from '../utils/request-router'
23-
import { assignableWindow } from '../utils/globals'
24-
import { generateSurveys } from '../extensions/surveys'
2522
import * as globals from '../utils/globals'
23+
import { assignableWindow, window } from '../utils/globals'
24+
import { RequestRouter } from '../utils/request-router'
2625

2726
describe('surveys', () => {
2827
let config: PostHogConfig
@@ -914,8 +913,8 @@ describe('surveys', () => {
914913
{ type: SurveyQuestionType.Open, question: 'Question A' },
915914
{ type: SurveyQuestionType.Open, question: 'Question B' },
916915
] as SurveyQuestion[]
917-
expect(surveys.getNextSurveyStep(survey, 0, 'Some response')).toEqual(1)
918-
expect(surveys.getNextSurveyStep(survey, 1, 'Some response')).toEqual(SurveyQuestionBranchingType.End)
916+
expect(getNextSurveyStep(survey, 0, 'Some response')).toEqual(1)
917+
expect(getNextSurveyStep(survey, 1, 'Some response')).toEqual(SurveyQuestionBranchingType.End)
919918
})
920919

921920
it('should branch out to `end`', () => {
@@ -927,7 +926,7 @@ describe('surveys', () => {
927926
},
928927
{ type: SurveyQuestionType.Open, question: 'Question B' },
929928
] as SurveyQuestion[]
930-
expect(surveys.getNextSurveyStep(survey, 0, 'Some response')).toEqual(SurveyQuestionBranchingType.End)
929+
expect(getNextSurveyStep(survey, 0, 'Some response')).toEqual(SurveyQuestionBranchingType.End)
931930
})
932931

933932
it('should branch out to a specific question', () => {
@@ -940,7 +939,7 @@ describe('surveys', () => {
940939
{ type: SurveyQuestionType.Open, question: 'Question B' },
941940
{ type: SurveyQuestionType.Open, question: 'Question C' },
942941
] as SurveyQuestion[]
943-
expect(surveys.getNextSurveyStep(survey, 0, 'Some response')).toEqual(2)
942+
expect(getNextSurveyStep(survey, 0, 'Some response')).toEqual(2)
944943
})
945944

946945
// Single-choice
@@ -960,9 +959,9 @@ describe('surveys', () => {
960959
{ type: SurveyQuestionType.Open, question: 'Why no?' },
961960
{ type: SurveyQuestionType.Open, question: 'Why maybe?' },
962961
] as unknown[] as SurveyQuestion[]
963-
expect(surveys.getNextSurveyStep(survey, 0, 'Yes')).toEqual(1)
964-
expect(surveys.getNextSurveyStep(survey, 0, 'No')).toEqual(2)
965-
expect(surveys.getNextSurveyStep(survey, 0, 'Maybe')).toEqual(3)
962+
expect(getNextSurveyStep(survey, 0, 'Yes')).toEqual(1)
963+
expect(getNextSurveyStep(survey, 0, 'No')).toEqual(2)
964+
expect(getNextSurveyStep(survey, 0, 'Maybe')).toEqual(3)
966965
})
967966

968967
// Response-based branching, scale 1-3
@@ -982,9 +981,9 @@ describe('surveys', () => {
982981
{ type: SurveyQuestionType.Open, question: 'Glad to hear that. Tell us more!' },
983982
] as unknown[] as SurveyQuestion[]
984983

985-
expect(surveys.getNextSurveyStep(survey, 0, 1)).toEqual(1)
986-
expect(surveys.getNextSurveyStep(survey, 0, 2)).toEqual(2)
987-
expect(surveys.getNextSurveyStep(survey, 0, 3)).toEqual(3)
984+
expect(getNextSurveyStep(survey, 0, 1)).toEqual(1)
985+
expect(getNextSurveyStep(survey, 0, 2)).toEqual(2)
986+
expect(getNextSurveyStep(survey, 0, 3)).toEqual(3)
988987
})
989988

990989
// Response-based branching, scale 1-5
@@ -1004,9 +1003,9 @@ describe('surveys', () => {
10041003
{ type: SurveyQuestionType.Open, question: 'Glad to hear that. Tell us more!' },
10051004
] as unknown as SurveyQuestion[]
10061005

1007-
expect(surveys.getNextSurveyStep(survey, 0, 1)).toEqual(1)
1008-
expect(surveys.getNextSurveyStep(survey, 0, 3)).toEqual(2)
1009-
expect(surveys.getNextSurveyStep(survey, 0, 5)).toEqual(3)
1006+
expect(getNextSurveyStep(survey, 0, 1)).toEqual(1)
1007+
expect(getNextSurveyStep(survey, 0, 3)).toEqual(2)
1008+
expect(getNextSurveyStep(survey, 0, 5)).toEqual(3)
10101009
})
10111010

10121011
// Response-based branching, scale 1-7
@@ -1026,13 +1025,13 @@ describe('surveys', () => {
10261025
{ type: SurveyQuestionType.Open, question: 'Great! What did you enjoy the most?' },
10271026
] as unknown as SurveyQuestion[]
10281027

1029-
expect(surveys.getNextSurveyStep(survey, 0, 1)).toEqual(1)
1030-
expect(surveys.getNextSurveyStep(survey, 0, 2)).toEqual(1)
1031-
expect(surveys.getNextSurveyStep(survey, 0, 3)).toEqual(1)
1032-
expect(surveys.getNextSurveyStep(survey, 0, 4)).toEqual(2)
1033-
expect(surveys.getNextSurveyStep(survey, 0, 5)).toEqual(3)
1034-
expect(surveys.getNextSurveyStep(survey, 0, 6)).toEqual(3)
1035-
expect(surveys.getNextSurveyStep(survey, 0, 7)).toEqual(3)
1028+
expect(getNextSurveyStep(survey, 0, 1)).toEqual(1)
1029+
expect(getNextSurveyStep(survey, 0, 2)).toEqual(1)
1030+
expect(getNextSurveyStep(survey, 0, 3)).toEqual(1)
1031+
expect(getNextSurveyStep(survey, 0, 4)).toEqual(2)
1032+
expect(getNextSurveyStep(survey, 0, 5)).toEqual(3)
1033+
expect(getNextSurveyStep(survey, 0, 6)).toEqual(3)
1034+
expect(getNextSurveyStep(survey, 0, 7)).toEqual(3)
10361035
})
10371036

10381037
// Response-based branching, scale 0-10 (NPS)
@@ -1052,9 +1051,9 @@ describe('surveys', () => {
10521051
{ type: SurveyQuestionType.Open, question: 'Glad to hear that. Tell us more!' },
10531052
] as unknown as SurveyQuestion[]
10541053

1055-
expect(surveys.getNextSurveyStep(survey, 0, 1)).toEqual(1)
1056-
expect(surveys.getNextSurveyStep(survey, 0, 8)).toEqual(2)
1057-
expect(surveys.getNextSurveyStep(survey, 0, 10)).toEqual(3)
1054+
expect(getNextSurveyStep(survey, 0, 1)).toEqual(1)
1055+
expect(getNextSurveyStep(survey, 0, 8)).toEqual(2)
1056+
expect(getNextSurveyStep(survey, 0, 10)).toEqual(3)
10581057
})
10591058

10601059
it('should display questions in the order AGCEHDFB', () => {
@@ -1108,7 +1107,7 @@ describe('surveys', () => {
11081107
for (let i = 0; i < survey.questions.length; i++) {
11091108
const currentQuestion = survey.questions[currentStep]
11101109
actualOrder.push(currentQuestion.question)
1111-
currentStep = surveys.getNextSurveyStep(survey, currentStep, 'Some response')
1110+
currentStep = getNextSurveyStep(survey, currentStep, 'Some response')
11121111
}
11131112

11141113
expect(desiredOrder).toEqual(actualOrder)
@@ -1167,7 +1166,7 @@ describe('surveys', () => {
11671166
for (const answer of answers) {
11681167
const currentQuestion = survey.questions[currentStep]
11691168
actualOrder.push(currentQuestion.question)
1170-
currentStep = surveys.getNextSurveyStep(survey, currentStep, answer)
1169+
currentStep = getNextSurveyStep(survey, currentStep, answer)
11711170
}
11721171
expect(desiredOrder).toEqual(actualOrder)
11731172
expect(currentStep).toEqual(SurveyQuestionBranchingType.End)
@@ -1180,7 +1179,7 @@ describe('surveys', () => {
11801179
for (const answer of answers) {
11811180
const currentQuestion = survey.questions[currentStep]
11821181
actualOrder.push(currentQuestion.question)
1183-
currentStep = surveys.getNextSurveyStep(survey, currentStep, answer)
1182+
currentStep = getNextSurveyStep(survey, currentStep, answer)
11841183
}
11851184
expect(desiredOrder).toEqual(actualOrder)
11861185
expect(currentStep).toEqual(SurveyQuestionBranchingType.End)
@@ -1193,7 +1192,7 @@ describe('surveys', () => {
11931192
for (const answer of answers) {
11941193
const currentQuestion = survey.questions[currentStep]
11951194
actualOrder.push(currentQuestion.question)
1196-
currentStep = surveys.getNextSurveyStep(survey, currentStep, answer)
1195+
currentStep = getNextSurveyStep(survey, currentStep, answer)
11971196
}
11981197
expect(desiredOrder).toEqual(actualOrder)
11991198
expect(currentStep).toEqual(SurveyQuestionBranchingType.End)
@@ -1210,7 +1209,7 @@ describe('surveys', () => {
12101209
for (const answer of answers) {
12111210
const currentQuestion = survey.questions[currentStep]
12121211
actualOrder.push(currentQuestion.question)
1213-
currentStep = surveys.getNextSurveyStep(survey, currentStep, answer)
1212+
currentStep = getNextSurveyStep(survey, currentStep, answer)
12141213
}
12151214
expect(desiredOrder).toEqual(actualOrder)
12161215
expect(currentStep).toEqual(SurveyQuestionBranchingType.End)
@@ -1231,7 +1230,7 @@ describe('surveys', () => {
12311230
{ type: SurveyQuestionType.Open, question: 'Seems you are not completely happy. Tell us more!' },
12321231
{ type: SurveyQuestionType.Open, question: 'Glad to hear that. Tell us more!' },
12331232
] as unknown as SurveyQuestion[]
1234-
expect(() => surveys.getNextSurveyStep(survey, 0, 1)).toThrow('The scale must be one of: 3, 5, 7, 10')
1233+
expect(() => getNextSurveyStep(survey, 0, 1)).toThrow('The scale must be one of: 3, 5, 7, 10')
12351234
})
12361235

12371236
it('should throw an error for a response value out of the valid range', () => {
@@ -1249,13 +1248,13 @@ describe('surveys', () => {
12491248
{ type: SurveyQuestionType.Open, question: 'Seems you are not completely happy. Tell us more!' },
12501249
{ type: SurveyQuestionType.Open, question: 'Glad to hear that. Tell us more!' },
12511250
] as unknown as SurveyQuestion[]
1252-
expect(() => surveys.getNextSurveyStep(survey, 0, 20)).toThrow('The response must be in range 1-3')
1251+
expect(() => getNextSurveyStep(survey, 0, 20)).toThrow('The response must be in range 1-3')
12531252
;(survey.questions[0] as RatingSurveyQuestion).scale = 5
1254-
expect(() => surveys.getNextSurveyStep(survey, 0, 20)).toThrow('The response must be in range 1-5')
1253+
expect(() => getNextSurveyStep(survey, 0, 20)).toThrow('The response must be in range 1-5')
12551254
;(survey.questions[0] as RatingSurveyQuestion).scale = 7
1256-
expect(() => surveys.getNextSurveyStep(survey, 0, 20)).toThrow('The response must be in range 1-7')
1255+
expect(() => getNextSurveyStep(survey, 0, 20)).toThrow('The response must be in range 1-7')
12571256
;(survey.questions[0] as RatingSurveyQuestion).scale = 10
1258-
expect(() => surveys.getNextSurveyStep(survey, 0, 20)).toThrow('The response must be in range 0-10')
1257+
expect(() => getNextSurveyStep(survey, 0, 20)).toThrow('The response must be in range 0-10')
12591258
})
12601259

12611260
it('should throw an error for if a response value in a rating question is not an integer', () => {
@@ -1273,10 +1272,8 @@ describe('surveys', () => {
12731272
{ type: SurveyQuestionType.Open, question: 'Seems you are not completely happy. Tell us more!' },
12741273
{ type: SurveyQuestionType.Open, question: 'Glad to hear that. Tell us more!' },
12751274
] as unknown as SurveyQuestion[]
1276-
expect(() => surveys.getNextSurveyStep(survey, 0, '2')).toThrow('The response type must be an integer')
1277-
expect(() => surveys.getNextSurveyStep(survey, 0, 'some_string')).toThrow(
1278-
'The response type must be an integer'
1279-
)
1275+
expect(() => getNextSurveyStep(survey, 0, '2')).toThrow('The response type must be an integer')
1276+
expect(() => getNextSurveyStep(survey, 0, 'some_string')).toThrow('The response type must be an integer')
12801277
})
12811278
})
12821279

src/entrypoints/surveys-preview.es.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
export { renderFeedbackWidgetPreview, renderSurveysPreview } from '../extensions/surveys'
2-
export { getNextSurveyStep } from '../posthog-surveys'
1+
export { getNextSurveyStep, renderFeedbackWidgetPreview, renderSurveysPreview } from '../extensions/surveys'

src/extensions/surveys.tsx

+104-12
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,109 @@ const logger = createLogger('[Surveys]')
4444
const window = _window as Window & typeof globalThis
4545
const document = _document as Document
4646

47+
function getRatingBucketForResponseValue(responseValue: number, scale: number) {
48+
if (scale === 3) {
49+
if (responseValue < 1 || responseValue > 3) {
50+
throw new Error('The response must be in range 1-3')
51+
}
52+
53+
return responseValue === 1 ? 'negative' : responseValue === 2 ? 'neutral' : 'positive'
54+
} else if (scale === 5) {
55+
if (responseValue < 1 || responseValue > 5) {
56+
throw new Error('The response must be in range 1-5')
57+
}
58+
59+
return responseValue <= 2 ? 'negative' : responseValue === 3 ? 'neutral' : 'positive'
60+
} else if (scale === 7) {
61+
if (responseValue < 1 || responseValue > 7) {
62+
throw new Error('The response must be in range 1-7')
63+
}
64+
65+
return responseValue <= 3 ? 'negative' : responseValue === 4 ? 'neutral' : 'positive'
66+
} else if (scale === 10) {
67+
if (responseValue < 0 || responseValue > 10) {
68+
throw new Error('The response must be in range 0-10')
69+
}
70+
71+
return responseValue <= 6 ? 'detractors' : responseValue <= 8 ? 'passives' : 'promoters'
72+
}
73+
74+
throw new Error('The scale must be one of: 3, 5, 7, 10')
75+
}
76+
77+
export function getNextSurveyStep(
78+
survey: Survey,
79+
currentQuestionIndex: number,
80+
response: string | string[] | number | null
81+
) {
82+
const question = survey.questions[currentQuestionIndex]
83+
const nextQuestionIndex = currentQuestionIndex + 1
84+
85+
if (!question.branching?.type) {
86+
if (currentQuestionIndex === survey.questions.length - 1) {
87+
return SurveyQuestionBranchingType.End
88+
}
89+
90+
return nextQuestionIndex
91+
}
92+
93+
if (question.branching.type === SurveyQuestionBranchingType.End) {
94+
return SurveyQuestionBranchingType.End
95+
} else if (question.branching.type === SurveyQuestionBranchingType.SpecificQuestion) {
96+
if (Number.isInteger(question.branching.index)) {
97+
return question.branching.index
98+
}
99+
} else if (question.branching.type === SurveyQuestionBranchingType.ResponseBased) {
100+
// Single choice
101+
if (question.type === SurveyQuestionType.SingleChoice) {
102+
// :KLUDGE: for now, look up the choiceIndex based on the response
103+
// TODO: once QuestionTypes.MultipleChoiceQuestion is refactored, pass the selected choiceIndex into this method
104+
const selectedChoiceIndex = question.choices.indexOf(`${response}`)
105+
106+
if (question.branching?.responseValues?.hasOwnProperty(selectedChoiceIndex)) {
107+
const nextStep = question.branching.responseValues[selectedChoiceIndex]
108+
109+
// Specific question
110+
if (Number.isInteger(nextStep)) {
111+
return nextStep
112+
}
113+
114+
if (nextStep === SurveyQuestionBranchingType.End) {
115+
return SurveyQuestionBranchingType.End
116+
}
117+
118+
return nextQuestionIndex
119+
}
120+
} else if (question.type === SurveyQuestionType.Rating) {
121+
if (typeof response !== 'number' || !Number.isInteger(response)) {
122+
throw new Error('The response type must be an integer')
123+
}
124+
125+
const ratingBucket = getRatingBucketForResponseValue(response, question.scale)
126+
127+
if (question.branching?.responseValues?.hasOwnProperty(ratingBucket)) {
128+
const nextStep = question.branching.responseValues[ratingBucket]
129+
130+
// Specific question
131+
if (Number.isInteger(nextStep)) {
132+
return nextStep
133+
}
134+
135+
if (nextStep === SurveyQuestionBranchingType.End) {
136+
return SurveyQuestionBranchingType.End
137+
}
138+
139+
return nextQuestionIndex
140+
}
141+
}
142+
143+
return nextQuestionIndex
144+
}
145+
146+
logger.warn('Falling back to next question index due to unexpected branching type')
147+
return nextQuestionIndex
148+
}
149+
47150
export class SurveyManager {
48151
private posthog: PostHog
49152
private surveyInFocus: string | null
@@ -663,18 +766,7 @@ export function Questions({
663766

664767
setQuestionsResponses({ ...questionsResponses, [responseKey]: res })
665768

666-
// Old SDK, no branching
667-
if (!posthog.getNextSurveyStep) {
668-
const isLastDisplayedQuestion = displayQuestionIndex === survey.questions.length - 1
669-
if (isLastDisplayedQuestion) {
670-
sendSurveyEvent({ ...questionsResponses, [responseKey]: res }, survey, posthog)
671-
} else {
672-
setCurrentQuestionIndex(displayQuestionIndex + 1)
673-
}
674-
return
675-
}
676-
677-
const nextStep = posthog.getNextSurveyStep(survey, displayQuestionIndex, res)
769+
const nextStep = getNextSurveyStep(survey, displayQuestionIndex, res)
678770
if (nextStep === SurveyQuestionBranchingType.End) {
679771
sendSurveyEvent({ ...questionsResponses, [responseKey]: res }, survey, posthog)
680772
} else {

src/posthog-core.ts

+1-10
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ import { PageViewManager } from './page-view'
5252
import { PostHogSurveys } from './posthog-surveys'
5353
import { RateLimiter } from './rate-limiter'
5454
import { uuidv7 } from './uuidv7'
55-
import { Survey, SurveyCallback, SurveyQuestionBranchingType } from './posthog-surveys-types'
55+
import { SurveyCallback } from './posthog-surveys-types'
5656
import {
5757
isArray,
5858
isEmptyObject,
@@ -1341,15 +1341,6 @@ export class PostHog {
13411341
this.surveys.canRenderSurvey(surveyId)
13421342
}
13431343

1344-
/** Get the next step of the survey: a question index or `end` */
1345-
getNextSurveyStep(
1346-
survey: Survey,
1347-
currentQuestionIndex: number,
1348-
response: string | string[] | number | null
1349-
): number | SurveyQuestionBranchingType.End {
1350-
return this.surveys.getNextSurveyStep(survey, currentQuestionIndex, response)
1351-
}
1352-
13531344
/**
13541345
* Identify a user with a unique ID instead of a PostHog
13551346
* randomly generated distinct_id. If the method is never called,

0 commit comments

Comments
 (0)