diff --git a/e2e/src/basic/layout.e2e-spec.js b/e2e/src/basic/layout.e2e-spec.js index 9a138808d657648f486a80e7b1b7453ca97d39e6..148a11d4c32867bdc26c5d4adc42872ce7aef5cc 100644 --- a/e2e/src/basic/layout.e2e-spec.js +++ b/e2e/src/basic/layout.e2e-spec.js @@ -4,8 +4,6 @@ const MAT_SIDENAV_TIMEOUT = 500 describe('> sidenav', () => { let layoutPage - let toggleTab - let sidenav beforeEach(async () => { layoutPage = new LayoutPage() @@ -13,32 +11,29 @@ describe('> sidenav', () => { await layoutPage.goto('/?templateSelected=MNI+152+ICBM+2009c+Nonlinear+Asymmetric&parcellationSelected=JuBrain+Cytoarchitectonic+Atlas') await layoutPage.wait(MAT_SIDENAV_TIMEOUT) await layoutPage.dismissModal() - - toggleTab = await layoutPage.getSideNavTag() - sidenav = await layoutPage.getSideNav() }) it('> on init, side panel should be visible', async () => { - const sideNavIsDisplayed = await sidenav.isDisplayed() + const sideNavIsDisplayed = await layoutPage.sideNavIsVisible() expect(sideNavIsDisplayed).toEqual(true) - const toggleTabIsDIsplayed = await toggleTab.isDisplayed() + const toggleTabIsDIsplayed = await layoutPage.sideNavTabIsVisible() expect(toggleTabIsDIsplayed).toEqual(true) }) describe('> toggling', () => { it('> toggle tab should toggle side nav', async () => { - const init = await sidenav.isDisplayed() + const init = await layoutPage.sideNavIsVisible() expect(init).toEqual(true) - await toggleTab.click() + await layoutPage.clickSideNavTab() await layoutPage.wait(MAT_SIDENAV_TIMEOUT) - const expectHidden = await sidenav.isDisplayed() + const expectHidden = await layoutPage.sideNavIsVisible() expect(expectHidden).toEqual(false) - await toggleTab.click() + await layoutPage.clickSideNavTab() await layoutPage.wait(MAT_SIDENAV_TIMEOUT) - const expectShown = await sidenav.isDisplayed() + const expectShown = await layoutPage.sideNavIsVisible() expect(expectShown).toEqual(true) }) }) @@ -47,8 +42,6 @@ describe('> sidenav', () => { describe('> status panel', () => { let layoutPage - let toggleTab - let sidenav beforeEach(async () => { layoutPage = new LayoutPage() @@ -56,60 +49,38 @@ describe('> status panel', () => { await layoutPage.goto('/?templateSelected=MNI+152+ICBM+2009c+Nonlinear+Asymmetric&parcellationSelected=JuBrain+Cytoarchitectonic+Atlas') await layoutPage.wait(MAT_SIDENAV_TIMEOUT) await layoutPage.dismissModal() - - toggleTab = await layoutPage.getSideNavTag() - sidenav = await layoutPage.getSideNav() - }) afterEach(() => { layoutPage = null - toggleTab = null - sidenav = null - statusPanel = null }) it('> on init, status panel should not be visible', async () => { - let statusPanel - try { - statusPanel = await layoutPage.getStatusPanel() - } catch (e) { - - } - - if (statusPanel) { - const init = await statusPanel.isDisplayed() - expect(init).toEqual(false) - } + + const init = await layoutPage.statusPanelIsVisible() + expect(init).toEqual(false) }) it('> on toggling side panel, status panel should become visible', async () => { - await toggleTab.click() + await layoutPage.clickSideNavTab() await layoutPage.wait(MAT_SIDENAV_TIMEOUT) - const statusPanel = await layoutPage.getStatusPanel() - const expectVisible = await statusPanel.isDisplayed() + const expectVisible = await layoutPage.statusPanelIsVisible() expect(expectVisible).toEqual(true) }) it('> on click status panel, side nav become visible, status panel become invisible', async () => { - await toggleTab.click() + await layoutPage.clickSideNavTab() await layoutPage.wait(MAT_SIDENAV_TIMEOUT) - - const statusPanel = await layoutPage.getStatusPanel() - - await statusPanel.click() + + await layoutPage.clickStatusPanel() await layoutPage.wait(MAT_SIDENAV_TIMEOUT) - try { - const expectHidden = await statusPanel.isDisplayed() - expect(expectHidden).toEqual(false) - } catch (e) { - - } - - const expectVisible = await sidenav.isDisplayed() + const expectHidden = await layoutPage.statusPanelIsVisible() + expect(expectHidden).toEqual(false) + + const expectVisible = await layoutPage.sideNavIsVisible() expect(expectVisible).toEqual(true) }) }) diff --git a/e2e/src/util.js b/e2e/src/util.js index b43524d943ba41018329e023a37d55450f0d7f5a..7baa48efaf3a26b3a1e1028e9b36ee99480b4b95 100644 --- a/e2e/src/util.js +++ b/e2e/src/util.js @@ -10,9 +10,13 @@ function getActualUrl(url) { return /^http\:\/\//.test(url) ? url : `${ATLAS_URL}/${url.replace(/^\//, '')}` } -async function getIndexFromArrayOfWebElements(search, webElements) { +function _getTextFromWebElement(webElement) { + return webElement.getText() +} + +async function _getIndexFromArrayOfWebElements(search, webElements) { const texts = await Promise.all( - webElements.map(e => e.getText()) + webElements.map(_getTextFromWebElement) ) return texts.findIndex(text => text.indexOf(search) >= 0) } @@ -23,24 +27,24 @@ class WdBase{ constructor() { browser.waitForAngularEnabled(false) } - get browser(){ + get _browser(){ return browser } - get driver(){ - return this.browser.driver + get _driver(){ + return this._browser.driver } async init() { const wSizeArg = chromeOpts.find(arg => arg.indexOf('--window-size') >= 0) const [ _, width, height ] = /\=([0-9]{1,})\,([0-9]{1,})$/.exec(wSizeArg) - const newDim = await this.browser.executeScript(async () => { + const newDim = await this._browser.executeScript(async () => { return [ window.outerWidth - window.innerWidth + (+ arguments[0]), window.outerHeight - window.innerHeight + (+ arguments[1]), ] }, width, height) - await this.browser.manage() + await this._browser.manage() .window() .setRect({ width: newDim[0], @@ -55,7 +59,7 @@ class WdBase{ if (!x) throw new Error(`cursorGoto: position.x or position[0] must be defined`) if (!y) throw new Error(`cursorGoto: position.y or position[1] must be defined`) - return this.driver.actions() + return this._driver.actions() .move() .move({ x, @@ -66,7 +70,7 @@ class WdBase{ } async initHttpInterceptor(){ - await this.browser.executeScript(() => { + await this._browser.executeScript(() => { if (window.__isIntercepting__) return window.__isIntercepting__ = true const open = window.XMLHttpRequest.prototype.open @@ -82,23 +86,23 @@ class WdBase{ } async isHttpIntercepting(){ - return await this.browser.executeScript(() => { + return await this._browser.executeScript(() => { return window.__isIntercepting__ }) } async getInterceptedHttpCalls(){ - return await this.browser.executeScript(() => { + return await this._browser.executeScript(() => { return window['__interceptedXhr__'] }) } async goto(url = '/', { interceptHttp, doNotAutomate } = {}){ const actualUrl = getActualUrl(url) if (interceptHttp) { - this.browser.get(actualUrl) + this._browser.get(actualUrl) await this.initHttpInterceptor() } else { - await this.browser.get(actualUrl) + await this._browser.get(actualUrl) } if (!doNotAutomate) { @@ -110,7 +114,7 @@ class WdBase{ async wait(ms) { if (!ms) throw new Error(`wait duration must be specified!`) - await this.browser.sleep(ms) + await this._browser.sleep(ms) } } @@ -120,18 +124,10 @@ class WdLayoutPage extends WdBase{ super() } - async findElement(selector){ - return await this.browser.findElement( By.css(selector) ) - } - - async getModal() { - return await this.browser.findElement( By.tagName('mat-dialog-container') ) - } - async dismissModal() { try { - const modal = await this.getModal() - const okBtn = await modal + const okBtn = await this._browser + .findElement( By.tagName('mat-dialog-container') ) .findElement( By.tagName('mat-dialog-actions') ) .findElement( By.css('button[color="primary"]') ) await okBtn.click() @@ -140,46 +136,77 @@ class WdLayoutPage extends WdBase{ } } - async findTitleCards() { - return await this.browser + async _findTitleCard(title) { + const titleCards = await this._browser .findElement( By.tagName('ui-splashscreen') ) .findElements( By.tagName('mat-card') ) - } - - async findTitleCard(title) { - const titleCards = await this.findTitleCards() - const idx = await getIndexFromArrayOfWebElements(title, titleCards) + const idx = await _getIndexFromArrayOfWebElements(title, titleCards) if (idx >= 0) return titleCards[idx] else throw new Error(`${title} does not fit any titleCards`) } async selectTitleCard( title ) { - const titleCard = await this.findTitleCard(title) + const titleCard = await this._findTitleCard(title) await titleCard.click() } async selectTitleTemplateParcellation(templateName, parcellationName){ - const titleCard = await this.findTitleCard(templateName) + const titleCard = await this._findTitleCard(templateName) const parcellations = await titleCard .findElement( By.css('mat-card-content.available-parcellations-container') ) .findElements( By.tagName('button') ) - const idx = await getIndexFromArrayOfWebElements( parcellationName, parcellations ) + const idx = await _getIndexFromArrayOfWebElements( parcellationName, parcellations ) if (idx >= 0) await parcellations[idx].click() else throw new Error(`parcellationName ${parcellationName} does not exist`) } - async getSideNav() { - return await this.browser.findElement( By.tagName('search-side-nav') ) + + // SideNav + _getSideNav() { + return this._browser.findElement( By.tagName('search-side-nav') ) } async getSideNavTag(){ - return await this.browser + return await this._browser + .findElement( By.css('[mat-drawer-trigger]') ) + .findElement( By.tagName('i') ) + } + + sideNavIsVisible(){ + return this._getSideNav().isDisplayed() + } + + // SideNavTag + _getSideNavTab(){ + return this._browser .findElement( By.css('[mat-drawer-trigger]') ) .findElement( By.tagName('i') ) } - async getStatusPanel(){ - return await this.browser.findElement( By.css('[mat-drawer-status-panel]') ) + sideNavTabIsVisible(){ + return this._getSideNavTab().isDisplayed() + } + + clickSideNavTab(){ + return this._getSideNavTab().click() + } + + // statusPanel + _getStatusPanel(){ + return this._browser.findElement( By.css('[mat-drawer-status-panel]') ) + } + + async statusPanelIsVisible() { + try { + return await this._getStatusPanel().isDisplayed() + } catch (e) { + return false + } + } + + clickStatusPanel() { + // Will throw if status panel is not visible + return this._getStatusPanel().click() } } @@ -189,7 +216,7 @@ class WdIavPage extends WdLayoutPage{ } async clearAllSelectedRegions() { - const clearAllRegionBtn = await this.browser.findElement( + const clearAllRegionBtn = await this._browser.findElement( By.css('[aria-label="Clear all regions"]') ) await clearAllRegionBtn.click() @@ -198,7 +225,7 @@ class WdIavPage extends WdLayoutPage{ async waitUntilAllChunksLoaded(){ const checkReady = async () => { - const el = await this.browser.findElements( + const el = await this._browser.findElements( By.css('div.loadingIndicator') ) return !el.length @@ -213,7 +240,7 @@ class WdIavPage extends WdLayoutPage{ } async getFloatingCtxInfoAsText(){ - const floatingContainer = await this.browser.findElement( + const floatingContainer = await this._browser.findElement( By.css('div[floatingMouseContextualContainerDirective]') ) @@ -222,26 +249,26 @@ class WdIavPage extends WdLayoutPage{ } async selectDropdownTemplate(title) { - const templateBtn = await (await this.getSideNav()) + const templateBtn = await this._getSideNav() .findElement( By.tagName('viewer-state-controller') ) .findElement( By.css('[aria-label="Select a new template"]') ) await templateBtn.click() - const options = await this.browser.findElements( + const options = await this._browser.findElements( By.tagName('mat-option') ) - const idx = await getIndexFromArrayOfWebElements(title, options) + const idx = await _getIndexFromArrayOfWebElements(title, options) if (idx >= 0) await options[idx].click() else throw new Error(`${title} is not found as one of the dropdown templates`) } - async getSearchRegionInput(){ - return await (await this.getSideNav()) + _getSearchRegionInput(){ + return this._getSideNav() .findElement( By.css(`[aria-label="${regionSearchAriaLabelText}"]`) ) } async searchRegionWithText(text=''){ - const searchRegionInput = await this.getSearchRegionInput() + const searchRegionInput = await this._getSearchRegionInput() await searchRegionInput .sendKeys( Key.chord(Key.CONTROL, 'a'), @@ -250,7 +277,7 @@ class WdIavPage extends WdLayoutPage{ } async clearSearchRegionWithText() { - const searchRegionInput = await this.getSearchRegionInput() + const searchRegionInput = await this._getSearchRegionInput() await searchRegionInput .sendKeys( Key.chord(Key.CONTROL, 'a'), @@ -259,27 +286,36 @@ class WdIavPage extends WdLayoutPage{ ) } + async _getAutcompleteOptions(){ + const input = await this._getSearchRegionInput() + const autocompleteId = await input.getAttribute('aria-owns') + const el = await this._browser.findElement( By.css( `[id=${autocompleteId}]` ) ) + return this._browser + .findElement( By.id( autocompleteId ) ) + .findElements( By.tagName('mat-option') ) + } + async getSearchRegionInputAutoCompleteOptions(){ + const options = await this._getAutcompleteOptions() + return await Promise.all( + options.map(_getTextFromWebElement) + ) } async selectSearchRegionAutocompleteWithText(text = ''){ - const input = await this.getSearchRegionInput() - const autocompleteId = await input.getAttribute('aria-owns') - const options = await this.browser - .findElement( By.id( autocompleteId ) ) - .findElements( By.tagName('mat-option') ) + const options = await this._getAutcompleteOptions() - const idx = await getIndexFromArrayOfWebElements(text, options) + const idx = await _getIndexFromArrayOfWebElements(text, options) if (idx >= 0) { await options[idx].click() } else { - throw new Error(`getIndexFromArrayOfWebElements ${text} option not founds`) + throw new Error(`_getIndexFromArrayOfWebElements ${text} option not founds`) } } async getVisibleDatasets() { - const singleDatasetListView = await this.browser + const singleDatasetListView = await this._browser .findElement( By.tagName('data-browser') ) .findElement( By.css('div.cdk-virtual-scroll-content-wrapper') ) .findElements( By.tagName('single-dataset-list-view') ) @@ -292,7 +328,7 @@ class WdIavPage extends WdLayoutPage{ } async viewerIsPopulated() { - const ngContainer = await this.browser.findElement( + const ngContainer = await this._browser.findElement( By.id('neuroglancer-container') ) const canvas = await ngContainer.findElement( @@ -302,7 +338,7 @@ class WdIavPage extends WdLayoutPage{ } async getNavigationState() { - const actualNav = await this.browser.executeScript(async () => { + const actualNav = await this._browser.executeScript(async () => { let returnObj, sub const getPr = () => new Promise(rs => { @@ -332,15 +368,15 @@ class WdIavPage extends WdLayoutPage{ class PptrIAVPage{ constructor(){ - this.browser = null - this.page = null + this._browser = null + this._page = null } async init() { - this.browser = browser + this._browser = browser - this.page = await this.browser.newPage() - await this.page.setViewport({ + this._page = await this._browser.newPage() + await this._page.setViewport({ width: 1600, height: 900 }) @@ -348,29 +384,15 @@ class PptrIAVPage{ async goto(url = '/') { const actualUrl = getActualUrl(url) - await this.page.goto(actualUrl, { waitUntil: 'networkidle2' }) + await this._page.goto(actualUrl, { waitUntil: 'networkidle2' }) } async wait(ms) { if (!ms) throw new Error(`wait duration must be specified!`) - await this.page.waitFor(ms) + await this._page.waitFor(ms) } } -exports.getSearchParam = page => { - return page.evaluate(`window.location.search`) -} - -exports.wait = (browser) => new Promise(resolve => { - - /** - * TODO figure out how to wait until the select parcellation is populated - */ - - browser.sleep(1000) - .then(resolve) -}) - exports.waitMultiple = process.env.WAIT_ULTIPLE || 1 exports.AtlasPage = WdIavPage