@@ -20,13 +20,26 @@ import {
2020 messageAction ,
2121} from "./template-messages.js" ;
2222
23+ const loneHighSurrogate = / [ \uD800 - \uDBFF ] (? ! [ \uDC00 - \uDFFF ] ) / ;
24+
2325describe ( "createConfirmTemplate" , ( ) => {
2426 it ( "truncates text to 240 characters" , ( ) => {
2527 const longText = "x" . repeat ( 300 ) ;
2628 const template = createConfirmTemplate ( longText , messageAction ( "Yes" ) , messageAction ( "No" ) ) ;
2729
2830 expect ( ( template . template as { text : string } ) . text . length ) . toBe ( 240 ) ;
2931 } ) ;
32+
33+ it ( "drops a surrogate-pair emoji from fallback altText instead of splitting it" , ( ) => {
34+ const template = createConfirmTemplate (
35+ `${ "x" . repeat ( 399 ) } 😀` ,
36+ messageAction ( "Yes" ) ,
37+ messageAction ( "No" ) ,
38+ ) ;
39+
40+ expect ( template . altText ) . toBe ( "x" . repeat ( 399 ) ) ;
41+ expect ( loneHighSurrogate . test ( template . altText ) ) . toBe ( false ) ;
42+ } ) ;
3043} ) ;
3144
3245describe ( "createButtonTemplate" , ( ) => {
@@ -51,7 +64,16 @@ describe("createButtonTemplate", () => {
5164 const title = ( template . template as { title : string } ) . title ;
5265
5366 expect ( title ) . toBe ( "x" . repeat ( 39 ) ) ;
54- expect ( / [ \uD800 - \uDBFF ] (? ! [ \uDC00 - \uDFFF ] ) / . test ( title ) ) . toBe ( false ) ;
67+ expect ( loneHighSurrogate . test ( title ) ) . toBe ( false ) ;
68+ } ) ;
69+
70+ it ( "drops a surrogate-pair emoji from explicit altText instead of splitting it" , ( ) => {
71+ const template = createButtonTemplate ( "Title" , "Text" , [ messageAction ( "OK" ) ] , {
72+ altText : `${ "x" . repeat ( 399 ) } 😀` ,
73+ } ) ;
74+
75+ expect ( template . altText ) . toBe ( "x" . repeat ( 399 ) ) ;
76+ expect ( loneHighSurrogate . test ( template . altText ) ) . toBe ( false ) ;
5577 } ) ;
5678
5779 it ( "truncates text to 60 chars when no thumbnail is provided" , ( ) => {
@@ -105,6 +127,17 @@ describe("createCarouselColumn", () => {
105127 expect ( column . text . length ) . toBe ( 60 ) ;
106128 } ) ;
107129
130+ it ( "drops a surrogate-pair emoji from the title instead of splitting it" , ( ) => {
131+ const column = createCarouselColumn ( {
132+ title : `${ "x" . repeat ( 39 ) } 😀` ,
133+ text : "Text" ,
134+ actions : [ messageAction ( "OK" ) ] ,
135+ } ) ;
136+
137+ expect ( column . title ) . toBe ( "x" . repeat ( 39 ) ) ;
138+ expect ( loneHighSurrogate . test ( column . title ?? "" ) ) . toBe ( false ) ;
139+ } ) ;
140+
108141 it ( "does not split an emoji grapheme at the 60-code-unit boundary" , ( ) => {
109142 const text = `${ "x" . repeat ( 59 ) } 👨👩👧👦after` ;
110143 const column = createCarouselColumn ( {
@@ -172,6 +205,16 @@ describe("carousel column limits", () => {
172205 const template = createTemplate ( ) ;
173206 expect ( ( template . template as { columns : unknown [ ] } ) . columns . length ) . toBe ( 10 ) ;
174207 } ) ;
208+
209+ it ( "drops a surrogate-pair emoji from image-carousel altText instead of splitting it" , ( ) => {
210+ const template = createImageCarousel (
211+ [ createImageCarouselColumn ( "https://example.com/0.jpg" , messageAction ( "View" ) ) ] ,
212+ `${ "x" . repeat ( 399 ) } 😀` ,
213+ ) ;
214+
215+ expect ( template . altText ) . toBe ( "x" . repeat ( 399 ) ) ;
216+ expect ( loneHighSurrogate . test ( template . altText ) ) . toBe ( false ) ;
217+ } ) ;
175218} ) ;
176219
177220describe ( "createProductCarousel" , ( ) => {
0 commit comments