@@ -24,6 +24,8 @@ const expectTextEndsWith = (expected) => {
2424 }
2525}
2626
27+ const isChromium = Cypress . isBrowser ( { family : 'chromium' } )
28+
2729describe ( 'src/cy/commands/actions/type - #type' , ( ) => {
2830 beforeEach ( ( ) => {
2931 cy . visit ( '/fixtures/dom.html' )
@@ -643,6 +645,7 @@ describe('src/cy/commands/actions/type - #type', () => {
643645 view : cy . state ( 'window' ) ,
644646 which : 65 , // deprecated but fired by chrome
645647 } )
648+ . not . have . property ( 'inputType' )
646649
647650 done ( )
648651 } )
@@ -1810,6 +1813,219 @@ describe('src/cy/commands/actions/type - #type', () => {
18101813 } )
18111814 } )
18121815
1816+ // https://github.com/cypress-io/cypress/issues/7088
1817+ describe ( 'beforeInput event' , ( ) => {
1818+ it ( 'sends beforeinput in text input' , ( ) => {
1819+ const call1 = ( e ) => {
1820+ expect ( e . code ) . not . exist
1821+ expect ( e . data ) . eq ( ' ' )
1822+ expect ( e . inputType ) . eq ( 'insertText' )
1823+ stub . callsFake ( call2 )
1824+ }
1825+ const call2 = ( e ) => {
1826+ expect ( e . code ) . not . exist
1827+ expect ( e . data ) . eq ( 'f' )
1828+ expect ( e . inputType ) . eq ( 'insertText' )
1829+ stub . callsFake ( call3 )
1830+ }
1831+ const call3 = ( e ) => {
1832+ expect ( e . data ) . eq ( null )
1833+ expect ( e . inputType ) . eq ( 'insertLineBreak' )
1834+ stub . callsFake ( call4 )
1835+ }
1836+ const call4 = ( e ) => {
1837+ expect ( e . data ) . eq ( null )
1838+ expect ( e . inputType ) . eq ( 'deleteContentBackward' )
1839+ stub . callsFake ( call5 )
1840+ }
1841+ const call5 = ( e ) => {
1842+ expect ( e . data ) . eq ( null )
1843+ expect ( e . inputType ) . eq ( 'deleteContentForward' )
1844+ }
1845+
1846+ const stub = cy . stub ( )
1847+ . callsFake ( call1 )
1848+
1849+ cy . get ( 'input:first' )
1850+ . then ( ( $el ) => {
1851+ $el . val ( 'foo bar baz' )
1852+ $el [ 0 ] . addEventListener ( 'beforeinput' , stub )
1853+ } )
1854+ . type ( ' f\n{backspace}' )
1855+ . type ( '{moveToStart}{del}' )
1856+ . then ( ( $el ) => {
1857+ if ( isChromium ) {
1858+ expect ( stub ) . callCount ( 5 )
1859+ expect ( $el [ 0 ] . value ) . eq ( 'oo bar baz ' )
1860+ } else {
1861+ expect ( stub , 'should NOT send beforeinput unless in chromium based browser' ) . not . called
1862+ }
1863+ } )
1864+ } )
1865+
1866+ it ( 'sends beforeinput in textarea' , ( ) => {
1867+ const call1 = ( e ) => {
1868+ expect ( e . code ) . not . exist
1869+ expect ( e . data ) . eq ( ' ' )
1870+ expect ( e . inputType ) . eq ( 'insertText' )
1871+ stub . callsFake ( call2 )
1872+ }
1873+ const call2 = ( e ) => {
1874+ expect ( e . code ) . not . exist
1875+ expect ( e . data ) . eq ( 'f' )
1876+ expect ( e . inputType ) . eq ( 'insertText' )
1877+ stub . callsFake ( call3 )
1878+ }
1879+ const call3 = ( e ) => {
1880+ expect ( e . data ) . eq ( null )
1881+ expect ( e . inputType ) . eq ( 'insertLineBreak' )
1882+ stub . callsFake ( call4 )
1883+ }
1884+ const call4 = ( e ) => {
1885+ expect ( e . data ) . eq ( null )
1886+ expect ( e . inputType ) . eq ( 'deleteContentBackward' )
1887+ stub . callsFake ( call5 )
1888+ }
1889+ const call5 = ( e ) => {
1890+ expect ( e . data ) . eq ( null )
1891+ expect ( e . inputType ) . eq ( 'deleteContentForward' )
1892+ }
1893+
1894+ const stub = cy . stub ( )
1895+ . callsFake ( call1 )
1896+
1897+ cy . get ( 'textarea:first' )
1898+ . then ( ( $el ) => {
1899+ $el . val ( 'foo bar baz' )
1900+ $el [ 0 ] . addEventListener ( 'beforeinput' , stub )
1901+ } )
1902+ . type ( ' f\n{backspace}' )
1903+ . type ( '{moveToStart}{del}' )
1904+ . then ( ( $el ) => {
1905+ if ( isChromium ) {
1906+ expect ( stub ) . callCount ( 5 )
1907+ expect ( $el [ 0 ] . value ) . eq ( 'oo bar baz f' )
1908+ } else {
1909+ expect ( stub , 'should NOT send beforeinput unless in chromium based browser' ) . not . called
1910+ }
1911+ } )
1912+ } )
1913+
1914+ it ( 'sends beforeinput in [contenteditable]' , ( ) => {
1915+ const call1 = ( e ) => {
1916+ expect ( e . code ) . not . exist
1917+ expect ( e . data ) . eq ( ' ' )
1918+ expect ( e . inputType ) . eq ( 'insertText' )
1919+ stub . callsFake ( call2 )
1920+ }
1921+ const call2 = ( e ) => {
1922+ expect ( e . code ) . not . exist
1923+ expect ( e . data ) . eq ( 'f' )
1924+ expect ( e . inputType ) . eq ( 'insertText' )
1925+ stub . callsFake ( call3 )
1926+ }
1927+ const call3 = ( e ) => {
1928+ expect ( e . data ) . eq ( null )
1929+ expect ( e . inputType ) . eq ( 'insertParagraph' )
1930+ stub . callsFake ( call4 )
1931+ }
1932+ const call4 = ( e ) => {
1933+ expect ( e . data ) . eq ( null )
1934+ expect ( e . inputType ) . eq ( 'deleteContentBackward' )
1935+ stub . callsFake ( call5 )
1936+ }
1937+ const call5 = ( e ) => {
1938+ expect ( e . data ) . eq ( null )
1939+ expect ( e . inputType ) . eq ( 'deleteContentForward' )
1940+ }
1941+
1942+ const stub = cy . stub ( )
1943+ . callsFake ( call1 )
1944+
1945+ cy . get ( '#input-types [contenteditable]' )
1946+ . then ( ( $el ) => {
1947+ $el . text ( 'foo bar baz' )
1948+ $el [ 0 ] . addEventListener ( 'beforeinput' , stub )
1949+ } )
1950+ . type ( ' f\n{backspace}' )
1951+ . type ( '{moveToStart}{del}' )
1952+ . then ( ( $el ) => {
1953+ if ( isChromium ) {
1954+ expect ( stub ) . callCount ( 5 )
1955+ expect ( $el [ 0 ] . textContent ) . eq ( 'oo bar baz f' )
1956+ } else {
1957+ expect ( stub , 'should NOT send beforeinput unless in chromium based browser' ) . not . called
1958+ }
1959+ } )
1960+ } )
1961+
1962+ it ( 'beforeinput special inputTypes' , ( ) => {
1963+ const call1 = ( e ) => {
1964+ expect ( e . code ) . not . exist
1965+ expect ( e . data ) . eq ( null )
1966+ expect ( e . inputType ) . eq ( 'deleteWordForward' )
1967+ stub . callsFake ( call2 )
1968+ }
1969+ const call2 = ( e ) => {
1970+ expect ( e . code ) . not . exist
1971+ expect ( e . data ) . eq ( null )
1972+ expect ( e . inputType ) . eq ( 'deleteHardLineForward' )
1973+ stub . callsFake ( call3 )
1974+ }
1975+ const call3 = ( e ) => {
1976+ expect ( e . data ) . eq ( null )
1977+ expect ( e . inputType ) . eq ( 'deleteWordBackward' )
1978+ stub . callsFake ( call4 )
1979+ }
1980+ const call4 = ( e ) => {
1981+ expect ( e . data ) . eq ( null )
1982+ expect ( e . inputType ) . eq ( 'deleteHardLineBackward' )
1983+ }
1984+
1985+ const stub = cy . stub ( )
1986+ . callsFake ( call1 )
1987+
1988+ cy . get ( '#input-types [contenteditable]' )
1989+ . then ( ( $el ) => {
1990+ $el . text ( 'foo bar baz' )
1991+ $el [ 0 ] . addEventListener ( 'beforeinput' , stub )
1992+ } )
1993+ . type ( '{ctrl}{del}' )
1994+ . type ( '{ctrl}{shift}{del}' )
1995+ . type ( '{ctrl}{backspace}' )
1996+ . type ( '{ctrl}{shift}{backspace}' )
1997+ . then ( ( $el ) => {
1998+ if ( isChromium ) {
1999+ expect ( stub ) . callCount ( 4 )
2000+ } else {
2001+ expect ( stub , 'should NOT send beforeinput unless in chromium based browser' ) . not . called
2002+ }
2003+ } )
2004+ } )
2005+
2006+ it ( 'can cancel beforeinput' , ( ) => {
2007+ let callCount = 0
2008+
2009+ cy . get ( 'input:first' )
2010+ . then ( ( $el ) => {
2011+ $el . val ( 'foo bar baz' )
2012+ $el [ 0 ] . addEventListener ( 'beforeinput' , ( e ) => {
2013+ callCount ++
2014+ e . preventDefault ( )
2015+ } )
2016+ } )
2017+ . type ( 'foo' )
2018+ . then ( ( $el ) => {
2019+ if ( isChromium ) {
2020+ expect ( callCount ) . eq ( 3 )
2021+ expect ( $el [ 0 ] . value ) . eq ( 'foo bar baz' )
2022+ } else {
2023+ expect ( callCount , 'should NOT send beforeinput unless in chromium based browser' ) . eq ( 0 )
2024+ }
2025+ } )
2026+ } )
2027+ } )
2028+
18132029 // type follows focus
18142030 // https://github.com/cypress-io/cypress/issues/2240
18152031 describe ( 'element reference loss' , ( ) => {
@@ -3013,18 +3229,20 @@ describe('src/cy/commands/actions/type - #type', () => {
30133229 // eslint-disable-next-line
30143230 console . table ( table . data , table . columns )
30153231
3232+ const beforeInput = isChromium ? 'beforeinput, ' : ''
3233+
30163234 expect ( table . name ) . to . eq ( 'Keyboard Events' )
30173235 const expectedTable = {
30183236 1 : { 'Details' : '{ code: MetaLeft, which: 91 }' , Typed : '{cmd}' , 'Events Fired' : 'keydown' , 'Active Modifiers' : 'meta' , 'Prevented Default' : null , 'Target Element' : $input [ 0 ] } ,
30193237 2 : { 'Details' : '{ code: AltLeft, which: 18 }' , Typed : '{option}' , 'Events Fired' : 'keydown' , 'Active Modifiers' : 'alt, meta' , 'Prevented Default' : null , 'Target Element' : $input [ 0 ] } ,
3020- 3 : { 'Details' : '{ code: KeyF, which: 70 }' , Typed : 'f' , 'Events Fired' : ' keydown, keypress, textInput, input, keyup' , 'Active Modifiers' : 'alt, meta' , 'Prevented Default' : null , 'Target Element' : $input [ 0 ] } ,
3021- 4 : { 'Details' : '{ code: KeyO, which: 79 }' , Typed : 'o' , 'Events Fired' : ' keydown, keypress, textInput, input, keyup' , 'Active Modifiers' : 'alt, meta' , 'Prevented Default' : null , 'Target Element' : $input [ 0 ] } ,
3022- 5 : { 'Details' : '{ code: KeyO, which: 79 }' , Typed : 'o' , 'Events Fired' : ' keydown, keypress, textInput, input, keyup' , 'Active Modifiers' : 'alt, meta' , 'Prevented Default' : null , 'Target Element' : $input [ 0 ] } ,
3023- 6 : { 'Details' : '{ code: Enter, which: 13 }' , Typed : '{enter}' , 'Events Fired' : ' keydown, keypress, keyup' , 'Active Modifiers' : 'alt, meta' , 'Prevented Default' : null , 'Target Element' : $input [ 0 ] } ,
3024- 7 : { 'Details' : '{ code: KeyB, which: 66 }' , Typed : 'b' , 'Events Fired' : ' keydown, keypress, textInput, input, keyup' , 'Active Modifiers' : 'alt, meta' , 'Prevented Default' : null , 'Target Element' : $input [ 0 ] } ,
3238+ 3 : { 'Details' : '{ code: KeyF, which: 70 }' , Typed : 'f' , 'Events Fired' : ` keydown, keypress, ${ beforeInput } textInput, input, keyup` , 'Active Modifiers' : 'alt, meta' , 'Prevented Default' : null , 'Target Element' : $input [ 0 ] } ,
3239+ 4 : { 'Details' : '{ code: KeyO, which: 79 }' , Typed : 'o' , 'Events Fired' : ` keydown, keypress, ${ beforeInput } textInput, input, keyup` , 'Active Modifiers' : 'alt, meta' , 'Prevented Default' : null , 'Target Element' : $input [ 0 ] } ,
3240+ 5 : { 'Details' : '{ code: KeyO, which: 79 }' , Typed : 'o' , 'Events Fired' : ` keydown, keypress, ${ beforeInput } textInput, input, keyup` , 'Active Modifiers' : 'alt, meta' , 'Prevented Default' : null , 'Target Element' : $input [ 0 ] } ,
3241+ 6 : { 'Details' : '{ code: Enter, which: 13 }' , Typed : '{enter}' , 'Events Fired' : ` keydown, keypress, ${ beforeInput } keyup` , 'Active Modifiers' : 'alt, meta' , 'Prevented Default' : null , 'Target Element' : $input [ 0 ] } ,
3242+ 7 : { 'Details' : '{ code: KeyB, which: 66 }' , Typed : 'b' , 'Events Fired' : ` keydown, keypress, ${ beforeInput } textInput, input, keyup` , 'Active Modifiers' : 'alt, meta' , 'Prevented Default' : null , 'Target Element' : $input [ 0 ] } ,
30253243 8 : { 'Details' : '{ code: ArrowLeft, which: 37 }' , Typed : '{leftarrow}' , 'Events Fired' : 'keydown, keyup' , 'Active Modifiers' : 'alt, meta' , 'Prevented Default' : null , 'Target Element' : $input [ 0 ] } ,
3026- 9 : { 'Details' : '{ code: Delete, which: 46 }' , Typed : '{del}' , 'Events Fired' : ' keydown, input, keyup' , 'Active Modifiers' : 'alt, meta' , 'Prevented Default' : null , 'Target Element' : $input [ 0 ] } ,
3027- 10 : { 'Details' : '{ code: Enter, which: 13 }' , Typed : '{enter}' , 'Events Fired' : ' keydown, keypress, keyup' , 'Active Modifiers' : 'alt, meta' , 'Prevented Default' : null , 'Target Element' : $input [ 0 ] } ,
3244+ 9 : { 'Details' : '{ code: Delete, which: 46 }' , Typed : '{del}' , 'Events Fired' : ` keydown, ${ beforeInput } input, keyup` , 'Active Modifiers' : 'alt, meta' , 'Prevented Default' : null , 'Target Element' : $input [ 0 ] } ,
3245+ 10 : { 'Details' : '{ code: Enter, which: 13 }' , Typed : '{enter}' , 'Events Fired' : ` keydown, keypress, ${ beforeInput } keyup` , 'Active Modifiers' : 'alt, meta' , 'Prevented Default' : null , 'Target Element' : $input [ 0 ] } ,
30283246 11 : { 'Details' : '{ code: MetaLeft, which: 91 }' , Typed : '{cmd}' , 'Events Fired' : 'keyup' , 'Active Modifiers' : 'alt' , 'Prevented Default' : null , 'Target Element' : $input [ 0 ] } ,
30293247 12 : { 'Details' : '{ code: AltLeft, which: 18 }' , Typed : '{option}' , 'Events Fired' : 'keyup' , 'Active Modifiers' : null , 'Prevented Default' : null , 'Target Element' : $input [ 0 ] } ,
30303248 }
@@ -3040,8 +3258,10 @@ describe('src/cy/commands/actions/type - #type', () => {
30403258 cy . get ( ':text:first' ) . type ( 'f' ) . then ( function ( $el ) {
30413259 const table = this . lastLog . invoke ( 'consoleProps' ) . table [ 2 ] ( )
30423260
3261+ const beforeInput = isChromium ? 'beforeinput, ' : ''
3262+
30433263 expect ( table . data ) . to . deep . eq ( {
3044- 1 : { Typed : 'f' , 'Events Fired' : ' keydown, keypress, textInput, input, keyup' , 'Active Modifiers' : null , Details : '{ code: KeyF, which: 70 }' , 'Prevented Default' : null , 'Target Element' : $el [ 0 ] } ,
3264+ 1 : { Typed : 'f' , 'Events Fired' : ` keydown, keypress, ${ beforeInput } textInput, input, keyup` , 'Active Modifiers' : null , Details : '{ code: KeyF, which: 70 }' , 'Prevented Default' : null , 'Target Element' : $el [ 0 ] } ,
30453265 } )
30463266 } )
30473267 } )
0 commit comments