From a6ed7e96eb3a7d2d804a7ef823bdbc95d59b8d54 Mon Sep 17 00:00:00 2001
From: Li Yi Yu
Date: Thu, 19 Oct 2023 10:57:08 -0400
Subject: [PATCH] fix(surveys): fix multiple choice input unique ID bug (#841)
* fix surveys unique input ID bug
* add test
---
src/__tests__/extensions/surveys.js | 36 ++++++++++++++++++++++++++--
src/extensions/surveys.ts | 37 +++++++++++++++++++----------
2 files changed, 58 insertions(+), 15 deletions(-)
diff --git a/src/__tests__/extensions/surveys.js b/src/__tests__/extensions/surveys.js
index 516a744c1..fc80bfe5b 100644
--- a/src/__tests__/extensions/surveys.js
+++ b/src/__tests__/extensions/surveys.js
@@ -1,4 +1,4 @@
-import { createShadow, callSurveys, generateSurveys } from '../../extensions/surveys'
+import { createShadow, callSurveys, generateSurveys, createMultipleQuestionSurvey } from '../../extensions/surveys'
describe('survey display logic', () => {
beforeEach(() => {
@@ -83,7 +83,7 @@ describe('survey display logic', () => {
// submit the survey
const ratingButton = document
.getElementsByClassName(`PostHogSurvey${mockSurveys[0].id}`)[0]
- .shadowRoot.querySelectorAll('.rating_1')[0]
+ .shadowRoot.querySelectorAll('.question-0-rating-1')[0]
ratingButton.click()
const submitButton = document
.getElementsByClassName(`PostHogSurvey${mockSurveys[0].id}`)[0]
@@ -152,4 +152,36 @@ describe('survey display logic', () => {
expect(mockPostHog.getActiveMatchingSurveys).toBeCalledTimes(1)
expect(setInterval).toHaveBeenLastCalledWith(expect.any(Function), 1500)
})
+
+ test('multiple choice type question elements are unique', () => {
+ mockSurveys = [
+ {
+ id: 'testSurvey2',
+ name: 'Test survey 2',
+ appearance: null,
+ conditions: { seenSurveyWaitPeriodInDays: 10 },
+ questions: [
+ {
+ question: 'Which types of content would you like to see more of?',
+ description: 'This is a question description',
+ type: 'multiple_choice',
+ choices: ['Tutorials', 'Product Updates', 'Events', 'Other'],
+ },
+ {
+ question: 'Which features do you use the most?',
+ description: 'This is a question description',
+ type: 'multiple_choice',
+ choices: ['Surveys', 'Feature flags', 'Analytics'],
+ },
+ ],
+ },
+ ]
+ const multipleQuestionSurveyForm = createMultipleQuestionSurvey(mockPostHog, mockSurveys[0])
+ const allSelectOptions = multipleQuestionSurveyForm.querySelectorAll('input[type=checkbox]')
+ const uniqueIds = new Set()
+ allSelectOptions.forEach((element) => {
+ uniqueIds.add(element.id)
+ })
+ expect(uniqueIds.size).toBe(allSelectOptions.length)
+ })
})
diff --git a/src/extensions/surveys.ts b/src/extensions/surveys.ts
index a99ca5924..106d74316 100644
--- a/src/extensions/surveys.ts
+++ b/src/extensions/surveys.ts
@@ -335,7 +335,8 @@ export const closeSurveyPopup = (surveyId: string, surveyPopup: HTMLFormElement)
export const createOpenTextOrLinkPopup = (
posthog: PostHog,
survey: Survey,
- question: BasicSurveyQuestion | LinkSurveyQuestion
+ question: BasicSurveyQuestion | LinkSurveyQuestion,
+ questionIndex: number
) => {
const surveyQuestionType = question.type
const surveyDescription = question.description
@@ -351,7 +352,7 @@ export const createOpenTextOrLinkPopup = (
${surveyDescription ? `${surveyDescription}` : ''}
${
surveyQuestionType === 'open'
- ? ``
: ''
@@ -461,7 +462,12 @@ export const addCancelListeners = (
})
}
-export const createRatingsPopup = (posthog: PostHog, survey: Survey, question: RatingSurveyQuestion) => {
+export const createRatingsPopup = (
+ posthog: PostHog,
+ survey: Survey,
+ question: RatingSurveyQuestion,
+ questionIndex: number
+) => {
const scale = question.scale
const starting = question.scale === 10 ? 0 : 1
const displayType = question.display
@@ -472,7 +478,7 @@ export const createRatingsPopup = (posthog: PostHog, survey: Survey, question: R
ratingOptionsElement.style.gridTemplateColumns = `repeat(${scale - starting + 1}, minmax(0, 1fr))`
for (let i = starting; i <= scale; i++) {
const buttonElement = document.createElement('button')
- buttonElement.className = `ratings-number rating_${i} auto-text-color`
+ buttonElement.className = `ratings-number question-${questionIndex}-rating-${i} auto-text-color`
buttonElement.type = 'submit'
buttonElement.value = `${i}`
buttonElement.innerHTML = `${i}`
@@ -484,7 +490,7 @@ export const createRatingsPopup = (posthog: PostHog, survey: Survey, question: R
const fiveEmojis = [veryDissatisfiedEmoji, dissatisfiedEmoji, neutralEmoji, satisfiedEmoji, verySatisfiedEmoji]
for (let i = 1; i <= scale; i++) {
const emojiElement = document.createElement('button')
- emojiElement.className = `ratings-emoji rating_${i}`
+ emojiElement.className = `ratings-emoji question-${questionIndex}-rating-${i}`
emojiElement.type = 'submit'
emojiElement.value = `${i}`
emojiElement.innerHTML = scale === 3 ? threeEmojis[i - 1] : fiveEmojis[i - 1]
@@ -551,7 +557,7 @@ export const createRatingsPopup = (posthog: PostHog, survey: Survey, question: R
formElement.getElementsByClassName('rating-options')[0].insertAdjacentElement('afterbegin', ratingOptionsElement)
const allElements = question.scale === 10 ? [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] : [1, 2, 3, 4, 5]
for (const x of allElements) {
- const ratingEl = formElement.getElementsByClassName(`rating_${x}`)[0]
+ const ratingEl = formElement.getElementsByClassName(`question-${questionIndex}-rating-${x}`)[0]
ratingEl.addEventListener('click', (e) => {
e.preventDefault()
for (const activeRatingEl of formElement.getElementsByClassName('rating-active')) {
@@ -568,7 +574,12 @@ export const createRatingsPopup = (posthog: PostHog, survey: Survey, question: R
return formElement
}
-export const createMultipleChoicePopup = (posthog: PostHog, survey: Survey, question: MultipleSurveyQuestion) => {
+export const createMultipleChoicePopup = (
+ posthog: PostHog,
+ survey: Survey,
+ question: MultipleSurveyQuestion,
+ questionIndex: number
+) => {
const surveyQuestion = question.question
const surveyDescription = question.description
const surveyQuestionChoices = question.choices
@@ -586,8 +597,8 @@ export const createMultipleChoicePopup = (posthog: PostHog, survey: Survey, ques
${surveyQuestionChoices
.map((option, idx) => {
const inputType = singleOrMultiSelect === 'single_choice' ? 'radio' : 'checkbox'
- const singleOrMultiSelectString = `
- ${checkSVG}
`
+ const singleOrMultiSelectString = `
+ ${checkSVG}
`
return singleOrMultiSelectString
})
.join(' ')}
@@ -801,7 +812,7 @@ export const createMultipleQuestionSurvey = (posthog: PostHog, survey: Survey) =
questions.map((question, idx) => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // TODO: Fix this, error because of survey question type mapping
- const questionElement = questionTypeMapping[question.type](posthog, survey, question)
+ const questionElement = questionTypeMapping[question.type](posthog, survey, question, idx)
const questionTab = document.createElement('div')
questionTab.className = `tab question-${idx} ${question.type}`
if (idx < questions.length - 1) {
@@ -825,11 +836,11 @@ export const createMultipleQuestionSurvey = (posthog: PostHog, survey: Survey) =
const createSingleQuestionSurvey = (posthog: PostHog, survey: Survey, question: SurveyQuestion) => {
const questionType = question.type
if (questionType === 'rating') {
- return createRatingsPopup(posthog, survey, question)
+ return createRatingsPopup(posthog, survey, question, 0)
} else if (questionType === 'open' || questionType === 'link') {
- return createOpenTextOrLinkPopup(posthog, survey, question)
+ return createOpenTextOrLinkPopup(posthog, survey, question, 0)
} else if (questionType === 'single_choice' || questionType === 'multiple_choice') {
- return createMultipleChoicePopup(posthog, survey, question)
+ return createMultipleChoicePopup(posthog, survey, question, 0)
}
return null
}