-
-
Notifications
You must be signed in to change notification settings - Fork 10.1k
CLI: Introduce Agentic Setup workflow #34297
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
Merged
Merged
Changes from all commits
Commits
Show all changes
377 commits
Select commit
Hold shift + click to select a range
3155701
feat(telemetry): add ai-setup-evidence event type
Sidnioulz 2f2e6a9
feat(telemetry): preserve userSince for agents in CI
Sidnioulz 559a09a
feat: add mock telemetry receiver for local debugging
Sidnioulz 1fea584
refactor(ghost-stories): move trigger from modal to 10min delay, simp…
Sidnioulz 1cb3610
feat(ai): thread traits accumulator through prompt generation
Sidnioulz 5f11032
feat(ai): add telemetry, baseline snapshot, and frontmatter to sb ai …
Sidnioulz 241710a
feat(telemetry): add evidence-based ai-setup completion tracking at C…
Sidnioulz cc92a8c
fix: update tests for ghost-stories, withTelemetry, and detect-agent …
Sidnioulz ae591fc
Merge branch 'next' into project/sb-agentic-setup
yannbf 798eb60
Eval: refine trial collection and batch controls
kasperpeulen ec41d25
Apply suggestion from @Sidnioulz
Sidnioulz a6f4f1f
Apply suggestion from @Sidnioulz
Sidnioulz 0155a76
Apply suggestion from @Sidnioulz
Sidnioulz e3f41aa
Tests: fix formatting and stabilize CI assertions
kasperpeulen eec68c2
Apply suggestion from @Sidnioulz
Sidnioulz b571cf5
Apply suggestion from @Sidnioulz
Sidnioulz 959740b
Vitest: keep screenshot config out of public templates
kasperpeulen 9ce34d7
Build: fix production check failures
kasperpeulen 25f017e
Eval: fast-forward source baseline before sync
kasperpeulen eeccece
Format eval batch types and baseline test assertions
kasperpeulen 090c511
refactor: rename ai-setup-evidence to ai-prepare-evidence, add ai-pre…
Sidnioulz fec53a5
feat: create ai-prepare-evidence module with evidence collection, sto…
Sidnioulz 8606a4a
refactor: replace inline AiSetupPendingRecord with type import from a…
Sidnioulz a529bcb
refactor: move AiSetupPendingRecord and isStoryCreatedByAISetup to te…
Sidnioulz d22240d
refactor: remove evidence collection from withTelemetry, import from …
Sidnioulz f60ecfe
feat: fire ai-prepare evidence from doTelemetry with story index for …
Sidnioulz 1826b68
test: add unit tests for ai-prepare-evidence module
Sidnioulz a6a2532
chore: clean up dead detect-agent mock, fix test name for agent detec…
Sidnioulz 82f7bcd
feat: add AI story scoring to ghost stories channel with CPU capacity…
Sidnioulz 8c9eaa0
Fix linting
Sidnioulz c891c83
Update implementation
Sidnioulz b9bb015
Update test mocks and fixtures
Sidnioulz 50ddc1f
Remove spike script for feature adoption data flow
Sidnioulz f802462
Align type imports between two files
Sidnioulz 91c0d05
CLI: Rework --dev default and ai prepare UX
Sidnioulz f351600
Flush event cache when ai prepare event is expired
Sidnioulz 115de94
feat: add centralised AI prepare prompt copy
Sidnioulz 0207230
feat: add optional icon field to ChecklistData type
Sidnioulz ea0c654
feat: support custom icon field in ChecklistWidget
Sidnioulz 5c87352
feat: add forceCollapsed prop to Checklist component
Sidnioulz 67d3f86
feat: add aiPrepare checklist item with WandIcon
Sidnioulz 8100b5c
feat: add AI prepare CTA block to Guide page
Sidnioulz 6cdf869
feat: detect ai-prepare telemetry at startup and mark checklist item …
Sidnioulz a9590c2
Reorganise LLM code
Sidnioulz 6f45a42
Align UI with Figma
Sidnioulz 8c18046
Adjust behaviour of AI prepare checklist item post done
Sidnioulz 7b7112c
Adjust the prompt to the copy we currently use
Sidnioulz 0b5ce36
Only show agent success message with followup to supported frameworks
Sidnioulz 51aef29
Re-add storybookCommand
Sidnioulz c0ceb72
Fix up mistakes in GuidePage
Sidnioulz 721dc82
Add unit tests for ai prepare checklist
Sidnioulz fd96be3
Update FinalizationCommand tests
Sidnioulz 993868a
docs: add agent vitest telemetry implementation plan
Sidnioulz 473bd11
refactor: extract shared test result types from ghost-stories
Sidnioulz 8d8d4fb
Track when users request AI prepare prompt in init
Sidnioulz ff2b625
refactor: extract shared test analysis logic from ghost-stories
Sidnioulz 2acb09d
refactor: rename render analysis gate to support both ghost stories a…
Sidnioulz 16beee4
feat: add agent-test-run telemetry event type
Sidnioulz 983c0d1
feat: add AgentTelemetryReporter for vitest CLI agent runs
Sidnioulz 60762e8
feat: inject AgentTelemetryReporter when agent detected in vitest CLI
Sidnioulz 4d91e1c
Add telemetry when users copy prompts
Sidnioulz 545dac9
improve ai prepare prompt
yannbf 11bf99f
Merge pull request #34532 from storybookjs/yann/improved-prompt
yannbf 22a5bc1
PR feedback
Sidnioulz 7fe4da6
Merge pull request #34526 from storybookjs/sidnioulz/cli-init-changes
Sidnioulz c46a39a
fix error message extraction logic
yannbf 33ae28e
refactor eval harness for play-driven trials
kasperpeulen 0372c7a
Remove screenshot plumbing from addon-vitest
kasperpeulen fbfdfdf
improve error categorization
yannbf 14d1e91
Revert extra ghost-story and vitest test changes
kasperpeulen 94d9872
Restore review-pr skill and trim Vitest noise
kasperpeulen 5c90b6c
Merge remote-tracking branch 'origin/project/sb-agentic-setup' into k…
kasperpeulen 3062995
Drop remaining non-eval review noise
kasperpeulen a3e829f
add isWithinInitialSession utility to easily check session windows
yannbf b3ae6dc
feat: collapse AiSetupBlock to heading row with animation when skipped
Sidnioulz bfb5bb1
Changes from Codex
kasperpeulen 50a19ea
feat: add AiSetupBlock stories (Open, Skipped, SkippedToOpen)
Sidnioulz 3117fa3
feat: add WithAiPrepare and WithAiPrepareSkipped stories to Checklist
Sidnioulz 73db61e
feat: add AiCtaSkipped and AllDone stories to GuidePage
Sidnioulz 951fc88
feat: add WithAiPrepare story to ChecklistWidget
Sidnioulz ca96d8d
remove ghostStories global
yannbf 0834932
remove duplicated tsconfig json key
yannbf 580885e
fix: allow useCopyButton onClick to be called without event argument
Sidnioulz 8b926cb
Fix formatting in eval scripts
kasperpeulen 69cd8c0
Make last adjustements to block sizing
Sidnioulz 07cb30b
Fix eval scripts lint and type errors
kasperpeulen 44a11df
Add story
Sidnioulz 33accf7
Merge branch 'next' into project/sb-agentic-setup
yannbf 4bf38d3
Fix types
Sidnioulz 9e795d3
Apply suggestion from @Sidnioulz
Sidnioulz f00c02f
Apply suggestion from @Sidnioulz
Sidnioulz 1687113
Merge branch 'project/sb-agentic-setup' into sidnioulz/agentic-teleme…
Sidnioulz 656cdea
Merge branch 'sidnioulz/agentic-telemetry-ws1' into sidnioulz/agentic…
yannbf 956d2fe
Merge telemetry loggers
Sidnioulz 8119825
Switch delayed analytics to a 4m timeout
Sidnioulz cd66a6a
Merge remote-tracking branch 'origin/sidnioulz/agentic-telemetry-ws1'…
yannbf f51a483
Fix timings in tests
Sidnioulz 920b29d
Merge pull request #34510 from storybookjs/sidnioulz/agentic-telemetr…
Sidnioulz de096e0
Merge branch 'project/sb-agentic-setup' into sidnioulz/copy-prompt-cta
Sidnioulz de01e41
Clarify vitest pass-rate wording
kasperpeulen 7b6155a
Merge pull request #34527 from storybookjs/sidnioulz/copy-prompt-cta
Sidnioulz 22dd5e2
refactor: rename 'ai prepare' to 'ai setup' across the codebase
Sidnioulz 5685647
Eval: store sync baselines as string templates
kasperpeulen 3e26b59
Eval: make baseline templates readable
kasperpeulen c4a883e
Eval: make baseline MDX consumers safe
kasperpeulen 4a76b60
Chore: fix eval formatting
kasperpeulen 8929a4c
Fix CI: TypeScript error and stale project list in eval tests
kasperpeulen e495640
Eval: remove syncLocalBuildsToTrial
kasperpeulen d7720a8
Restore trailing newline in scripts/.eslintignore
kasperpeulen 4bf9804
Fix formatting in prepare-trial.test.ts
kasperpeulen bcdfeb2
Repair global exports mashed up by merge resolution
Sidnioulz f997d25
Fix sync-baselines: auto-clone missing repos and remove premature mai…
kasperpeulen 93cd9dd
Fix formatting in sync-baselines files
kasperpeulen ef3857b
eval: format scores as percentages; default batch to Claude+Codex at …
kasperpeulen c9bba6f
Fix formatting in run-batch.test.ts
kasperpeulen ec0fa15
Add stuff missed by the LLM
Sidnioulz 3609ad8
Merge pull request #34543 from storybookjs/sidnioulz/rename-prepare-t…
Sidnioulz 0045954
Fix CI: remove unused BATCH_AGENT_IDS import
kasperpeulen 2524f56
Merge branch 'next' into project/sb-agentic-setup
Sidnioulz 907c256
Merge pull request #34421 from storybookjs/kasper/eval-worktrees-chro…
yannbf bacd3ce
fix initial session code
yannbf f52e589
Add --help flag to all eval CLI scripts
kasperpeulen 6714b03
Revert "remove ghostStories global"
yannbf 396eba6
Fix up issues with next merge
Sidnioulz f0d0c94
Merge branch 'project/sb-agentic-setup' into sidnioulz/agentic-teleme…
yannbf 175b59c
dangling changes
yannbf 512183d
Agentic Setup: Rename final scoring event
Sidnioulz 48a55f9
Merge pull request #34549 from storybookjs/sidnioulz/rename-story-sco…
yannbf 7cac0a4
fix reporting time
yannbf 611b996
Eval harness: address review feedback and improve CLIs
kasperpeulen 1c0580d
eval: document and spawn trials via node from repo root
kasperpeulen f694ac3
refactor ghost stories test result parsing
yannbf d437782
fix error message extraction
yannbf a12571a
Clean up diff: remove ./ prefix, add diagrams, fix MCP repo links
kasperpeulen a8ab777
add --include and --exclude log flags to event log collector
yannbf 2089cea
add --no-metadata flag in event log collector
yannbf ba64b84
Address PR review: sanitize labels, use esMain, remove duplicate gain…
kasperpeulen bd1f96e
Use comma-separated --add-label; remove unnecessary JSDoc
kasperpeulen e4a4aaf
chore: oxfmt eval scripts (fix Circle format-check)
kasperpeulen 5b6aa67
Merge branch 'next' into project/sb-agentic-setup
yannbf d565bef
Merge branch 'project/sb-agentic-setup' into kasper/eval-scripts-help
kasperpeulen 054986e
Merge branch 'project/sb-agentic-setup' into sidnioulz/agentic-teleme…
yannbf 9881a88
eval: validate prompt name in requireBatchPrompt
kasperpeulen 6d29099
account for PR feedback
yannbf 8a008b2
refactor ghost run logic
yannbf e81a5db
fix tests
yannbf 7821847
Merge pull request #34537 from storybookjs/sidnioulz/agentic-telemetr…
yannbf 627ebbd
feat(init): write onboarding-pending cache entry after successful init
Sidnioulz 53aae10
feat(init): remove --initial-path=/onboarding from dev subprocess launch
Sidnioulz 09dc917
feat(dev): resolve initialPath from onboarding-pending cache with CLI…
Sidnioulz a34e916
Avoid onboarding agents
Sidnioulz b6829a8
fix(dev): remove detectAgent guard, restore addon-onboarding check an…
Sidnioulz 78a8c24
feat: implement AI setup tracking and conditional telemetry firing
yannbf 8334c6d
fix(dev): drop addon check, restore detectAgent guard, simplify resol…
Sidnioulz 7c569fd
Merge branch 'project/sb-agentic-setup' into sidnioulz/fix-onboarding…
Sidnioulz ebc33b5
skip AI feature recommendation for empty projects during initialization
yannbf 69535ce
Eval: use vitest:storybook script for grading, compact agent output
kasperpeulen dc22d9c
Eval: pass verbose flag to agent drivers for full output logging
kasperpeulen 5005276
Merge remote-tracking branch 'origin/project/sb-agentic-setup' into k…
kasperpeulen aad59f0
Address CodeRabbit review: loadPrompt path traversal, --add-label safety
kasperpeulen 7fa1c26
Eval: restore manual vitest grading, add labels to story render passes
kasperpeulen 6d203ea
Eval prompt: clarify preview-first goal, add args story examples
kasperpeulen ca69287
Fix formatting in story-render.ts to pass CI format-check
kasperpeulen c473959
First pass at agentic flow docs
yannbf 96d1021
gracefully handle cache failures
yannbf bb7bc99
Merge pull request #34552 from storybookjs/sidnioulz/fix-onboarding-u…
yannbf 047c282
Merge branch 'next' into project/sb-agentic-setup
yannbf 1b2e10d
Merge branch 'project/sb-agentic-setup' into yann/skip-ai-prompts-emp…
yannbf f5cf0db
Merge branch 'project/sb-agentic-setup' into yann/conditional-ai-feature
yannbf 056c8ff
add ai as feature metadata
yannbf cd51da6
rework logic
yannbf af4587a
fix tests
yannbf 18f76fc
fix tests
yannbf a9caa31
first pass at fixing stale data
yannbf c85561f
move logic to the server
yannbf fc8bd08
add bluesky
yannbf 26094d3
skip ai prompts in react native
yannbf b819806
fix tests
yannbf 558da6d
Merge pull request #34546 from storybookjs/kasper/eval-scripts-help
yannbf 6e9182c
Merge branch 'next' into project/sb-agentic-setup
yannbf fe2b0c9
fix tests
yannbf 21be9dc
fix
yannbf e416fb6
accomodate for review feedback
yannbf 9a43d2c
Merge pull request #34577 from storybookjs/yann/skip-ai-in-react-native
yannbf ffaabc7
Merge pull request #34561 from storybookjs/yann/skip-ai-prompts-empty…
yannbf a4f12d3
Merge branch 'next' into project/sb-agentic-setup
yannbf 2ec3044
Improve agentic setup docs: style, structure, and links
kylegach 822568b
account for test runs
yannbf 12ae3fe
Address feedback and format
kylegach 809ba4e
Add new page to "more resources" list
kylegach a6355f4
Merge branch 'project/sb-agentic-setup' into yann/storybook-ai-api-docs
kylegach 3ef7a4d
Merge pull request #34560 from storybookjs/yann/storybook-ai-api-docs
kylegach 6ad855d
add stories
yannbf 1164d23
Merge branch 'project/sb-agentic-setup' into yann/conditional-ai-feature
yannbf 0c8eb06
fixes
yannbf f2b55f5
slight improvements
yannbf 8ed4332
Merge pull request #34555 from storybookjs/yann/conditional-ai-feature
yannbf 407f451
Eval: require a getComputedStyle assertion in stories to prove CSS is…
kasperpeulen 720d018
Eval prompt: reword end-state sentence to avoid biasing toward render()
kasperpeulen 88dffdb
Eval grade: scope CSS-assertion check to added lines in story files
kasperpeulen fd48b03
Eval: name the CSS-check story `CssCheck` so telemetry can find it
kasperpeulen d0fe90e
Telemetry: attribute the CssCheck story result in ai-setup-final-scoring
kasperpeulen 28fea35
Build: Source eval prompts from the CLI via EVAL_SETUP_PROMPT
kasperpeulen 9412695
CLI: Port pattern-copy-play prompt improvements from #34596
kasperpeulen 5a85358
Merge remote-tracking branch 'origin/kasper/eval-prompts-from-cli' in…
kasperpeulen 741237e
chore: oxfmt scripts/eval/eval.ts (fix CI format-check)
kasperpeulen 5be3f0b
CLI: Capture real ai-setup markdown in trial records and normalize pr…
kasperpeulen 42f4ed9
CLI: Address ai-setup eval review findings
kasperpeulen d86161f
Docs: Drop stray eslint-plugin.mdx quote-style change
kasperpeulen 86ae333
Merge remote-tracking branch 'origin/kasper/eval-prompts-from-cli' in…
kasperpeulen 391a8c1
Telemetry: tighten JSDoc on CssCheck helper + storyResults order
kasperpeulen a320350
Telemetry: simplify cssCheck to a boolean on TestRunAnalysis
kasperpeulen 5d2a7fb
Telemetry: make cssCheck a 3-state enum on TestRunAnalysis
kasperpeulen 7cb6490
Eval: add sync-storybook-version script + --skip-automigrations
kasperpeulen 8c8312b
Eval: hoist default sync hooks to avoid TDZ from CLI entry
kasperpeulen d8de741
Eval: let reruns push existing local sync commits
kasperpeulen 9140f6c
Merge remote-tracking branch 'origin/kasper/eval-sync-storybook-versi…
kasperpeulen 60a3006
Core: fix ghost stories telemetry test for cssCheck
cursoragent 62f2fa6
Merge remote-tracking branch 'origin/kasper/eval-sync-storybook-versi…
kasperpeulen a6aaf4f
CI: type sync-storybook-version env as NodeJS.ProcessEnv
kasperpeulen d9db8a8
Eval: Type-annotate env literal in sync-storybook-version
kasperpeulen 01068aa
Merge remote-tracking branch 'origin/kasper/eval-prompts-from-cli' in…
kasperpeulen 448d4d4
CI: type sync-storybook-version env as NodeJS.ProcessEnv
kasperpeulen 3ce2bac
Merge branch 'next' into project/sb-agentic-setup
yannbf 817d8b9
fix tests
yannbf 7013d94
fix test flake
yannbf 59b8813
Merge pull request #34600 from storybookjs/cursor/telemetry-css-check…
yannbf fbf3baa
Merge pull request #34612 from storybookjs/kasper/eval-sync-storybook…
yannbf 585d962
fix tests
yannbf 99ade86
Merge branch 'project/sb-agentic-setup' into kasper/eval-prompts-from…
yannbf 9729a8b
Merge branch 'kasper/eval-prompts-from-cli' into cursor/eval-css-load…
yannbf 14d97d2
simplify css check
yannbf 470626f
improve eval batch run script and docs
yannbf ce0e6cb
Merge branch 'next' into project/sb-agentic-setup
yannbf 96b782c
Merge branch 'project/sb-agentic-setup' into kasper/eval-prompts-from…
yannbf 1557244
Merge branch 'kasper/eval-prompts-from-cli' into cursor/eval-css-load…
yannbf fd6a2b0
add csscheck to pr body
yannbf 3b67e50
Merge pull request #34595 from storybookjs/cursor/eval-css-loaded-pro…
yannbf 8e7c397
Fix inconsistencies in eval README
Sidnioulz 6d13586
do not show onboarding when AI is selected
yannbf 66ab0cb
fix tests
yannbf ab56f65
Avoid mutating env in tests
Sidnioulz 62849d4
Merge pull request #34650 from storybookjs/yann/skip-onboarding-with-ai
Sidnioulz af1479a
Account for PR feedback
yannbf b35ff84
fix test
yannbf db8eabc
Merge pull request #34602 from storybookjs/kasper/eval-prompts-from-cli
yannbf e8b2899
account for review feedback
yannbf 61aa8ea
fix minor bug
yannbf de31a57
Merge branch 'next' into project/sb-agentic-setup
yannbf 8f1a55d
fix types
yannbf File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
206 changes: 206 additions & 0 deletions
206
code/addons/vitest/src/vitest-plugin/agent-telemetry-reporter.test.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,206 @@ | ||
| import { beforeEach, describe, expect, it, vi } from 'vitest'; | ||
|
|
||
| import { AgentTelemetryReporter } from './agent-telemetry-reporter.ts'; | ||
|
|
||
| vi.mock('storybook/internal/telemetry', () => ({ | ||
| telemetry: vi.fn(), | ||
| isExampleStoryId: vi.fn( | ||
| (id: string) => | ||
| id.startsWith('example-button--') || | ||
| id.startsWith('example-header--') || | ||
| id.startsWith('example-page--') | ||
| ), | ||
| })); | ||
|
|
||
| const { telemetry } = await import('storybook/internal/telemetry'); | ||
|
|
||
| function createMockTestCase({ | ||
| storyId, | ||
| status, | ||
| reports = [], | ||
| errors = [], | ||
| }: { | ||
| storyId?: string; | ||
| status: 'passed' | 'failed' | 'pending'; | ||
| reports?: Array<{ type: string; result?: Record<string, unknown> }>; | ||
| errors?: Array<{ message: string; stack?: string }>; | ||
| }) { | ||
| return { | ||
| meta: () => ({ storyId, reports }), | ||
| result: () => ({ | ||
| state: status, | ||
| errors: status === 'failed' ? errors : [], | ||
| }), | ||
| }; | ||
| } | ||
|
|
||
| function createMockTestModules(testCounts: { passed: number; failed: number }) { | ||
| const tests: Array<{ result: () => { state: string } }> = []; | ||
| for (let i = 0; i < testCounts.passed; i++) { | ||
| tests.push({ result: () => ({ state: 'passed' }) }); | ||
| } | ||
| for (let i = 0; i < testCounts.failed; i++) { | ||
| tests.push({ result: () => ({ state: 'failed' }) }); | ||
| } | ||
| return [ | ||
| { | ||
| children: { | ||
| allTests: function* (filter?: string) { | ||
| for (const t of tests) { | ||
| if (!filter || t.result().state === filter) { | ||
| yield t; | ||
| } | ||
| } | ||
| }, | ||
| }, | ||
| errors: () => [], | ||
| }, | ||
| ]; | ||
| } | ||
|
|
||
| describe('AgentTelemetryReporter', () => { | ||
| let reporter: AgentTelemetryReporter; | ||
|
|
||
| beforeEach(() => { | ||
| vi.clearAllMocks(); | ||
| reporter = new AgentTelemetryReporter({ | ||
| configDir: '.storybook', | ||
| agent: { name: 'claude' }, | ||
| }); | ||
| }); | ||
|
|
||
| describe('onTestCaseResult', () => { | ||
| it('should collect story test results', () => { | ||
| const testCase = createMockTestCase({ | ||
| storyId: 'my-story--primary', | ||
| status: 'passed', | ||
| }); | ||
| reporter.onTestCaseResult(testCase as any); | ||
| }); | ||
|
|
||
| it('should skip tests without storyId', () => { | ||
| const testCase = createMockTestCase({ | ||
| storyId: undefined, | ||
| status: 'passed', | ||
| }); | ||
| reporter.onTestCaseResult(testCase as any); | ||
| }); | ||
|
|
||
| it('should skip example story IDs', () => { | ||
| const testCase = createMockTestCase({ | ||
| storyId: 'example-button--primary', | ||
| status: 'passed', | ||
| }); | ||
| reporter.onTestCaseResult(testCase as any); | ||
| }); | ||
| }); | ||
|
|
||
| describe('onTestRunEnd', () => { | ||
| it('should send telemetry with analysis of collected results', async () => { | ||
| reporter.onInit({ config: { watch: false } } as any); | ||
|
|
||
| reporter.onTestCaseResult(createMockTestCase({ storyId: 's1', status: 'passed' }) as any); | ||
| reporter.onTestCaseResult( | ||
| createMockTestCase({ | ||
| storyId: 's2', | ||
| status: 'failed', | ||
| errors: [{ message: 'Error: Module not found: foo' }], | ||
| }) as any | ||
| ); | ||
| reporter.onTestCaseResult( | ||
| createMockTestCase({ | ||
| storyId: 's3', | ||
| status: 'passed', | ||
| reports: [{ type: 'render-analysis', result: { emptyRender: true } }], | ||
| }) as any | ||
| ); | ||
|
|
||
| await reporter.onTestRunEnd(createMockTestModules({ passed: 2, failed: 1 }) as any, []); | ||
|
|
||
| expect(telemetry).toHaveBeenCalledWith( | ||
| 'ai-setup-self-healing-scoring', | ||
| expect.objectContaining({ | ||
| agent: { name: 'claude' }, | ||
| analysis: expect.objectContaining({ | ||
| total: 3, | ||
| passed: 2, | ||
| passedButEmptyRender: 1, | ||
| successRate: 0.67, | ||
| successRateWithoutEmptyRender: 0.33, | ||
| uniqueErrorCount: 1, | ||
| }), | ||
| unhandledErrorCount: 0, | ||
| watch: false, | ||
| }), | ||
| { configDir: '.storybook', stripMetadata: true } | ||
| ); | ||
| }); | ||
|
|
||
| it('should filter out example stories from analysis', async () => { | ||
| reporter.onInit({ config: { watch: false } } as any); | ||
|
|
||
| reporter.onTestCaseResult( | ||
| createMockTestCase({ storyId: 'my-story--primary', status: 'passed' }) as any | ||
| ); | ||
| reporter.onTestCaseResult( | ||
| createMockTestCase({ storyId: 'example-button--primary', status: 'passed' }) as any | ||
| ); | ||
|
|
||
| await reporter.onTestRunEnd(createMockTestModules({ passed: 2, failed: 0 }) as any, []); | ||
|
|
||
| expect(telemetry).toHaveBeenCalledWith( | ||
| 'ai-setup-self-healing-scoring', | ||
| expect.objectContaining({ | ||
| analysis: expect.objectContaining({ | ||
| total: 1, | ||
| passed: 1, | ||
| }), | ||
| }), | ||
| expect.anything() | ||
| ); | ||
| }); | ||
|
|
||
| it('should count unhandled errors', async () => { | ||
| reporter.onInit({ config: { watch: false } } as any); | ||
|
|
||
| await reporter.onTestRunEnd( | ||
| createMockTestModules({ passed: 0, failed: 0 }) as any, | ||
| [{ message: 'unhandled' }, { message: 'another' }] as any | ||
| ); | ||
|
|
||
| expect(telemetry).toHaveBeenCalledWith( | ||
| 'ai-setup-self-healing-scoring', | ||
| expect.objectContaining({ | ||
| unhandledErrorCount: 2, | ||
| }), | ||
| expect.anything() | ||
| ); | ||
| }); | ||
|
|
||
| it('should reset collected results after each run', async () => { | ||
| reporter.onInit({ config: { watch: false } } as any); | ||
|
|
||
| reporter.onTestCaseResult(createMockTestCase({ storyId: 's1', status: 'passed' }) as any); | ||
| await reporter.onTestRunEnd(createMockTestModules({ passed: 1, failed: 0 }) as any, []); | ||
|
|
||
| reporter.onTestCaseResult( | ||
| createMockTestCase({ | ||
| storyId: 's2', | ||
| status: 'failed', | ||
| errors: [{ message: 'err' }], | ||
| }) as any | ||
| ); | ||
| await reporter.onTestRunEnd(createMockTestModules({ passed: 0, failed: 1 }) as any, []); | ||
|
|
||
| const secondCall = vi.mocked(telemetry).mock.calls[1]; | ||
| expect(secondCall[1]).toEqual( | ||
| expect.objectContaining({ | ||
| analysis: expect.objectContaining({ | ||
| total: 1, | ||
| passed: 0, | ||
| }), | ||
| }) | ||
| ); | ||
| }); | ||
| }); | ||
| }); |
88 changes: 88 additions & 0 deletions
88
code/addons/vitest/src/vitest-plugin/agent-telemetry-reporter.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| import type { SerializedError } from 'vitest'; | ||
| import type { TestCase, TestModule, Vitest } from 'vitest/node'; | ||
| import type { Reporter } from 'vitest/reporters'; | ||
|
|
||
| import type { TaskMeta } from '@vitest/runner'; | ||
| import type { Report } from 'storybook/preview-api'; | ||
| import { analyzeTestResults, toStoryTestResult } from 'storybook/internal/core-server'; | ||
| import type { StoryTestResult } from 'storybook/internal/core-server'; | ||
| import { isExampleStoryId, telemetry } from 'storybook/internal/telemetry'; | ||
| import type { AgentInfo } from 'storybook/internal/telemetry'; | ||
|
|
||
| interface AgentTelemetryReporterOptions { | ||
| configDir: string; | ||
| agent: AgentInfo; | ||
| } | ||
|
|
||
| export class AgentTelemetryReporter implements Reporter { | ||
| private ctx!: Vitest; | ||
|
|
||
| private testResults: StoryTestResult[] = []; | ||
|
|
||
| private startTime = Date.now(); | ||
|
|
||
| private configDir: string; | ||
|
|
||
| private agent: AgentInfo; | ||
|
|
||
| constructor(options: AgentTelemetryReporterOptions) { | ||
| this.configDir = options.configDir; | ||
| this.agent = options.agent; | ||
| } | ||
|
|
||
| onInit(ctx: Vitest) { | ||
| this.ctx = ctx; | ||
| } | ||
|
|
||
| onTestRunStart() { | ||
| this.startTime = Date.now(); | ||
| } | ||
|
|
||
| onTestCaseResult(testCase: TestCase) { | ||
| const { storyId, reports } = testCase.meta() as TaskMeta & | ||
| Partial<{ storyId: string; reports: Report[] }>; | ||
|
|
||
| if (!storyId || isExampleStoryId(storyId)) { | ||
| return; | ||
| } | ||
|
|
||
| const testResult = testCase.result(); | ||
| const result = toStoryTestResult({ | ||
| storyId, | ||
| statusRaw: testResult.state, | ||
| reports, | ||
| errors: testResult.errors, | ||
| }); | ||
|
|
||
| if (result) { | ||
| this.testResults.push(result); | ||
| } | ||
| } | ||
|
|
||
| async onTestRunEnd( | ||
| testModules: readonly TestModule[], | ||
| unhandledErrors: readonly SerializedError[] | ||
| ) { | ||
| const analysis = analyzeTestResults(this.testResults); | ||
| const duration = Date.now() - this.startTime; | ||
|
|
||
| const testModulesErrors = testModules.flatMap((t) => t.errors()); | ||
| const unhandledErrorCount = unhandledErrors.length + testModulesErrors.length; | ||
|
|
||
| // Fire and forget — same pattern as the existing test-run telemetry | ||
| telemetry( | ||
| 'ai-setup-self-healing-scoring', | ||
| { | ||
| agent: this.agent, | ||
| analysis, | ||
| unhandledErrorCount, | ||
| duration, | ||
| watch: this.ctx.config.watch, | ||
| }, | ||
| { configDir: this.configDir, stripMetadata: true } | ||
| ); | ||
|
|
||
| // Reset for next run (watch mode) | ||
| this.testResults = []; | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.