@@ -245,6 +245,86 @@ describe('weread/search regression', () => {
245245 } ,
246246 ] ) ;
247247 } ) ;
248+ it ( 'decodes named and astral HTML entities before matching search cards' , async ( ) => {
249+ const command = getRegistry ( ) . get ( 'weread/search' ) ;
250+ expect ( command ?. func ) . toBeTypeOf ( 'function' ) ;
251+ const fetchMock = vi . fn ( )
252+ . mockResolvedValueOnce ( {
253+ ok : true ,
254+ json : ( ) => Promise . resolve ( {
255+ books : [
256+ {
257+ bookInfo : {
258+ title : 'A <B> 😊' ,
259+ author : "O'Neil & Co" ,
260+ bookId : 'entity-book' ,
261+ } ,
262+ } ,
263+ ] ,
264+ } ) ,
265+ } )
266+ . mockResolvedValueOnce ( {
267+ ok : true ,
268+ text : ( ) => Promise . resolve ( `
269+ <ul class="search_bookDetail_list">
270+ <li class="wr_bookList_item">
271+ <a class="wr_bookList_item_link" href="/web/reader/entity-reader"></a>
272+ <p class="wr_bookList_item_title">A <B> 😊</p>
273+ <p class="wr_bookList_item_author">O'Neil & Co</p>
274+ </li>
275+ </ul>
276+ ` ) ,
277+ } ) ;
278+ vi . stubGlobal ( 'fetch' , fetchMock ) ;
279+ const result = await command . func ( { query : 'entities' , limit : 5 } ) ;
280+ expect ( result ) . toEqual ( [
281+ {
282+ rank : 1 ,
283+ title : 'A <B> 😊' ,
284+ author : "O'Neil & Co" ,
285+ bookId : 'entity-book' ,
286+ url : 'https://weread.qq.com/web/reader/entity-reader' ,
287+ } ,
288+ ] ) ;
289+ } ) ;
290+ it ( 'leaves invalid numeric HTML entities literal instead of throwing raw RangeError' , async ( ) => {
291+ const command = getRegistry ( ) . get ( 'weread/search' ) ;
292+ expect ( command ?. func ) . toBeTypeOf ( 'function' ) ;
293+ const fetchMock = vi . fn ( )
294+ . mockResolvedValueOnce ( {
295+ ok : true ,
296+ json : ( ) => Promise . resolve ( {
297+ books : [
298+ {
299+ bookInfo : {
300+ title : 'Bad � Entity' ,
301+ author : 'Tester' ,
302+ bookId : 'bad-entity-book' ,
303+ } ,
304+ } ,
305+ ] ,
306+ } ) ,
307+ } )
308+ . mockResolvedValueOnce ( {
309+ ok : true ,
310+ text : ( ) => Promise . resolve ( `
311+ <ul class="search_bookDetail_list">
312+ <li class="wr_bookList_item">
313+ <a class="wr_bookList_item_link" href="/web/reader/bad-entity-reader"></a>
314+ <p class="wr_bookList_item_title">Bad � Entity</p>
315+ <p class="wr_bookList_item_author">Tester</p>
316+ </li>
317+ </ul>
318+ ` ) ,
319+ } ) ;
320+ vi . stubGlobal ( 'fetch' , fetchMock ) ;
321+ const result = await command . func ( { query : 'bad entity' , limit : 5 } ) ;
322+ expect ( result [ 0 ] ) . toMatchObject ( {
323+ title : 'Bad � Entity' ,
324+ bookId : 'bad-entity-book' ,
325+ url : 'https://weread.qq.com/web/reader/bad-entity-reader' ,
326+ } ) ;
327+ } ) ;
248328 it ( 'leaves urls empty when same-title results are ambiguous and html cards have no author' , async ( ) => {
249329 const command = getRegistry ( ) . get ( 'weread/search' ) ;
250330 expect ( command ?. func ) . toBeTypeOf ( 'function' ) ;
0 commit comments