@@ -136,6 +136,26 @@ const fallbackEmoji: Misskey.entities.EmojiSimple = {
136136 roleIdsThatCanBeUsedThisEmojiAsReaction : [ ] ,
137137} ;
138138
139+ const thresholdEmoji : Misskey . entities . EmojiSimple = {
140+ name : 'threshold_ok' ,
141+ aliases : [ 'threshold' ] ,
142+ category : 'story' ,
143+ url : '/client-assets/about-icon.png' ,
144+ localOnly : false ,
145+ isSensitive : false ,
146+ roleIdsThatCanBeUsedThisEmojiAsReaction : [ ] ,
147+ } ;
148+
149+ const belowThresholdEmoji : Misskey . entities . EmojiSimple = {
150+ name : 'below_threshold' ,
151+ aliases : [ 'below' ] ,
152+ category : 'story' ,
153+ url : '/client-assets/about-icon.png' ,
154+ localOnly : false ,
155+ isSensitive : false ,
156+ roleIdsThatCanBeUsedThisEmojiAsReaction : [ ] ,
157+ } ;
158+
139159function createNote ( overrides : Partial < Misskey . entities . Note > = { } ) : Misskey . entities . Note {
140160 return {
141161 id : 'qa-note-fixture' ,
@@ -210,7 +230,7 @@ beforeEach(() => {
210230 clearFlatEmojiSuggestionPublicMeta ( ) ;
211231 setEmojiSuggestionPublicMeta ( { enabled : true , maxSuggestions : 4 } ) ;
212232
213- customEmojis . value = [ suggestedEmoji , fallbackEmoji ] ;
233+ customEmojis . value = [ suggestedEmoji , fallbackEmoji , thresholdEmoji , belowThresholdEmoji ] ;
214234 mockedRecentlyUsedEmojis . value = [ ] ;
215235 customEmojisMap . clear ( ) ;
216236 for ( const emoji of customEmojis . value ) {
@@ -327,8 +347,64 @@ describe('MkEmojiPicker emoji suggestions QA flows', () => {
327347 expect ( mockedMisskeyApi . mock . calls [ 0 ] [ 0 ] ) . toBe ( 'notes/reactions/suggestions' ) ;
328348 } ) ;
329349
350+ test ( 'shows eligible home suggestions' , async ( ) => {
351+ mockedMisskeyApi . mockResolvedValueOnce ( {
352+ items : [ {
353+ name : suggestedEmoji . name ,
354+ score : 0.98 ,
355+ aliases : suggestedEmoji . aliases ,
356+ category : suggestedEmoji . category ,
357+ } ] ,
358+ source : 'live' ,
359+ reason : 'component-test' ,
360+ modelVersion : 'fixture-model' ,
361+ emojiIndexVersion : 'fixture-index' ,
362+ } ) ;
363+
364+ const result = await renderPicker ( {
365+ targetNote : createNote ( { visibility : 'home' } ) ,
366+ pinnedEmojis : [ ':fallback_ok:' ] ,
367+ } ) ;
368+
369+ await waitFor ( ( ) => expect ( result . getByText ( 'Suggested' ) ) . not . toBeNull ( ) ) ;
370+ await waitFor ( ( ) => expect ( mockedMisskeyApi ) . toHaveBeenCalledTimes ( 1 ) ) ;
371+ expect ( mockedMisskeyApi . mock . calls [ 0 ] [ 0 ] ) . toBe ( 'notes/reactions/suggestions' ) ;
372+ } ) ;
373+
374+ test ( 'filters suggestion items below the minimum score before rendering' , async ( ) => {
375+ mockedMisskeyApi . mockResolvedValueOnce ( {
376+ items : [
377+ {
378+ name : belowThresholdEmoji . name ,
379+ score : 0.39 ,
380+ aliases : belowThresholdEmoji . aliases ,
381+ category : belowThresholdEmoji . category ,
382+ } ,
383+ {
384+ name : thresholdEmoji . name ,
385+ score : 0.4 ,
386+ aliases : thresholdEmoji . aliases ,
387+ category : thresholdEmoji . category ,
388+ } ,
389+ ] ,
390+ source : 'live' ,
391+ reason : 'component-test' ,
392+ modelVersion : 'fixture-model' ,
393+ emojiIndexVersion : 'fixture-index' ,
394+ } ) ;
395+
396+ const result = await renderPicker ( {
397+ targetNote : createNote ( { visibility : 'home' } ) ,
398+ pinnedEmojis : [ ':fallback_ok:' ] ,
399+ } ) ;
400+
401+ await waitFor ( ( ) => expect ( result . getByText ( 'Suggested' ) ) . not . toBeNull ( ) ) ;
402+ await waitFor ( ( ) => expect ( mockedMisskeyApi ) . toHaveBeenCalledTimes ( 1 ) ) ;
403+ expect ( result . container . querySelector ( '[data-emoji=":threshold_ok:"]' ) ) . not . toBeNull ( ) ;
404+ expect ( result . container . querySelector ( '[data-emoji=":below_threshold:"]' ) ) . toBeNull ( ) ;
405+ } ) ;
406+
330407 test . each ( [
331- { visibility : 'home' } ,
332408 { visibility : 'followers' } ,
333409 { visibility : 'specified' } ,
334410 ] satisfies Partial < Misskey . entities . Note > [ ] ) ( 'does not request suggestions for ineligible note fixture %#' , async ( overrides ) => {
0 commit comments