import { ok } from 'assert' ; import { Application } from 'spectron' ; import { BadgeSpec , Util } from '@kui-shell/core' ; import * as Common from './common' ; import * as CLI from './cli' ; import * as ReplExpect from './repl-expect' ; import * as SidecarExpect from './sidecar-expect' ; import * as Selectors from './selectors' ; interface TestParam { command : string ; testName ? : string ; metadata : { name : string ; namespace ? : string ; } ; } export type MMRExpectMode = Label & ( PlainTextContent | YamlContentWithEditor | TableContent | ReactContent ) ; export class TestMMR { param { TestParam } param param { string } command param { string } testName param { string } metadata public constructor ( public readonly param ) { } private testClickResult = ( cmdIdx , command , expect ) => async ( app ) => { await CLI . expectPriorInput ( Selectors . PROMPT_N ( cmdIdx ) , command ) ( app ) ; if ( typeof expect === 'string' ) { await ReplExpect . okWithString ( expect , true ) ( { app : app , count : cmdIdx } ) ; } } ; /**
     * name() starts a Mocha Test Suite
     * name() executes `command` in REPL and expects `prettyName` or `name` is shown in Sidecar
     */ public name ( opt ? ) { const { command , testName , metadata } = this . param ; const testClickResult = this . testClickResult ; describe ( `mmr name ${ testName || command || '' } ${ process . env . MOCHA_RUN_TARGET || '' }` , function ( this ) { before ( Common . before ( this ) ) ; after ( Common . after ( this ) ) ; const { nameHash , prettyName , onclick , heroName } = opt ; let cmdIdx = 0 ; const showName = prettyName || metadata . name ; it ( `should show name ${ showName } ${ nameHash ? ' and namehash ' + nameHash : '' } in sidecar header` , ( ) => CLI . command ( command , this . app ) . then ( res => { cmdIdx = res . count ; return res ; } ) . then ( ReplExpect . ok ) . then ( SidecarExpect . open ) . then ( async ( res ) => { if ( heroName ) { await SidecarExpect . heroName ( res . count , showName ) ; } else { await SidecarExpect . name ( res . count , showName ) ; } if ( nameHash ) { await SidecarExpect . namehash ( res . count , nameHash ) ; } } ) . catch ( Common . oops ( this , true ) ) ) ; if ( onclick && onclick . name ) { it ( 'should click the name part of sidecar and expect the command shows in repl' , async ( ) => { try { await this . app . client . $ ( Selectors . SIDECAR_TITLE ( cmdIdx ) ) . then ( _ => _ . click ( ) ) ; await testClickResult ( ++ cmdIdx , onclick . name . command , onclick . name . expect ) ( this . app ) ; } catch ( err ) { await Common . oops ( this , true ) ( err ) ; } } ) ; } if ( onclick && onclick . nameHash ) { it ( 'should click the namehash part of sidecar and expect the command shows in repl' , async ( ) => { try { await this . app . client . $ ( Selectors . SIDECAR_ACTIVATION_TITLE ( cmdIdx ) ) . then ( _ => _ . click ( ) ) ; await testClickResult ( ++ cmdIdx , onclick . nameHash . command , onclick . nameHash . expect ) ( this . app ) ; } catch ( err ) { await Common . oops ( this , true ) ( err ) ; } } ) ; } } ) ; } /**
     * namespace() starts a Mocha Test Suite
     * namespace() executes `command` in REPL and expects `namespace` is shown in Sidecar
     *
     */ public namespace ( opt ? ) { const { command , testName , metadata } = this . param ; const testClickResult = this . testClickResult ; describe ( `mmr namespace ${ testName || command || '' } ${ process . env . MOCHA_RUN_TARGET || '' }` , function ( this ) { before ( Common . before ( this ) ) ; after ( Common . after ( this ) ) ; const onclick = opt && opt . onclick ; let cmdIdx = 0 ; it ( `should show namespace ${ metadata . namespace } in sidecar` , ( ) => CLI . command ( command , this . app ) . then ( res => { cmdIdx = res . count ; return res ; } ) . then ( ReplExpect . ok ) . then ( SidecarExpect . open ) . then ( SidecarExpect . namespace ( metadata . namespace ) ) . catch ( Common . oops ( this , true ) ) ) ; if ( onclick ) { it ( `should click the namespace part of sidecar and expect the command shows in repl` , async ( ) => { try { await this . app . client . $ ( Selectors . SIDECAR_PACKAGE_NAME_TITLE ( cmdIdx ) ) . then ( _ => _ . click ( ) ) ; await testClickResult ( ++ cmdIdx , onclick . command , onclick . expect ) ( this . app ) ; } catch ( err ) { await Common . oops ( this , true ) ( err ) ; } } ) ; } } ) ; } param { string } kind public kind ( kind ) { const { command , testName } = this . param ; describe ( `mmr kind ${ testName || command || '' } ${ process . env . MOCHA_RUN_TARGET || '' }` , function ( this ) { before ( Common . before ( this ) ) ; after ( Common . after ( this ) ) ; it ( `should show kind ${ kind } in sidecar` , ( ) => CLI . command ( command , this . app ) . then ( ReplExpect . ok ) . then ( SidecarExpect . open ) . then ( SidecarExpect . kind ( kind ) ) . catch ( Common . oops ( this , true ) ) ) ; } ) ; } param { BadgeSpec [ ] } badges public badges ( badges ) { const { command , testName } = this . param ; describe ( `mmr badges ${ testName || '' } ${ process . env . MOCHA_RUN_TARGET || '' }` , function ( this ) { before ( Common . before ( this ) ) ; after ( Common . after ( this ) ) ; it ( `should show badges in sidecar` , ( ) => CLI . command ( command , this . app ) . then ( ReplExpect . ok ) . then ( SidecarExpect . open ) . then ( res => Promise . all ( badges . map ( badge => SidecarExpect . badge ( badge . title , badge . css ) ( res ) ) ) ) ) ; } ) ; } param { MMRExpectMode [ ] } expectModes param { MMRExpectMode } defaultMode public modes ( expectModes , defaultMode ) { const { command , testName } = this . param ; describe ( `mmr modes ${ testName || command || '' } ${ process . env . MOCHA_RUN_TARGET || '' }` , function ( this ) { before ( Common . before ( this ) ) ; after ( Common . after ( this ) ) ; let cmdIdx ; const showModes = ( ) => { it ( `should show sidecar tabs with command=${ command }` , ( ) => CLI . command ( command , this . app ) . then ( ReplExpect . ok ) . then ( SidecarExpect . open ) . then ( SidecarExpect . defaultMode ( defaultMode ) ) . then ( SidecarExpect . modes ( expectModes ) ) . then ( res => { cmdIdx = res . count ; return res ; } ) . catch ( Common . oops ( this , true ) ) ) ; } ; const clickToActivateTab = async ( mode ) => { const sel = Selectors . SIDECAR_MODE_BUTTON ( cmdIdx , mode ) ; await this . app . client . $ ( sel ) . then ( _ => _ . waitForExist ( ) ) ; await this . app . client . execute ( sel => { ; ( document . querySelector ( sel ) as HTMLElement ) . focus ( ) ; } , sel ) ; const elt = await this . app . client . $ ( sel ) ; ok ( await elt . isDisplayedInViewport ( ) ) ; await elt . click ( ) ; await this . app . client . $ ( Selectors . SIDECAR_MODE_BUTTON_SELECTED ( cmdIdx , mode ) ) . then ( _ => _ . waitForExist ( ) ) ; } ; const cycleTheTabs = ( ) => expectModes . forEach ( expectMode => { it ( `should switch to the ${ expectMode . mode } tab` , async ( ) => { try { await clickToActivateTab ( expectMode . mode ) ; } catch ( err ) { return Common . oops ( this , true ) ( err ) ; } } ) ; if ( expectMode . contentType === 'text/plain' ) { it ( `should show plain text content via monaco in the ${ expectMode . mode } tab` , async ( ) => { try { if ( await this . app . client . $ ( Selectors . SIDECAR_MODE_BUTTON ( cmdIdx , expectMode . mode ) ) . then ( _ => _ . isDisplayed ( ) ) ) { await SidecarExpect . textPlainContentFromMonaco ( expectMode . content ) ( { app : this . app , count : cmdIdx } ) ; } } catch ( err ) { return Common . oops ( this , true ) ( err ) ; } } ) ; } else if ( expectMode . contentType === 'react' ) { it ( `should show react content` , async ( ) => { if ( await this . app . client . $ ( Selectors . SIDECAR_MODE_BUTTON ( cmdIdx , expectMode . mode ) ) . then ( _ => _ . isDisplayed ( ) ) ) { const selector = `${ Selectors . SIDECAR_TAB_CONTENT ( cmdIdx ) } ${ expectMode . selector }` ; await this . app . client . waitUntil ( async ( ) => { const elt = await this . app . client . $ ( selector ) ; await elt . waitForDisplayed ( ) ; return expectMode . innerText === ( await elt . getText ( ) ) ; } ) ; } } ) ; } else if ( expectMode . contentType === 'table' ) { it ( `should show ${ expectMode . nRows } table rows in the ${ expectMode . mode } tab` , async ( ) => { try { if ( await this . app . client . $ ( Selectors . SIDECAR_MODE_BUTTON ( cmdIdx , expectMode . mode ) ) . then ( _ => _ . isDisplayed ( ) ) ) { let idx = 0 ; await this . app . client . waitUntil ( async ( ) => { const rows = await this . app . client . $$ ( `${ Selectors . SIDECAR_TAB_CONTENT ( cmdIdx ) } tbody tr` ) ; const actualRows = rows . length ; const expectedRows = expectMode . nRows ; if ( ++ idx > 5 ) { console . error ( `still waiting for table rows actualRows=${ actualRows } expectedRows=${ expectedRows }` , `${ Selectors . SIDECAR_TAB_CONTENT ( cmdIdx ) } tbody tr` ) ; } return actualRows === expectedRows ; } , { timeout : CLI . waitTimeout } ) ; } } catch ( err ) { return Common . oops ( this , true ) ( err ) ; } } ) ; it ( `should show ${ expectMode . nCells } table cells in the ${ expectMode . mode } tab` , async ( ) => { try { if ( await this . app . client . $ ( Selectors . SIDECAR_MODE_BUTTON ( cmdIdx , expectMode . mode ) ) . then ( _ => _ . isDisplayed ( ) ) ) { await this . app . client . waitUntil ( async ( ) => { const cells = await this . app . client . $$ ( `${ Selectors . SIDECAR_TAB_CONTENT ( cmdIdx ) } td` ) ; return cells . length === expectMode . nCells ; } , { timeout : CLI . waitTimeout } ) ; } } catch ( err ) { return Common . oops ( this , true ) ( err ) ; } } ) ; } else if ( expectMode . contentType === 'yaml' ) { if ( expectMode . editor === true ) { it ( `should open editor and show yaml content via monaco in the ${ expectMode . mode } tab` , async ( ) => { try { if ( await this . app . client . $ ( Selectors . SIDECAR_MODE_BUTTON ( cmdIdx , expectMode . mode ) ) . then ( _ => _ . isDisplayed ( ) ) ) { await SidecarExpect . yaml ( expectMode . content ) ( { app : this . app , count : cmdIdx } ) ; } } catch ( err ) { return Common . oops ( this , true ) ( err ) ; } } ) ; } else { it ( `should show random content in the ${ expectMode . mode } tab` , async ( ) => { try { if ( await this . app . client . $ ( Selectors . SIDECAR_MODE_BUTTON ( cmdIdx , expectMode . mode ) ) . then ( _ => _ . isDisplayed ( ) ) ) { await SidecarExpect . textPlainContent ( expectMode . content ) ( { app : this . app , count : cmdIdx } ) ; } } catch ( err ) { return Common . oops ( this , true ) ( err ) ; } } ) ; } } } ) ; showModes ( ) ; cycleTheTabs ( ) ; cycleTheTabs ( ) ; } ) ; } public diffPlainText ( mode , textB ) { const { command , testName } = this . param ; describe ( `diff ${ testName } ${ process . env . MOCHA_RUN_TARGET || '' }` , function ( this ) { before ( Common . before ( this ) ) ; after ( Common . after ( this ) ) ; it ( 'should should open sidecar with diff view' , ( ) => CLI . command ( command , this . app ) . then ( ReplExpect . ok ) . then ( SidecarExpect . open ) . then ( SidecarExpect . mode ( mode ) ) . then ( SidecarExpect . textPlainContentFromMonaco ( textB ) ) . catch ( Common . oops ( this , true ) ) ) ; } ) ; } param buttons public toolbarButtons ( buttons ) { const { command , testName } = this . param ; describe ( `mmr toolbar buttons ${ testName || command || '' } ${ process . env . MOCHA_RUN_TARGET || '' }` , function ( this ) { before ( Common . before ( this ) ) ; after ( Common . after ( this ) ) ; let res ; it ( `should show toolbar buttons in sidecar ` , ( ) => CLI . command ( command , this . app ) . then ( ReplExpect . ok ) . then ( SidecarExpect . open ) . then ( appAndCount => { res = appAndCount ; return appAndCount ; } ) . then ( res => Promise . all ( buttons . map ( button => SidecarExpect . button ( button ) ( res ) ) ) ) . catch ( Common . oops ( this , true ) ) ) ; const drilldownButtons = buttons . filter ( _ => _ . kind === 'drilldown' ) ; if ( drilldownButtons . length > 0 ) { it ( `should drilldown toolbar buttons in sidecar` , async ( ) => { try { const { app , count } = await CLI . command ( command , this . app ) ; await ReplExpect . ok ( { app , count } ) ; await SidecarExpect . open ( { app , count } ) ; await Util . promiseEach ( drilldownButtons , async ( button , index ) => { const buttonSelector = Selectors . SIDECAR_TOOLBAR_BUTTON ( res . count , button . mode ) ; const buttonElt = await app . client . $ ( buttonSelector ) ; await CLI . waitForRepl ( this . app ) ; await buttonElt . waitForDisplayed ( ) ; await buttonElt . click ( ) ; if ( button . confirm ) { const denyItSel = Selectors . CONFIRM_DIALOG_CANCEL_BUTTON ; const confirmItSel = Selectors . CONFIRM_DIALOG_CONFIRM_BUTTON ; const [ denyIt , confirmIt ] = await Promise . all ( [ app . client . $ ( denyItSel ) , app . client . $ ( confirmItSel ) ] ) ; await Promise . all ( [ denyIt , confirmIt ] . map ( _ => _ . waitForDisplayed ( ) ) ) ; await denyIt . click ( ) ; await denyIt . waitForExist ( { timeout : 5000 , reverse : true } ) ; const nextPromptSelector = Selectors . PROMPT_N ( count + 1 + index + 1 ) ; await app . client . $ ( nextPromptSelector ) . then ( _ => _ . waitForExist ( { timeout : 5000 , reverse : true } ) ) ; await buttonElt . click ( ) ; const [ denyIt2 , confirmIt2 ] = await Promise . all ( [ app . client . $ ( denyItSel ) , app . client . $ ( confirmItSel ) ] ) ; await Promise . all ( [ denyIt2 , confirmIt2 ] . map ( _ => _ . waitForDisplayed ( ) ) ) ; await confirmIt2 . click ( ) ; } const promptSelector = Selectors . PROMPT_N ( count + 1 + index ) ; if ( ! button . expectError ) { await ReplExpect . ok ( { app , count : count + 1 + index } ) ; } else { await ReplExpect . error ( button . expectError ) ; } if ( typeof button . command === 'string' ) { await CLI . expectPriorInput ( promptSelector , button . command ) ( app ) ; } } ) ; } catch ( err ) { await Common . oops ( this , true ) ( err ) ; } } ) ; } } ) ; } param toolbarText public toolbarText ( toolbarText ) { const { command , testName } = this . param ; describe ( `mmr toolbar text ${ testName || command || '' } ${ process . env . MOCHA_RUN_TARGET || '' }` , function ( this ) { before ( Common . before ( this ) ) ; after ( Common . after ( this ) ) ; it ( `should show toolbar text in sidecar ` , ( ) => CLI . command ( command , this . app ) . then ( ReplExpect . ok ) . then ( SidecarExpect . open ) . then ( SidecarExpect . toolbarText ( toolbarText ) ) . catch ( Common . oops ( this , true ) ) ) ; } ) ; } public toolbarNotExist ( ) { const { command , testName } = this . param ; describe ( `mmr toolbar ${ testName || command || '' } ${ process . env . MOCHA_RUN_TARGET || '' }` , function ( this ) { before ( Common . before ( this ) ) ; after ( Common . after ( this ) ) ; it ( `should not show toolbar in sidecar ` , ( ) => CLI . command ( command , this . app ) . then ( ReplExpect . ok ) . then ( SidecarExpect . open ) . then ( res => this . app . client . $ ( Selectors . SIDECAR_TOOLBAR ( res . count ) ) . then ( _ => _ . waitForExist ( { timeout : CLI . waitTimeout , reverse : true } ) ) ) . catch ( Common . oops ( this , true ) ) ) ; } ) ; } } interface Label { mode : string ; label ? : string ; } interface PlainTextContent { content ? : string ; contentType : 'text/plain' | 'text/markdown' | 'text/html' | 'yaml' ; editor ? : false ; } interface ReactContent { selector : string ; innerText : string ; contentType : 'react' ; } interface TableContent { nRows : number ; nCells : number ; contentType : 'table' ; } interface YamlContentWithEditor { content : object ; contentType : 'yaml' ; editor : true ; } interface ClickExpect { command : string ; expect ? : string ; }