From e07e26cae5a24ea62b7c81dcf2817d20ff07c940 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 29 Jan 2026 17:40:04 +0000 Subject: [PATCH] Fix emoji verification responsive layout (#31899) * Extract SasEmoji to shared-components and improve responsive layout Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Add baseline screenshots Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Update tests Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix e2e test Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Add SasEmoji snapshot test Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Add figma link Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Improve doc Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Add new dir to crypto-web-reviewers codeowners as per ask Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- .github/CODEOWNERS | 1 + package.json | 1 - .../SasEmoji.stories.tsx/default-auto.png | Bin 0 -> 19544 bytes .../worst-case-albanian-auto.png | Bin 0 -> 20962 bytes .../worst-case-german-auto.png | Bin 0 -> 17775 bytes packages/shared-components/package.json | 1 + .../src/crypto/SasEmoji/SasEmoji.module.css | 33 +++++ .../src/crypto/SasEmoji/SasEmoji.stories.tsx | 48 +++++++ .../src/crypto/SasEmoji/SasEmoji.test.tsx | 19 +++ .../src/crypto/SasEmoji/SasEmoji.tsx | 43 ++++++ .../crypto/SasEmoji/SasEmojiTranslate.test.ts | 26 ++++ .../src/crypto/SasEmoji/SasEmojiTranslate.ts | 122 ++++++++++++++++++ .../__snapshots__/SasEmoji.test.tsx.snap | 115 +++++++++++++++++ .../src/crypto/SasEmoji/index.ts | 8 ++ packages/shared-components/src/index.ts | 1 + packages/shared-components/yarn.lock | 5 + playwright/e2e/crypto/utils.ts | 2 +- .../verification/_VerificationShowSas.pcss | 31 ----- .../verification/VerificationShowSas.tsx | 73 ++--------- .../views/VerificationShowSas-test.tsx | 23 ---- .../views/dialogs/IncomingSasDialog-test.tsx | 9 +- .../VerificationRequestDialog-test.tsx.snap | 17 +-- .../right_panel/VerificationPanel-test.tsx | 9 +- 23 files changed, 444 insertions(+), 143 deletions(-) create mode 100644 packages/shared-components/__vis__/linux/__baselines__/crypto/SasEmoji/SasEmoji.stories.tsx/default-auto.png create mode 100644 packages/shared-components/__vis__/linux/__baselines__/crypto/SasEmoji/SasEmoji.stories.tsx/worst-case-albanian-auto.png create mode 100644 packages/shared-components/__vis__/linux/__baselines__/crypto/SasEmoji/SasEmoji.stories.tsx/worst-case-german-auto.png create mode 100644 packages/shared-components/src/crypto/SasEmoji/SasEmoji.module.css create mode 100644 packages/shared-components/src/crypto/SasEmoji/SasEmoji.stories.tsx create mode 100644 packages/shared-components/src/crypto/SasEmoji/SasEmoji.test.tsx create mode 100644 packages/shared-components/src/crypto/SasEmoji/SasEmoji.tsx create mode 100644 packages/shared-components/src/crypto/SasEmoji/SasEmojiTranslate.test.ts create mode 100644 packages/shared-components/src/crypto/SasEmoji/SasEmojiTranslate.ts create mode 100644 packages/shared-components/src/crypto/SasEmoji/__snapshots__/SasEmoji.test.tsx.snap create mode 100644 packages/shared-components/src/crypto/SasEmoji/index.ts delete mode 100644 test/unit-tests/components/views/VerificationShowSas-test.tsx diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index bb802ef03e..ad1804bfc5 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -16,6 +16,7 @@ /src/components/views/dialogs/devtools/Crypto.tsx @element-hq/element-crypto-web-reviewers /playwright/e2e/crypto/ @element-hq/element-crypto-web-reviewers /playwright/e2e/settings/encryption-user-tab/ @element-hq/element-crypto-web-reviewers +/packages/shared-components/src/crypto/ @element-hq/element-crypto-web-reviewers /src/models/Call.ts @element-hq/element-call-reviewers diff --git a/package.json b/package.json index 2b8c1e243f..92cf154988 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,6 @@ "@matrix-org/analytics-events": "^0.31.0", "@matrix-org/emojibase-bindings": "^1.5.0", "@matrix-org/react-sdk-module-api": "^2.4.0", - "@matrix-org/spec": "^1.7.0", "@sentry/browser": "^10.0.0", "@types/png-chunks-extract": "^1.0.2", "@vector-im/compound-design-tokens": "6.9.0", diff --git a/packages/shared-components/__vis__/linux/__baselines__/crypto/SasEmoji/SasEmoji.stories.tsx/default-auto.png b/packages/shared-components/__vis__/linux/__baselines__/crypto/SasEmoji/SasEmoji.stories.tsx/default-auto.png new file mode 100644 index 0000000000000000000000000000000000000000..8e27242e4781ca1d6dec4529acc0e03ad00d04a9 GIT binary patch literal 19544 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 T9rpdc1?PjJh642M$8Y})j{%Xh literal 0 HcmV?d00001 diff --git a/packages/shared-components/__vis__/linux/__baselines__/crypto/SasEmoji/SasEmoji.stories.tsx/worst-case-albanian-auto.png b/packages/shared-components/__vis__/linux/__baselines__/crypto/SasEmoji/SasEmoji.stories.tsx/worst-case-albanian-auto.png new file mode 100644 index 0000000000000000000000000000000000000000..c845bdeabe2be792d0c2f4a1bd54f6a8fc82ab8b GIT binary patch literal 20962 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 S@4vWnNkvgZq5S#lxBm|&d{Y1b literal 0 HcmV?d00001 diff --git a/packages/shared-components/__vis__/linux/__baselines__/crypto/SasEmoji/SasEmoji.stories.tsx/worst-case-german-auto.png b/packages/shared-components/__vis__/linux/__baselines__/crypto/SasEmoji/SasEmoji.stories.tsx/worst-case-german-auto.png new file mode 100644 index 0000000000000000000000000000000000000000..6565cf86b702970b3bf3c3478f8e4a86e60aa8c6 GIT binary patch literal 17775 zcmeIacT|(v`snYBqs$SJu^=h}qlhR~K|lxr9YmxHQl&(sN(((efQ%LC0s@8-Mi7v$ zp$AA*n$$=qgd|D}5J(7wB&1%>nKN_Fz2AH9I^XqMcm4jE|FZVVUi;Zkd*A(hp8Y1? zwlo$yaO%LGJ$uAVZr!livuE#zJ$t_Y^5gfrBVQ!a=J)LRX^+W`>$Xt^YXn&E#CGAb zQ2fPS9g)!cKQ4&;bgKS)(UEHw7o{1s@WVd$yh9WL{S7nHtH-?GjOpGfbcQgSC_!M_ zq$S=J-xg(zQVA@by(j9{$$AD&ZTq?>+w1o0B*})0^1L5!JvX_e5d3|-fdac~aSyuj z_Ve`K4H1LPEW@Y{QW2TFrE_K<7`@~D!=63u2Kx^0*|UNEo9~`IKmPpNcYA*R@a4I| z5w-I^FD{QB)Gy1s-g8S>(ege2b=PBjp$^>?+WT+{TKvfUY3I>Ccf(%E^vY9(GH#cY zA1S3~cyC;uIH-P;6MCsj_=)cBX;m2ietn}y$Z8wx3%KHWOHt?k+N&y?&Z8@@4Sno$ zB_-0He@(jo=47n7=HrwM^y!1pjgKO7`fpzwCcMdd+TC}!5X|Tf?CjdLZhZ3Ka z-8`)`sqy}e@APf8%x|XuHucA4aj#p)x|_}VlZ*vUJIh_~+@*V=R-Rla)T%%?f-`hD z@eIFwAldk4@ZzOEHU>J>{$xIVr2-`MrhpH%Z(Up;@J2`X&i+{Icr))~udT-C6DtOP zliV@*ZLQ)CJPU^oU^4J>&{f9D7zU<=^umH?K(w^4ruY8bLM$6}RsVUEn~+~h;%yor z)YMctj6qbze81??ea6rjKuiotXJ3j4inh?#=?au^D3xnzKlxz4?46;XJ>IA(eb0IP zTx5GZ-|*%+8~k1IwEzHPh2t;fr+}Fu;v&}wVd#0dIg_#S>09EDs?a}$97y_A@bj}n z(l%~-mCA*d3RxlmKt5y*HzwfNRb(h|tqP+bvt2g6QVNZp%2k@0oo!kBpBFu$>-o8B zbS~4n&!e}bYM_6Zx0KkdaCNe<@ATEk0Gq{Eo}Zk4cGx2~^wp#Cq-P4lt6TDL{I%|i z!$mDIF6tTNgKreFqDwpYQ6Lbh?~dBKLFkMy>{IrKTN>u(!(%B>>2V%oUs@T@pFl1PuRA%Q#2IxH|N`z0tTn6Vz^e)l$et0 z3yUr4pqa#PZNE+$&mX_R1vnY3)fkjP!aWA(jN~1L$1KGXQiQqI2Q!~e(zY#7J zC?)+l%jU=z$$>Ag4SULrvyYd$0eLahWKSz^uBGR^j{adWo$(P(zZ=DGgKzxcaOh8a z%FF$xR?K#J*B&+g`CFocxNI`)BsQdsc7twLVksttqHR!~c0O~}L(J@jq~T{u&;Ath$WLD+ zU1JSOH!H)TQ}o)wM0PGN00stw6z#57UT7rW>y_$IFg2D>P&iO|LAWwTr|o72UFcb8CCxL|W}3L&Bc*_}EA5u!X{WlJ`O|ok*}tN1JQI^v z5AE8>;+G$SbQ~@cc9Wk@*<}mM4TO&Or{AT`gBvjM?VFXwmyIqeJaW1CugU4TFF?9R zPdn#7N^9#D0xp`Ln;SzXmabF{m}Yh+U``qZ_M$AgwJ%((|1~F(!pyaGqJO4TDWRa; z7>=c2Y2!UR1xy>6+RbJu!V8NSZSn!nKaFtW2Zp@erEp&hClj(%93BP@o_Z)(*8tf~ z!1@uK@V?KUvAQQneu@8{Y)`cB=h*Blt^usO`&-gyN=EhC&JdE&I=g1X{Kqig=q?%E_kQ!xxlNR8b{( z7-w5{{iJqDQ$SZM!VudeA>`F@&kvv8T1A5E0Q!x!-s1^^WVcZ-Gi9hRSD4zo461f& zMy-&vf?zunh6-8P*_0FoI?U z^~NcQ0FD4zesg^IbZ&}%wHYcPahpm&FVQ2armoa*K$Lv#4n`=&A2%8@Uw0}4QYPXB zZEqGsLh~_v63osKuoJa~q!~D{^QUT~qt`wGatBX`+i!IHcr!XhM}exc5$P+Qnsm zSj3ozk^^wGW8ontkDb9|DOVS=;7O1AZBYwpM%fi34#W2Scw|CzolA!%w-28~bh?v~ zf=XL+BDF;BBrOZnNRHdqJeGM%1$Ur(!pOtsX}x5;_stmFE(rx_aGb|jlV@i!G^p;P z+Mo=8@yphH>Hx?rb}_8p%pg+(D7XV5WUE*xlsv;r8q3S#7%j-}QFSGNtWySYJ#Ub6 zvueGr&;c?!l25-8^Bba#)p(^gFlOhrmQG~t_fbZ)=+dxq`k_D$9ir`^ z${*$BjeqDPiO0`Gc4k8Bu)zDYhZX~}GlEYK(Vn;kTr;uhH&ygnJ`h#!wU`CKbLX+X zChP51YSn6H3#v!-P{{H!E#2vvkoGpryQOD45TebU0^nwB*uYp_`y^ggey)7xl25!V zuZOOgzpa$tw1gn{mJwnpJe{olf(Po{Ni{HTlQM-g%AV3X*vH)r9$3GiGirI?UVZR^)nI(@I5QV6Qsv(WAM)jghf!@6Q)P zpQKjhPtt%g7+5H;`l%@RRpz8pu47Ykxki4$)h$$FcB{n&Cp&E+k*@8Xwb$9EX{&pw zu}YivAYCEMkI&l|rmr8oqIl?~EDXXG#Q+dd(CkhwgD5@c*UyTz+y zod$Re2ST*Qk11@X_d5HRbD}5@5mc&x@kZ)6F~q|{ajdDa^Z^B30vFu4Zf!&m+mb5l zayT5r0)qnrh&fP%rpBoy)%KA4RF7>Rrrvf*w(z}zTad%lP%9|&Mz6l*&mZCmjn}m+IBE@Ros(4Z#PPssrR^5 z)hXZP%M;t87+Z~I*!YL1rS;mVhXn3g#q&9Spq+DsMZ;Dp6@}G%7kt0BEFx7ZvROt4 zal+LOe+lfaS4vlDq4C@2bJU1{s&l7W9&Oi@n;wTPHjU2iWww7|EGN~}NLy3ClO)nB zW-Sq5y}9J4q-alQcZ3JPEv^PIb~F{C4*6E@ldG^vgZoH(DPnoqShq|tl7jrf^dsiYaKo4Pg8(6Bu%vf62EbM*b}Na-A>6*64a@kn(<>Lgb ze(Gk<)ND9;bcXsi>fR?Tae2QWZa63%Ju8^h*jc4Ys~Oc(h5hXeqD87zQ2Yv{5Lf(O zGeTRrKowr>x+w-fcu&I@0=e`)B=miSU~e##={ zRDO=OcM!U^x}^bGspsUP`_9e_pk3>-9sW@)8Kc{w*j7$Y@OOCAOLWe~_k*SZJGE-D z+r$x|O1d7(yR%{D>76-DIPHBC)2T=>Qyhg|okh;kQ{hs%0&?5D3Y4E@=bz_)UM(+n zxcmi>$PC2}0(R3Gk!3SBpRTE8RV!F~*-6ROq*ge!cs_77q185u*SSpCqCBrh@LJbt z(2y3v8XGk?WQ_{Q+CvLq6RH~Y@ceQ&x}?zw5x}vyN|N* zg$drXtqZj#MuArPsOlXY?he_mt3FeQfghaRb+lIYB~p|7ga=ka)iIVdID#V#RoPeL zZac?059t&cHqB>G68F(xWryocHSqcxEhfxpl~jBtSZ}zxu+~{0CUgz?6a->+EN!b< zfm}L#EW-S|3(ayYlbYurOG#-504{|PmnVDe8^Wgu%*K{ypa;>O+w&HSX5ch~>Gwc2 z@1W!&A3JX{lBTWQ;nLP1_`ay5Hh0(I#VYE_u^$@-m+S_#B~@FQl#0Mr_TBR6bLPO z%9_;<`^7pEJeHn+x9a$82OCvP1!=2b%bvvjQ44S$YhTQh-?~|}rQ@02*mS&0oDE<2 zW}yT_)`o0#alt3?yMbKR1t#!kz+7_dj#8sX@#Eb%ZFpcvNZBXvytxi{9@g!jg&Dqt zm>`7hD){%5HF=FT0QU8_8DGeJQsa6AjNhm>bxt>u#}=WBsI)eJlZ)=%wz>ce>e1|5 zw5XDyfM4mL-!!x%)m^VFnfpd!!kIUle=ckWhC2L&V#+GJwJ>BU{WgR)SUa+mkHXJa zok;Y+JE(#%-n^Hk+6ZWKjBwrhxI7XV$Q8|1MMF$=>$$l;-pDig5Ud{e!q(FjYc%s! zoWRPO`59+cc7OG?Ucxgv`D%;H!`f;Ov-^Y9c$!&I;LN*-^?}0mUd~+Ak43((>VI=L zrN1ZOnUaH!wy?nH_K*p+=u52h4B+f3c~kGf2hUj~Hu$c_>*W=XUTFPZ@t4&Far_VP z+qUXZIxHHh?&oc;IKwt2!<%&yJ|$74g7R|OE?o+<`4XMau+U8Xk3(>*Wdev~k z5EP|wWw1s{(xCKmb3FZG-V#a)C-`8r_E*g$h{Zj86Fi%sI+ zv{m^wBb=og6}sIMxkCOv`79s8B^a^#V&7B~aLP%S(uA9!yJQcxk}-pcp$b&%;&=B~ z3v~7#bv!H_sY@rTrY^`-EU#KkP8}@hbqZI<;Pw z+Uk??3E)I?A0mh&HPO8#k@waI3-Y+j)+nT+^g1SO)aQyuNBEr8evE_}8rYNu%#D@AP<>MpJ7PK%lUt;M)?tG1N=enLb!O-Wtvr9;VW_g$+MT%3L8tFbj-b z0nM0k&{0qjR;6q7!PY4)V0)YuSIogP(4{X)U&eU#Nltk)*bx`|R!+c@Hdrsy2_sMD zdV%`tN4&(1$pPt`E3nIr%B(s#Vsi(A{$53=H8OlaBLO=1H$7HZ6lwi3=4av+GX=3h z*vk|j_3Zq+Lw>46pzy|+^6UKf?BzP%^DS{$#{PYt4dw{ zAkD#Q)wUH;kTRkD+e(@76z`mM1i@m9JmIh%9?1%)?#RM~gKacGQ%5;TI1swh4QV^B ziqPK}TYFuoQZ-c#imd+X4|&;@@XeO9wm0NDim{$yd8~`;%&aNuDG^M9ecGJ0YahgO z7Ms#EG+Zz3@E&KGo+q8Ezu~SpLc$Y@fW1)*%oa%Q@HKf)Zpr9MkEyDwzrHOBv80mq2GU;<(N^aqkxitPYMN_Nk;8 zEFdv_$U@XV=oCAeD)D2gMY;;jBt9ZusH24nGdH5X5Khv(0Y%^-zZsMd3=20nwVk+S z@Hi>~=FdD}L+`Gmnm2Jz&s!s$0To>|E5EZ?gi}@@?4{0Bre2YrSy_`hwjg~SIC+w^ z1Gk)P6F2V_a>y4dFxy<5g|0k zGjlYD0Fkmf@!n--RV7>c4_O2mzK6)9<&wLTAm7GT6SRp1wQmfG2R zBDqRK64_?BVFG|w|Vyiz4J{h(b%x^zB6^;Rf|-OrS_i=Db<4XdmB> z6r+j@p!OBOS)O*To#gqj6!wd)1+0TID4*RA!YZdq3IplsS8MLt^I~!R0`Bo+^2v&1 zRX5~U7U*0aK{n)XUWe9a8Vxj~y|>{2(Zqg~4kS{RV{hgRz4HF*$wsoOH2M4)eB7IL zM_cPifw9zynE-N5cDg}f0h9zQL_p7M*7joFBYnP#XVKPk%$EqAu{1bn!CQ^^G7KNy zK0uaEFOl9c2rh0|D#IkfZn#2=TwCYpi|{tgRrICiU?Kur!WH)#&6bP-ZqmTUtr_}T zg59t#Eh@5SB!rD*T5)55^? zF3CZT|5iZwJh9hs$!)k{b1@_t&4EnyupCj4-BJP{2hJK|V4Q2=gLr5pjCSp8*OdBZ znlbgJms?^zYf#S^UMY%xRs1vSF1i`v*o5J(mq$!yUgYFEDh#dukB=XEVprm zrSFSPKAdamGN{&G01xKB?AKVyKtzo_+6jchW+H#qXup8H2@x=_YQ%TcHSnT_(EgGH zDD6!#TQy`rZeaKauh{*^w=skhd?3xuJxaJ9GAvE2)?#lK>-6put}XmstF}Z!(WyUWDa$_^WN#tkpv6}7~^U?00>-u#j7ikgUfmF zqv~n_#IP$;q@SZI=pqI&0sdHS%xCJF2?_>98+d?njN*JMCL5>1Et~_ z;sZs%m(Z`C-A^h3;GD_1!WD)`tSz>7ZM+A}+n)5vH}>z6xL5_TzRx^vE1t(YD< z5FoyU@MsFdCnaFE#?iCj^QM01v%4fEv*Oxhxm1jv)&}FqN`D@m4);>mM0xit4+mPU zpNKk-D*@!gcmo;+OdTK^66-RF+~F_ozgR9`=)oe9sOp$wWh62#LaDz zz1(Tl6zR$i4Gh{pql+w^$leS3F)A3pM3Cmw>45xO=_;0|!N6GFpmDU|106y<6LycQ z0S%iEVN9&6Z6BL3zwozH>BNp9QuHzzzu(@A&Q5fYlsGrKZ)KI!XHC%ni1%RdjsAS3 ztR9-av9BoZ`pOe)oCkMC#2dw*0Is*%y#V(eG(h+aC-+RcWd-0H=!1e6!1faQ`z119 zkRcC=G9K%v1;@N3h^v>5dN!^&c&3ce`+S>b}@!O_ljJ$qZMNd7{77Z@@^+J}Siiy{p zYG2%M#Jzw>@hi8{@<-RPVZIkGAZ|Nn<2vFgAKn@R+lpd%?=3{2a;i0hA62Ys@6s2{ z5{6?}>)}lx1FnsgiA99AW5+MxYXEDaYv|dJcj^&@!^tj%kMnx}V-q}4J`5JDGr4HmBf_QU8 zN4<{vgWK29R)=C=$94KhdQH{}miCgcH}-i&KvZh$l&^+=OE9-1j9&_I8bj8B6-~~Y zl?~=?CGMq6Ry%@FQNu%1>35k~3Boe3fNu88jDL?H^4>4?{KQdzKcq^!U?|C4%lb+* zk(XaJpAJ-|MTIZ&f1S`)ZF%j*Uo8q;TVJ8BBvz7@1q&@V{AOK2%MSv0BOO)qQZJuo zkz>6DZ#*NpJ4G?~2P4E9^X-8=R-0mvgJnfkr3ozwxszi)YiQ&%6djvQpOiNn^Ou5c zbTqb-PusZ&S6V|tO_t57S_Dm{)@EBvy_iPtuM@>3O8#ZTcR8h;i*(KLa71b?<&(J6 zl~Q;6?#)J0)I0e?^qs7RpiVq1XC+7q_aNci>!`e@ddPsoxR>B zw%=IcnHc3N5qcI+!b9iAE5^WSw+^ltxVq`7f3K>pbXZly{;X_DZgA{4aGOF3;14~7 z^!%olzq2GACiis|dE{H@J^4-j*30z6nZO9eFm-(H5F#Gxe>H-`SRolaoBHqEmPTD6Z4sgdOj9F_@L7IdM}s5u|&i?5N3=Cz{gvBt8cWN zc1(;tA&^~8f8lPJ;FhhJQhbI0KN^P<_D=TBc`RXRnV?Veqf6;H>nGAe4#!4S~-FeG^4xqAohXgMjREKSxx zt1yk`-Z9C)d4Kr}a?aW?@Wh`={SYgcon9=sQ=TS61J1{;D{G&aWWDAorrKQ%aFA&p6Oiv0z;{JTC76Tcgyu=C=QMZep8>*$wu z|K%@dJjO~)lWpo`;(@I0&kFT%3P^f<$k|h&Z%h2gpWm?l_WZ||&%fKEAmP^~Ru_48 zvAg8vA*=Qnwj*yK3iFv!cmeG%!EIG6D8RxiOaLDhI`pm9n8OM?;{}WCg z-f86ZyWRr6&*L5Ge3oXB&Rh4dE7}p5!uEs&p(73$rvM9MJH~o$l)ih% zest$1iAj=~jrjUmX~U0{wJZl(#H9N3h~kK}+Nz>gj5u4J+yDp#V=yw# zzA;t_;?abS?%XXk8s)+T{&Y)m`@r1kEZ!NH(ThWvR8JO|!!)$$Esu@0iE)esZ#4_K zbqD+vWWjDs{w^t>;2&;EFl(I%?(UbF5y0j(*~yv|du=|xXI%{wv+RjPB9*ftP6zw< z&OwU|nP19ae6W?LU!Br4gYRXP`nFI<^<NWm$KwCzoWVFSvCTU1M%Av#XlD4WjX* z0Dr|y>!}PNMQTbFbeJGql&aECGJf3k3WafTalLZh?ke<~kM|p6BNv_B_L!XY^_9W% z3d8L|_r0hmva2ieVKlZ>ecwYl`#;$zHZAW`W4z#zj;xw=RQVu!d%(Gg$7u|(UThTG zqP3TvZ-k9O;#*4Y`-Nh|M5?GQkO!{b_$*3Zkw1ZS6l7Qh*8vN759CLPOE4FrE*Bvm zcK+P{;p@3IgM)GR=!{)J$ohj2j=Zg+EGf6o-_fj?m4E*`%|$@(&ikmiM0LIlpIe?R zif2_kIyuqnEY1jru*ww(?>5q;{B7V(H7XX)Ea@SJ!hs~k)u30TOY-`0Gy?zJ&h(i+QwM$A3cTX)bk3lJpioV{h;{^F)QChWb5v> zdwydh$obBQ_{GNE!eqv2K&ksM4~2Z|0oi>smORArCZFn;^`NUg^j`RW!>RrRmlidHAmeIbIdsv8!Nb zj;3SUT0>WImx`RcQVrM-@M31v4t>`14iPOCm@ijUgp=u&zgy04J7HM%QQV?T>o6D=v?=myQ7mW zYXa)CU9K%jb`IaIDFw#(`QYE1H~sco)F;NyR#3GGnFKuB@*-fVk^0v2CcmL_boN6^ zMJbO=Hc#Jd6 ziYJB)NYV=Jj)=K1_>*_!lQE&r)D!uvUtj$TWsCiRvK8jdKGRJrT7m+4tLh?rVv0xZ zEUEGsYnwL&M)dgR42VNNU>C^N{4XF`|Le`2DfHgCq8GoSr;m8l!reyN;}@-N4q;xG zg@-#$Jjt|u(Dy;s3$MkC?HQBn8Qz*KWQNgy3BD5(dX4W&ZQHtkh!|#c^YdzNet)j&Ei$uLl4*&ih=MvG z;Z_53>9x2^HId(1wqR)}w;-nujga148b69h{U_ZeyqI}Mg(IGE(Jr#!YS*?rDQz0O z{a%b8jpLOH^*gTWbk||D&40a9$w4z))#>)}k55zbT(mFy1>7aRYTZF0=SKT0H$Ca_ z>{sivEuj-*`?Qq>tBlGuM2~E(YlaLI>`F9Av*H!k@aaDL;4>A-nVAu1XBnuTP93_e;q851%bacBHQ$>Zb?qb*bj1bJ8^HeyR{b}W zx}ftjQN1Z{t8y`4RC0DJ8@I@>vEuvUk|Ih$t#PKjNkSdJ2{xRIu>qXdo!;ad=WC4* zIo?LflZvM|cU}1+S$NC~5Lp=ap^#7rTPNdym2#?L-^Go{pPy}Em>E&>o141I6ODDb zqNeAuD0e}-)1Az^Kxl1!_+(&x)qK@$`7r8^T39F;@j$kv_~=w*?7@K?hwPi&84bQQ z)yvw*0ft0-e^s}#>$BF6A8PNkZyudNLiuyl@147Pg3P>;1Tdh*MuF0HJ_TI%5M zaL{3~)--#lK%2j^h@TJJnPI19WowilD(Eg#su~@kBG|7*Gp)&H`OW%8)tJanE%{VV z058E6-%MMnL)E`-QjeeJ;05kqm*K$E7+7D5ju^e{IL2YR}exuZZR z0{5<@#r>|u3gc<=T>bL^f7Clx>$;VJL+Dn7rbpS3v$_ha567QHP&cK55O*^HprY|h zKA$kvq!?dntjFL!`JO=(AH6VHCgwbap2fvitD!$L5})aao+>*gi|+`8eM~Xhp33PR zsE+S@+-f~669k+(r_f(6>>fwXqD-uIcmR-LW`PR;wFvJ7hEx=Bb&lD)kb=h=X6N#B z%H!vi0P)ajKt$~>7 z{T-oKXj-8UpW6Ji>xf8WoBzUKzZ2lX)@6dftH|5Onsps%e_%F%Di_C05{7@e*$aL37Y-RnHKf)DuB-h~3n(x?OZu)E zGNm&qz_l4~Pd_*NCEDcxT?O&f$IbLGsdxs5j2Ys1^&UV+8k@x4FfZMT?YWc$O2Q**qHu+nLM}^T#xnDcDKV-ic{c zaogIUC{WxSjS8J3U~uEZ#CYyLnlTbt>u%!ucg{5|sePp;NPye)UFpcug_e8@-xN3A zamgyUbzGi!_YAygUBy2SvZf!}4*NP)Ix(_y?to1R=})dXKP%_@!c?+-D~+x(yac*v zL?FO#@O*s;EkpIGF84523(nzQ+Hv2KOY^n$2#n>tqH~qCZ4U(PoJvF(Z8r`53-!?i z(*CD*Unz-Myj7lnWze@5bE}l(hQJMz^YinXs5nxX_n9Y@cn`gWTCUYz92l5 z8Yhg1p+5cGCL`?WM?5qzM?=Vco=6;vcQ(x1Bas6YsRTNW7b#a3v|U9LwxIi94RS&e z%a@b03^Db79)w>-#INUADV zbG#CFz4q3m3W#4{yD*BiQmU--Qk{AhKzH;RbmXA4Nu?XJ)EbZjjbp- z~HdW3$of;sZt6_P1f07{GP?(Ee{M>}mzQpkB zC{%ptIA?J9F`X8ZHh(#8u4vNzI^%gd)h@APw|(@~Rrh6J%X>O~$sy)! z%WnbH(xd^0ruJ$2GFgC>Pn9{pwbB?i-YNqgXZjpTMu}zW~34lyEJqsYz-jD*mpYupWQN zGgQ3IeF9?N(BP%IF@Ch~eQ6@1sk1jMeY}JARHN+<*au-W)y#cQ6AXClwNlHdtv)FW z5;ZUTB~qLXOn_XeahYh@{^~5!MwC+vB90(VXh(vARE(*?9QZnKT8?M0vwL%MeG{j$2#O@D0J)0MOxyG5NUe8*Lu=E(;75hDU!~TuZA|H(gl}9PqNo4Q=wx!q?asso&IsOE zh1vPQ(y+enL~u=}C>`ZX?;r|9atprNGg(q!^%EdQ;S zLG*5ORgZm2T}_Ag8aS-YD(Itpzn_Av8!Ht9JR(alD*TsxF%S@VD+(AMs0 zE|1YD@m4;;?tk4b`;ODIPrIRdH({i900}^#^>#sb(dpbeH*vxDQH^CSxjfJBEusY>3OYR>+g(O7gL$s;+$-Y0fD#0^;n5Bm%sHGwZ^WbeC659 zFDVNsU0G6jGSR-cjCuaP62+dW!B-g1Abv~K8Dcour#{t!)B?6^zi;|48W+>Gd$7;< z4svbey^bqgc{I-E=!n^+O38pO3&N7?inb+>#y4!fPC&>QP*+W|6mlgO&^PtbJ^B9y z#~E5E`o1|DZEqT(E-}>M^AVLzFC?&+op0|*CI?}(q}TO@VOCb{E6E!dm3VCU(o$)lR_s#b#BfJU2Z1F|B4OHQY9YUrz2ZidQCym`@E3 zHDA#Gpp|*bfU>kIt%PBHsp}s&Z(gY773=QbWI*~3vdfZu)+LRjA>v|ji3g*%hP37O z?D@(M+4mpc3;EA)ko@(}|Ky&{Ut0Q0OS`vx|1USO{_>E&JmfDA`ETKx{|6!C_kD`b zZr1|i@81jfZ(O7Ne;~; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; + +export const WorstCaseAlbanian: Story = { + globals: { + language: "sq", + }, + args: { + emoji: ["πŸŽ…", "πŸŽ…", "πŸŽ…", "πŸŽ…", "πŸŽ…", "πŸŽ…", "πŸŽ…"], + }, +}; + +export const WorstCaseGerman: Story = { + globals: { + language: "de", + }, + args: { + emoji: ["πŸ”§", "πŸ”§", "πŸ”§", "πŸ”§", "πŸ”§", "πŸ”§", "πŸ”§"], + }, +}; diff --git a/packages/shared-components/src/crypto/SasEmoji/SasEmoji.test.tsx b/packages/shared-components/src/crypto/SasEmoji/SasEmoji.test.tsx new file mode 100644 index 0000000000..c9946d52a0 --- /dev/null +++ b/packages/shared-components/src/crypto/SasEmoji/SasEmoji.test.tsx @@ -0,0 +1,19 @@ +/* +Copyright 2026 Element Creations Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE files in the repository root for full details. +*/ + +import React from "react"; +import { describe, it, expect } from "vitest"; +import { render } from "@test-utils"; + +import { SasEmoji } from "./SasEmoji"; + +describe("", () => { + it("should match snapshot", () => { + const { asFragment } = render(); + expect(asFragment()).toMatchSnapshot(); + }); +}); diff --git a/packages/shared-components/src/crypto/SasEmoji/SasEmoji.tsx b/packages/shared-components/src/crypto/SasEmoji/SasEmoji.tsx new file mode 100644 index 0000000000..6701cb37c9 --- /dev/null +++ b/packages/shared-components/src/crypto/SasEmoji/SasEmoji.tsx @@ -0,0 +1,43 @@ +/* + * Copyright 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +import React, { type JSX } from "react"; +import classNames from "classnames"; + +import { type SasEmoji, tEmoji } from "./SasEmojiTranslate.ts"; +import styles from "./SasEmoji.module.css"; +import { useI18n } from "../../utils/i18nContext.ts"; + +export type Props = { + /** + * The emoji to render + */ + emoji: [SasEmoji, SasEmoji, SasEmoji, SasEmoji, SasEmoji, SasEmoji, SasEmoji]; + /** + * Optional className to apply to the container + */ + className?: string; +}; + +/** + * Renders the 7 emoji used for SAS verification. + * The component is responsive so can be rendered in any context, dialog, side panel. + */ +export function SasEmoji({ emoji, className }: Props): JSX.Element { + const { language } = useI18n(); + + const emojiBlocks = emoji.map((emoji, i) => ( +
+
+ {emoji} +
+
{tEmoji(emoji, language)}
+
+ )); + + return
{emojiBlocks}
; +} diff --git a/packages/shared-components/src/crypto/SasEmoji/SasEmojiTranslate.test.ts b/packages/shared-components/src/crypto/SasEmoji/SasEmojiTranslate.test.ts new file mode 100644 index 0000000000..8251e52ea4 --- /dev/null +++ b/packages/shared-components/src/crypto/SasEmoji/SasEmojiTranslate.test.ts @@ -0,0 +1,26 @@ +/* +Copyright 2026 Element Creations Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE files in the repository root for full details. +*/ + +import { describe, it, expect } from "vitest"; + +import { tEmoji, type SasEmoji } from "./SasEmojiTranslate.ts"; + +describe("tEmoji", () => { + it.each([ + ["🐢", "en-GB", "Dog"], + ["🐢", "en", "Dog"], + ["🐢", "de-DE", "Hund"], + ["🐢", "pt", "Cachorro"], + ["πŸ”§", "de-DE", "SchraubenschlΓΌssel"], + ["πŸŽ…", "sq", "Babagjyshi i Vitit tΓ« Ri"], + ] as [emoji: SasEmoji, locale: string, expectation: string][])( + "should handle locale %s", + (emoji, locale, expectation) => { + expect(tEmoji(emoji, locale)).toEqual(expectation); + }, + ); +}); diff --git a/packages/shared-components/src/crypto/SasEmoji/SasEmojiTranslate.ts b/packages/shared-components/src/crypto/SasEmoji/SasEmojiTranslate.ts new file mode 100644 index 0000000000..da977a98e0 --- /dev/null +++ b/packages/shared-components/src/crypto/SasEmoji/SasEmojiTranslate.ts @@ -0,0 +1,122 @@ +/* + * Copyright 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +import SasEmojiJson from "@matrix-org/spec/sas-emoji.json"; +import { getNormalizedLanguageKeys } from "matrix-web-i18n"; + +// Type as specified in https://spec.matrix.org/v1.17/client-server-api/#sas-method-emoji +export type SasEmoji = + | "🐢" + | "🐱" + | "🦁" + | "🐎" + | "πŸ¦„" + | "🐷" + | "🐘" + | "🐰" + | "🐼" + | "πŸ“" + | "🐧" + | "🐒" + | "🐟" + | "πŸ™" + | "πŸ¦‹" + | "🌷" + | "🌳" + | "🌡" + | "πŸ„" + | "🌏" + | "πŸŒ™" + | "☁" + | "πŸ”₯" + | "🍌" + | "🍎" + | "πŸ“" + | "🌽" + | "πŸ•" + | "πŸŽ‚" + | "❀" + | "πŸ˜€" + | "πŸ€–" + | "🎩" + | "πŸ‘“" + | "πŸ”§" + | "πŸŽ…" + | "πŸ‘" + | "β˜‚" + | "βŒ›" + | "⏰" + | "🎁" + | "πŸ’‘" + | "πŸ“•" + | "✏" + | "πŸ“Ž" + | "βœ‚" + | "πŸ”’" + | "πŸ”‘" + | "πŸ”¨" + | "☎" + | "🏁" + | "πŸš‚" + | "🚲" + | "✈" + | "πŸš€" + | "πŸ†" + | "⚽" + | "🎸" + | "🎺" + | "πŸ””" + | "βš“" + | "🎧" + | "πŸ“" + | "πŸ“Œ"; + +const SasEmojiMap = new Map< + SasEmoji, + [ + description: string, + translations: { + [normalizedLanguageKey: string]: string; + }, + ] +>( + SasEmojiJson.map(({ emoji, description, translated_descriptions: translations }) => [ + emoji as SasEmoji, + [ + description, + // Normalize the translation keys + Object.keys(translations).reduce>((o, k) => { + for (const key of getNormalizedLanguageKeys(k)) { + o[key] = translations[k as keyof typeof translations]!; + } + return o; + }, {}), + ], + ]), +); + +/** + * Translate given SAS emoji into the target locale + * @param emoji - the SAS emoji to translate + * @param locale - the BCP 47 locale to translate to, will fall back to English as the base locale for Matrix SAS Emoji. + */ +export function tEmoji(emoji: SasEmoji, locale: string): string { + const mapping = SasEmojiMap.get(emoji); + if (!mapping) { + throw new Error(`Emoji mapping not found for emoji ${emoji}`); + } + + const [description, translations] = mapping; + + for (const key of getNormalizedLanguageKeys(locale)) { + if (translations[key]) { + return translations[key]; + } + } + + return description; +} diff --git a/packages/shared-components/src/crypto/SasEmoji/__snapshots__/SasEmoji.test.tsx.snap b/packages/shared-components/src/crypto/SasEmoji/__snapshots__/SasEmoji.test.tsx.snap new file mode 100644 index 0000000000..27f53cb870 --- /dev/null +++ b/packages/shared-components/src/crypto/SasEmoji/__snapshots__/SasEmoji.test.tsx.snap @@ -0,0 +1,115 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[` > should match snapshot 1`] = ` + +
+
+ +
+ Butterfly +
+
+
+ +
+ Mushroom +
+
+
+ +
+ Ball +
+
+
+ +
+ Globe +
+
+
+ +
+ Unicorn +
+
+
+ +
+ Rocket +
+
+
+ +
+ Spanner +
+
+
+
+`; diff --git a/packages/shared-components/src/crypto/SasEmoji/index.ts b/packages/shared-components/src/crypto/SasEmoji/index.ts new file mode 100644 index 0000000000..5c6dc18fb7 --- /dev/null +++ b/packages/shared-components/src/crypto/SasEmoji/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +export { SasEmoji } from "./SasEmoji.tsx"; diff --git a/packages/shared-components/src/index.ts b/packages/shared-components/src/index.ts index 245c553e92..b33af6c9ff 100644 --- a/packages/shared-components/src/index.ts +++ b/packages/shared-components/src/index.ts @@ -12,6 +12,7 @@ export * from "./audio/PlayPauseButton"; export * from "./audio/SeekBar"; export * from "./avatar/AvatarWithDetails"; export * from "./composer/Banner"; +export * from "./crypto/SasEmoji"; export * from "./event-tiles/TextualEventView"; export * from "./message-body/MediaBody"; export * from "./pill-input/Pill"; diff --git a/packages/shared-components/yarn.lock b/packages/shared-components/yarn.lock index 2341936db5..62e161d50d 100644 --- a/packages/shared-components/yarn.lock +++ b/packages/shared-components/yarn.lock @@ -667,6 +667,11 @@ dependencies: "@babel/runtime" "^7.17.9" +"@matrix-org/spec@^1.7.0": + version "1.16.0" + resolved "https://registry.yarnpkg.com/@matrix-org/spec/-/spec-1.16.0.tgz#c88f4ed521e4c0bd3a4c108bcaf13f25173a0fdc" + integrity sha512-xUKHkwGXXISMCfTrx6JW6uGEK5O8IeZVOjBm7FX1h/ihpK6l50nlSIMRYdtz4V6q3pvOVBOCft4hPYTJVeTZDA== + "@mdx-js/react@^3.0.0": version "3.1.1" resolved "https://registry.yarnpkg.com/@mdx-js/react/-/react-3.1.1.tgz#24bda7fffceb2fe256f954482123cda1be5f5fef" diff --git a/playwright/e2e/crypto/utils.ts b/playwright/e2e/crypto/utils.ts index 8b677ed4cb..4aab27f51a 100644 --- a/playwright/e2e/crypto/utils.ts +++ b/playwright/e2e/crypto/utils.ts @@ -290,7 +290,7 @@ export async function doTwoWaySasVerification(page: Page, verifier: JSHandle div"); await expect(emojiBlocks).toHaveCount(emojis.length); // then, check that our application shows an emoji panel with the same emojis. diff --git a/res/css/views/verification/_VerificationShowSas.pcss b/res/css/views/verification/_VerificationShowSas.pcss index 9e4d1f138b..57fae76788 100644 --- a/res/css/views/verification/_VerificationShowSas.pcss +++ b/res/css/views/verification/_VerificationShowSas.pcss @@ -20,40 +20,9 @@ Please see LICENSE files in the repository root for full details. } .mx_VerificationShowSas_emojiSas { - text-align: center; - display: flex; - flex-wrap: wrap; - justify-content: center; margin: 25px 0; } -.mx_VerificationShowSas_emojiSas_block { - display: inline-block; - margin-bottom: 16px; - position: relative; - width: 52px; -} - -.mx_Dialog .mx_VerificationShowSas_emojiSas_block, -.mx_AuthPage_modal .mx_VerificationShowSas_emojiSas_block { - width: 60px; -} - -.mx_VerificationShowSas_emojiSas_emoji { - font-size: $font-32px; - /* Use the Twemoji font for consistency with other clients */ - font-family: Twemoji, var(--cpd-font-family-sans); -} - -.mx_VerificationShowSas_emojiSas_label { - font-size: $font-12px; - word-break: break-word; -} - -.mx_VerificationShowSas_emojiSas_break { - flex-basis: 100%; -} - .mx_VerificationShowSas_buttonRow { text-align: center; display: flex; diff --git a/src/components/views/verification/VerificationShowSas.tsx b/src/components/views/verification/VerificationShowSas.tsx index 0f6272a885..84490e556b 100644 --- a/src/components/views/verification/VerificationShowSas.tsx +++ b/src/components/views/verification/VerificationShowSas.tsx @@ -6,12 +6,12 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import React from "react"; +import React, { type ComponentProps } from "react"; import { type Device } from "matrix-js-sdk/src/matrix"; -import { type GeneratedSas, type EmojiMapping } from "matrix-js-sdk/src/crypto-api"; -import SasEmoji from "@matrix-org/spec/sas-emoji.json"; +import { type GeneratedSas } from "matrix-js-sdk/src/crypto-api"; +import { SasEmoji } from "@element-hq/web-shared-components"; -import { _t, getNormalizedLanguageKeys, getUserLanguage } from "../../../languageHandler"; +import { _t } from "../../../languageHandler"; import { PendingActionSpinner } from "../right_panel/EncryptionInfo"; import AccessibleButton from "../elements/AccessibleButton"; @@ -34,52 +34,6 @@ interface IState { cancelling?: boolean; } -const SasEmojiMap = new Map< - string, // lowercase - { - description: string; - translations: { - [normalizedLanguageKey: string]: string; - }; - } ->( - SasEmoji.map(({ description, translated_descriptions: translations }) => [ - description.toLowerCase(), - { - description, - // Normalize the translation keys - translations: Object.keys(translations).reduce>((o, k) => { - for (const key of getNormalizedLanguageKeys(k)) { - o[key] = translations[k as keyof typeof translations]!; - } - return o; - }, {}), - }, - ]), -); - -/** - * Translate given EmojiMapping into the target locale - * @param mapping - the given EmojiMapping to translate - * @param locale - the BCP 47 locale to translate to, will fall back to English as the base locale for Matrix SAS Emoji. - */ -export function tEmoji(mapping: EmojiMapping, locale: string): string { - const name = mapping[1]; - const emoji = SasEmojiMap.get(name.toLowerCase()); - if (!emoji) { - console.warn("Emoji not found for translation", name); - return name; - } - - for (const key of getNormalizedLanguageKeys(locale)) { - if (!!emoji.translations[key]) { - return emoji.translations[key]; - } - } - - return emoji.description; -} - export default class VerificationShowSas extends React.Component { public constructor(props: IProps) { super(props); @@ -100,25 +54,14 @@ export default class VerificationShowSas extends React.Component }; public render(): React.ReactNode { - const locale = getUserLanguage(); - let sasDisplay; let sasCaption; if (this.props.sas.emoji) { - const emojiBlocks = this.props.sas.emoji.map((emoji, i) => ( -
-
- {emoji[0]} -
-
{tEmoji(emoji, locale)}
-
- )); sasDisplay = ( -
- {emojiBlocks.slice(0, 4)} -
- {emojiBlocks.slice(4)} -
+ e[0]) as ComponentProps["emoji"]} + /> ); sasCaption = this.props.isSelf ? _t("encryption|verification|confirm_the_emojis") diff --git a/test/unit-tests/components/views/VerificationShowSas-test.tsx b/test/unit-tests/components/views/VerificationShowSas-test.tsx deleted file mode 100644 index f9312e906e..0000000000 --- a/test/unit-tests/components/views/VerificationShowSas-test.tsx +++ /dev/null @@ -1,23 +0,0 @@ -/* -Copyright 2024 New Vector Ltd. -Copyright 2023 The Matrix.org Foundation C.I.C. - -SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial -Please see LICENSE files in the repository root for full details. -*/ - -import { type EmojiMapping } from "matrix-js-sdk/src/crypto-api"; - -import { tEmoji } from "../../../../src/components/views/verification/VerificationShowSas"; - -describe("tEmoji", () => { - it.each([ - ["en-GB", "Dog"], - ["en", "Dog"], - ["de-DE", "Hund"], - ["pt", "Cachorro"], - ])("should handle locale %s", (locale, expectation) => { - const emoji: EmojiMapping = ["🐢", "Dog"]; - expect(tEmoji(emoji, locale)).toEqual(expectation); - }); -}); diff --git a/test/unit-tests/components/views/dialogs/IncomingSasDialog-test.tsx b/test/unit-tests/components/views/dialogs/IncomingSasDialog-test.tsx index cf9e103ee6..2a7ed61f13 100644 --- a/test/unit-tests/components/views/dialogs/IncomingSasDialog-test.tsx +++ b/test/unit-tests/components/views/dialogs/IncomingSasDialog-test.tsx @@ -34,7 +34,7 @@ describe("IncomingSasDialog", () => { it("should show some emojis once keys are exchanged", () => { const mockVerifier = makeMockVerifier(); - const { container } = renderComponent(mockVerifier); + const { getAllByText } = renderComponent(mockVerifier); // fire the ShowSas event const sasEvent = makeMockSasCallbacks(); @@ -42,11 +42,8 @@ describe("IncomingSasDialog", () => { mockVerifier.emit(VerifierEvent.ShowSas, sasEvent); }); - const emojis = container.getElementsByClassName("mx_VerificationShowSas_emojiSas_block"); - expect(emojis.length).toEqual(7); - for (const emoji of emojis) { - expect(emoji).toHaveTextContent("πŸ¦„Unicorn"); - } + expect(getAllByText("πŸ¦„")).toHaveLength(7); + expect(getAllByText("Unicorn")).toHaveLength(7); }); }); diff --git a/test/unit-tests/components/views/dialogs/__snapshots__/VerificationRequestDialog-test.tsx.snap b/test/unit-tests/components/views/dialogs/__snapshots__/VerificationRequestDialog-test.tsx.snap index 79737988d0..79d21cf19f 100644 --- a/test/unit-tests/components/views/dialogs/__snapshots__/VerificationRequestDialog-test.tsx.snap +++ b/test/unit-tests/components/views/dialogs/__snapshots__/VerificationRequestDialog-test.tsx.snap @@ -456,41 +456,38 @@ exports[`VerificationRequestDialog When other device accepted emoji, displays em Confirm that the emojis below match those shown on your other device.

Dog
Cat
-

", () => { }); it("should show some emojis once keys are exchanged", () => { - const { container } = renderComponent({ + const { getAllByText } = renderComponent({ request: mockRequest, phase: Phase.Started, }); @@ -117,11 +117,8 @@ describe("", () => { mockVerifier.emit(VerifierEvent.ShowSas, sasEvent); }); - const emojis = container.getElementsByClassName("mx_VerificationShowSas_emojiSas_block"); - expect(emojis.length).toEqual(7); - for (const emoji of emojis) { - expect(emoji).toHaveTextContent("πŸ¦„Unicorn"); - } + expect(getAllByText("πŸ¦„")).toHaveLength(7); + expect(getAllByText("Unicorn")).toHaveLength(7); }); describe("'Verify own device' flow", () => {