Files
Sauci/apps/web/app/join/[code]/JoinClient.test.ts
T

82 lines
3.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { readFile } from 'node:fs/promises'
import { describe, expect, it } from 'vitest'
const componentPath = new URL('./JoinClient.tsx', import.meta.url)
describe('/join/[code] JoinClient', () => {
it('validates the code shape client-side without calling a private API', async () => {
const source = await readFile(componentPath, 'utf8')
expect(source).toContain("isValidInviteCode(code)")
expect(source).not.toMatch(/\/public\/v1\//)
expect(source).not.toMatch(/fetch\(/)
})
it('only attempts the app scheme link after an explicit Open in Sauci action', async () => {
const source = await readFile(componentPath, 'utf8')
expect(source).toContain('buildInviteSchemeUrl')
expect(source).toContain('Open in Sauci')
expect(source.indexOf('const handleOpenInApp')).toBeLessThan(source.indexOf('window.location.href = buildInviteSchemeUrl'))
expect(source).toContain('invite-code-display')
})
it('copies only the raw code, not a share message', async () => {
const source = await readFile(componentPath, 'utf8')
expect(source).toContain('navigator.clipboard.writeText(normalizedCode)')
})
it('links to both app stores', async () => {
const source = await readFile(componentPath, 'utf8')
expect(source).toContain('APP_STORE_URL')
expect(source).toContain('PLAY_STORE_URL')
})
it('instruments the funnel with PostHog page view, copy, and store-click events', async () => {
const source = await readFile(componentPath, 'utf8')
expect(source).toContain("posthog?.capture('join_page_viewed'")
expect(source).toContain("posthog?.capture('join_page_code_copied'")
expect(source).toContain("posthog?.capture('join_page_store_button_clicked'")
expect(source).toContain("posthog?.capture('join_page_open_app_clicked'")
expect(source).toContain("posthog?.capture('join_page_open_app_fallback_shown'")
expect(source).toContain("posthog?.capture('join_page_offline_shown'")
})
it('does not put an invite code in a PostHog payload', async () => {
const source = await readFile(componentPath, 'utf8')
expect(source).not.toMatch(/posthog\?\.capture\([^)]*normalizedCode/)
expect(source).not.toMatch(/posthog\?\.capture\([^)]*\bcode\s*:/)
})
it('uses the required recovery and accessibility states', async () => {
const source = await readFile(componentPath, 'utf8')
expect(source).toContain('Copy this before you install')
expect(source).toContain('setTimeout(() =>')
expect(source).toContain('}, 1500)')
expect(source).toContain("document.visibilityState === 'visible'")
expect(source).toContain("aria-live=\"polite\"")
expect(source).toContain('navigator.onLine')
expect(source).toContain('surface-solid')
expect(source).not.toContain('glass-light')
})
it('describes open-answer visibility truthfully', async () => {
const source = await readFile(componentPath, 'utf8')
expect(source).toContain('For open-answer questions, each response can be visible after you have both answered.')
expect(source).not.toContain('Neither of you sees the other’s individual answers.')
})
it('shows a clear fallback message for a malformed invite code', async () => {
const source = await readFile(componentPath, 'utf8')
expect(source).toContain('Invite link not recognized')
expect(source).not.toContain('has expired')
})
})