Files
orca/src/shared/feature-tips.test.ts
T
Jinwoo Hong 64704daac5 feat(feature-tips): one-time tip for agent session search (#22923)
* feat(feature-tips): one-time tip for agent session search

Session search is only discoverable from Settings. Add a feature tip that
existing users see once, which turns search on, shows the first index
build's progress in place, and opens the sidebar search once it is ready.
A toast says when a build left running in the background finishes.

Also share the two-column tip layout across the voice, Cmd+J and session
search dialogs, and move the CLI tip dialog into its own file.

* refactor(feature-tips): simplify the session search tip after review

- Watch for a background finish only when this tip closes mid-index; closing
  any other tip no longer arms a stray "ready" toast.
- The hook detects the close itself, so dialogClosed/reset and the onStatus
  callback on useSessionSearchStatus are gone.
- Table-driven dialog copy, reuse FeatureTipActions, and share the eyebrow
  badge and settings link across the voice, Cmd+J and session search tips.
- One getPendingFeatureTips for the startup gate and the modal.
- Demo: a phase timing table and hoisted header props.
- e2e helpers mark the new tip seen too.

* fix(feature-tips): retire the session search tip once the user has switched search

Turning session search on or off in Settings, or enabling it from the
sidebar, now marks the tip seen, the way the Voice switch does, so a user
who turned search on and later off is not pitched it again.

* test(ai-vault): give the legacy-filter store mock markFeatureTipsSeen

Also mark the tip seen only after the sidebar's enable actually saves.
2026-09-25 17:14:15 -04:00

124 lines
3.8 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import {
FEATURE_TIPS,
getCompletedFeatureTipIds,
getOrderedUnseenFeatureTips,
normalizeFeatureTipIds,
type FeatureTipId
} from './feature-tips'
describe('feature tips', () => {
it('orders new unseen tips before older unseen tips', () => {
const tips = getOrderedUnseenFeatureTips({ seenTipIds: new Set<FeatureTipId>() })
expect(tips.map((tip) => tip.id)).toEqual([
'agent-session-search',
'orca-cli',
'cmd-j-palette',
'voice-dictation'
])
})
it('skips tips the user has already seen', () => {
const tips = getOrderedUnseenFeatureTips({
seenTipIds: new Set<FeatureTipId>([
'voice-dictation',
'orca-cli',
'cmd-j-palette',
'agent-session-search'
])
})
expect(tips.map((tip) => tip.id)).toEqual([])
})
it('skips tips for features the user has already completed', () => {
const tips = getOrderedUnseenFeatureTips({
// cmd-j is a seen-based tip with no feature completion, so mark it seen here.
seenTipIds: new Set<FeatureTipId>(['cmd-j-palette']),
completedTipIds: getCompletedFeatureTipIds({
cliInstalled: true,
voiceDictationEnabled: true,
sessionSearchTipCompleted: true
})
})
expect(tips.map((tip) => tip.id)).toEqual([])
})
it('skips the CLI tip when the CLI is already installed', () => {
const tips = getOrderedUnseenFeatureTips({
seenTipIds: new Set<FeatureTipId>(['voice-dictation', 'cmd-j-palette']),
completedTipIds: getCompletedFeatureTipIds({
cliInstalled: true,
voiceDictationEnabled: false,
sessionSearchTipCompleted: true
})
})
expect(tips.map((tip) => tip.id)).toEqual([])
})
it('skips tips for features the user has already interacted with', () => {
const tips = getOrderedUnseenFeatureTips({
seenTipIds: new Set<FeatureTipId>(),
completedTipIds: getCompletedFeatureTipIds({
cliInstalled: false,
voiceDictationEnabled: false,
sessionSearchTipCompleted: true,
featureInteractions: {
'voice-dictation': { firstInteractedAt: 100, interactionCount: 1 }
}
})
})
expect(tips.map((tip) => tip.id)).toEqual(['orca-cli', 'cmd-j-palette'])
})
it('normalizes persisted tip ids', () => {
expect(
normalizeFeatureTipIds([
'feature-tour',
'orca-cli',
'bogus',
'cmd-j-palette',
'voice-dictation'
])
).toEqual(['orca-cli', 'cmd-j-palette', 'voice-dictation'])
})
it('describes the command palette tip as a passive acknowledgement', () => {
const paletteTip = FEATURE_TIPS.find((tip) => tip.id === 'cmd-j-palette')
expect(paletteTip).toMatchObject({
action: 'learn-cmd-j-palette',
priority: 'new',
eyebrow: 'Tip',
ctaLabel: 'Got it'
})
expect(paletteTip?.description).toContain('worktrees')
expect(paletteTip?.description).toContain('spin up a new worktree')
})
it('describes the CLI tip as an install action with concrete workflows', () => {
const cliTip = FEATURE_TIPS.find((tip) => tip.id === 'orca-cli')
expect(cliTip).toMatchObject({
action: 'setup-cli',
title: 'Let agents drive Orca with the Orca CLI',
ctaLabel: 'Install CLI & Skills'
})
expect(cliTip?.description).toContain('coordinate child worktrees')
expect(cliTip?.description).toContain('communicate between worktrees')
})
it('does not label the voice dictation tip as new', () => {
const voiceTip = FEATURE_TIPS.find((tip) => tip.id === 'voice-dictation')
expect(voiceTip?.eyebrow).toBe('Tip')
expect(voiceTip?.priority).toBe('unseen')
expect(voiceTip?.title).toBe('Dictate into any pane')
expect(voiceTip?.ctaLabel).toBe('Set up voice dictation')
})
})