import path from 'path' ; import os from 'os' ; import { exec } from 'child_process' ; import fs from 'fs' ; import { AppConstructorOptions , Application } from 'spectron' ; import assert from 'assert' ; import { IIdentity } from '@essential-projects/iam_contracts' ; import { SolutionExplorer } from './test-classes/solution-explorer' ; import { DesignViewClient } from './test-classes/design-view' ; function getUserConfigFolder ( ) { const userHomeDir = os . homedir ( ) ; switch ( process . platform ) { case 'darwin' : return path . join ( userHomeDir , 'Library' , 'Application Support' ) ; case 'win32' : return path . join ( userHomeDir , 'AppData' , 'Roaming' ) ; default : return path . join ( userHomeDir , '.config' ) ; } } const APP_BASE_URL = `file://${ __dirname }/../../../../index.html` ; const TESTS_FOLDER_PATH = path . join ( getUserConfigFolder ( ) , 'bpmn-studio-tests' ) ; const DATABASE_PATH = path . join ( TESTS_FOLDER_PATH , 'process_engine_databases' ) ; const SAVE_DIAGRAM_DIR = path . join ( TESTS_FOLDER_PATH , 'saved_diagrams' ) ; const VISIBLE_TIMEOUT = 40000 ; const REMOVE_COMMAND = process . platform === 'win32' ? 'rmdir /s /q' : 'rm -rf' ; export class TestClient { public solutionExplorer : SolutionExplorer = new SolutionExplorer ( this ) ; public designView : DesignViewClient = new DesignViewClient ( this , SAVE_DIAGRAM_DIR ) ; public creatingFirstDiagram : boolean = true ; private app : Application ; constructor ( applicationArgs ) { this . app = new Application ( applicationArgs ) ; } public async startSpectronApp ( ) { await this . app . start ( ) ; } public async awaitReadiness ( ) { await this . app . client . waitUntilWindowLoaded ( ) ; await this . app . browserWindow . isVisible ( ) ; } public async startPageLoaded ( ) { await this . ensureVisible ( '[data-test-start-page]' , VISIBLE_TIMEOUT ) ; } public async clickOnBpmnElementWithName ( name ) { await this . ensureVisible ( `.djs-label=${ name }` , VISIBLE_TIMEOUT ) ; await this . clickOn ( `.djs-label=${ name }` ) ; } public async assertCanvasModelIsVisible ( ) { const canvasModelIsVisible = await this . webdriverClient . isVisible ( '[data-test-canvas-model]' ) ; assert . equal ( canvasModelIsVisible , true ) ; } public async assertDiagramIsOnFileSystem ( ) { await this . ensureVisible ( '[data-test-navbar-icon-local-solution]' , VISIBLE_TIMEOUT ) ; } public async assertDiagramIsOnProcessEngine ( ) { await this . ensureVisible ( '[data-test-navbar-icon-remote-solution]' , VISIBLE_TIMEOUT ) ; } public async assertNavbarTitleIs ( name ) { await this . ensureVisible ( '[data-test-navbar-title]' , VISIBLE_TIMEOUT ) ; const navbarTitle = await this . getTextFromElement ( '[data-test-navbar-title]' ) ; assert . equal ( navbarTitle , name ) ; } public async assertDiagramIsSaved ( ) { await this . ensureNotVisible ( '[data-test-edited-label]' ) ; } public async assertDiagramIsUnsaved ( ) { await this . ensureVisible ( '[data-test-edited-label]' , VISIBLE_TIMEOUT ) ; } public async ensureVisible ( selector , timeout ? ) { return this . webdriverClient . waitForVisible ( selector , timeout ) ; } public async removeTestsFolder ( ) { await this . execCommand ( `${ REMOVE_COMMAND } ${ TESTS_FOLDER_PATH . replace ( /\s/g , '\\ ' ) }` ) ; } public async clearDatabase ( ) { if ( fs . existsSync ( DATABASE_PATH ) ) { try { await this . execCommand ( `${ REMOVE_COMMAND } ${ DATABASE_PATH . replace ( /\s/g , '\\ ' ) }` ) ; } catch ( error ) { console . error ( error ) ; } } } public async clearSavedDiagrams ( ) { if ( fs . existsSync ( SAVE_DIAGRAM_DIR ) ) { try { await this . execCommand ( `${ REMOVE_COMMAND } ${ SAVE_DIAGRAM_DIR . replace ( /\s/g , '\\ ' ) }` ) ; } catch ( error ) { console . error ( error ) ; } } } public async isSpectronAppRunning ( ) { return this . app . isRunning ( ) ; } public async stopSpectronApp ( ) { return this . app . stop ( ) ; } public get webdriverClient ( ) : any { return this . app . client ; } public async clickOn ( selector ) { return this . webdriverClient . $ ( selector ) . leftClick ( ) ; } public async openDesignView ( subPath , diagramName , diagramUri , solutionUri ? ) { const encodedName = encodeURIComponent ( diagramName ) ; const encodedUri = encodeURIComponent ( diagramUri ) ; const encodedSolutionUri = solutionUri ? encodeURIComponent ( solutionUri ) : '' ; const uriFragment = `#/design/${ subPath }/diagram/${ encodedName }?diagramUri=${ encodedUri }&solutionUri=${ encodedSolutionUri }` ; return this . openView ( uriFragment ) ; } public async openThinkView ( diagramName ? , diagramUri ? , solutionUri ? ) { if ( diagramName && diagramUri ) { const encodedName = encodeURIComponent ( diagramName ) ; const encodedUri = encodeURIComponent ( diagramUri ) ; const encodedSolutionUri = solutionUri ? encodeURIComponent ( solutionUri ) : '' ; const uriFragment = `#/think/diagram-list/diagram/${ encodedName }?diagramUri=${ encodedUri }&solutionUri=${ encodedSolutionUri }` ; await this . openView ( uriFragment ) ; } else { await this . openView ( '#/think/diagram-list/diagram' ) ; } await this . ensureVisible ( 'diagram-list' , VISIBLE_TIMEOUT ) ; } public async openThinkViewFromNavbar ( ) { await this . ensureVisible ( '[data-test-navbar="Think"]' , VISIBLE_TIMEOUT ) ; await this . clickOn ( '[data-test-navbar="Think"]' ) ; await this . ensureVisible ( 'diagram-list' , VISIBLE_TIMEOUT ) ; } public async openStartPage ( ) { return this . openView ( '' ) ; } public async createAndOpenNewDiagram ( ) { if ( ! this . creatingFirstDiagram ) { await this . openStartPage ( ) ; } await this . ensureVisible ( '[data-test-create-new-diagram]' , VISIBLE_TIMEOUT ) ; await this . clickOn ( '[data-test-create-new-diagram]' ) ; await this . ensureVisible ( '[data-test-navbar-title]' , VISIBLE_TIMEOUT ) ; } public async assertSelectedBpmnElementHasName ( name ) { await this . ensureVisible ( '[data-test-property-panel-element-name]' , VISIBLE_TIMEOUT ) ; const selectedElementText = await this . getValueFromElement ( '[data-test-property-panel-element-name]' ) ; assert . equal ( selectedElementText , name ) ; } public async rejectSelectedBpmnElementHasName ( name ) { await this . ensureVisible ( '[data-test-property-panel-element-name]' , VISIBLE_TIMEOUT ) ; const selectedElementText = await this . getValueFromElement ( '[data-test-property-panel-element-name]' ) ; assert . notEqual ( selectedElementText , name ) ; } public async assertDiffViewHasRenderedAllContainer ( ) { const leftDiffViewContainerIsVisible = await this . webdriverClient . isVisible ( '[data-test-left-diff-view]' ) ; const rightDiffViewContainerIsVisible = await this . webdriverClient . isVisible ( '[data-test-right-diff-view]' ) ; const lowerDiffViewContainerIsVisible = await this . webdriverClient . isVisible ( '[data-test-lower-diff-view]' ) ; assert . equal ( leftDiffViewContainerIsVisible , true ) ; assert . equal ( rightDiffViewContainerIsVisible , true ) ; assert . equal ( lowerDiffViewContainerIsVisible , true ) ; } public async elementHasText ( selector , text ) { return this . webdriverClient . waitUntilTextExists ( selector , text ) ; } public async assertWindowTitleIs ( name ) { const windowTitle = await this . webdriverClient . getTitle ( ) ; assert . equal ( windowTitle , name ) ; } public async pause ( timeInMilliseconds ) { await new Promise ( ( c ) : any => setTimeout ( c , timeInMilliseconds ) ) ; } public async getElement ( selector ) { return this . webdriverClient . element ( selector ) ; } public async getElements ( selector ) { return this . webdriverClient . elements ( selector ) ; } public async getAttributeFromElement ( selector , attribute ) { return this . webdriverClient . getAttribute ( selector , attribute ) ; } public async getTextFromElement ( selector ) { return this . webdriverClient . getText ( selector ) ; } public async getValueFromElement ( selector ) { return this . webdriverClient . getValue ( selector ) ; } public async ensureNotVisible ( selector ) { const collection = await this . webdriverClient . elements ( selector ) ; return collection . value . length === 0 ; } public getDefaultIdentity ( ) { const identity = { token : 'ZHVtbXlfdG9rZW4=' , userId : '' , } ; return identity ; } public async openView ( uriPath ) { try { await this . app . browserWindow . loadURL ( `${ APP_BASE_URL }${ uriPath }` ) ; } catch ( error ) { const errorIsNavigatedError = error . message . includes ( 'Inspected target navigated or closed' ) ; if ( ! errorIsNavigatedError ) { throw error ; } } } private async execCommand ( command ) { return new Promise ( ( resolve , reject ) : any => { exec ( command , ( err , stdin , stderr ) => { if ( err || stderr ) { reject ( err , stderr ) ; } return resolve ( stdin ) ; } ) ; } ) ; } }