From 683f79964001dc0fe8c37994006b04ee39ff7992 Mon Sep 17 00:00:00 2001 From: Xiao Gui <xgui3783@gmail.com> Date: Wed, 25 Mar 2020 15:57:54 +0100 Subject: [PATCH] bugfix: some preview cannot be viewed --- .../advanced/browsingForDatasets.e2e-spec.js | 67 +++++++++++- e2e/src/advanced/favDatasets.e2e-spec.js | 17 ++- e2e/src/util.js | 101 ++++++++++++------ src/atlasViewer/atlasViewer.component.ts | 32 +----- src/services/state/uiState.store.ts | 53 ++++++--- .../databrowser.useEffect.ts | 3 +- .../kgSingleDatasetService.service.ts | 3 + 7 files changed, 185 insertions(+), 91 deletions(-) diff --git a/e2e/src/advanced/browsingForDatasets.e2e-spec.js b/e2e/src/advanced/browsingForDatasets.e2e-spec.js index d6ec2e810..b5cb270a7 100644 --- a/e2e/src/advanced/browsingForDatasets.e2e-spec.js +++ b/e2e/src/advanced/browsingForDatasets.e2e-spec.js @@ -24,7 +24,7 @@ const areasShouldHaveRecptor = [ 'Area FG2 (FusG)' ] -describe('dataset browser', () => { +describe('> dataset browser', () => { let iavPage beforeAll(async () => { iavPage = new AtlasPage() @@ -32,7 +32,7 @@ describe('dataset browser', () => { }) for (const template of templates) { - describe(`in template: ${template}`, () => { + describe(`> in template: ${template}`, () => { beforeAll(async () => { await iavPage.goto() await iavPage.selectTitleCard(template) @@ -45,7 +45,7 @@ describe('dataset browser', () => { await iavPage.clearAllSelectedRegions() }) for (const area of areasShouldHaveRecptor) { - it(`receptor data ${area} should be able to be found`, async () => { + it(`> receptor data ${area} should be able to be found`, async () => { await iavPage.searchRegionWithText(area) await iavPage.wait(2000) await iavPage.selectSearchRegionAutocompleteWithText() @@ -60,4 +60,65 @@ describe('dataset browser', () => { } }) } +}) + +const template = 'ICBM 2009c Nonlinear Asymmetric' +const area = 'Area hOc1 (V1, 17, CalcS)' + +const receptorName = `Density measurements of different receptors for Area hOc1 (V1, 17, CalcS) [human, v1.0]` + +describe('> dataset previews', () => { + let iavPage + beforeEach(async () => { + iavPage = new AtlasPage() + await iavPage.init() + await iavPage.goto() + await iavPage.selectTitleCard(template) + await iavPage.wait(500) + await iavPage.waitUntilAllChunksLoaded() + + await iavPage.searchRegionWithText(area) + await iavPage.wait(2000) + await iavPage.selectSearchRegionAutocompleteWithText() + await iavPage.dismissModal() + await iavPage.searchRegionWithText('') + + const datasets = await iavPage.getVisibleDatasets() + const receptorIndex = datasets.indexOf(receptorName) + + await iavPage.clickNthDataset(receptorIndex) + await iavPage.waitFor(true, true) + await iavPage.clickModalBtnByText(/preview/i) + await iavPage.waitFor(true, true) + }) + + describe('> can display graph', () => { + + it('> can display radar graph', async () => { + const files = await iavPage.getBottomSheetList() + const fingerprintIndex = files.findIndex(file => /fingerprint/i.test(file)) + await iavPage.clickNthItemFromBottomSheetList(fingerprintIndex) + await iavPage.waitFor(true, true) + const modalHasCanvas = await iavPage.modalHasChild('canvas') + expect(modalHasCanvas).toEqual(true) + }) + + it('> can display profile', async () => { + + const files = await iavPage.getBottomSheetList() + const profileIndex = files.findIndex(file => /profile/i.test(file)) + await iavPage.clickNthItemFromBottomSheetList(profileIndex) + await iavPage.waitFor(true, true) + const modalHasCanvas = await iavPage.modalHasChild('canvas') + expect(modalHasCanvas).toEqual(true) + }) + }) + it('> can display image', async () => { + const files = await iavPage.getBottomSheetList() + const imageIndex = files.findIndex(file => /image\//i.test(file)) + await iavPage.clickNthItemFromBottomSheetList(imageIndex) + await iavPage.waitFor(true, true) + const modalHasImage = await iavPage.modalHasChild('div[data-img-src]') + expect(modalHasImage).toEqual(true) + }) }) \ No newline at end of file diff --git a/e2e/src/advanced/favDatasets.e2e-spec.js b/e2e/src/advanced/favDatasets.e2e-spec.js index 9d71c8f87..5e35cabf7 100644 --- a/e2e/src/advanced/favDatasets.e2e-spec.js +++ b/e2e/src/advanced/favDatasets.e2e-spec.js @@ -27,19 +27,19 @@ describe(`fav'ing dataset`, () => { await iavPage.wait(500) await iavPage.clearAllSelectedRegions() }catch(e) { - + console.warn(`#afterEach error: clearing text field`, e) } try { await iavPage.showPinnedDatasetPanel() - const textsArr = await iavPage.getPinnedDatasetsFromOpenedPanel() + const textsArr = await iavPage.getBottomSheetList() let length = textsArr.length while(length > 0){ - await iavPage.unpinNthDatasetFromOpenedPanel(0) + await iavPage.clickNthItemFromBottomSheetList(0, `[aria-label="Toggle pinning this dataset"]`) length -- } }catch(e){ - + console.warn(`#afterEach error: unfav all`, e) } await iavPage.wait(500) @@ -71,7 +71,6 @@ describe(`fav'ing dataset`, () => { expect(txt2).toEqual(`Pinned dataset: ${pmapName}`) }) - describe('> fav dataset list', () => { beforeEach(async () => { @@ -98,7 +97,7 @@ describe(`fav'ing dataset`, () => { it('> clicking pin shows pinned datasets', async () => { await iavPage.showPinnedDatasetPanel() await iavPage.wait(500) - const textsArr = await iavPage.getPinnedDatasetsFromOpenedPanel() + const textsArr = await iavPage.getBottomSheetList() expect(textsArr.length).toEqual(2) expect(textsArr).toContain(receptorName) @@ -108,10 +107,10 @@ describe(`fav'ing dataset`, () => { it('> click unpin in fav data panel unpins, but also allow user to undo', async () => { await iavPage.showPinnedDatasetPanel() await iavPage.wait(1000) - const textsArr = await iavPage.getPinnedDatasetsFromOpenedPanel() + const textsArr = await iavPage.getBottomSheetList() const idx = textsArr.indexOf(receptorName) if (idx < 0) throw new Error(`index of receptor name not found: ${receptorName}: ${textsArr}`) - await iavPage.unpinNthDatasetFromOpenedPanel(idx) + await iavPage.clickNthItemFromBottomSheetList(idx, `[aria-label="Toggle pinning this dataset"]`) await iavPage.wait(500) const txt = await iavPage.getSnackbarMessage() @@ -123,7 +122,7 @@ describe(`fav'ing dataset`, () => { await iavPage.clickSnackbarAction() await iavPage.wait(500) - const textsArr3 = await iavPage.getPinnedDatasetsFromOpenedPanel() + const textsArr3 = await iavPage.getBottomSheetList() const number2 = await iavPage.getNumberOfFavDataset() expect(number2).toEqual(2) expect( diff --git a/e2e/src/util.js b/e2e/src/util.js index d1128db02..e8f4ece07 100644 --- a/e2e/src/util.js +++ b/e2e/src/util.js @@ -61,6 +61,23 @@ class WdBase{ }) } + async waitForAsync(){ + + const checkReady = async () => { + const el = await this._browser.findElements( + By.css('.spinnerAnimationCircle') + ) + return !el.length + } + + do { + // Do nothing, until ready + } while ( + await this.wait(100), + !(await checkReady()) + ) + } + async cursorMoveTo({ position }) { if (!position) throw new Error(`cursorGoto: position must be defined!`) const x = Array.isArray(position) ? position[0] : position.x @@ -128,6 +145,11 @@ class WdBase{ await this._browser.sleep(ms) } + async waitFor(animation = false, async = false){ + if (animation) await this.wait(500) + if (async) await this.waitForAsync() + } + async getSnackbarMessage(){ const txt = await this._driver .findElement( By.tagName('simple-snack-bar') ) @@ -143,6 +165,40 @@ class WdBase{ .click() } + _getBottomSheet() { + return this._driver.findElement( By.tagName('mat-bottom-sheet-container') ) + } + + _getBottomSheetList(){ + return this._getBottomSheet().findElements( By.tagName('mat-list-item') ) + } + + async getBottomSheetList(){ + const listItems = await this._getBottomSheetList() + const output = [] + for (const item of listItems) { + output.push( + await _getTextFromWebElement(item) + ) + } + return output + } + + async clickNthItemFromBottomSheetList(index, cssSelector){ + + const list = await this._getBottomSheetList() + + if (!list[index]) throw new Error(`index out of bound: ${index} in list with size ${list.length}`) + + if (cssSelector) { + await list[index] + .findElement( By.css(cssSelector) ) + .click() + } else { + await list[index].click() + } + } + async clearAlerts() { await this._driver .actions() @@ -193,6 +249,18 @@ class WdLayoutPage extends WdBase{ return arr } + async modalHasChild(cssSelector){ + try { + const isDisplayed = await this._getModal() + .findElement( By.css( cssSelector ) ) + .isDisplayed() + return isDisplayed + } catch (e) { + console.warn(`modalhaschild thrown error`, e) + return false + } + } + // text can be instance of regex or string async clickModalBtnByText(text){ const btns = await this._getModalBtns() @@ -355,39 +423,6 @@ class WdLayoutPage extends WdBase{ await this._getFavDatasetIcon().click() await this.wait(500) } - - _getPinnedDatasetPanel(){ - return this._driver - .findElement( - By.css('[aria-label="Pinned datasets panel"]') - ) - } - - async getPinnedDatasetsFromOpenedPanel(){ - const list = await this._getPinnedDatasetPanel() - .findElements( - By.tagName('mat-list-item') - ) - - const returnArr = [] - for (const el of list) { - const text = await _getTextFromWebElement(el) - returnArr.push(text) - } - return returnArr - } - - async unpinNthDatasetFromOpenedPanel(index){ - const list = await this._getPinnedDatasetPanel() - .findElements( - By.tagName('mat-list-item') - ) - - if (!list[index]) throw new Error(`index out of bound: ${index} in list with size ${list.length}`) - await list[index] - .findElement( By.css('[aria-label="Toggle pinning this dataset"]') ) - .click() - } } class WdIavPage extends WdLayoutPage{ diff --git a/src/atlasViewer/atlasViewer.component.ts b/src/atlasViewer/atlasViewer.component.ts index 94b0ced53..94466205b 100644 --- a/src/atlasViewer/atlasViewer.component.ts +++ b/src/atlasViewer/atlasViewer.component.ts @@ -29,7 +29,7 @@ import { AtlasViewerConstantsServices, UNSUPPORTED_INTERVAL, UNSUPPORTED_PREVIEW import { WidgetServices } from "./widgetUnit/widgetService.service"; import { LocalFileService } from "src/services/localFile.service"; -import { AGREE_COOKIE, AGREE_KG_TOS, SHOW_BOTTOM_SHEET, SHOW_KG_TOS } from "src/services/state/uiState.store"; +import { AGREE_COOKIE, AGREE_KG_TOS, SHOW_KG_TOS } from "src/services/state/uiState.store"; import { CLOSE_SIDE_PANEL, OPEN_SIDE_PANEL, @@ -39,7 +39,6 @@ import { getViewer, isSame } from "src/util/fn"; import { NehubaContainer } from "../ui/nehubaContainer/nehubaContainer.component"; import { colorAnimation } from "./atlasViewer.animation" import { MouseHoverDirective } from "src/util/directives/mouseOver.directive"; -import {MatBottomSheet, MatBottomSheetRef} from "@angular/material/bottom-sheet"; import {MatSnackBar, MatSnackBarRef} from "@angular/material/snack-bar"; import {MatDialog, MatDialogRef} from "@angular/material/dialog"; @@ -95,8 +94,6 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { private snackbarRef: MatSnackBarRef<any> public snackbarMessage$: Observable<string> - private bottomSheetRef: MatBottomSheetRef - private bottomSheet$: Observable<TemplateRef<any>> public dedicatedView$: Observable<string | null> public onhoverSegments$: Observable<string[]> @@ -138,8 +135,7 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { private dispatcher$: ActionsSubject, private rd: Renderer2, public localFileService: LocalFileService, - private snackbar: MatSnackBar, - private bottomSheet: MatBottomSheet + private snackbar: MatSnackBar ) { this.snackbarMessage$ = this.store.pipe( @@ -158,12 +154,6 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { distinctUntilChanged(), ) - this.bottomSheet$ = this.store.pipe( - select('uiState'), - select('bottomSheetTemplate'), - distinctUntilChanged(), - ) - /** * TODO deprecated */ @@ -255,24 +245,6 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { ) - this.subscriptions.push( - this.bottomSheet$.subscribe(templateRef => { - if (!templateRef) { - if (this.bottomSheetRef) { - this.bottomSheetRef.dismiss() - } - } else { - this.bottomSheetRef = this.bottomSheet.open(templateRef) - this.bottomSheetRef.afterDismissed().subscribe(() => { - this.store.dispatch({ - type: SHOW_BOTTOM_SHEET, - bottomSheetTemplate: null, - }) - this.bottomSheetRef = null - }) - } - }), - ) this.subscriptions.push( this.onhoverSegments$.subscribe(hr => { this.hoveringRegions = hr diff --git a/src/services/state/uiState.store.ts b/src/services/state/uiState.store.ts index 2340438b7..f02d62672 100644 --- a/src/services/state/uiState.store.ts +++ b/src/services/state/uiState.store.ts @@ -1,11 +1,12 @@ -import { Injectable, TemplateRef } from '@angular/core'; +import { Injectable, TemplateRef, OnDestroy } from '@angular/core'; import { Action, select, Store } from '@ngrx/store' -import { Effect } from "@ngrx/effects"; -import { Observable } from "rxjs"; +import { Effect, Actions, ofType } from "@ngrx/effects"; +import { Observable, Subscription } from "rxjs"; import { filter, map, mapTo, scan, startWith } from "rxjs/operators"; import { COOKIE_VERSION, KG_TOS_VERSION, LOCAL_STORAGE_CONST } from 'src/util/constants' import { IavRootStoreInterface } from '../stateStore.service' +import { MatBottomSheetRef, MatBottomSheet } from '@angular/material/bottom-sheet'; export const defaultState: StateInterface = { mouseOverSegments: [], @@ -20,7 +21,6 @@ export const defaultState: StateInterface = { sidePanelExploreCurrentViewIsOpen: false, snackbarMessage: null, - bottomSheetTemplate: null, pluginRegionSelectionEnabled: false, persistentStateNotifierMessage: null, @@ -143,13 +143,6 @@ export const getStateStore = ({ state = defaultState } = {}) => (prevState: Stat agreedKgTos: true, } } - case SHOW_BOTTOM_SHEET: { - const { bottomSheetTemplate } = action - return { - ...prevState, - bottomSheetTemplate, - } - } default: return prevState } } @@ -191,8 +184,6 @@ export interface StateInterface { agreedCookies: boolean agreedKgTos: boolean - - bottomSheetTemplate: TemplateRef<any> } export interface ActionInterface extends Action { @@ -216,7 +207,9 @@ export interface ActionInterface extends Action { providedIn: 'root', }) -export class UiStateUseEffect { +export class UiStateUseEffect implements OnDestroy{ + + private subscriptions: Subscription[] = [] private numRegionSelectedWithHistory$: Observable<any[]> @@ -226,7 +219,13 @@ export class UiStateUseEffect { @Effect() public viewCurrentOpen$: Observable<any> - constructor(store$: Store<IavRootStoreInterface>) { + private bottomSheetRef: MatBottomSheetRef + + constructor( + store$: Store<IavRootStoreInterface>, + actions$: Actions, + bottomSheet: MatBottomSheet + ) { this.numRegionSelectedWithHistory$ = store$.pipe( select('viewerState'), select('regionsSelected'), @@ -248,6 +247,30 @@ export class UiStateUseEffect { type: EXPAND_SIDE_PANEL_CURRENT_VIEW, }), ) + + this.subscriptions.push( + actions$.pipe( + ofType(SHOW_BOTTOM_SHEET) + ).subscribe(({ bottomSheetTemplate, config }) => { + if (!bottomSheetTemplate) { + if (this.bottomSheetRef) { + this.bottomSheetRef.dismiss() + this.bottomSheetRef = null + } + } else { + this.bottomSheetRef = bottomSheet.open(bottomSheetTemplate, config) + this.bottomSheetRef.afterDismissed().subscribe(() => { + this.bottomSheetRef = null + }) + } + }) + ) + } + + ngOnDestroy(){ + while(this.subscriptions.length > 0) { + this.subscriptions.pop().unsubscribe() + } } } diff --git a/src/ui/databrowserModule/databrowser.useEffect.ts b/src/ui/databrowserModule/databrowser.useEffect.ts index f202ab20c..b30394864 100644 --- a/src/ui/databrowserModule/databrowser.useEffect.ts +++ b/src/ui/databrowserModule/databrowser.useEffect.ts @@ -63,7 +63,8 @@ export class DataBrowserUseEffect implements OnDestroy { map((datasetPreviews) => datasetPreviews[datasetPreviews.length - 1]), switchMap(({ datasetId, filename }) =>{ const re = getKgSchemaIdFromFullId(datasetId) - return this.http.get(`${DATASET_PREVIEW_URL}/${re[1]}/${filename}`).pipe( + const url = `${DATASET_PREVIEW_URL}/${re[1]}/${encodeURIComponent(filename)}` + return this.http.get(url).pipe( filter((file: any) => PREVIEW_FILE_TYPES_NO_UI.indexOf( determinePreviewFileType(file) ) < 0), mapTo({ datasetId, diff --git a/src/ui/databrowserModule/kgSingleDatasetService.service.ts b/src/ui/databrowserModule/kgSingleDatasetService.service.ts index 0ad31491a..82d26d408 100644 --- a/src/ui/databrowserModule/kgSingleDatasetService.service.ts +++ b/src/ui/databrowserModule/kgSingleDatasetService.service.ts @@ -70,6 +70,9 @@ export class KgSingleDatasetService implements OnDestroy { this.store$.dispatch({ type: SHOW_BOTTOM_SHEET, bottomSheetTemplate: template, + config: { + ariaLabel: `List of preview files` + } }) } -- GitLab