diff --git a/playwright/surveys/feedback-widget.spec.ts b/playwright/surveys/feedback-widget.spec.ts index 0eba9201f..5f650efd7 100644 --- a/playwright/surveys/feedback-widget.spec.ts +++ b/playwright/surveys/feedback-widget.spec.ts @@ -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' @@ -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 + ) + }) + + 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') + }) }) diff --git a/src/__tests__/extensions/surveys/survey-popup.test.tsx b/src/__tests__/extensions/surveys/survey-popup.test.tsx new file mode 100644 index 000000000..4030f37f3 --- /dev/null +++ b/src/__tests__/extensions/surveys/survey-popup.test.tsx @@ -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( + + ) + const cancelButton2 = screen.getByRole('button', { name: 'Close survey', hidden: true }) + // Click the cancel button + fireEvent.click(cancelButton2) + // Verify that onCloseConfirmationMessage was called + expect(mockOnCloseConfirmationMessage).toHaveBeenCalledTimes(1) + }) + + test('calls onCloseConfirmationMessage when survey is closed in the confirmation message', () => { + const mockOnCloseConfirmationMessage = jest.fn() + const mockRemoveSurveyFromFocus = jest.fn() + render( + + ) + + const closeButton = screen.getByRole('button', { name: /close/i }) + fireEvent.click(closeButton) + expect(mockOnCloseConfirmationMessage).toHaveBeenCalledTimes(1) + }) +}) diff --git a/src/extensions/surveys.tsx b/src/extensions/surveys.tsx index 5648c4060..941f2a0ef 100644 --- a/src/extensions/surveys.tsx +++ b/src/extensions/surveys.tsx @@ -693,7 +693,7 @@ interface SurveyPopupProps { isPopup?: boolean onPreviewSubmit?: (res: string | string[] | number | null) => void onPopupSurveyDismissed?: () => void - onPopupSurveySent?: () => void + onCloseConfirmationMessage?: () => void } export function SurveyPopup({ @@ -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 @@ -741,9 +741,6 @@ export function SurveyPopup({ }, isPopup: isPopup || false, onPreviewSubmit, - onPopupSurveySent: () => { - onPopupSurveySent() - }, }} > {!shouldShowConfirmation ? ( @@ -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() + }} /> )} @@ -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]) @@ -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) } @@ -1036,7 +1034,7 @@ export function FeedbackWidget({ removeSurveyFromFocus={removeSurveyFromFocus} isPopup={true} onPopupSurveyDismissed={resetShowSurvey} - onPopupSurveySent={resetShowSurvey} + onCloseConfirmationMessage={resetShowSurvey} /> )} diff --git a/src/extensions/surveys/components/BottomSection.tsx b/src/extensions/surveys/components/BottomSection.tsx index 8ec0c5030..871a8d460 100644 --- a/src/extensions/surveys/components/BottomSection.tsx +++ b/src/extensions/surveys/components/BottomSection.tsx @@ -31,6 +31,7 @@ export function BottomSection({ diff --git a/src/extensions/surveys/surveys-utils.tsx b/src/extensions/surveys/surveys-utils.tsx index 22a3a8f33..31c517f53 100644 --- a/src/extensions/surveys/surveys-utils.tsx +++ b/src/extensions/surveys/surveys-utils.tsx @@ -741,7 +741,6 @@ interface SurveyContextProps { onPopupSurveyDismissed: () => void isPopup: boolean onPreviewSubmit: (res: string | string[] | number | null) => void - onPopupSurveySent: () => void } export const SurveyContext = createContext({ @@ -750,7 +749,6 @@ export const SurveyContext = createContext({ onPopupSurveyDismissed: () => {}, isPopup: true, onPreviewSubmit: () => {}, - onPopupSurveySent: () => {}, }) interface RenderProps {