diff --git a/common/constants.js b/common/constants.js index dc425aa2e0f37b9ed4ff0353e137d7fb3335b3d8..a2809d6b76625aaef42c4fa54abc3c668dd3747c 100644 --- a/common/constants.js +++ b/common/constants.js @@ -21,7 +21,7 @@ CLEAR_SELECTED_REGION: 'Clear selected region', // overlay/layout specific - SELECT_ATLAS: 'Select a different atlas', + SELECT_ATLAS: 'Atlas', CONTEXT_MENU: `Viewer context menu`, TOGGLE_FRONTAL_OCTANT: `Toggle perspective view frontal octant`, ZOOM_IN: 'Zoom in', diff --git a/e2e/src/selecting/region.prod.e2e-spec.js b/e2e/src/selecting/region.prod.e2e-spec.js index de84b5b93fa6e043c42fd28d9602305e0769aa24..d2f63699d7a34f2094914815620890d4031833d1 100644 --- a/e2e/src/selecting/region.prod.e2e-spec.js +++ b/e2e/src/selecting/region.prod.e2e-spec.js @@ -40,14 +40,38 @@ describe('> selecting regions', () => { describe('> [bkwdCompat] multi region select is handled gracefully', () => { const url = `?templateSelected=Waxholm+Space+rat+brain+MRI%2FDTI&parcellationSelected=Waxholm+Space+rat+brain+atlas+v2&cRegionsSelected=%7B%22v2%22%3A%2213.a.b.19.6.c.q.x.1.1L.Y.1K.r.s.y.z._.1G.-.Z.18.v.f.g.1J.1C.k.14.15.7.1E.1F.10.11.12.1D.1S.A.1V.1W.1X.1Y.1Z.1a.1i.1j.1k.1m.1n.1o.1p.U.V.W.3.1I.e.d.1T.1H.m.h.n.1U.o.t.2.17.p.w.4.5.1A.1B.u.l.j.16%22%7D&cNavigation=0.0.0.-W000..2-8Bnd.2_tvb9._yymE._tYzz..1Sjt..9Hnn%7E.Lqll%7E.Vcf..9fo` - it('> handles waxholm v2 whole brains election', async () => { - const newPage = new AtlasPage() + + const humanAtlasName = `Multilevel Human Atlas` + let newPage = new AtlasPage() + beforeAll(async () => { await newPage.init() await newPage.goto(url) + /** + * clear cookie alert + */ + await newPage.clearAlerts() + await newPage.wait(500) + /** + * clear KG ToS alert + */ + await newPage.clearAlerts() + }) + it('> handles waxholm v2 whole brains election', async () => { const allChipsVisibility = await newPage.getAllChipsVisibility() expect(allChipsVisibility.filter(v => !!v).length).toEqual(2) const allChipsText = await newPage.getAllChipsText() expect(allChipsText).toContain(CONST.MULTI_REGION_SELECTION) }) + + it('> on change atlas, multi region panel are dismissed', async () => { + await newPage.selectAtlasTemplateParcellation(humanAtlasName) + await newPage.wait(500) + await newPage.waitForAsync() + + const allChipsVisibility = await newPage.getAllChipsVisibility() + expect(allChipsVisibility.filter(v => !!v).length).toEqual(1) + const allChipsText = await newPage.getAllChipsText() + expect(allChipsText).not.toContain(CONST.MULTI_REGION_SELECTION) + }) }) }) diff --git a/e2e/util/selenium/layout.js b/e2e/util/selenium/layout.js index c60043ad398887dd3f39a4371713a0bd79b3fd4c..d3891a351d79cb5dde32f34e357ad5f656f54dbf 100644 --- a/e2e/util/selenium/layout.js +++ b/e2e/util/selenium/layout.js @@ -1,7 +1,8 @@ const { WdBase } = require('./base') const { _getIndexFromArrayOfWebElements, - _getTextFromWebElement + _getTextFromWebElement, + _compareText } = require('./util') const { ARIA_LABELS } = require('../../../common/constants') @@ -10,6 +11,42 @@ class WdLayoutPage extends WdBase{ super() } + /** + * Dropdown + */ + /** + * + * @param {string} cssSelector for the mat-select DOM element + * @param {string|RegExp} optionStrRegExp substring that option's text node contains, or regexp whose .test method will be called on text node of the option + * @returns void + * @description finds a mat-select DOM element, then selects a mat-option attached to the mat-select element + */ + async selectDropdownOption(cssSelector, optionStrRegExp){ + if (!cssSelector) throw new Error(`cssSelector is required for selectDropdownOption method`) + const selectEl = await this._browser.findElement( + By.css(cssSelector) + ) + if (!selectEl) throw new Error(`element with ${cssSelector} could not be found`) + const tagName = await selectEl.getTagName() + if (tagName !== 'mat-select') throw new Error(`cssSelector ${cssSelector} did not return a mat-select element, but returned a tagName element`) + await selectEl.click() + await this.wait(500) + const ariaOwnsAttr = await selectEl.getAttribute('aria-owns') + + const opts = [] + for (const ariaOwnEntry of ariaOwnsAttr.split(' ')) { + const matOpt = await this._browser.findElement( + By.css(`mat-option#${ariaOwnEntry}`) + ) + const txt = await matOpt.getText() + if (_compareText(txt, optionStrRegExp)) { + await matOpt.click() + return + } + } + throw new Error(`option ${optionStrRegExp} not found.`) + } + /** * Snackbar */ @@ -292,6 +329,7 @@ class WdLayoutPage extends WdBase{ * if not at title screen * select from dropdown */ + await this.selectDropdownOption(`[aria-label="${ARIA_LABELS.SELECT_ATLAS}"]`, atlasName) } if (templateName) { diff --git a/e2e/util/selenium/util.js b/e2e/util/selenium/util.js index b08adb34bea8a064c397a9ab76209c4f73cf65d4..07aadf6a27365d35aa076a368b12e66583c6d760 100644 --- a/e2e/util/selenium/util.js +++ b/e2e/util/selenium/util.js @@ -12,7 +12,14 @@ async function _getIndexFromArrayOfWebElements(search, webElements) { : text.indexOf(search) >= 0) } +function _compareText(textString, testStrRegExp){ + return testStrRegExp instanceof RegExp + ? testStrRegExp.test(textString) + : textString.indexOf(testStrRegExp) >= 0 +} + module.exports = { _getTextFromWebElement, - _getIndexFromArrayOfWebElements + _getIndexFromArrayOfWebElements, + _compareText } \ No newline at end of file diff --git a/src/services/effect/effect.ts b/src/services/effect/effect.ts index 76f12e022c52776bc96b386ae473b5f433717784..c206014533f352a8530b8b232b2b96141a05b8e8 100644 --- a/src/services/effect/effect.ts +++ b/src/services/effect/effect.ts @@ -6,7 +6,7 @@ import { filter, map, shareReplay, switchMap, take, withLatestFrom, mapTo, disti import { LoggingService } from "src/logging"; import { ADD_TO_REGIONS_SELECTION_WITH_IDS, DESELECT_REGIONS, NEWVIEWER, SELECT_PARCELLATION, SELECT_REGIONS, SELECT_REGIONS_WITH_ID, SELECT_LANDMARKS } from "../state/viewerState.store"; import { generateLabelIndexId, getNgIdLabelIndexFromId, IavRootStoreInterface, recursiveFindRegionWithLabelIndexId } from '../stateStore.service'; -import { viewerStateSetSelectedRegionsWithIds, viewerStateToggleLayer } from "../state/viewerState.store.helper"; +import { viewerStateSelectAtlas, viewerStateSetSelectedRegionsWithIds, viewerStateToggleLayer } from "../state/viewerState.store.helper"; @Injectable({ providedIn: 'root', @@ -213,13 +213,16 @@ export class UseEffects implements OnDestroy { * side effect of selecting a parcellation means deselecting all regions */ @Effect() - public onParcellationSelected$ = merge( + public onParcChange$ = merge( this.actions$.pipe( ofType(viewerStateToggleLayer.type) ), this.parcellationSelected$, this.actions$.pipe( ofType(NEWVIEWER) + ), + this.actions$.pipe( + ofType(viewerStateSelectAtlas) ) ).pipe( mapTo({ diff --git a/src/ui/atlasDropdown/atlasDropdown.component.ts b/src/ui/atlasDropdown/atlasDropdown.component.ts index e8949f2aef61976866a2ea684a9c6906557d327f..c44816155bcbb23701aa04e7a9de767b70dd056f 100644 --- a/src/ui/atlasDropdown/atlasDropdown.component.ts +++ b/src/ui/atlasDropdown/atlasDropdown.component.ts @@ -4,6 +4,7 @@ import { Observable } from "rxjs"; import { distinctUntilChanged } from "rxjs/operators"; import { viewerStateHelperStoreName, viewerStateSelectAtlas } from "src/services/state/viewerState.store.helper"; import { ARIA_LABELS } from 'common/constants' +import { viewerStateGetSelectedAtlas } from "src/services/state/viewerState/selectors"; @Component({ selector: 'atlas-dropdown-selector', @@ -27,11 +28,7 @@ export class AtlasDropdownSelector{ distinctUntilChanged() ) this.selectedAtlas$ = this.store$.pipe( - select(viewerStateHelperStoreName), - distinctUntilChanged(), - select(({ selectedAtlasId, fetchedAtlases }) => { - return fetchedAtlases.find(atlas => atlas['@id'] === selectedAtlasId) - }) + select(viewerStateGetSelectedAtlas) ) } diff --git a/src/ui/atlasDropdown/atlasDropdown.template.html b/src/ui/atlasDropdown/atlasDropdown.template.html index 12c30c3a5d8a64f7531f77cf584e2a100a7feff2..3516dc424273afd50b6f98a4bf04d6d94f3d2455 100644 --- a/src/ui/atlasDropdown/atlasDropdown.template.html +++ b/src/ui/atlasDropdown/atlasDropdown.template.html @@ -1,9 +1,9 @@ <mat-form-field> <mat-label> - Atlas + {{ SELECT_ATLAS_ARIA_LABEL }} </mat-label> <mat-select - [attr.aria-label]="SELECT_ATLAS_ARIA_LABEL" + [aria-label]="SELECT_ATLAS_ARIA_LABEL" [value]="selectedAtlas$ | async | mapToProperty" (selectionChange)="handleChangeAtlas($event)"> <mat-option