1- import React from 'react' ;
1+ import React , { useState } from 'react' ;
22import Terminal , { ColorMode , TerminalInput , TerminalOutput } from '../src/index' ;
33import { render , fireEvent , screen } from '@testing-library/react' ;
44import '@testing-library/jest-dom' ;
@@ -14,14 +14,14 @@ describe('Terminal component', () => {
1414 } )
1515
1616 test ( 'Should render prompt' , ( ) => {
17- const { container } = render ( < Terminal onInput = { ( input : string ) => '' } /> ) ;
17+ const { container } = render ( < Terminal onInput = { ( input : string ) => '' } /> ) ;
1818 expect ( container . querySelectorAll ( '.react-terminal-line' ) ) . toHaveLength ( 1 ) ;
1919 expect ( container . querySelector ( '.react-terminal-line.react-terminal-active-input[data-terminal-prompt="$"]' ) ) . not . toBeNull ( ) ;
2020 expect ( screen . getByPlaceholderText ( 'Terminal Hidden Input' ) ) . toBeInTheDocument ( ) ;
2121 } ) ;
2222
2323 test ( 'Should not render prompt if onInput prop is null or not defined' , ( ) => {
24- const { container } = render ( < Terminal onInput = { null } > < TerminalOutput > Some terminal output</ TerminalOutput > </ Terminal > ) ;
24+ const { container } = render ( < Terminal onInput = { null } > < TerminalOutput > Some terminal output</ TerminalOutput > </ Terminal > ) ;
2525 // Still renders output line...
2626 expect ( container . querySelectorAll ( '.react-terminal-line' ) ) . toHaveLength ( 1 ) ;
2727 // ... but not the prompt
@@ -30,7 +30,7 @@ describe('Terminal component', () => {
3030
3131 test ( 'Should render terminal lines' , ( ) => {
3232 const { container } = render (
33- < Terminal onInput = { ( input : string ) => '' } >
33+ < Terminal onInput = { ( input : string ) => '' } >
3434 < TerminalInput > Some terminal input</ TerminalInput > ,
3535 < TerminalOutput > Some terminal output</ TerminalOutput >
3636 </ Terminal >
@@ -44,7 +44,7 @@ describe('Terminal component', () => {
4444
4545 test ( 'Input prompt should not scroll into view when component first loads' , ( ) => {
4646 render (
47- < Terminal onInput = { ( input : string ) => '' } >
47+ < Terminal onInput = { ( input : string ) => '' } >
4848 < TerminalInput > Some terminal input</ TerminalInput > ,
4949 < TerminalOutput > Some terminal output</ TerminalOutput >
5050 </ Terminal >
@@ -55,26 +55,26 @@ describe('Terminal component', () => {
5555
5656 test ( 'Should accept input and scroll into view' , ( ) => {
5757 const onInput = jest . fn ( ) ;
58- const { rerender } = render ( < Terminal onInput = { onInput } /> ) ;
58+ const { rerender } = render ( < Terminal onInput = { onInput } /> ) ;
5959 const hiddenInput = screen . getByPlaceholderText ( 'Terminal Hidden Input' ) ;
6060 fireEvent . change ( hiddenInput , { target : { value : 'a' } } ) ;
6161 expect ( screen . getByText ( 'a' ) . className ) . toEqual ( 'react-terminal-line react-terminal-input react-terminal-active-input' ) ;
6262 screen . getByDisplayValue ( 'a' ) ;
6363 expect ( onInput . mock . calls . length ) . toEqual ( 0 ) ;
6464 fireEvent . keyDown ( hiddenInput , { key : 'Enter' , code : 'Enter' } ) ;
6565 expect ( onInput ) . toHaveBeenCalledWith ( 'a' ) ;
66- rerender ( < Terminal onInput = { onInput } > < TerminalInput > a</ TerminalInput > </ Terminal > )
66+ rerender ( < Terminal onInput = { onInput } > < TerminalInput > a</ TerminalInput > </ Terminal > )
6767 jest . runAllTimers ( ) ;
6868 expect ( scrollIntoViewFn ) . toHaveBeenCalledTimes ( 1 ) ;
6969 } ) ;
7070
7171 test ( 'Should support changing color mode' , ( ) => {
72- const { container } = render ( < Terminal colorMode = { ColorMode . Light } onInput = { ( input : string ) => '' } /> ) ;
72+ const { container } = render ( < Terminal colorMode = { ColorMode . Light } onInput = { ( input : string ) => '' } /> ) ;
7373 expect ( container . querySelector ( '.react-terminal-wrapper.react-terminal-light' ) ) . not . toBeNull ( ) ;
7474 } ) ;
7575
7676 test ( 'Should focus if onInput is defined' , ( ) => {
77- const { container } = render ( < Terminal onInput = { ( input : string ) => '' } /> )
77+ const { container } = render ( < Terminal onInput = { ( input : string ) => '' } /> )
7878 expect ( container . ownerDocument . activeElement ?. nodeName ) . toEqual ( 'INPUT' ) ;
7979 expect ( container . ownerDocument . activeElement ?. className ) . toEqual ( 'terminal-hidden-input' ) ;
8080 } ) ;
@@ -85,7 +85,7 @@ describe('Terminal component', () => {
8585 } ) ;
8686
8787 test ( 'Should take starting input value' , ( ) => {
88- render ( < Terminal onInput = { ( input : string ) => '' } startingInputValue = "cat file.txt " /> )
88+ render ( < Terminal onInput = { ( input : string ) => '' } startingInputValue = "cat file.txt " /> )
8989 const renderedLine = screen . getByText ( 'cat file.txt' ) ;
9090 expect ( renderedLine . className ) . toContain ( 'react-terminal-line' ) ;
9191 } ) ;
@@ -96,7 +96,48 @@ describe('Terminal component', () => {
9696 } ) ;
9797
9898 test ( 'Should not render top button panel if null props passed' , ( ) => {
99- const { container } = render ( < Terminal TopButtonsPanel = { ( ) => null } /> ) ;
99+ const { container } = render ( < Terminal TopButtonsPanel = { ( ) => null } /> ) ;
100100 expect ( container . querySelector ( '.react-terminal-window-buttons' ) ) . toBeNull ( ) ;
101101 } ) ;
102+
103+ test ( 'renders input as password and handles masked input' , ( ) => {
104+ const TerminalWrapper = ( ) => {
105+ const [ lines , setLines ] = useState < React . ReactNode [ ] > ( [
106+ < TerminalOutput key = "welcome" > Welcome!</ TerminalOutput >
107+ ] ) ;
108+ const [ isPasswordMode , setIsPasswordMode ] = useState ( true ) ;
109+
110+ return (
111+ < Terminal
112+ passwordField = { isPasswordMode }
113+ onInput = { ( input : string ) => {
114+ const newLines = [ ...lines ] ;
115+ if ( isPasswordMode ) {
116+ newLines . push ( < TerminalInput key = "masked" > { '*' . repeat ( input . length ) } </ TerminalInput > ) ;
117+ newLines . push ( < TerminalOutput key = "success" > Password received</ TerminalOutput > ) ;
118+ setIsPasswordMode ( false ) ;
119+ } else {
120+ newLines . push ( < TerminalInput key = { input } > { input } </ TerminalInput > ) ;
121+ }
122+ setLines ( newLines ) ;
123+ } }
124+ >
125+ { lines }
126+ </ Terminal >
127+ ) ;
128+ } ;
129+
130+ render ( < TerminalWrapper /> ) ;
131+
132+ const hiddenInput = screen . getByPlaceholderText ( 'Terminal Hidden Input' ) as HTMLInputElement ;
133+
134+ expect ( hiddenInput . type ) . toBe ( 'password' ) ;
135+
136+ fireEvent . change ( hiddenInput , { target : { value : 'mypassword' } } ) ;
137+ expect ( hiddenInput . value ) . toBe ( 'mypassword' ) ;
138+
139+ fireEvent . keyDown ( hiddenInput , { key : 'Enter' , code : 'Enter' } ) ;
140+
141+ expect ( screen . getByText ( 'Password received' ) ) . toBeInTheDocument ( ) ;
142+ } ) ;
102143} ) ;
0 commit comments