@@ -8,29 +8,36 @@ import type {
88import type { Plugin } from 'claude-code/testing'
99import { expect , memoryEnv , seat , test } from 'claude-code/testing'
1010
11+ import type { LogEntry } from '../hooks/telemetry-types'
12+
1113seat ( 'builtin' )
1214
1315const BEARER : SessionAuthorization = { handle : 'the-handle' , kind : 'bearer' }
1416const ACCEPTED : HttpResponse = { status : 200 , ok : true , headers : { } , text : '' }
1517
18+ const SURVEY : LogEntry = {
19+ event : 'survey_answered' ,
20+ props : { answer : 2 , seen : true } ,
21+ }
22+
1623/**
17- * `/record <event >`, which the recording plugin answers.
24+ * `/record <entry >`, which the recording plugin answers.
1825 */
19- const record = ( event : string ) : CommandRunInput => ( {
26+ const record = ( entry : LogEntry ) : CommandRunInput => ( {
2027 command : 'record' ,
21- args : event ,
28+ args : JSON . stringify ( entry ) ,
2229 origin : { kind : 'composer' } ,
2330} )
2431
2532/**
26- * A plugin whose `/record <event >` logs that event through `$.telemetry`,
33+ * A plugin whose `/record <entry >` logs the entry through `$.telemetry`,
2734 * answering "sent", or why the row was refused.
2835 */
2936const recording : Plugin = {
3037 name : 'recording' ,
3138 register ( on ) {
3239 on ( 'command.run' , { command : 'record' } , ( $ , e ) =>
33- $ . telemetry . log ( { event : e . args , props : { answer : 2 , seen : true } } ) . then (
40+ $ . telemetry . log ( JSON . parse ( e . args ) ) . then (
3441 ( ) => ( { text : 'sent' } ) ,
3542 ( error : unknown ) => ( { text : String ( error ) } ) ,
3643 ) ,
7380 memoryEnv ( on , { USER_TYPE : 'ant' } )
7481 const posts = firstPartySession ( on )
7582
76- expect ( await $ . command . run ( record ( 'survey_answered' ) ) ) . toEqual ( {
83+ expect ( await $ . command . run ( record ( SURVEY ) ) ) . toEqual ( {
7784 text : 'sent' ,
7885 } )
7986 expect ( posts ) . toHaveLength ( 1 )
@@ -103,7 +110,9 @@ test(
103110 memoryEnv ( on , { } )
104111 const posts = firstPartySession ( on )
105112
106- await $ . command . run ( record ( 'tengu_repl_diff_panel_shown' ) )
113+ await $ . command . run (
114+ record ( { ...SURVEY , event : 'tengu_repl_diff_panel_shown' } ) ,
115+ )
107116
108117 expect ( posts . map ( batchOf ) ) . toMatchObject ( [
109118 {
@@ -127,7 +136,7 @@ test(
127136 memoryEnv ( on , { DO_NOT_TRACK : '1' } )
128137 const posts = firstPartySession ( on )
129138
130- expect ( await $ . command . run ( record ( 'survey_answered' ) ) ) . toEqual ( {
139+ expect ( await $ . command . run ( record ( SURVEY ) ) ) . toEqual ( {
131140 text : 'sent' ,
132141 } )
133142 expect ( posts ) . toEqual ( [ ] )
@@ -141,7 +150,7 @@ test(
141150 memoryEnv ( on , { CLAUDE_CODE_USE_BEDROCK : '1' } )
142151 const posts = firstPartySession ( on )
143152
144- await $ . command . run ( record ( 'survey_answered' ) )
153+ await $ . command . run ( record ( SURVEY ) )
145154
146155 expect ( posts ) . toEqual ( [ ] )
147156 } ,
@@ -153,7 +162,7 @@ test(
153162 async ( $ , on ) => {
154163 memoryEnv ( on , { } )
155164 const posts = firstPartySession ( on , null )
156- const { text } = await $ . command . run ( record ( 'survey_answered' ) )
165+ const { text } = await $ . command . run ( record ( SURVEY ) )
157166
158167 expect ( text ) . toEndWith (
159168 '$.telemetry.log: this session has no first-party credential to ' +
@@ -162,3 +171,19 @@ test(
162171 expect ( posts ) . toEqual ( [ ] )
163172 } ,
164173)
174+
175+ test (
176+ 'free text in a row is refused, nothing sent' ,
177+ { plugins : [ recording ] } ,
178+ async ( $ , on ) => {
179+ memoryEnv ( on , { } )
180+ const posts = firstPartySession ( on )
181+ const { text } = await $ . command . run ( {
182+ ...record ( SURVEY ) ,
183+ args : '{"event":"survey_answered","props":{"note":"hello world"}}' ,
184+ } )
185+
186+ expect ( text ) . toContain ( 'props.note: free text is refused' )
187+ expect ( posts ) . toEqual ( [ ] )
188+ } ,
189+ )
0 commit comments