diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index e8f8aed0c0c4717bc1eaf2f9c09d52c7548c33ec..207bf47c85ba30ea9c8454a71c6fa176689957ba 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -6,11 +6,11 @@ on: - dev env: - DOCKER_IMAGE_NAME: interactive-viewer + DOCKER_IMAGE_NAME: gha-iav-image DOCKER_IMAGE_TAG: ${{ github.sha }} DOCKER_CONTAINER_NAME: gha-iav-built-${{ github.sha }} DOCKER_E2E_PPTR: gha-iav-e2e-pptr-${{ github.sha }} - DOCKER_E2E_NETWORK: gha-dkr-network-${{ github.sha }} + DOCKER_E2E_NETWORK: gha-dkr-network ATLAS_URL: http://gha-iav-built-${{ github.sha }}:3000/ jobs: @@ -33,6 +33,10 @@ jobs: runs-on: self-hosted needs: buildimage steps: + - name: clean up previous + run: | + GHA_CONTAINERS=$( docker ps | grep gha | awk '{print $1}' ) + if [ -z "$GHA_CONTAINERS" ]; then for f in $GHA_CONTAINERS; do docker stop $f; done; fi - name: run docker image ${{ env.DOCKER_IMAGE_NAME }}:${{ env.DOCKER_IMAGE_TAG }} as container ${{ env.DOCKER_CONTAINER_NAME }} run: | docker run \ @@ -58,16 +62,17 @@ jobs: docker exec -t ${DOCKER_E2E_PPTR} npm i puppeteer - name: Setup docker network run: | - docker network create ${{ env.DOCKER_E2E_NETWORK }} docker network connect ${{ env.DOCKER_E2E_NETWORK }} ${{ env.DOCKER_E2E_PPTR }} docker network connect ${{ env.DOCKER_E2E_NETWORK }} ${{ env.DOCKER_CONTAINER_NAME }} - name: run pptr tests - ${{ env.ATLAS_URL }} run: | docker exec --env ATLAS_URL=${ATLAS_URL} -t -w /iav ${DOCKER_E2E_PPTR} npm run e2e - - name: cleanup, stop container ${{ env.DOCKER_CONTAINER_NAME }} + - name: cleanup, stop container ${{ env.DOCKER_CONTAINER_NAME }} && ${{ env.DOCKER_E2E_PPTR }} if: success() run: | docker stop ${DOCKER_CONTAINER_NAME} docker stop ${DOCKER_E2E_PPTR} - docker network rm ${DOCKER_E2E_NETWORK} + - name: cleanup, remove image ${{ env.DOCKER_IMAGE_NAME }}:${{ env.DOCKER_IMAGE_TAG }} + if: success() + run: | docker rmi ${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_TAG} diff --git a/e2e/src/layout/layout.e2e-spec.js b/e2e/src/layout/layout.e2e-spec.js new file mode 100644 index 0000000000000000000000000000000000000000..5da91629a1c9d2c28ceb314d1641da09282d737d --- /dev/null +++ b/e2e/src/layout/layout.e2e-spec.js @@ -0,0 +1,131 @@ +const chromeOpts = require('../../chromeOpts') +const pptr = require('puppeteer') +const ATLAS_URL = (process.env.ATLAS_URL || 'http://localhost:3000').replace(/\/$/, '') +if (ATLAS_URL.length === 0) throw new Error(`ATLAS_URL must either be left unset or defined.`) +if (ATLAS_URL[ATLAS_URL.length - 1] === '/') throw new Error(`ATLAS_URL should not trail with a slash: ${ATLAS_URL}`) + +const MAT_SIDENAV_TIMEOUT = 500 + +const getVisibility = page => async selector => await page.evaluate(sel => { + const el = document.querySelector(sel) + if (el) return el.style.visibility + else return null +}, selector) + +const clickTab = async page => { + await page.evaluate(() => { + const el = document.querySelector('button[mat-drawer-trigger]') + el.click() + }) +} + +let browser +describe('IAV layout e2e', () => { + beforeAll(async () => { + browser = await pptr.launch({ + ...( + chromeOpts.indexOf('--headless') >= 0 + ? { headless: true } + : {} + ), + args: [ + ...chromeOpts + ] + }) + }) + + describe('toggling side panel', () => { + let page + + beforeAll(async () => { + const urlMni152JuBrain = `${ATLAS_URL}/?templateSelected=MNI+152+ICBM+2009c+Nonlinear+Asymmetric&parcellationSelected=JuBrain+Cytoarchitectonic+Atlas&cRegionsSelected=%7B%22jubrain+mni152+v18+left%22%3A%222%22%2C%22jubrain+mni152+v18+right%22%3A%222%22%7D&cNavigation=0.0.0.-W000..2_ZG29.-ASCS.2-8jM2._aAY3..BSR0..70hl~.1w4W0~.70hk..1Pl9` + page = await browser.newPage() + await page.goto(urlMni152JuBrain, {waitUntil: 'networkidle2'}) + await page.waitFor('mat-drawer') + }) + + it('on init, side drawer should be visible', async () => { + const visibility = await (getVisibility(page))('mat-drawer[mat-drawer-opened]') + expect( + visibility + ).toBe('visible') + }) + + it('toggle tab should hide', async () => { + await clickTab(page) + await page.waitFor('mat-drawer[mat-drawer-opened=false]') + await page.waitFor(MAT_SIDENAV_TIMEOUT) + + const visibility = await (getVisibility(page))('mat-drawer[mat-drawer-opened]') + expect( + visibility + ).toBe('hidden') + }) + + it('toggle tab should show', async () => { + await clickTab(page) + await page.waitFor('mat-drawer[mat-drawer-opened=true]') + await page.waitFor(MAT_SIDENAV_TIMEOUT) + + const visibility = await (getVisibility(page))('mat-drawer[mat-drawer-opened]') + expect( + visibility + ).toBe('visible') + }) + + it('sidepanel property window should be hidden when side panel is shown', async () => { + + const visibility = await (getVisibility(page))('mat-drawer[mat-drawer-opened]') + expect( + visibility + ).toBe('visible') + + const statusPanel = await page.$('[mat-drawer-status-panel]') + expect(statusPanel).toBeNull + }) + + it('side panel property window should be visible when panel is hidden', async () => { + await clickTab(page) + + await page.waitFor('mat-drawer[mat-drawer-opened=false]') + await page.waitFor(MAT_SIDENAV_TIMEOUT) + const visibility = await (getVisibility(page))('mat-drawer[mat-drawer-opened]') + expect( + visibility + ).toBe('hidden') + + const statusPanel = await page.$('[mat-drawer-status-panel]') + expect(statusPanel).toBeTruthy + }) + + it('side panel, if visible, should open side panel', async () => { + + const statusPanel = await page.$('[mat-drawer-status-panel]') + expect(statusPanel).toBeTruthy + + await page.evaluate(() => { + const el = document.querySelector('[mat-drawer-status-panel]') + if (el) el.click() + else throw new Error(`mat-drawer-status-panel not found`) + }) + + await page.waitFor(MAT_SIDENAV_TIMEOUT) + + const visibility = await (getVisibility(page))('mat-drawer[mat-drawer-opened]') + expect( + visibility + ).toBe('visible') + }) + + it('after open with status panel, tag should continue to work', async () => { + await clickTab(page) + + await page.waitFor('mat-drawer[mat-drawer-opened=false]') + await page.waitFor(MAT_SIDENAV_TIMEOUT) + const visibility = await (getVisibility(page))('mat-drawer[mat-drawer-opened]') + expect( + visibility + ).toBe('hidden') + }) + }) +}) diff --git a/src/atlasViewer/atlasViewer.template.html b/src/atlasViewer/atlasViewer.template.html index d1a50e4f9da121741ad3bb98718dbdaabdc9cd9a..e9fd9570375c524f81e52552e80794161e40c668 100644 --- a/src/atlasViewer/atlasViewer.template.html +++ b/src/atlasViewer/atlasViewer.template.html @@ -41,7 +41,6 @@ <!-- atlas template --> <ng-template #viewerBody> <div class="atlas-container" (drag-drop)="localFileService.handleFileDrop($event)"> - <ui-nehuba-container iav-mouse-hover #iavMouseHoverEl="iavMouseHover" @@ -55,11 +54,17 @@ <div class="z-index-10 position-absolute pe-none w-100 h-100"> <!-- dataset search side nav --> - <mat-drawer-container *ngIf="newViewer$ | async" [hasBackdrop]="false" + <mat-drawer-container + *ngIf="newViewer$ | async" + [hasBackdrop]="false" class="w-100 h-100 bg-none mat-drawer-content-overflow-visible"> <mat-drawer mode="push" class="col-10 col-sm-10 col-md-4 col-lg-3 col-xl-2 p-2 bg-none box-shadow-none overflow-visible" - [disableClose]="true" [autoFocus]="false" [opened]="sidePanelIsOpen$ | async" #sideNavDrawer> + [disableClose]="true" + [autoFocus]="false" + [opened]="sidePanelIsOpen$ | async" + [attr.mat-drawer-opened]="sidePanelIsOpen$ | async" + #sideNavDrawer> <search-side-nav (dismiss)="toggleSideNavMenu(true)" class="h-100 d-block overflow-visible" #searchSideNav> </search-side-nav> @@ -69,17 +74,25 @@ <!-- tag for opening and closing side nav --> <div class="d-flex h-100 align-items-start bg-none pe-none"> - <button mat-flat-button matBadgePosition="above after" matBadgeColor="accent" + <button mat-flat-button + matBadgePosition="above after" + matBadgeColor="accent" [matBadge]="!sideNavDrawer.opened && (selectedRegions$ | async)?.length ? (selectedRegions$ | async)?.length : null" [matTooltip]="!sideNavDrawer.opened ? (selectedRegions$ | async)?.length ? ('Explore ' + (selectedRegions$ | async)?.length + ' selected regions.') : 'Explore current view' : null" [ngClass]="{'translate-x-6-n': !sideNavDrawer.opened, 'translate-x-7-n': sideNavDrawer.opened}" - class="pe-all mt-5" (click)="toggleSideNavMenu(sideNavDrawer.opened)"> + class="pe-all mt-5" + (click)="toggleSideNavMenu(sideNavDrawer.opened)" + mat-drawer-trigger> <i [ngClass]="{'fa-chevron-left': sideNavDrawer.opened, 'fa-chevron-right': !sideNavDrawer.opened}" class="fas translate-x-3"></i> </button> - <mat-card *ngIf="!sideNavDrawer.opened" (click)="toggleSideNavMenu(false)" mat-ripple + <mat-card + *ngIf="!sideNavDrawer.opened" + (click)="toggleSideNavMenu(false)" + mat-ripple + mat-drawer-status-panel class="pe-all mt-4 muted translate-x-4-n"> <mat-card-content> <viewer-state-mini> @@ -95,8 +108,8 @@ <div class="d-flex flex-row justify-content-end z-index-10 position-absolute pe-none w-100 h-100"> <signin-banner - signinWrapper - [parcellationIsSelected]="selectedParcellation? true : false"> + signinWrapper + [parcellationIsSelected]="selectedParcellation? true : false"> </signin-banner> </div> diff --git a/src/components/dropdown/dropdown.component.spec.ts b/src/components/dropdown/dropdown.component.spec.ts index 6bf288d0648e3b7db0196b3abb14ad61a3ff389b..d4d9e9381441ed2c67cd5fee24c6e3d967182ab0 100644 --- a/src/components/dropdown/dropdown.component.spec.ts +++ b/src/components/dropdown/dropdown.component.spec.ts @@ -6,9 +6,6 @@ import { RadioList } from '../radiolist/radiolist.component' import { DropdownComponent } from './dropdown.component'; describe('dropdown component', () => { - it('jasmine works', () => { - expect(1).toBe(1) - }) beforeEach(async(() => { TestBed.configureTestingModule({ imports: [