@@ -124,6 +124,68 @@ test('enter key with alt and escape key revert', async ({ page }) => {
124124 expect ( await largeEditor . inputValue ( ) ) . toBe ( 'Change1' ) ;
125125} ) ;
126126
127+ test ( 'IME composition input' , async ( { page } ) => {
128+ await go ( page , 'basic-simple--sheet' ) ;
129+ const a1 = page . locator ( "[data-address='A1']" ) ;
130+ const editor = page . locator ( '.gs-editor textarea' ) ;
131+ const largeEditor = page . locator ( '.gs-formula-bar textarea' ) ;
132+ const address = page . locator ( '.gs-selecting-address' ) ;
133+
134+ // ---- IME composition in cell editor ----
135+ // Clicking a cell and starting composition should enter edit mode
136+ await a1 . click ( ) ;
137+ await page . evaluate ( ( ) => {
138+ const el = document . querySelector ( '.gs-editor textarea' ) ! ;
139+ el . dispatchEvent ( new CompositionEvent ( 'compositionstart' , { bubbles : true } ) ) ;
140+ } ) ;
141+ // Simulate typing "かな" during composition
142+ await page . evaluate ( ( ) => {
143+ const el = document . querySelector ( '.gs-editor textarea' ) as HTMLTextAreaElement ;
144+ el . value = 'かな' ;
145+ el . dispatchEvent ( new InputEvent ( 'input' , { bubbles : true , data : 'かな' , isComposing : true } ) ) ;
146+ } ) ;
147+ // Enter during composition should NOT commit the cell
148+ await page . keyboard . press ( 'Enter' ) ;
149+ // Still composing — address should stay at A1 (not move to A2)
150+ expect ( await address . textContent ( ) ) . toBe ( 'A1' ) ;
151+
152+ // End composition and commit
153+ await page . evaluate ( ( ) => {
154+ const el = document . querySelector ( '.gs-editor textarea' ) as HTMLTextAreaElement ;
155+ el . value = '漢字' ;
156+ el . dispatchEvent ( new CompositionEvent ( 'compositionend' , { bubbles : true , data : '漢字' } ) ) ;
157+ el . dispatchEvent ( new InputEvent ( 'input' , { bubbles : true , data : '漢字' } ) ) ;
158+ } ) ;
159+ await page . keyboard . press ( 'Enter' ) ;
160+ expect ( await a1 . locator ( '.gs-cell-rendered' ) . textContent ( ) ) . toBe ( '漢字' ) ;
161+
162+ // ---- IME composition in formula bar ----
163+ const b2 = page . locator ( "[data-address='B2']" ) ;
164+ await b2 . click ( ) ;
165+ await largeEditor . click ( ) ;
166+ await page . evaluate ( ( ) => {
167+ const el = document . querySelector ( '.gs-formula-bar textarea' ) ! ;
168+ el . dispatchEvent ( new CompositionEvent ( 'compositionstart' , { bubbles : true } ) ) ;
169+ } ) ;
170+ await page . evaluate ( ( ) => {
171+ const el = document . querySelector ( '.gs-formula-bar textarea' ) as HTMLTextAreaElement ;
172+ el . value = 'にほんご' ;
173+ el . dispatchEvent ( new InputEvent ( 'input' , { bubbles : true , data : 'にほんご' , isComposing : true } ) ) ;
174+ } ) ;
175+ // Enter during composition should NOT commit
176+ await page . keyboard . press ( 'Enter' ) ;
177+ expect ( await address . textContent ( ) ) . toBe ( 'B2' ) ;
178+
179+ await page . evaluate ( ( ) => {
180+ const el = document . querySelector ( '.gs-formula-bar textarea' ) as HTMLTextAreaElement ;
181+ el . value = '日本語' ;
182+ el . dispatchEvent ( new CompositionEvent ( 'compositionend' , { bubbles : true , data : '日本語' } ) ) ;
183+ el . dispatchEvent ( new InputEvent ( 'input' , { bubbles : true , data : '日本語' } ) ) ;
184+ } ) ;
185+ await page . keyboard . press ( 'Enter' ) ;
186+ expect ( await b2 . locator ( '.gs-cell-rendered' ) . textContent ( ) ) . toBe ( '日本語' ) ;
187+ } ) ;
188+
127189test ( 'rendered cell' , async ( { page } ) => {
128190 const largeEditor = page . locator ( '.gs-formula-bar textarea' ) ;
129191 await go ( page , 'basic-renderer--render-to-kanji' ) ;
0 commit comments