Files
zeekay ec6f6b50c1 chore: kill ALL posthog — zero refs, zero filenames (1452 -> 0)
We own the ingestion server (hanzoai/insights: Django + rust/capture + nodejs
plugin) AND this SDK, so there is no external wire contract to preserve. The
server is already 100% posthog-free; this SDK was the last laggard.

- $last_posthog_reset -> $last_insights_reset. This FIXES A LIVE MISMATCH: the
  server taxonomy (insights/taxonomy/taxonomy.py, insights/insightsql/ai.py)
  already expected the insights form while the SDK emitted the posthog form.
- __PosthogExtensions__ -> __InsightsExtensions__; all PostHog/posthog/POSTHOG
  identifiers -> Insights/insights/INSIGHTS (src, tests, playground, playwright,
  scripts, rrweb subpackages, package.json keywords).
- Hosts: DEFAULT_PLUGIN_HOST + DEFAULT_NUXT_HOST + the core host default pointed
  at PostHog's cloud (us.i.posthog.com) — a real bug. All -> insights.hanzo.ai.
- Removed the us-assets/eu-assets CDN split in getRemoteConfig (PostHog-specific;
  Hanzo serves remote config from the same host) — it had degenerated to a no-op.
- Fixed generate-docs writing to a stray references/@hanzo/ subdir.
- Renamed the 3 posthog-named test files; dropped 58MB of stale reference
  snapshots named for upstream posthog versions we never shipped (they are
  generated output — references/ is now gitignored).

Verified: typecheck errors 42 (HEAD) -> 18 (all pre-existing test-mock
looseness); types package 0; every package.json valid with @hanzo/* names.
Guard: grep -rioE 'posthog' packages ... | wc -l  => 0
2026-07-16 09:09:18 -07:00

383 lines
11 KiB
TypeScript

import { sendSurveyEvent } from '../src/surveys/components/Surveys'
import { Survey, SurveyQuestion } from '@hanzo/insights-core'
const createMockSurvey = (overrides: Partial<Survey> = {}): Survey => ({
id: 'test-survey-id',
name: 'Test Survey',
questions: [
{
id: 'question-1',
question: 'How satisfied are you?',
type: 'rating',
scale: 5,
originalQuestionIndex: 0,
} as SurveyQuestion,
{
id: 'question-2',
question: 'Any additional comments?',
type: 'open',
originalQuestionIndex: 1,
} as SurveyQuestion,
],
...overrides,
})
describe('sendSurveyEvent', () => {
let mockInsights: any
beforeEach(() => {
mockInsights = {
capture: jest.fn(),
}
})
describe('basic functionality', () => {
it('should capture survey sent event with correct base properties', () => {
const survey = createMockSurvey()
const responses = {
'$survey_response_question-1': 4,
'$survey_response_question-2': 'Great service!',
}
sendSurveyEvent(responses, survey, mockInsights)
expect(mockInsights.capture).toHaveBeenCalledWith('survey sent', {
$survey_name: 'Test Survey',
$survey_id: 'test-survey-id',
$survey_questions: [
{
id: 'question-1',
question: 'How satisfied are you?',
response: 4,
},
{
id: 'question-2',
question: 'Any additional comments?',
response: 'Great service!',
},
],
'$survey_response_question-1': 4,
'$survey_response_question-2': 'Great service!',
$survey_response: 4,
$survey_response_1: 'Great service!',
$set: {
'$survey_responded/test-survey-id': true,
},
})
})
it('should include survey language when provided', () => {
const survey = createMockSurvey()
sendSurveyShownEvent(survey, mockInsights, 'pt')
dismissedSurveyEvent(survey, {}, mockInsights, 'pt')
sendSurveyEvent({}, survey, mockInsights, 'pt')
expect(mockInsights.capture).toHaveBeenNthCalledWith(
1,
'survey shown',
expect.objectContaining({ $survey_language: 'pt' })
)
expect(mockInsights.capture).toHaveBeenNthCalledWith(
2,
'survey dismissed',
expect.objectContaining({ $survey_language: 'pt' })
)
expect(mockInsights.capture).toHaveBeenNthCalledWith(
3,
'survey sent',
expect.objectContaining({ $survey_language: 'pt' })
)
})
})
describe('survey iterations', () => {
it('should include iteration properties when survey has current_iteration', () => {
const survey = createMockSurvey({
current_iteration: 2,
current_iteration_start_date: '2024-01-15',
})
const responses = {
'$survey_response_question-1': 4,
'$survey_response_question-2': 'Great service!',
}
sendSurveyEvent(responses, survey, mockInsights)
expect(mockInsights.capture).toHaveBeenCalledWith('survey sent', {
$survey_name: 'Test Survey',
$survey_id: 'test-survey-id',
$survey_iteration: 2,
$survey_iteration_start_date: '2024-01-15',
$survey_questions: [
{
id: 'question-1',
question: 'How satisfied are you?',
response: 4,
},
{
id: 'question-2',
question: 'Any additional comments?',
response: 'Great service!',
},
],
'$survey_response_question-1': 4,
'$survey_response_question-2': 'Great service!',
$survey_response: 4,
$survey_response_1: 'Great service!',
$set: {
'$survey_responded/test-survey-id/2': true,
},
})
})
it('should not include iteration properties when survey has no current_iteration', () => {
const survey = createMockSurvey({
current_iteration: undefined,
current_iteration_start_date: undefined,
})
const responses = { '$survey_response_question-1': 3 }
sendSurveyEvent(responses, survey, mockInsights)
const captureCall = mockInsights.capture.mock.calls[0][1]
expect(captureCall).not.toHaveProperty('$survey_iteration')
expect(captureCall).not.toHaveProperty('$survey_iteration_start_date')
expect(captureCall.$set).toEqual({
'$survey_responded/test-survey-id': true,
})
})
})
describe('response handling', () => {
it('should handle string responses', () => {
const survey = createMockSurvey()
const responses = {
'$survey_response_question-2': 'This is a text response',
}
sendSurveyEvent(responses, survey, mockInsights)
const captureCall = mockInsights.capture.mock.calls[0][1]
expect(captureCall.$survey_questions[1].response).toBe('This is a text response')
})
it('should handle numeric responses', () => {
const survey = createMockSurvey()
const responses = {
'$survey_response_question-1': 5,
}
sendSurveyEvent(responses, survey, mockInsights)
const captureCall = mockInsights.capture.mock.calls[0][1]
expect(captureCall.$survey_questions[0].response).toBe(5)
})
it('should handle array responses by creating a copy', () => {
const survey = createMockSurvey({
questions: [
{
id: 'question-multi',
question: 'Select all that apply',
type: 'multiple_choice',
choices: ['Option 1', 'Option 2', 'Option 3'],
} as SurveyQuestion,
],
})
const originalArray = ['Option 1', 'Option 3']
const responses = {
'$survey_response_question-multi': originalArray,
}
sendSurveyEvent(responses, survey, mockInsights)
const captureCall = mockInsights.capture.mock.calls[0][1]
const responseArray = captureCall.$survey_questions[0].response
expect(responseArray).toEqual(['Option 1', 'Option 3'])
expect(responseArray).not.toBe(originalArray) // Should be a copy, not the same reference
})
it('should handle null responses', () => {
const survey = createMockSurvey()
const responses = {
'$survey_response_question-1': null,
}
sendSurveyEvent(responses, survey, mockInsights)
const captureCall = mockInsights.capture.mock.calls[0][1]
expect(captureCall.$survey_questions[0].response).toBeNull()
})
it('should return null for questions without responses', () => {
const survey = createMockSurvey()
const responses = {
'$survey_response_question-1': 4,
// question-2 has no response
}
sendSurveyEvent(responses, survey, mockInsights)
const captureCall = mockInsights.capture.mock.calls[0][1]
expect(captureCall.$survey_questions[0].response).toBe(4)
expect(captureCall.$survey_questions[1].response).toBeUndefined()
})
})
describe('survey interaction property', () => {
it('should generate correct interaction property without iteration', () => {
const survey = createMockSurvey()
const responses = {}
sendSurveyEvent(responses, survey, mockInsights)
const captureCall = mockInsights.capture.mock.calls[0][1]
expect(captureCall.$set).toEqual({
'$survey_responded/test-survey-id': true,
})
})
it('should generate correct interaction property with iteration', () => {
const survey = createMockSurvey({
current_iteration: 3,
})
const responses = {}
sendSurveyEvent(responses, survey, mockInsights)
const captureCall = mockInsights.capture.mock.calls[0][1]
expect(captureCall.$set).toEqual({
'$survey_responded/test-survey-id/3': true,
})
})
})
describe('complex scenarios', () => {
it('should handle survey with mixed question types and responses', () => {
const survey = createMockSurvey({
questions: [
{
id: 'rating-q',
question: 'Rate us',
type: 'rating',
scale: 10,
} as SurveyQuestion,
{
id: 'multi-q',
question: 'Select options',
type: 'multiple_choice',
choices: ['A', 'B', 'C'],
} as SurveyQuestion,
{
id: 'text-q',
question: 'Comments',
type: 'open',
} as SurveyQuestion,
],
})
const responses = {
'$survey_response_rating-q': 8,
'$survey_response_multi-q': ['A', 'C'],
'$survey_response_text-q': 'Good job!',
}
sendSurveyEvent(responses, survey, mockInsights)
const captureCall = mockInsights.capture.mock.calls[0][1]
expect(captureCall.$survey_questions).toEqual([
{
id: 'rating-q',
question: 'Rate us',
response: 8,
},
{
id: 'multi-q',
question: 'Select options',
response: ['A', 'C'],
},
{
id: 'text-q',
question: 'Comments',
response: 'Good job!',
},
])
})
})
})
describe('dismissedSurveyEvent', () => {
let mockInsights: any
beforeEach(() => {
mockInsights = {
capture: jest.fn(),
}
})
it.each([
{
label: 'captures dismissal responses and marks partial completion when there are answers',
responses: {
'$survey_response_question-1': 4,
'$survey_response_question-2': 'Great service!',
},
expectedPayload: {
$survey_name: 'Test Survey',
$survey_id: 'test-survey-id',
$survey_partially_completed: true,
$survey_questions: [
{
id: 'question-1',
question: 'How satisfied are you?',
response: 4,
},
{
id: 'question-2',
question: 'Any additional comments?',
response: 'Great service!',
},
],
'$survey_response_question-1': 4,
'$survey_response_question-2': 'Great service!',
$survey_response: 4,
$survey_response_1: 'Great service!',
$set: {
'$survey_dismissed/test-survey-id': true,
},
},
},
{
label: 'marks dismissal as not partially completed when no answers exist',
responses: {},
expectedPayload: {
$survey_name: 'Test Survey',
$survey_id: 'test-survey-id',
$survey_partially_completed: false,
$survey_questions: [
{
id: 'question-1',
question: 'How satisfied are you?',
response: undefined,
},
{
id: 'question-2',
question: 'Any additional comments?',
response: undefined,
},
],
$set: {
'$survey_dismissed/test-survey-id': true,
},
},
},
])('$label', ({ responses, expectedPayload }) => {
const survey = createMockSurvey()
dismissedSurveyEvent(survey, responses, mockInsights)
expect(mockInsights.capture).toHaveBeenCalledWith('survey dismissed', expectedPayload)
})
})