Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: make callback on confirmation message instead #1845

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions playwright/surveys/feedback-widget.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { SurveySchedule } from '../../src/posthog-surveys-types'
import { pollUntilEventCaptured } from '../utils/event-capture-utils'
import { expect, test } from '../utils/posthog-playwright-test-base'
import { start } from '../utils/setup'
Expand Down Expand Up @@ -210,4 +211,109 @@ test.describe('surveys - feedback widget', () => {
white
)
})

// ... existing code ...
test('auto contrasts text color for feedback tab', async ({ page, context }) => {
const surveysAPICall = page.route('**/surveys/**', async (route) => {
await route.fulfill({
json: {
surveys: [
{
id: '123',
name: 'Test survey',
type: 'widget',
start_date: '2021-01-01T00:00:00Z',
questions: [openTextQuestion],
appearance: {
widgetLabel: 'white widget',
widgetType: 'tab',
widgetColor: 'white',
},
},
],
},
})
})

await start(startOptions, page, context)
await surveysAPICall

await expect(page.locator('.PostHogWidget123').locator('.ph-survey-widget-tab')).toBeVisible()

await expect(page.locator('.PostHogWidget123').locator('.ph-survey-widget-tab')).toHaveCSS('color', black)
await expect(page.locator('.PostHogWidget123').locator('.ph-survey-widget-tab')).toHaveCSS(
'background-color',
white
)
})
Comment on lines +215 to +248
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: This test is a duplicate of the previous 'auto contrasts text color for feedback tab' test. Should be removed to avoid redundant test coverage.


test('renders survey with schedule always and allows multiple submissions', async ({ page, context }) => {
const surveysAPICall = page.route('**/surveys/**', async (route) => {
await route.fulfill({
json: {
surveys: [
{
id: '123',
name: 'Test survey',
type: 'widget',
start_date: '2021-01-01T00:00:00Z',
questions: [openTextQuestion],
appearance: {
widgetLabel: 'Feedback',
widgetType: 'tab',
displayThankYouMessage: true,
},
conditions: {
url: null,
selector: null,
scrolled: null,
},
schedule: SurveySchedule.Always,
},
],
},
})
})

await start(startOptions, page, context)
await surveysAPICall

// 1. Check that the survey widget is rendered
await expect(page.locator('.PostHogWidget123').locator('.ph-survey-widget-tab')).toBeVisible()

// 2. Open the survey
await page.locator('.PostHogWidget123').locator('.ph-survey-widget-tab').click()
await expect(page.locator('.PostHogWidget123').locator('.survey-form')).toBeVisible()

// 3. Answer the survey
await page.locator('.PostHogWidget123').locator('.survey-form').locator('textarea').fill('first submission')
await page.locator('.PostHogWidget123').locator('.survey-form').locator('.form-submit').click()

// 4. Check for thank you message
await expect(page.locator('.PostHogWidget123').locator('.thank-you-message-header')).toBeVisible()
await expect(page.locator('.PostHogWidget123').locator('.thank-you-message-header')).toHaveText('Thank you!')

// Verify the event was sent
await pollUntilEventCaptured(page, 'survey sent')

// 5. Close the thank you message and click the survey tab again
await page.locator('.PostHogWidget123').locator('.form-submit').click()
await expect(page.locator('.PostHogWidget123').locator('.survey-form')).not.toBeVisible()

// Open the survey again
await page.locator('.PostHogWidget123').locator('.ph-survey-widget-tab').click()

// 6. Verify survey is rendered again
await expect(page.locator('.PostHogWidget123').locator('.survey-form')).toBeVisible()

// Submit again with different text
await page.locator('.PostHogWidget123').locator('.survey-form').locator('textarea').fill('second submission')
await page.locator('.PostHogWidget123').locator('.survey-form').locator('.form-submit').click()

// Verify thank you message appears again
await expect(page.locator('.PostHogWidget123').locator('.thank-you-message-header')).toBeVisible()

// Verify second event was sent
await pollUntilEventCaptured(page, 'survey sent')
})
})
87 changes: 87 additions & 0 deletions src/__tests__/extensions/surveys/survey-popup.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import '@testing-library/jest-dom'
import { cleanup, fireEvent, render, screen } from '@testing-library/preact'
import { SurveyPopup } from '../../../extensions/surveys'
import { Survey, SurveyQuestionType, SurveyType } from '../../../posthog-surveys-types'

describe('SurveyPopup', () => {
// Create a basic mock survey for testing
const mockSurvey: Survey = {
id: 'test-survey',
name: 'Test Survey',
description: 'A test survey',
type: SurveyType.Popover,
feature_flag_keys: null,
linked_flag_key: null,
targeting_flag_key: null,
internal_targeting_flag_key: null,
questions: [
{
type: SurveyQuestionType.Open,
question: 'Test question',
description: 'Test description',
id: 'q1',
},
],
appearance: {
displayThankYouMessage: true,
thankYouMessageHeader: 'Thank you for your feedback!',
thankYouMessageDescription: 'We appreciate your input.',
backgroundColor: '#ffffff',
borderColor: '#e5e5e5',
thankYouMessageCloseButtonText: 'Close',
whiteLabel: true,
},
conditions: null,
start_date: null,
end_date: null,
current_iteration: null,
current_iteration_start_date: null,
schedule: null,
}

beforeEach(() => {
// Reset DOM
cleanup()
localStorage.clear()
jest.clearAllMocks()
})

test('calls onCloseConfirmationMessage when X button is clicked in the confirmation message', () => {
// Create a mock function to test if it gets called
const mockOnCloseConfirmationMessage = jest.fn()
const mockRemoveSurveyFromFocus = jest.fn()
render(
<SurveyPopup
survey={mockSurvey}
removeSurveyFromFocus={mockRemoveSurveyFromFocus}
isPopup={true}
onCloseConfirmationMessage={mockOnCloseConfirmationMessage}
// Force the confirmation message to show
previewPageIndex={mockSurvey.questions.length}
/>
)
const cancelButton2 = screen.getByRole('button', { name: 'Close survey', hidden: true })
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: The button name 'Close survey' doesn't match the actual button text 'Close' defined in mockSurvey.appearance.thankYouMessageCloseButtonText

Suggested change
const cancelButton2 = screen.getByRole('button', { name: 'Close survey', hidden: true })
const cancelButton2 = screen.getByRole('button', { name: mockSurvey.appearance.thankYouMessageCloseButtonText, hidden: true })

// Click the cancel button
fireEvent.click(cancelButton2)
// Verify that onCloseConfirmationMessage was called
expect(mockOnCloseConfirmationMessage).toHaveBeenCalledTimes(1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Should also verify mockRemoveSurveyFromFocus was called to ensure proper cleanup

})

test('calls onCloseConfirmationMessage when survey is closed in the confirmation message', () => {
const mockOnCloseConfirmationMessage = jest.fn()
const mockRemoveSurveyFromFocus = jest.fn()
render(
<SurveyPopup
survey={mockSurvey}
removeSurveyFromFocus={mockRemoveSurveyFromFocus}
isPopup={true}
onCloseConfirmationMessage={mockOnCloseConfirmationMessage}
previewPageIndex={mockSurvey.questions.length}
/>
)

const closeButton = screen.getByRole('button', { name: /close/i })
fireEvent.click(closeButton)
expect(mockOnCloseConfirmationMessage).toHaveBeenCalledTimes(1)
})
})
18 changes: 8 additions & 10 deletions src/extensions/surveys.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -693,7 +693,7 @@ interface SurveyPopupProps {
isPopup?: boolean
onPreviewSubmit?: (res: string | string[] | number | null) => void
onPopupSurveyDismissed?: () => void
onPopupSurveySent?: () => void
onCloseConfirmationMessage?: () => void
}

export function SurveyPopup({
Expand All @@ -706,7 +706,7 @@ export function SurveyPopup({
isPopup,
onPreviewSubmit = () => {},
onPopupSurveyDismissed = () => {},
onPopupSurveySent = () => {},
onCloseConfirmationMessage = () => {},
}: SurveyPopupProps) {
const isPreviewMode = Number.isInteger(previewPageIndex)
// NB: The client-side code passes the millisecondDelay in seconds, but setTimeout expects milliseconds, so we multiply by 1000
Expand Down Expand Up @@ -741,9 +741,6 @@ export function SurveyPopup({
},
isPopup: isPopup || false,
onPreviewSubmit,
onPopupSurveySent: () => {
onPopupSurveySent()
},
}}
>
{!shouldShowConfirmation ? (
Expand All @@ -761,7 +758,10 @@ export function SurveyPopup({
contentType={survey.appearance?.thankYouMessageDescriptionContentType}
appearance={survey.appearance || defaultSurveyAppearance}
styleOverrides={{ ...style, ...confirmationBoxLeftStyle }}
onClose={() => setIsPopupVisible(false)}
onClose={() => {
setIsPopupVisible(false)
onCloseConfirmationMessage()
}}
/>
)}
</SurveyContext.Provider>
Expand All @@ -783,8 +783,7 @@ export function Questions({
survey.appearance?.backgroundColor || defaultSurveyAppearance.backgroundColor
)
const [questionsResponses, setQuestionsResponses] = useState({})
const { previewPageIndex, onPopupSurveyDismissed, isPopup, onPreviewSubmit, onPopupSurveySent } =
useContext(SurveyContext)
const { previewPageIndex, onPopupSurveyDismissed, isPopup, onPreviewSubmit } = useContext(SurveyContext)
const [currentQuestionIndex, setCurrentQuestionIndex] = useState(previewPageIndex || 0)
const surveyQuestions = useMemo(() => getDisplayOrderQuestions(survey), [survey])

Expand Down Expand Up @@ -819,7 +818,6 @@ export function Questions({
const nextStep = getNextSurveyStep(survey, displayQuestionIndex, res)
if (nextStep === SurveyQuestionBranchingType.End) {
sendSurveyEvent({ ...questionsResponses, [responseKey]: res }, survey, posthog)
onPopupSurveySent()
} else {
setCurrentQuestionIndex(nextStep)
}
Expand Down Expand Up @@ -1036,7 +1034,7 @@ export function FeedbackWidget({
removeSurveyFromFocus={removeSurveyFromFocus}
isPopup={true}
onPopupSurveyDismissed={resetShowSurvey}
onPopupSurveySent={resetShowSurvey}
onCloseConfirmationMessage={resetShowSurvey}
/>
)}
</Preact.Fragment>
Expand Down
1 change: 1 addition & 0 deletions src/extensions/surveys/components/BottomSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export function BottomSection({
<button
className="form-submit"
disabled={submitDisabled}
aria-label="Submit survey"
type="button"
style={isPopup ? { color: textColor } : {}}
onClick={() => {
Expand Down
52 changes: 25 additions & 27 deletions src/extensions/surveys/components/ConfirmationMessage.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { BottomSection } from './BottomSection'
import { Cancel } from './QuestionHeader'
import { h } from 'preact'
import { SurveyAppearance, SurveyQuestionDescriptionContentType } from '../../../posthog-surveys-types'
import { defaultSurveyAppearance, getContrastingTextColor, renderChildrenAsTextOrHtml } from '../surveys-utils'
import { h } from 'preact'
import { BottomSection } from './BottomSection'
import { Cancel } from './QuestionHeader'

import { useContext } from 'preact/hooks'
import { SurveyContext } from '../../surveys/surveys-utils'
Expand All @@ -29,30 +29,28 @@ export function ConfirmationMessage({
const { isPopup } = useContext(SurveyContext)

return (
<>
<div className="thank-you-message" style={{ ...styleOverrides }}>
<div className="thank-you-message-container">
{isPopup && <Cancel onClick={() => onClose()} />}
<h3 className="thank-you-message-header" style={{ color: textColor }}>
{header}
</h3>
{description &&
renderChildrenAsTextOrHtml({
component: h('div', { className: 'thank-you-message-body' }),
children: description,
renderAsHtml: !forceDisableHtml && contentType !== 'text',
style: { color: textColor },
})}
{isPopup && (
<BottomSection
text={appearance.thankYouMessageCloseButtonText || 'Close'}
submitDisabled={false}
appearance={appearance}
onSubmit={() => onClose()}
/>
)}
</div>
<div className="thank-you-message" style={{ ...styleOverrides }}>
<div className="thank-you-message-container">
{isPopup && <Cancel onClick={() => onClose()} />}
<h3 className="thank-you-message-header" style={{ color: textColor }}>
{header}
</h3>
{description &&
renderChildrenAsTextOrHtml({
component: h('div', { className: 'thank-you-message-body' }),
children: description,
renderAsHtml: !forceDisableHtml && contentType !== 'text',
style: { color: textColor },
})}
{isPopup && (
<BottomSection
text={appearance.thankYouMessageCloseButtonText || 'Close'}
submitDisabled={false}
appearance={appearance}
onSubmit={() => onClose()}
/>
)}
</div>
</>
</div>
)
}
16 changes: 11 additions & 5 deletions src/extensions/surveys/components/QuestionHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { SurveyContext, defaultSurveyAppearance, renderChildrenAsTextOrHtml } from '../surveys-utils'
import { cancelSVG } from '../icons'
import { h } from 'preact'
import { useContext } from 'preact/hooks'
import { SurveyQuestionDescriptionContentType } from '../../../posthog-surveys-types'
import { h } from 'preact'
import { cancelSVG } from '../icons'
import { SurveyContext, defaultSurveyAppearance, renderChildrenAsTextOrHtml } from '../surveys-utils'

export function QuestionHeader({
question,
Expand Down Expand Up @@ -35,8 +35,14 @@ export function Cancel({ onClick }: { onClick: () => void }) {
const { isPreviewMode } = useContext(SurveyContext)

return (
<div className="cancel-btn-wrapper" onClick={onClick} disabled={isPreviewMode}>
<button className="form-cancel" onClick={onClick} disabled={isPreviewMode}>
<div className="cancel-btn-wrapper">
<button
className="form-cancel"
onClick={onClick}
disabled={isPreviewMode}
aria-label="Close survey"
role="button"
>
{cancelSVG}
</button>
</div>
Expand Down
2 changes: 0 additions & 2 deletions src/extensions/surveys/surveys-utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -741,7 +741,6 @@ interface SurveyContextProps {
onPopupSurveyDismissed: () => void
isPopup: boolean
onPreviewSubmit: (res: string | string[] | number | null) => void
onPopupSurveySent: () => void
}

export const SurveyContext = createContext<SurveyContextProps>({
Expand All @@ -750,7 +749,6 @@ export const SurveyContext = createContext<SurveyContextProps>({
onPopupSurveyDismissed: () => {},
isPopup: true,
onPreviewSubmit: () => {},
onPopupSurveySent: () => {},
})

interface RenderProps {
Expand Down
Loading