@@ -75,6 +75,43 @@ afterEach(() => {
7575} ) ;
7676
7777describe ( "SkillWorkshopPage lifecycle" , ( ) => {
78+ it ( "renders truncated Today previews without dangling surrogates" , async ( ) => {
79+ const previewText = `${ "a" . repeat ( 118 ) } 😀trailing` ;
80+ const proposal = {
81+ key : "proposal-utf16-preview" ,
82+ slug : "proposal-utf16-preview" ,
83+ name : "UTF-16 preview" ,
84+ oneLine : "Preview boundary coverage" ,
85+ body : `## Workflow\n- ${ previewText } ` ,
86+ status : "pending" ,
87+ version : 1 ,
88+ createdAt : 0 ,
89+ updatedAt : 0 ,
90+ recencyGroup : "today" ,
91+ ageLabel : "now" ,
92+ supportFiles : [ ] ,
93+ isNew : false ,
94+ origin : {
95+ agentId : "research" ,
96+ sessionKey : "agent:research:proposal-utf16-preview" ,
97+ } ,
98+ } satisfies SkillWorkshopProposal ;
99+ const loadedState = createSkillWorkshopState ( ) ;
100+ loadedState . skillWorkshopAgentId = "research" ;
101+ loadedState . skillWorkshopLoaded = true ;
102+ loadedState . skillWorkshopProposals = [ proposal ] ;
103+ loadedState . skillWorkshopSelectedKey = proposal . key ;
104+ const page = document . createElement (
105+ "openclaw-skill-workshop-page" ,
106+ ) as SkillWorkshopPageTestElement ;
107+ page . data = skillWorkshopRouteData ( loadedState ) ;
108+ page . context = createContext ( vi . fn ( async ( ) => ( { } ) ) ) ;
109+ document . body . append ( page ) ;
110+ await page . updateComplete ;
111+
112+ expect ( page . querySelector ( ".sw-today__does li" ) ?. textContent ) . toBe ( `${ "a" . repeat ( 118 ) } …` ) ;
113+ } ) ;
114+
78115 it ( "forces a fresh proposal load when the gateway source changes" , async ( ) => {
79116 const firstRequest = vi . fn ( async ( ) => ( { } ) ) ;
80117 const secondRequest = vi . fn ( async ( ) => ( {
0 commit comments