11import "@testing-library/jest-dom" ;
2- import { render , screen } from "@testing-library/react" ;
2+ import { render , screen , within } from "@testing-library/react" ;
33import userEvent from "@testing-library/user-event" ;
44import type { Editor } from "@tiptap/react" ;
5+ import { type ReactNode , useLayoutEffect } from "react" ;
56import { describe , expect , it , vi } from "vitest" ;
7+ import { I18nProvider , useI18n } from "@/contexts/I18nContext" ;
68import { NotesToolbar , type NotesToolbarProps } from "./NotesToolbar" ;
79
810vi . mock ( "@/components/ui/tooltip" , ( ) => ( {
911 Tooltip : ( { children } : { children : React . ReactNode } ) => children ,
1012} ) ) ;
1113
12- vi . mock ( "@/contexts/I18nContext" , ( ) => ( {
13- useScopedT : ( ) => ( key : string ) => {
14- const labels : Record < string , string > = {
15- "tooltips.notesToolbar.play" : "Play" ,
16- "tooltips.notesToolbar.pause" : "Pause" ,
17- "tooltips.notesToolbar.speed" : "Scroll speed" ,
18- "tooltips.notesToolbar.decreaseSpeed" : "Decrease scroll speed" ,
19- "tooltips.notesToolbar.increaseSpeed" : "Increase scroll speed" ,
20- "tooltips.notesToolbar.fontSize" : "Font size" ,
21- "tooltips.notesToolbar.decreaseFontSize" : "Decrease font size" ,
22- "tooltips.notesToolbar.increaseFontSize" : "Increase font size" ,
23- "tooltips.notesToolbar.mirror" : "Mirror" ,
24- } ;
25- return labels [ key ] ?? key ;
26- } ,
27- } ) ) ;
28-
2914function createEditor ( ) : Editor {
3015 const chain : Record < string , ReturnType < typeof vi . fn > > = { } ;
3116 for ( const command of [
@@ -68,28 +53,55 @@ function createProps(overrides: Partial<NotesToolbarProps> = {}): NotesToolbarPr
6853 } ;
6954}
7055
56+ function ActiveLocale ( { children, locale } : { children : ReactNode ; locale : string } ) {
57+ const { setLocale } = useI18n ( ) ;
58+
59+ useLayoutEffect ( ( ) => {
60+ setLocale ( locale ) ;
61+ } , [ locale , setLocale ] ) ;
62+
63+ return children ;
64+ }
65+
66+ function renderToolbar ( props : NotesToolbarProps , locale = "en" ) {
67+ return render (
68+ < I18nProvider >
69+ < ActiveLocale locale = { locale } >
70+ < NotesToolbar { ...props } />
71+ </ ActiveLocale >
72+ </ I18nProvider > ,
73+ ) ;
74+ }
75+
7176describe ( "NotesToolbar teleprompter controls" , ( ) => {
7277 it ( "exposes values and dispatches every manual control" , async ( ) => {
7378 const user = userEvent . setup ( ) ;
7479 const props = createProps ( ) ;
75- render ( < NotesToolbar { ... props } /> ) ;
80+ renderToolbar ( props ) ;
7681
77- expect ( screen . getByRole ( "status" , { name : "Scroll speed" } ) ) . toHaveTextContent ( "40 px/s" ) ;
78- expect ( screen . getByRole ( "status" , { name : "Font size" } ) ) . toHaveTextContent ( "16 px" ) ;
79- expect ( screen . getByRole ( "button" , { name : "Mirror" } ) ) . toHaveAttribute ( "aria-pressed" , "false" ) ;
82+ const speed = within ( screen . getByRole ( "group" , { name : "Scroll speed" } ) ) . getByRole ( "status" ) ;
83+ const fontSize = within ( screen . getByRole ( "group" , { name : "Font size" } ) ) . getByRole ( "status" ) ;
84+ expect ( speed ) . not . toHaveAccessibleName ( ) ;
85+ expect ( speed ) . toHaveTextContent ( "40 px/s" ) ;
86+ expect ( fontSize ) . not . toHaveAccessibleName ( ) ;
87+ expect ( fontSize ) . toHaveTextContent ( "16 px" ) ;
88+ expect ( screen . getByRole ( "button" , { name : "Mirror horizontally" } ) ) . toHaveAttribute (
89+ "aria-pressed" ,
90+ "false" ,
91+ ) ;
8092 expect ( screen . getByRole ( "button" , { name : "Decrease scroll speed" } ) ) . not . toHaveAttribute (
8193 "aria-pressed" ,
8294 ) ;
8395 expect ( screen . getByRole ( "button" , { name : "Increase font size" } ) ) . not . toHaveAttribute (
8496 "aria-pressed" ,
8597 ) ;
8698
87- await user . click ( screen . getByRole ( "button" , { name : "Play " } ) ) ;
99+ await user . click ( screen . getByRole ( "button" , { name : "Start auto-scroll " } ) ) ;
88100 await user . click ( screen . getByRole ( "button" , { name : "Decrease scroll speed" } ) ) ;
89101 await user . click ( screen . getByRole ( "button" , { name : "Increase scroll speed" } ) ) ;
90102 await user . click ( screen . getByRole ( "button" , { name : "Decrease font size" } ) ) ;
91103 await user . click ( screen . getByRole ( "button" , { name : "Increase font size" } ) ) ;
92- await user . click ( screen . getByRole ( "button" , { name : "Mirror" } ) ) ;
104+ await user . click ( screen . getByRole ( "button" , { name : "Mirror horizontally " } ) ) ;
93105
94106 expect ( props . onTogglePlaying ) . toHaveBeenCalledOnce ( ) ;
95107 expect ( props . onDecreaseSpeed ) . toHaveBeenCalledOnce ( ) ;
@@ -100,18 +112,33 @@ describe("NotesToolbar teleprompter controls", () => {
100112 } ) ;
101113
102114 it ( "disables controls at their bounds" , ( ) => {
103- const { rerender } = render ( < NotesToolbar { ... createProps ( { speed : 10 , fontSize : 14 } ) } /> ) ;
115+ const { rerender } = renderToolbar ( createProps ( { speed : 10 , fontSize : 14 } ) ) ;
104116 expect ( screen . getByRole ( "button" , { name : "Decrease scroll speed" } ) ) . toBeDisabled ( ) ;
105117 expect ( screen . getByRole ( "button" , { name : "Decrease font size" } ) ) . toBeDisabled ( ) ;
106118
107- rerender ( < NotesToolbar { ...createProps ( { speed : 100 , fontSize : 48 } ) } /> ) ;
119+ rerender (
120+ < I18nProvider >
121+ < NotesToolbar { ...createProps ( { speed : 100 , fontSize : 48 } ) } />
122+ </ I18nProvider > ,
123+ ) ;
108124 expect ( screen . getByRole ( "button" , { name : "Increase scroll speed" } ) ) . toBeDisabled ( ) ;
109125 expect ( screen . getByRole ( "button" , { name : "Increase font size" } ) ) . toBeDisabled ( ) ;
110126 } ) ;
111127
112128 it ( "keeps playback paused and disabled until the editor is ready" , ( ) => {
113- render ( < NotesToolbar { ...createProps ( { editor : null } ) } /> ) ;
114- expect ( screen . getByRole ( "button" , { name : "Play" } ) ) . toBeDisabled ( ) ;
115- expect ( screen . queryByRole ( "button" , { name : "Pause" } ) ) . not . toBeInTheDocument ( ) ;
129+ renderToolbar ( createProps ( { editor : null } ) ) ;
130+ expect ( screen . getByRole ( "button" , { name : "Start auto-scroll" } ) ) . toBeDisabled ( ) ;
131+ expect ( screen . queryByRole ( "button" , { name : "Pause auto-scroll" } ) ) . not . toBeInTheDocument ( ) ;
132+ } ) ;
133+
134+ it ( "formats readout values for the active locale" , ( ) => {
135+ renderToolbar ( createProps ( ) , "ar" ) ;
136+ const speed = within ( screen . getByRole ( "group" , { name : "سرعة التمرير" } ) ) . getByRole ( "status" ) ;
137+ const fontSize = within ( screen . getByRole ( "group" , { name : "حجم الخط" } ) ) . getByRole ( "status" ) ;
138+
139+ expect ( speed ) . not . toHaveAccessibleName ( ) ;
140+ expect ( speed ) . toHaveTextContent ( `${ new Intl . NumberFormat ( "ar" ) . format ( 40 ) } بكسل/ثانية` ) ;
141+ expect ( fontSize ) . not . toHaveAccessibleName ( ) ;
142+ expect ( fontSize ) . toHaveTextContent ( `${ new Intl . NumberFormat ( "ar" ) . format ( 16 ) } بكسل` ) ;
116143 } ) ;
117144} ) ;
0 commit comments