diff --git a/.github/workflows/code/create-checklist-comment.js b/.github/workflows/code/create-checklist-comment.js index f59b6f7516501d28f41416550f1d2f110861832f..47a4cdd8b28ede90b165a543dcd105734c0d1dd1 100644 --- a/.github/workflows/code/create-checklist-comment.js +++ b/.github/workflows/code/create-checklist-comment.js @@ -1,5 +1,5 @@ module.exports = async ({github, context}) => { - const pathToChecklist = './e2e/checklist.md' + const pathToChecklist = './checklist.md' const fs = require('fs') const { promisify } = require('util') const asyncReadFile = promisify(fs.readFile) diff --git a/.github/workflows/docker_img.yml b/.github/workflows/docker_img.yml index 54c2713dfa3ed669c446a6ae1298040a4e82400b..acd0d525a9393f0580ba06599ace4992341c3d69 100644 --- a/.github/workflows/docker_img.yml +++ b/.github/workflows/docker_img.yml @@ -65,9 +65,18 @@ jobs: - id: 'build-docker-image' name: 'Build docker image' run: | + GIT_DIGEST=${{ github.sha }} + echo "Git digest: $GIT_DIGEST" + + # 62 char limit in label + GIT_DIGEST=$(echo $GIT_DIGEST | grep -oP '^.{6}') + echo "Using first 6 chars of hash: $GIT_DIGEST" + echo "GIT_DIGEST=$GIT_DIGEST" >> $GITHUB_OUTPUT + DOCKER_BUILT_TAG=${{ env.DOCKER_REGISTRY }}siibra-explorer:$BRANCH_NAME echo "Building $DOCKER_BUILT_TAG" docker build \ + --build-arg BUILD_HASH=$GIT_DIGEST \ --build-arg MATOMO_URL=$MATOMO_URL \ --build-arg MATOMO_ID=$MATOMO_ID \ --build-arg SIIBRA_API_ENDPOINTS=$SIIBRA_API_ENDPOINTS \ @@ -79,15 +88,6 @@ jobs: inspect_str=$(docker image inspect --format='json' $DOCKER_BUILT_TAG) echo "Inspected tag: $inspect_str" - - GIT_DIGEST=${{ github.sha }} - echo "Git digest: $GIT_DIGEST" - - # 62 char limit in label - GIT_DIGEST=$(echo $GIT_DIGEST | grep -oP '^.{6}') - echo "Using first 6 chars of hash: $GIT_DIGEST" - - echo "GIT_DIGEST=$GIT_DIGEST" >> $GITHUB_OUTPUT - name: 'Push to docker registry' run: | @@ -155,6 +155,75 @@ jobs: secrets: KUBECONFIG: ${{ secrets.KUBECONFIG }} + cypress-staging: + needs: + - trigger-deploy-rc-rancher + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + # - windows-latest + - macos-latest + viewer: + - ng + - fsa + browser: + - chrome + - webkit + include: + - viewer: ng + url: https://atlases.ebrains.eu/viewer-staging/go/human + - viewer: fsa + url: https://atlases.ebrains.eu/viewer-staging/go/fsaverage + exclude: + - os: ubuntu-latest + browser: webkit + # - os: windows-latest + # browser: webkit + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + - name: Set variables + run: | + GIT_DIGEST=${{ github.sha }} + GIT_DIGEST=$(echo $GIT_DIGEST | head -c 6) + + SCREENSHOT_URL=${{ matrix.url }} + SCREENSHOT_PATH=screenshot_"$GIT_DIGEST"_${{ matrix.viewer }}_${{ matrix.os }}_${{ matrix.browser }} + + echo "SCREENSHOT_URL: $SCREENSHOT_URL" + echo "SCREENSHOT_PATH: $SCREENSHOT_PATH" + + echo "SCREENSHOT_URL=$SCREENSHOT_URL" >> $GITHUB_ENV + echo "SCREENSHOT_PATH=$SCREENSHOT_PATH" >> $GITHUB_ENV + + - name: Install dependency + run: npm install cypress + + - name: Install optional dependency + if: ${{ matrix.browser == 'webkit' }} + run: | + npm install --save-dev playwright-webkit + echo "USE_SAFARI=1" >> $GITHUB_ENV + + - name: Run Cypress + uses: cypress-io/github-action@v6 + with: + spec: cypress/e2e/screenshot.cy.js + browser: ${{ matrix.browser }} + + - uses: actions/upload-artifact@v4 + with: + name: ${{ env.SCREENSHOT_PATH }} + path: cypress/screenshots/screenshot.cy.js/*.png + retention-days: 5 + + trigger-deploy-expmt-rancher: if: ${{ needs.setting-vars.outputs.BRANCH_NAME == 'staging' && success() }} needs: diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml deleted file mode 100644 index 5ddc69dde8c3b983df3af45941d4894bf7be0bc9..0000000000000000000000000000000000000000 --- a/.github/workflows/e2e.yml +++ /dev/null @@ -1,116 +0,0 @@ -name: "[e2e] prod-specs" - -on: - workflow_dispatch: - inputs: - url: - required: true - default: https://interactive-viewer-next.apps-dev.hbp.eu/ - sha: - required: true - default: '' - -jobs: - update-e2e-status: - runs-on: ubuntu-latest - env: - URL_ROOT: https://api.github.com/repos/HumanBrainProject/interactive-viewer - SHA: ${{ github.event.inputs.sha }} - steps: - - name: update commit status - run: | - curl -v \ - -X POST \ - -H "Authorization: Bearer ${{ github.token }}" \ - -H 'accept: application/vnd.github.v3+json' \ - ${URL_ROOT}/statuses/${SHA} \ - -d '{ - "target_url":"'$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID'", - "description": "Running e2e", - "state": "pending" - }' - e2e: - needs: update-e2e-status - runs-on: [self-hosted, headless] - strategy: - fail-fast: false - matrix: - protractor-spec: [ - './src/advanced/urlParsing.prod.e2e-spec.js', - './src/advanced/pluginApi.prod.e2e-spec.js', - './src/advanced/nonAtlasImages.prod.e2e-spec.js', - # './src/advanced/browsingForDatasets.prod.e2e-spec.js', - './src/advanced/favDatasets.prod.e2e-spec.js', - './src/advanced/history.prod.e2e-spec.js', - - './src/selecting/region.prod.e2e-spec.js', - './src/selecting/template.prod.e2e-spec.js', - './src/selecting/atlas.prod.e2e-spec.js', - - './src/layout/home.prod.e2e-spec.js' - ] - env: - PROTRACTOR_SPECS: ${{ matrix.protractor-spec }} - ATLAS_URL: ${{ github.event.inputs.url }} - PPTR_VERSION: "5.3.1" - CHROMIUM_VERSION: "86.0.4240.0" - - outputs: - failure-state: ${{ steps.failure-state-step.outputs.failure-state }} - - steps: - - uses: actions/checkout@v4 - with: - ref: ${{ github.event.ref }} - - - name: Install dep - run: | - npm i - npm run wd -- update --versions.chrome=${CHROMIUM_VERSION} - npm i --no-save puppeteer@${PPTR_VERSION} - - - name: 'Run e2e for ${{ matrix.protractor-spec }} on ${{ github.event.inputs.url }}' - run: npm run e2e - - - name: Set output when workflow fails - if: failure() - run: echo "failure-state=true" >> $GITHUB_OUTPUT - id: failure-state-step - - - name: Define screenshot artefact - if: failure() - run: | - strip_prefix=${PROTRACTOR_SPECS#./src/} - strip_suffix=${strip_prefix%.e2e-spec.js} - replace_slash=${strip_suffix//\//-} - replace_dots=${replace_slash//\./-} - echo 'ARTEFACT_NAME='$replace_dots >> $GITHUB_ENV - - - name: 'Upload screenshots artefact' - if: failure() - uses: actions/upload-artifact@v2 - with: - name: ${{ env.ARTEFACT_NAME }} - path: ./scrnsht/ - - update-after-e2e-status: - if: always() - needs: e2e - runs-on: ubuntu-latest - env: - URL_ROOT: https://api.github.com/repos/HumanBrainProject/interactive-viewer - SHA: ${{ github.event.inputs.sha }} - steps: - - name: update badge - run: | - [[ '${{ needs.e2e.outputs.failure-state }}' = 'true' ]] && state=failure || state=success && - curl -v \ - -X POST \ - -H "Authorization: Bearer ${{ github.token }}" \ - -H 'accept: application/vnd.github.v3+json' \ - ${URL_ROOT}/statuses/${SHA} \ - -d '{ - "target_url":"'$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID'", - "description": "e2e completed successfully.", - "state": "'$state'" - }' diff --git a/Dockerfile b/Dockerfile index 2bae7e743c1afab9f08f24ec5ceae9df1fd19846..e5669e328840b8e6fc767ad8a3333ff993a8890f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,8 @@ FROM node:16 as builder +ARG BUILD_HASH +ENV BUILD_HASH=${BUILD_HASH:-devbuild} + ARG BACKEND_URL ENV BACKEND_URL=${BACKEND_URL} diff --git a/backend/app/app.py b/backend/app/app.py index 5d8c8be2c6589ccded5769329fea8e6e70786ce4..69ed12ab0cf369e2aed2391b207d8c5dbd091dab 100644 --- a/backend/app/app.py +++ b/backend/app/app.py @@ -15,6 +15,7 @@ from app.user import router as user_router from app.config import HOST_PATHNAME from app.logger import logger from app.bkwdcompat import BkwdCompatMW +from app.version_header import VersionHeaderMW app = FastAPI() @@ -26,6 +27,7 @@ def ready(): app.add_middleware(SessionMiddleware, secret_key=SESSION_SECRET) app.add_middleware(BkwdCompatMW) +app.add_middleware(VersionHeaderMW) for vip_route in vip_routes: @app.get(f"/{vip_route}") diff --git a/backend/app/config.py b/backend/app/config.py index d51631de39d3d3f0b2373a7dd7010e7db6d41f96..42ddbaace8377c189451d9a8dd61448ee5a8bf52 100644 --- a/backend/app/config.py +++ b/backend/app/config.py @@ -34,4 +34,6 @@ SXPLR_BUCKET_NAME = os.getenv("SXPLR_BUCKET_NAME", "interactive-atlas-viewer") LOGGER_DIR = os.getenv("LOGGER_DIR") -PATH_TO_PUBLIC = os.getenv("PATH_TO_PUBLIC", "../dist/aot") \ No newline at end of file +PATH_TO_PUBLIC = os.getenv("PATH_TO_PUBLIC", "../dist/aot") + +BUILD_HASH = os.getenv("BUILD_HASH", "devbuild") diff --git a/backend/app/version_header.py b/backend/app/version_header.py new file mode 100644 index 0000000000000000000000000000000000000000..8ece7c233df70edb79b486311e853ecfd08e7170 --- /dev/null +++ b/backend/app/version_header.py @@ -0,0 +1,16 @@ +from fastapi import Request +from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint +from starlette.responses import Response +from app.config import BUILD_HASH + +class VersionHeaderMW(BaseHTTPMiddleware): + async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) -> Response: + resp = await call_next(request) + if ( + resp.headers.get("ETag") # if the route sets its own etag, do not interfere + or request.method != "GET" # if the request is not a get method do not interfere + or (300 <= resp.status_code < 400) # if the request is redirect, do not interfere + ): + return resp + resp.headers["ETag"] = BUILD_HASH + return resp diff --git a/cypress.config.js b/cypress.config.js new file mode 100644 index 0000000000000000000000000000000000000000..4530a6ef45a09a50e8cc71760953abe3d49b398e --- /dev/null +++ b/cypress.config.js @@ -0,0 +1,16 @@ +const { defineConfig } = require("cypress"); + +module.exports = defineConfig({ + e2e: { + defaultCommandTimeout: 10000, + supportFile: false, + setupNodeEvents(on, config) { + // implement node event listeners here + }, + }, + env: { + SCREENSHOT_URL: process.env.SCREENSHOT_URL, + SCREENSHOT_PATH: process.env.SCREENSHOT_PATH, + }, + experimentalWebKitSupport: !!process.env.USE_SAFARI +}); diff --git a/cypress/e2e/screenshot.cy.js b/cypress/e2e/screenshot.cy.js new file mode 100644 index 0000000000000000000000000000000000000000..19e259eac0f2fc50b6dbeaa75cf8cc6c80d5e5b2 --- /dev/null +++ b/cypress/e2e/screenshot.cy.js @@ -0,0 +1,22 @@ +const { + SCREENSHOT_URL, + SCREENSHOT_PATH, +} = Cypress.env() + +describe(`Visiting ${SCREENSHOT_URL}`, () => { + it(`Screenshot to ${SCREENSHOT_PATH}`, () => { + if (!SCREENSHOT_URL) { + console.error(`SCREENSHOT_URL not defined. Exiting`) + return + } + + cy.visit(SCREENSHOT_URL) + cy.wait(10000) + + if (!SCREENSHOT_PATH) { + console.error(`SCREENSHOT_PATH not defined. Exiting`) + return + } + cy.screenshot(SCREENSHOT_PATH) + }) +}) diff --git a/docs/releases/v2.14.4.md b/docs/releases/v2.14.4.md index c6ba74a276d284dd2f32a7b2d115ebe2f04c0566..efb0e01efdb12eb7d3665ca369e5c00a1a384aaa 100644 --- a/docs/releases/v2.14.4.md +++ b/docs/releases/v2.14.4.md @@ -2,7 +2,7 @@ ## Feature -- Sagittal view of perspective PiP changes hemisphere when user navigates to the otehr hemisphere +- Sagittal view of perspective PiP changes hemisphere when user navigates to the other hemisphere - Adds an additional degree adjustment to perspective PiP - Encode maximised panel state diff --git a/docs/releases/v2.14.5.md b/docs/releases/v2.14.5.md index 233bc752233142b59218fbd48d29db3177033a02..8b2ffba5a6931aa714d5a311acf6c6853373996f 100644 --- a/docs/releases/v2.14.5.md +++ b/docs/releases/v2.14.5.md @@ -8,13 +8,13 @@ - Reworded point assignment UI - Allow multi selected region names to be copied - Added legend to region hierarchy -- Allow latest queried concept in feature view - Allow experimental flag to be set to be on at runtime (this also shows the button, allow toggling of experimental features) - Feature: added supported for .annot fsaverage label +- allow big brain template to be downloaded - (experimental) Added code snippet to limited panels - (experimental) allow addition of custom linear coordinate space - (experimental) show BigBrain slice number -- (experimental) allow big brain template to be downloaded + ## Bugfix @@ -24,7 +24,6 @@ ## Behind the Scenes -- Removed dependency on connectivity-component - Removed reference to JSC OKD instance, as the instance is no longer available - Updated google-site-verification - Allow inter-space transform to be configured at runtime diff --git a/docs/releases/v2.14.7.md b/docs/releases/v2.14.7.md new file mode 100644 index 0000000000000000000000000000000000000000..143702855fe09a2d38b3f5e72790d39711b327ae --- /dev/null +++ b/docs/releases/v2.14.7.md @@ -0,0 +1,12 @@ +# v2.14.7 + +## Bugfix + +- fixed issue on iOS/Safari volumetric viewer not displaying. (update called before config was populated). + +## Behind the Scenes + +- Minor refactor to remove unneeded code. +- Fixed typos/errors in release notes +- Removed unused tests (e2e) +- Added simple cypress for basic viewer rendering diff --git a/e2e/chromeOpts.js b/e2e/chromeOpts.js deleted file mode 100644 index fd9b30a00b9eca3251366ae8667391e5ebb1a6b3..0000000000000000000000000000000000000000 --- a/e2e/chromeOpts.js +++ /dev/null @@ -1,12 +0,0 @@ -const { width, height } = require('./opts') - -module.exports = [ - ...(process.env.DISABLE_CHROME_HEADLESS ? [] : ['--headless']), - '--no-sandbox', - ...(process.env.ENABLE_GPU ? []: ['--disable-gpu']), - '--disable-setuid-sandbox', - "--disable-extensions", - '--disable-dev-shm-usage', - `--window-size=${width},${height}`, - '--disable-application-cache' -] \ No newline at end of file diff --git a/e2e/opts.js b/e2e/opts.js deleted file mode 100644 index 9b75d287f6ec4ffa0100562d033d65b1eb9c4eb6..0000000000000000000000000000000000000000 --- a/e2e/opts.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - width: 800, - height: 796 -} diff --git a/e2e/protractor.conf.js b/e2e/protractor.conf.js deleted file mode 100644 index 2fbc49e5b62647cd050e47ea1fa2dc513c80753d..0000000000000000000000000000000000000000 --- a/e2e/protractor.conf.js +++ /dev/null @@ -1,134 +0,0 @@ - -// n.b. to start selenium, run npm run wd -- update && npm run wd -- start -// n.b. you will need to run `npm i --no-save puppeteer`, so that normal download script does not download chrome binary -const chromeOpts = require('./chromeOpts') -const fs = require('fs') -const path = require('path') -const { promisify } = require('util') -const asyncWrite = promisify(fs.writeFile) -const asyncMkdir = promisify(fs.mkdir) - -const SELENIUM_ADDRESS = process.env.SELENIUM_ADDRESS - -const { - BROWSERSTACK_TEST_NAME, - BROWSERSTACK_USERNAME, - BROWSERSTACK_ACCESS_KEY, -} = process.env -const directConnect = !!process.env.DIRECT_CONNECT - -const PROTRACTOR_SPECS = process.env.PROTRACTOR_SPECS - -const localConfig = { - ...(SELENIUM_ADDRESS - ? { seleniumAddress: SELENIUM_ADDRESS } - : { directConnect: true } - ), - capabilities: { - // Use headless chrome - browserName: 'chrome', - 'goog:chromeOptions': { - args: [ - ...chromeOpts - ], - ...( - SELENIUM_ADDRESS - ? {} - : { binary: (() => require('puppeteer').executablePath())() } - ) - } - }, - onPrepare: function() { - // polyfill for node10 or lower - if (typeof globalThis === 'undefined') global.globalThis = {} - jasmine.getEnv().addReporter({ - specDone: async ({ status, id, message, fullName, ...rest }) => { - if (status === 'failed') { - console.log(`spec failed, taking screenshot`) - const b64 = await globalThis.IAVBase.takeScreenshot() - const dir = './scrnsht/' - await asyncMkdir(dir, { recursive: true }) - await asyncWrite( - path.join(dir, `${id}.png`), - b64, - 'base64' - ) - await asyncWrite( - path.join(dir, `${id}.txt`), - JSON.stringify({ id, status, message, fullName }, null, 2), - 'utf-8' - ) - } - } - }) - } -} - - -const { Local } = require('browserstack-local'); - -let bsLocal -/** - * config adapted from - * https://github.com/browserstack/protractor-browserstack - * - * MIT licensed - */ -const bsConfig = { - 'browserstackUser': BROWSERSTACK_USERNAME, - 'browserstackKey': BROWSERSTACK_ACCESS_KEY, - - 'capabilities': { - 'build': 'protractor-browserstack', - 'name': BROWSERSTACK_TEST_NAME || 'iav_e2e', - "os" : "Windows", - "osVersion" : "10", - 'browserName': 'chrome', - 'browserstack.local': true, - "seleniumVersion" : "4.0.0-alpha-2", - 'browserstack.debug': 'true' - }, - "browserName" : "Chrome", - "browserVersion" : "83.0", - - // Code to start browserstack local before start of test - beforeLaunch: function(){ - console.log("Connecting local"); - return new Promise(function(resolve, reject){ - bsLocal = new Local(); - bsLocal.start({'key': BROWSERSTACK_ACCESS_KEY }, function(error) { - if (error) return reject(error); - console.log('Connected. Now testing...'); - - resolve(); - }); - }); - }, - - // Code to stop browserstack local after end of test - afterLaunch: function(){ - return new Promise(function(resolve, reject){ - if (bsLocal) bsLocal.stop(resolve) - else resolve() - }); - } -} - -exports.config = { - specs: [ - PROTRACTOR_SPECS || './src/**/*.prod.e2e-spec.js' - ], - jasmineNodeOpts: { - defaultTimeoutInterval: 1000 * 60 * 10 - }, - - ...( - BROWSERSTACK_ACCESS_KEY && BROWSERSTACK_USERNAME - ? bsConfig - : localConfig - ), - - ...( - (directConnect && { directConnect }) || {} - ) -} diff --git a/e2e/screenshots/gen.js b/e2e/screenshots/gen.js deleted file mode 100644 index 00533c07e64883ade9e0270bcfaa0c87fc7b2155..0000000000000000000000000000000000000000 --- a/e2e/screenshots/gen.js +++ /dev/null @@ -1,29 +0,0 @@ -const { spawn } = require("child_process") -const path = require('path') -const glob = require('glob') -describe('> generating screenshot', () => { - let childProcess - const matchCwdPath = path.join(__dirname, '../src') - const matches = glob.sync('**/*.e2e-screenshot.js', { cwd: matchCwdPath }) - const cwdPath = path.join(__dirname, '../../deploy/') - - beforeAll(done => { - throw "Need to reimplement. backend is rewritten from node to python" - childProcess = spawn('node', ['server.js'], { - cwd: cwdPath, - env: { - ...process.env, - BUILD_TEXT: '' - } - }) - setTimeout(done, 1000) - }) - - for (const match of matches) { - const requirePath = path.join(matchCwdPath, match) - require(requirePath) - } - afterAll(() => { - childProcess.kill() - }) -}) diff --git a/e2e/setup.sh b/e2e/setup.sh deleted file mode 100755 index 08597d425532f91194cacfc3e54d72e689c85e88..0000000000000000000000000000000000000000 --- a/e2e/setup.sh +++ /dev/null @@ -1,6 +0,0 @@ -#! /bin/bash - -export CHROMIUM_VERSION=80.0.3987.106 -export PPTR_VERSION=2.1.0 -npm run wd -- update --versions.chrome=${CHROMIUM_VERSION} -npm i --no-save puppeteer@${PPTR_VERSION} \ No newline at end of file diff --git a/e2e/src/advanced/browsingForDatasets.prod.e2e-spec.js b/e2e/src/advanced/browsingForDatasets.prod.e2e-spec.js deleted file mode 100644 index 56d74d804db8c2b908541a0dcdc7accf161c158d..0000000000000000000000000000000000000000 --- a/e2e/src/advanced/browsingForDatasets.prod.e2e-spec.js +++ /dev/null @@ -1,157 +0,0 @@ -const { AtlasPage } = require('../util') -const { CONST, ARIA_LABELS } = require('../../../common/constants') -const { retry } = require('../../../common/util') - -const { - RECORDING_FLAG -} = process.env - -const atlasName = `Multilevel Human Atlas` - -const templates = [ - 'MNI Colin 27', - 'ICBM 152 2009c Nonlinear Asymmetric' -] - -const newShouldHaveReceptor = [ - ["Area 4p (PreCG)", 1, 1, 1], - ["Area 3b (PostCG)", 1, 1, 1], - ["DG (Hippocampus)", 0, 0, 1], - ["Area FG2 (FusG)", 0, 1, 1], - ["Area hOc1 (V1, 17, CalcS)" ,1, 1, 1], - ["Area PFm (IPL)", 0, 1, 1], - ["Area 44 (IFG)", 0, 0, 1], - ["CA3 (Hippocampus)", 0, 0, 1], - ["CA2 (Hippocampus)", 0, 0, 1], - ["CA1 (Hippocampus)", 0, 0, 1], - ["Area PGp (IPL)", 0, 0, 1], - ["CA1 (Hippocampus)", 0, 0, 1], - ["Area 45 (IFG)", 1, 1, 1], - ["Area hOc3v (LingG)", 0, 0, 1], - ["Area hOc3d (Cuneus)", 0, 0, 1], - ["Area 7A (SPL)", 1, 1, 1], - ["Area 44 (IFG)", 1, 1, 1], - ["Area hOc2 (V2, 18)", 0, 0, 1], - ["Area PFop (IPL)", 0, 0, 1], - ["Area PF (IPL)", 0, 0, 1], - ["CA2 (Hippocampus)", 0, 0, 1], - ["Area PFt (IPL)", 0, 0, 1], - ["Area TE 2.1 (STG)", 0, 0, 1], - ["Area PFcm (IPL)", 0, 0, 1], - ["CA3 (Hippocampus)", 0, 0, 1], - ["DG (Hippocampus)", 0, 0, 1], - ["CA3 (Hippocampus)", 0, 0, 1], - ["CA2 (Hippocampus)", 0, 0, 1], - ["CA1 (Hippocampus)", 0, 0, 1], - ["CA3 (Hippocampus)", 0, 0, 1], - ["CA2 (Hippocampus)", 0, 0, 1], - ["CA1 (Hippocampus)", 0, 0, 1], - ["Area FG1 (FusG)", 0, 1, 1], - ["CA3 (Hippocampus)", 0, 0, 1], - ["Area TE 1.0 (HESCHL)", 0, 0, 1], - ["CA1 (Hippocampus)", 0, 0, 1], - ["Area hOc2 (V2, 18)", 0, 0, 1], - ["CA2 (Hippocampus)", 0, 0, 1], - ["CA3 (Hippocampus)", 0, 0, 1], - ["CA2 (Hippocampus)", 0, 0, 1], - ["CA1 (Hippocampus)", 0, 0, 1], - ["Area PGa (IPL)", 0, 0, 1], -].reduce((acc, curr) => { - const [ name, pr, ar, fp ] = curr - const foundIdx = acc.findIndex(([ accName ]) => name === accName ) - return foundIdx >= 0 - ? acc.map((el, idx) => idx === foundIdx - ? [ name, el[1] + pr, el[2] + ar, el[3] + fp ] - : el) - : acc.concat([curr]) - -}, []) - - -describe('> dataset browser', () => { - let iavPage - beforeAll(async () => { - iavPage = new AtlasPage() - await iavPage.init() - }) - - for (const template of templates) { - describe(`> in template: ${template}`, () => { - beforeAll(async () => { - await iavPage.goto() - await iavPage.setAtlasSpecifications(atlasName, [ template ]) - - // account for linear template translation backend - await iavPage.wait(5000) - await iavPage.waitUntilAllChunksLoaded() - }) - - afterEach(async () => { - try { - await iavPage.click(`[aria-label="${ARIA_LABELS.CLOSE}"]`) - } catch (e) { - - } - }) - for (const [ area, ...rest ] of newShouldHaveReceptor) { - it(`> receptor data ${area} should be able to be found`, async () => { - await iavPage.searchRegionWithText(area) - await iavPage.wait(2000) - await iavPage.selectSearchRegionAutocompleteWithText() - await retry(async () => { - await iavPage.dismissModal() - await iavPage.toggleExpansionPanelState(`${CONST.REGIONAL_FEATURES}`, true) - }, { - timeout: 2000, - retries: 10 - }) - await iavPage.wait(2000) - await iavPage.waitUntilAllChunksLoaded() - await iavPage.dismissModal() - const datasets = await iavPage.getVisibleDatasets() - const receptorDsIdx = datasets.findIndex(ds => ds.toLowerCase().indexOf('receptor') >= 0) - expect(receptorDsIdx).toBeGreaterThanOrEqual(0) - - if (RECORDING_FLAG) { - await iavPage.clickNthDataset(receptorDsIdx) - await iavPage.wait(1000) - await iavPage.toggleExpansionPanelState(/receptor/i, true) - await iavPage.wait(5000) - } - }) - } - }) - } - - describe('> modality filter', () => { - beforeAll(async () => { - await iavPage.goto() - await iavPage.setAtlasSpecifications(atlasName, [ templates[0] ]) - - await iavPage.wait(5000) - await iavPage.waitUntilAllChunksLoaded() - await iavPage.searchRegionWithText(newShouldHaveReceptor[0][0]) - await iavPage.wait(2000) - await iavPage.selectSearchRegionAutocompleteWithText() - await retry(async () => { - await iavPage.dismissModal() - await iavPage.toggleExpansionPanelState(`${CONST.REGIONAL_FEATURES}`, true) - }, { - timeout: 2000, - retries: 10 - }) - await iavPage.dismissModal() - await iavPage.wait(2000) - await iavPage.waitUntilAllChunksLoaded() - }) - - it('> should be populated', async () => { - await iavPage.click(`[aria-label="${ARIA_LABELS.MODALITY_FILTER}"]`) - const text = await iavPage.getText(`[aria-label="${ARIA_LABELS.LIST_OF_MODALITIES}"]`) - const re = /\(\d+\)/.exec(text) - expect( - re - ).toBeTruthy() - }) - }) -}) diff --git a/e2e/src/advanced/favDatasets.prod.e2e-spec.js b/e2e/src/advanced/favDatasets.prod.e2e-spec.js deleted file mode 100644 index ec5de6d63b1b5a84f080def6072457c218f0235c..0000000000000000000000000000000000000000 --- a/e2e/src/advanced/favDatasets.prod.e2e-spec.js +++ /dev/null @@ -1,251 +0,0 @@ -const { AtlasPage } = require('../util') -const { ARIA_LABELS, CONST } = require('../../../common/constants') -const { retry } = require('../../../common/util') - -const atlasName = `Multilevel Human Atlas` - -const templates = [ - 'MNI Colin 27', - 'ICBM 152 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]` -const ieegDatasetName = `Human Intracranial EEG Database (HID) [cohort I]` - -// TODO finish writing tests -describe(`fav'ing dataset`, () => { - let iavPage = new AtlasPage() - beforeEach(async () => { - iavPage = new AtlasPage() - await iavPage.init() - await iavPage.goto() - await iavPage.setAtlasSpecifications(atlasName, [ templates[1] ]) - - // account for linear template translation backend - await iavPage.wait(5000) - await iavPage.waitUntilAllChunksLoaded() - - await iavPage.searchRegionWithText(area) - await iavPage.wait(2000) - await iavPage.selectSearchRegionAutocompleteWithText() - await retry(async () => { - await iavPage.dismissModal() - await iavPage.toggleExpansionPanelState(`${CONST.REGIONAL_FEATURES}`, true) - }, { - timeout: 2000, - retries: 10 - }) - - await iavPage.wait(1000) - await iavPage.waitUntilAllChunksLoaded() - await iavPage.clearAlerts() - }) - - afterEach(async () => { - /** - * clear all fav'ed datasets - */ - - await iavPage.execScript(`window.localStorage.clear()`) - }) - - it('> dataset can be fav ed from result panel', async () => { - - const datasets = await iavPage.getVisibleDatasets() - - const receptorIndex = datasets.indexOf(receptorName) - const probMap = datasets.indexOf(ieegDatasetName) - expect(receptorIndex).toBeGreaterThanOrEqual(0) - expect(probMap).toBeGreaterThanOrEqual(0) - - await iavPage.togglePinNthDataset(receptorIndex) - await iavPage.wait(500) - const txt = await iavPage.getSnackbarMessage() - expect(txt).toEqual(`Pinned dataset: ${receptorName}`) - - await iavPage.togglePinNthDataset(probMap) - await iavPage.wait(500) - const txt2 = await iavPage.getSnackbarMessage() - expect(txt2).toEqual(`Pinned dataset: ${ieegDatasetName}`) - }) - - describe('> fav dataset list', () => { - beforeEach(async () => { - - const datasets = await iavPage.getVisibleDatasets() - - const receptorIndex = datasets.indexOf(receptorName) - const probMap = datasets.indexOf(ieegDatasetName) - - await iavPage.togglePinNthDataset(receptorIndex) - await iavPage.togglePinNthDataset(probMap) - }) - - it('> fav ed dataset is visible on UI', async () => { - const content = await iavPage.getBadgeContentByDesc(CONST.PINNED_DATASETS_BADGE_DESC) - expect(content).toEqual('2') - }) - - 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.getBottomSheetList() - const idx = textsArr.indexOf(receptorName) - if (idx < 0) throw new Error(`index of receptor name not found: ${receptorName}: ${textsArr}`) - await iavPage.clickNthItemFromBottomSheetList(idx, `[aria-label="Toggle pinning this dataset"]`) - await iavPage.wait(500) - - const txt = await iavPage.getSnackbarMessage() - expect(txt).toEqual(`Unpinned dataset: ${receptorName}`) - - const content = await await iavPage.getBadgeContentByDesc(CONST.PINNED_DATASETS_BADGE_DESC) - expect(content).toEqual('1') - - await iavPage.clickSnackbarAction() - await iavPage.wait(500) - - const textsArr3 = await iavPage.getBottomSheetList() - const content2 = await await iavPage.getBadgeContentByDesc(CONST.PINNED_DATASETS_BADGE_DESC) - expect(content2).toEqual('2') - expect( - textsArr3.indexOf(receptorName) - ).toBeGreaterThanOrEqual(0) - - }) - - // TODO effectively test the bulk dl button - // it('> if fav dataset >=1, bulk dl btn is visible', async () => { - - // }) - }) - - describe('> fav functionality in detailed dataset panel', () => { - - it('> click pin in dataset detail sheet pins fav, but also allows user to undo', async () => { - const datasets = await iavPage.getVisibleDatasets() - - const receptorIndex = datasets.indexOf(receptorName) - await iavPage.clickNthDataset(receptorIndex) - await iavPage.wait(500) - - // specificity is required, because single dataset card for julich brain also can be selected, and will be clicked and fail this test - await iavPage.click(`[aria-label="${ARIA_LABELS.PIN_DATASET}"]`) - await iavPage.wait(500) - - const txt = await iavPage.getSnackbarMessage() - expect(txt).toEqual(`Pinned dataset: ${receptorName}`) - - const content = await await iavPage.getBadgeContentByDesc(CONST.PINNED_DATASETS_BADGE_DESC) - expect(content).toEqual('1') - - await iavPage.clickSnackbarAction() - await iavPage.wait(500) - - const text = await await iavPage.getBadgeContentByDesc(CONST.PINNED_DATASETS_BADGE_DESC) - expect(text).toBeFalsy() - }) - - it('> click unpin in dataset detail sheet unpins fav, but also allows user to undo', async () => { - - const datasets = await iavPage.getVisibleDatasets() - - const receptorIndex = datasets.indexOf(receptorName) - await iavPage.clickNthDataset(receptorIndex) - await iavPage.wait(500) - - // specificity is required, because single dataset card for julich brain also can be selected, and will be clicked and fail this test - await iavPage.click(`[aria-label="${ARIA_LABELS.PIN_DATASET}"]`) - await iavPage.wait(500) - - const numberOfFav = await await iavPage.getBadgeContentByDesc(CONST.PINNED_DATASETS_BADGE_DESC) - expect(numberOfFav).toEqual('1') - - // this wait is unfortunately necessary, as the snack bar sometimes obscures the unpin this dataset button - await iavPage.wait(5000) - - // specificity is required, because single dataset card for julich brain also can be selected, and will be clicked and fail this test - await iavPage.click(`[aria-label="${ARIA_LABELS.PIN_DATASET}"]`) - await iavPage.wait(500) - - const txt = await iavPage.getSnackbarMessage() - expect(txt).toEqual(`Unpinned dataset: ${receptorName}`) - - const text = await await iavPage.getBadgeContentByDesc(CONST.PINNED_DATASETS_BADGE_DESC) - expect(text).toBeFalsy() - - await iavPage.clickSnackbarAction() - await iavPage.wait(500) - - const numberOfFav2 = await await iavPage.getBadgeContentByDesc(CONST.PINNED_DATASETS_BADGE_DESC) - expect(numberOfFav2).toEqual('1') - }) - - }) - - describe('> access via collection', () => { - beforeEach(async () => { - - const datasets = await iavPage.getVisibleDatasets() - - const receptorIndex = datasets.indexOf(receptorName) - const probMap = datasets.indexOf(ieegDatasetName) - - await iavPage.togglePinNthDataset(receptorIndex) - await iavPage.togglePinNthDataset(probMap) - }) - - it('> clicking pin shows collection of pinned datasets', async () => { - - await iavPage.showPinnedDatasetPanel() - await iavPage.wait(500) - const textsArr = await iavPage.getBottomSheetList() - - expect(textsArr.length).toEqual(2) - expect(textsArr).toContain(receptorName) - expect(textsArr).toContain(ieegDatasetName) - }) - - it('> dataset detail can be launched via collection', async () => { - await iavPage.showPinnedDatasetPanel() - const textsArr = await iavPage.getBottomSheetList() - const idx = textsArr.findIndex(t => t === receptorName) - expect(idx).toBeGreaterThanOrEqual(0) - await iavPage.clickNthItemFromBottomSheetList(idx) - await iavPage.wait(1000) - const modalText = await iavPage.getModalText() - expect(modalText.length).toBeGreaterThan(1e3) - }) - - it('> dataset can be pinned/unpinned via collection', async () => { - await iavPage.showPinnedDatasetPanel() - const textsArr = await iavPage.getBottomSheetList() - const idx = textsArr.findIndex(t => t === receptorName) - await iavPage.clickNthItemFromBottomSheetList(idx) - await iavPage.wait(1000) - - /** - * for now, from collection, a modal is launched - */ - await iavPage.click(`mat-dialog-container [aria-label="${ARIA_LABELS.PIN_DATASET}"]`) - await iavPage.wait(1000) - const txt = await iavPage.getSnackbarMessage() - expect(txt).toEqual(`Unpinned dataset: ${receptorName}`) - - const content = await await iavPage.getBadgeContentByDesc(CONST.PINNED_DATASETS_BADGE_DESC) - expect(content).toEqual('1') - - await iavPage.wait(5000) - - await iavPage.click(`mat-dialog-container [aria-label="${ARIA_LABELS.PIN_DATASET}"]`) - await iavPage.wait(1000) - const txt2 = await iavPage.getSnackbarMessage() - expect(txt2).toEqual(`Pinned dataset: ${receptorName}`) - - const content2 = await await iavPage.getBadgeContentByDesc(CONST.PINNED_DATASETS_BADGE_DESC) - expect(content2).toEqual('2') - - }) - }) -}) diff --git a/e2e/src/advanced/history.prod.e2e-spec.js b/e2e/src/advanced/history.prod.e2e-spec.js deleted file mode 100644 index c8cf1a937391989f4ec8628268e91478e4d91bde..0000000000000000000000000000000000000000 --- a/e2e/src/advanced/history.prod.e2e-spec.js +++ /dev/null @@ -1,60 +0,0 @@ -const { WdIavPage } = require('../../util/selenium/iav') -const { AtlasPage } = require('../util') -const { height, width } = require("../../opts") -const atlasName = `Multilevel Human Atlas` - -describe('> navigating IAV via history', () => { - let iavPage = new AtlasPage() - beforeEach(async () => { - iavPage = new AtlasPage() - await iavPage.init() - await iavPage.goto() - await iavPage.setAtlasSpecifications(atlasName) - - await iavPage.wait(5000) - await iavPage.waitUntilAllChunksLoaded() - }) - - it('> after navigate, navigation state differs', async () => { - const nav = await iavPage.getNavigationState() - await iavPage.cursorMoveToAndDrag({ - position: [ Math.round(width / 4), Math.round(height / 4) ], - delta: [ Math.round(width / 8), Math.round(height / 8) ] - }) - const nav2 = await iavPage.getNavigationState() - - // expect some positions to change after dragging - expect( - nav.position.some((v, idx) => v !== nav2.position[idx]) - ).toBeTrue() - }) - - it('> after navigate, history back, navigation should ', async () => { - const nav = await iavPage.getNavigationState() - await iavPage.cursorMoveToAndDrag({ - position: [ Math.round(width / 4), Math.round(height / 4) ], - delta: [ Math.round(width / 8), Math.round(height / 8) ] - }) - await iavPage.wait(5000) - await iavPage.historyBack() - await iavPage.wait(5000) - - const nav2 = await iavPage.getNavigationState() - // expect some positions to change after dragging - expect( - nav.position.every((v, idx) => v === nav2.position[idx]) - ).toBeTrue() - }) - - it('> history back, viewer should despawn ', async () => { - - await iavPage.wait(5000) - await iavPage.historyBack() - await iavPage.wait(5000) - - const flag = await iavPage.viewerIsPopulated() - expect(flag).toBeFalse() - - }) - -}) \ No newline at end of file diff --git a/e2e/src/advanced/nonAtlasImages.prod.e2e-spec.js b/e2e/src/advanced/nonAtlasImages.prod.e2e-spec.js deleted file mode 100644 index 3277e69e5a4328233addc63260b9fd06e876eb5b..0000000000000000000000000000000000000000 --- a/e2e/src/advanced/nonAtlasImages.prod.e2e-spec.js +++ /dev/null @@ -1,236 +0,0 @@ -const { AtlasPage } = require('../util') -const { URLSearchParams } = require('url') -const { ARIA_LABELS } = require('../../../common/constants') -describe('> non-atlas images', () => { - let iavPage - - beforeAll(async () => { - iavPage = new AtlasPage() - await iavPage.init() - }) - describe('> standalone volumes', () => { - - // TODO investigates why it occassionally fails - it('> loads standalone volumes when set (fails sometimes. Just rerun if it does.)', async () => { - const searchParam = new URLSearchParams() - searchParam.set('standaloneVolumes', '["precomputed://https://object.cscs.ch/v1/AUTH_08c08f9f119744cbbf77e216988da3eb/imgsvc-46d9d64f-bdac-418e-a41b-b7f805068c64"]') - await iavPage.goto(`/?${searchParam.toString()}`, { interceptHttp: true, doNotAutomate: true }) - await iavPage.wait(10000) - const interceptedCalls = await iavPage.getInterceptedHttpCalls() - expect( - interceptedCalls - ).toContain( - jasmine.objectContaining( - { - method: 'GET', - url: 'https://object.cscs.ch/v1/AUTH_08c08f9f119744cbbf77e216988da3eb/imgsvc-46d9d64f-bdac-418e-a41b-b7f805068c64/info' - } - ) - ) - }) - - it('> if there exist both standalone volumes & xyz template selected, template selected is ignored', async () => { - const searchParam = new URLSearchParams() - searchParam.set('templateSelected', 'Big Brain (Histology)') - searchParam.set('parcellationSelected', 'Cytoarchitectonic Maps') - searchParam.set('standaloneVolumes', '["precomputed://https://object.cscs.ch/v1/AUTH_08c08f9f119744cbbf77e216988da3eb/imgsvc-46d9d64f-bdac-418e-a41b-b7f805068c64"]') - - await iavPage.goto(`/?${searchParam.toString()}`, { interceptHttp: true, doNotAutomate: true }) - await iavPage.wait(30000) - const interceptedCalls = await iavPage.getInterceptedHttpCalls() - - expect( - interceptedCalls - ).toContain( - jasmine.objectContaining( - { - method: 'GET', - url: 'https://object.cscs.ch/v1/AUTH_08c08f9f119744cbbf77e216988da3eb/imgsvc-46d9d64f-bdac-418e-a41b-b7f805068c64/info' - } - ) - ) - - expect( - interceptedCalls - ).not.toContain( - jasmine.objectContaining( - { - method: 'GET', - url: 'https://neuroglancer.humanbrainproject.org/precomputed/BigBrainRelease.2015/8bit/info' - } - ) - ) - }) - }) - - describe('> registered volumes', () => { - it('> if ref tmpl is right, should load both tmpl and volume', async () => { - - const searchParam = new URLSearchParams() - searchParam.set('templateSelected', 'Big Brain (Histology)') - searchParam.set('parcellationSelected', 'Grey/White matter') - - const previewingDatasetFiles = [ - { - "datasetId":"minds/core/dataset/v1.0.0/b08a7dbc-7c75-4ce7-905b-690b2b1e8957", - "filename":"Overlay of data modalities" - } - ] - searchParam.set('previewingDatasetFiles', JSON.stringify(previewingDatasetFiles)) - - await iavPage.goto(`/?${searchParam.toString()}`, { interceptHttp: true, doNotAutomate: true }) - await iavPage.wait(30000) - const interceptedCalls = await iavPage.getInterceptedHttpCalls() - - const array = [ - "PLI Fiber Orientation Red Channel", - "PLI Fiber Orientation Green Channel", - "PLI Fiber Orientation Blue Channel", - "Blockface Image", - "PLI Transmittance", - "T2w MRI", - "MRI Labels" - ] - - expect( - interceptedCalls - ).toContain( - jasmine.objectContaining( - { - method: 'GET', - url: 'https://neuroglancer.humanbrainproject.org/precomputed/BigBrainRelease.2015/8bit/info' - } - ) - ) - - const arrPli = [ - "https://neuroglancer.humanbrainproject.eu/precomputed/PLI_FOM/BI-FOM-HSV_R", - "https://neuroglancer.humanbrainproject.eu/precomputed/PLI_FOM/BI-FOM-HSV_G", - "https://neuroglancer.humanbrainproject.eu/precomputed/PLI_FOM/BI-FOM-HSV_B", - "https://neuroglancer.humanbrainproject.eu/precomputed/PLI_FOM/BI", - "https://neuroglancer.humanbrainproject.eu/precomputed/PLI_FOM/BI-TIM", - "https://neuroglancer.humanbrainproject.eu/precomputed/PLI_FOM/BI-MRI", - "https://neuroglancer.humanbrainproject.eu/precomputed/PLI_FOM/BI-MRS", - ] - - expect( - interceptedCalls - ).toContain( - jasmine.objectContaining( - { - method: 'GET', - url: 'https://neuroglancer.humanbrainproject.org/precomputed/BigBrainRelease.2015/8bit/info' - } - ) - ) - - for (const url of arrPli) { - expect( - interceptedCalls - ).toContain( - jasmine.objectContaining( - { - method: 'GET', - url: `${url}/info` - } - ) - ) - } - }) - - it('> if ref tmpl is not right, only tmpl is loaded', async () => { - const searchParam = new URLSearchParams() - searchParam.set('templateSelected', 'MNI Colin 27') - searchParam.set('parcellationSelected', 'JuBrain Cytoarchitectonic Atlas') - - const previewingDatasetFiles = [ - { - "datasetId":"minds/core/dataset/v1.0.0/b08a7dbc-7c75-4ce7-905b-690b2b1e8957", - "filename":"Overlay of data modalities" - } - ] - searchParam.set('previewingDatasetFiles', JSON.stringify(previewingDatasetFiles)) - - await iavPage.goto(`/?${searchParam.toString()}`, { interceptHttp: true, doNotAutomate: true }) - await iavPage.wait(10000) - const interceptedCalls = await iavPage.getInterceptedHttpCalls() - - expect( - interceptedCalls - ).not.toContain( - jasmine.objectContaining( - { - method: 'GET', - url: 'https://zam10143.zam.kfa-juelich.de/chumni/nifti/5c38faad1b0deab8d1674248b0107cd3637faa46a88e7a039c511163/BI-TIM/info' - } - ) - ) - - expect( - interceptedCalls - ).toContain( - jasmine.objectContaining( - { - method: 'GET', - url: 'https://neuroglancer.humanbrainproject.org/precomputed/JuBrain/v2.2c/colin27_seg/info' - } - ) - ) - }) - - }) - - describe('> controls for non atlas volumes', () => { - it('if no additional volume is being shown, additional volume control is not visible', async () => { - const searchParam = new URLSearchParams() - searchParam.set('templateSelected', 'MNI Colin 27') - searchParam.set('parcellationSelected', 'JuBrain Cytoarchitectonic Atlas') - - const previewingDatasetFiles = [ - { - "datasetId":"minds/core/dataset/v1.0.0/b08a7dbc-7c75-4ce7-905b-690b2b1e8957", - "filename":"Overlay of data modalities" - } - ] - searchParam.set('previewingDatasetFiles', JSON.stringify(previewingDatasetFiles)) - - await iavPage.goto(`/?${searchParam.toString()}`) - await iavPage.wait(2000) - - try { - const additionalLayerControlIsShown = await iavPage.isVisible(`[aria-label="${ARIA_LABELS.ADDITIONAL_VOLUME_CONTROL}"]`) - expect(additionalLayerControlIsShown).toEqual(false) - } catch (e) { - /** - * error when css querying additional volume control - * expected behaviour, when it is not visible - */ - } - - }) - - it('if additonal volumes are being shown, additional volume control is visible', async () => { - - const searchParam = new URLSearchParams() - searchParam.set('templateSelected', 'Big Brain (Histology)') - searchParam.set('parcellationSelected', 'Grey/White matter') - - const previewingDatasetFiles = [ - { - "datasetId":"minds/core/dataset/v1.0.0/b08a7dbc-7c75-4ce7-905b-690b2b1e8957", - "filename":"Overlay of data modalities" - } - ] - searchParam.set('previewingDatasetFiles', JSON.stringify(previewingDatasetFiles)) - - await iavPage.goto(`/?${searchParam.toString()}`, { forceTimeout: 20000 }) - await iavPage.wait(2000) - - const additionalLayerCtrlIsExpanded2 = await iavPage.isVisible(`[aria-label="${ARIA_LABELS.ADDITIONAL_VOLUME_CONTROL}"]`) - expect(additionalLayerCtrlIsExpanded2).toEqual(true) - - }) - - }) - -}) diff --git a/e2e/src/advanced/pluginApi.prod.e2e-spec.js b/e2e/src/advanced/pluginApi.prod.e2e-spec.js deleted file mode 100644 index 3abcab7e33d34fbd737699e18360a4f750af662b..0000000000000000000000000000000000000000 --- a/e2e/src/advanced/pluginApi.prod.e2e-spec.js +++ /dev/null @@ -1,170 +0,0 @@ -const { AtlasPage } = require('../util') -const atlasName = 'Multilevel Human Atlas' -const template = 'ICBM 152 2009c Nonlinear Asymmetric' - -const pluginName = `fzj.xg.testWidget` -const pluginDisplayName = `Test Widget Title` - -const prepareWidget = ({ template = 'hello world', script = `console.log('hello world')` } = {}) => { - - return ` -const jsSrc = \`${script.replace(/\`/, '\\`')}\` -const blob = new Blob([jsSrc], { type: 'text/javascript' }) -window.interactiveViewer.uiHandle.launchNewWidget({ - name: '${pluginName}', - displayName: '${pluginDisplayName}', - template: \`${template.replace(/\`/, '\\`')}\`, - scriptURL: URL.createObjectURL(blob) -})` -} - -describe('> plugin api', () => { - let iavPage - - beforeEach(async () => { - iavPage = new AtlasPage() - await iavPage.init() - await iavPage.goto() - await iavPage.setAtlasSpecifications(atlasName) - await iavPage.wait(500) - await iavPage.waitUntilAllChunksLoaded() - }) - - describe('> interactiveViewer', () => { - describe('> uiHandle', () => { - describe('> launchNewWidget', () => { - it('should launch new widget', async () => { - - const prevTitle = await iavPage.execScript(() => window.document.title) - await iavPage.execScript(prepareWidget({ script: `window.document.title = 'hello world ' + window.document.title` })) - - await iavPage.wait(500) - - const isDisplayed = await iavPage.widgetPanelIsDispalyed(`Test Widget Title`) - expect(isDisplayed).toEqual(true) - - const newTitle = await iavPage.execScript(() => window.document.title) - expect(newTitle).toEqual(`hello world ${prevTitle}`) - }) - }) - - describe('> cancelPromise', () => { - let originalTitle - beforeEach(async () => { - originalTitle = await iavPage.execScript(() => window.document.title) - - await iavPage.execScript(() => { - const pr = interactiveViewer.uiHandle.getUserToSelectARegion('hello world title') - pr - .then(obj => window.document.title = 'success ' + obj.segment.name) - .catch(() => window.document.title = 'failed') - window.pr = pr - }) - - await iavPage.wait(500) - - await iavPage.execScript(() => { - const pr = window.pr - interactiveViewer.uiHandle.cancelPromise(pr) - }) - }) - - it('> cancelPromise rejects promise', async () => { - const newTitle = await iavPage.execScript(() => window.document.title) - expect(newTitle).toEqual('failed') - }) - }) - - describe('> getUserToSelectARegion', () => { - let originalTitle - const cursorPos = [250, 660] - const cursorRegion = 'Area hOc1 (V1, 17, CalcS)' - beforeEach(async () => { - originalTitle = await iavPage.execScript(() => window.document.title) - - await iavPage.execScript(() => { - interactiveViewer.uiHandle.getUserToSelectARegion('hello world title') - .then(obj => window.document.title = 'success ' + obj.segment.name) - .catch(() => window.document.title = 'failed') - }) - - await iavPage.wait(500) - }) - - it('> shows modal dialog', async () => { - const text = await iavPage.getModalText() - expect(text).toContain('hello world title') - }) - - it('> modal has cancel button', async () => { - const texts = await iavPage.getModalActions() - const idx = texts.findIndex(text => /cancel/i.test(text)) - expect(idx).toBeGreaterThanOrEqual(0) - }) - - it('> cancelling by esc rejects pr', async () => { - await iavPage.clearAlerts() - await iavPage.wait(500) - const newTitle = await iavPage.execScript(() => window.document.title) - expect(newTitle).toEqual('failed') - }) - - it('> cancelling by pressing cancel rejects pr', async () => { - await iavPage.clickModalBtnByText('Cancel') - await iavPage.wait(500) - const newTitle = await iavPage.execScript(() => window.document.title) - expect(newTitle).toEqual('failed') - }) - - it('> on clicking region, resolves pr', async () => { - await iavPage.cursorMoveToAndClick({ position: cursorPos }) - await iavPage.wait(500) - const newTitle = await iavPage.execScript(() => window.document.title) - expect(newTitle).toEqual(`success ${cursorRegion}`) - }) - - it('> on failusre, clears modal', async () => { - - await iavPage.clearAlerts() - await iavPage.wait(500) - try { - const text = await iavPage.getModalText() - fail(`expected modal to clear, but modal has text ${text}`) - } catch (e) { - expect(true).toEqual(true) - } - }) - - it('> on success, clears modal', async () => { - - await iavPage.cursorMoveToAndClick({ position: cursorPos }) - await iavPage.wait(500) - - try { - const text = await iavPage.getModalText() - fail(`expected modal to clear, but modal has text ${text}`) - } catch (e) { - expect(true).toEqual(true) - } - }) - }) - }) - }) - - describe('> pluginControl', () => { - describe('> onShutdown', () => { - it('> works', async () => { - const newTitle = `testing pluginControl onShutdown` - const script = `window.interactiveViewer.pluginControl['${pluginName}'].onShutdown(() => window.document.title = '${newTitle}')` - await iavPage.execScript(prepareWidget({ script })) - await iavPage.wait(500) - const oldTitle = await iavPage.execScript(() => window.document.title) - await iavPage.closeWidgetByname(pluginDisplayName) - await iavPage.wait(500) - const actualNewTitle = await iavPage.execScript(() => window.document.title) - expect(oldTitle).not.toEqual(actualNewTitle) - expect(actualNewTitle).toEqual(newTitle) - }) - }) - }) -}) diff --git a/e2e/src/advanced/urlParsing.prod.e2e-spec.js b/e2e/src/advanced/urlParsing.prod.e2e-spec.js deleted file mode 100644 index a9a7365cc0e70ab2838e527d431d59164b34a8de..0000000000000000000000000000000000000000 --- a/e2e/src/advanced/urlParsing.prod.e2e-spec.js +++ /dev/null @@ -1,145 +0,0 @@ -const { AtlasPage } = require("../util") - -describe('> url parsing', () => { - let iavPage - - beforeEach(async () => { - iavPage = new AtlasPage() - await iavPage.init() - }) - - it('incorrectly defined templateSelected should clear searchparam', async () => { - const searchParam = '/?templateSelected=NoName2&parcellationSelected=NoName' - - await iavPage.goto(searchParam, { doNotAutomate: true }) - await iavPage.waitFor(500) - const text = await iavPage.getSnackbarMessage() - expect(text).toEqual(`Template not found.`) - }) - - it('> navigation state should be perserved', async () => { - - const searchParam = `/?templateSelected=Big+Brain+%28Histology%29&parcellationSelected=Cytoarchitectonic+Maps&cNavigation=zvyba.z0UJ7._WMxv.-TTch..2_cJ0e.2-OUQG._a9qP._QPHw..7LIx..2CQ3O.1FYC.259Wu..2r6` - const expectedNav = { - "position": [ - 36806872, - 325772, - 34904120 - ], - "orientation": [ - 0.1131771132349968, - 0.031712327152490616, - 0.2527998387813568, - 0.9603527784347534 - ], - "zoom": 11590, - "perspectiveZoom": 1922235, - "perspectiveOrientation": [ - -0.2991955280303955, - -0.8824243545532227, - 0.28244855999946594, - 0.22810545563697815 - ] - } - - await iavPage.goto(searchParam, { doNotAutomate: true }) - await iavPage.wait(2000) - const actualNav = await iavPage.getNavigationState() - - expect(expectedNav.orientation).toEqual(actualNav.orientation) - expect(expectedNav.zoom).toEqual(actualNav.zoom) - - // TODO this test fails occassionally - // tracking issue: https://github.com/HumanBrainProject/interactive-viewer/issues/464 - // expect(expectedNav.position).toEqual(actualNav.position) - expect(expectedNav.perspectiveOrientation).toEqual(actualNav.perspectiveOrientation) - expect(expectedNav.perspectiveZoom).toEqual(actualNav.perspectiveZoom) - - }) - - it('> if cRegionSelected is defined, should select region in viewer', async () => { - const url = '/?templateSelected=MNI+152+ICBM+2009c+Nonlinear+Asymmetric&parcellationSelected=JuBrain+Cytoarchitectonic+Atlas&cRegionsSelected=%7B"jubrain+mni152+v18+left"%3A"8"%7D' - await iavPage.goto(url) - await iavPage.clearAlerts() - - const { red, green, blue } = await iavPage.getRgbAt({ position: [600, 490] }) - expect(red).toBeGreaterThan(0) - expect(red).toEqual(green) - expect(red).toEqual(blue) - }) - - it('> [bkwards compat] if ill defined labelIndex for regionsSelected are defined, should handle gracefully', async () => { - const url = '/?parcellationSelected=JuBrain+Cytoarchitectonic+Atlas&templateSelected=MNI+Colin+27&navigation=0_0_0_1__-0.2753947079181671_0.6631333827972412_-0.6360703706741333_0.2825356423854828__3000000__-17800000_-6700000_-7500000__200000®ionsSelected=142&niftiLayers=https%3A%2F%2Fneuroglancer.humanbrainproject.org%2Fprecomputed%2FJuBrain%2Fv2.2c%2FPMaps%2FBforebrain_4.nii' - await iavPage.goto(url) - await iavPage.clearAlerts() - await iavPage.wait(5000) - await iavPage.waitForAsync() - const log = await iavPage.getLog() - const filteredLog = log - // in headless & non gpu mode, a lot of webgl warnings are thrown - .filter(({ level }) => level.toString() === 'SEVERE') - .filter(({ message }) => !/Access-Control-Allow-Origin/.test(message)) - - // expecting some errors in the console. In catastrophic event, there will most likely be looped errors (on each render cycle) - // capture logs and write to spec - expect( - filteredLog.length - ).withContext( - JSON.stringify(filteredLog) - ).toBeLessThan( - 50, - ) - }) - - it('> if niftiLayers are defined, parcellation layer should be hidden', async () => { - const url = `/?parcellationSelected=JuBrain+Cytoarchitectonic+Atlas&templateSelected=MNI+Colin+27&cNavigation=0.0.0.-W000.._NjRq.2-Klk_._-Hmu.2_BdKx..DMVW..1vjMG.4eIG8~.hqT5~..10vB®ionsSelected=142&niftiLayers=https%3A%2F%2Fneuroglancer.humanbrainproject.org%2Fprecomputed%2FJuBrain%2Fv2.2c%2FPMaps%2FBforebrain_4.nii` - await iavPage.goto(url) - await iavPage.clearAlerts() - - const { red, green, blue } = await iavPage.getRgbAt({ position: [600, 490] }) - - expect(red).toBeGreaterThan(0) - expect(red).toEqual(green) - expect(red).toEqual(blue) - }) - - it('> if using niftilayers should show deprecation worning') - - it('> pluginStates should be fetched even if no template or parc are selected', async () => { - - const searchParam = new URLSearchParams() - searchParam.set('pluginStates', 'http://localhost:3001/manifest.json') - await iavPage.goto(`/?${searchParam.toString()}`, { interceptHttp: true, doNotAutomate: true }) - await iavPage.wait(10000) - const interceptedCalls = await iavPage.getInterceptedHttpCalls() - expect( - interceptedCalls - ).toContain(jasmine.objectContaining( - { - method: 'GET', - url: 'http://localhost:3001/manifest.json' - } - )) - }) - - it('> pluginStates should result in xhr to get pluginManifest', async () => { - - const searchParam = new URLSearchParams() - searchParam.set('templateSelected', 'MNI 152 ICBM 2009c Nonlinear Asymmetric') - searchParam.set('parcellationSelected', 'JuBrain Cytoarchitectonic Atlas') - searchParam.set('pluginStates', 'http://localhost:3001/manifest.json') - - await iavPage.goto(`/?${searchParam.toString()}`, { interceptHttp: true, doNotAutomate: true }) - await iavPage.wait(10000) - const interceptedCalls = await iavPage.getInterceptedHttpCalls() - expect( - interceptedCalls - ).toContain(jasmine.objectContaining( - { - method: 'GET', - url: 'http://localhost:3001/manifest.json' - } - )) - }) - -}) diff --git a/e2e/src/layout/atlasWidgetBtns.prod.e2e-spec.js b/e2e/src/layout/atlasWidgetBtns.prod.e2e-spec.js deleted file mode 100644 index a9936493c68400e87288e5ed8eace99dcf69c74c..0000000000000000000000000000000000000000 --- a/e2e/src/layout/atlasWidgetBtns.prod.e2e-spec.js +++ /dev/null @@ -1,40 +0,0 @@ -/** - * TODO finish tests! - */ - -describe('> atlas widget btns', () => { - it('> fails unless tests are written', () => { - expect(true).toEqual(false) - }) - describe('> when default layer is selected', () => { - it('> hierarchy btn should show hierarchy', () => { - - }) - - it('> connectivity btn should show connectivity', () => { - - }) - - it('> dataset should show dataset', () => { - - }) - }) - - describe('> when another layer is displayed', () => { - it('> mat-chip should update', () => { - - }) - - it('> cicking close on mat chip should result in removing additional layer', () => { - - }) - - it('> hierarchy should be updated', () => { - - }) - - it('> databrowser should be updated', () => { - - }) - }) -}) \ No newline at end of file diff --git a/e2e/src/layout/home.prod.e2e-spec.js b/e2e/src/layout/home.prod.e2e-spec.js deleted file mode 100644 index 0ef5abf53e2514e935dca67b9e3798cd5fca04aa..0000000000000000000000000000000000000000 --- a/e2e/src/layout/home.prod.e2e-spec.js +++ /dev/null @@ -1,30 +0,0 @@ -const { BasePage } = require('../util') - -describe('> home.prod.e2e-spec.js', () => { - describe('> home page', () => { - it('> should load home page', async () => { - const newPage = new BasePage() - await newPage.init() - await newPage.goto() - const cards = await newPage.areVisible(`mat-card`) - /** - * expecting 3 atlases - */ - expect(cards.length).toEqual(3) - }) - }) - - describe('> quickstart', () => { - it('> should load quickstart page', async () => { - - const newPage = new BasePage() - await newPage.init() - await newPage.goto(`/quickstart`) - const table = await newPage.areVisible(`table`) - /** - * expecting at least 1 table - */ - expect(table.length).toBeGreaterThan(0) - }) - }) -}) diff --git a/e2e/src/layout/layout.prod.e2e-spec.js b/e2e/src/layout/layout.prod.e2e-spec.js deleted file mode 100644 index e3fcfde8465be3e1cf1251d2e72d414cd2a8b831..0000000000000000000000000000000000000000 --- a/e2e/src/layout/layout.prod.e2e-spec.js +++ /dev/null @@ -1,108 +0,0 @@ -const { AtlasPage } = require('../util') - -const MAT_SIDENAV_TIMEOUT = 500 - -describe('> sidenav', () => { - let atlasPage - - beforeEach(async () => { - atlasPage = new AtlasPage() - await atlasPage.init() - await atlasPage.goto('/?templateSelected=MNI+152+ICBM+2009c+Nonlinear+Asymmetric&parcellationSelected=JuBrain+Cytoarchitectonic+Atlas') - await atlasPage.wait(MAT_SIDENAV_TIMEOUT) - await atlasPage.dismissModal() - - do { - - } while( - await atlasPage.wait(100), - !(await atlasPage.viewerIsPopulated()) - ) - }) - - it('> on init, side panel should be visible', async () => { - const sideNavIsDisplayed = await atlasPage.sideNavIsVisible() - expect(sideNavIsDisplayed).toEqual(true) - - const toggleTabIsDIsplayed = await atlasPage.sideNavTabIsVisible() - expect(toggleTabIsDIsplayed).toEqual(true) - }) - - describe('> toggling', () => { - it('> toggle tab should toggle side nav', async () => { - const init = await atlasPage.sideNavIsVisible() - expect(init).toEqual(true) - - await atlasPage.clickSideNavTab() - await atlasPage.wait(MAT_SIDENAV_TIMEOUT) - const expectHidden = await atlasPage.sideNavIsVisible() - expect(expectHidden).toEqual(false) - - await atlasPage.clickSideNavTab() - await atlasPage.wait(MAT_SIDENAV_TIMEOUT) - const expectShown = await atlasPage.sideNavIsVisible() - expect(expectShown).toEqual(true) - }) - }) -}) - -describe('> status panel', () => { - - let atlasPage - - beforeEach(async () => { - atlasPage = new AtlasPage() - await atlasPage.init() - await atlasPage.goto('/?templateSelected=MNI+152+ICBM+2009c+Nonlinear+Asymmetric&parcellationSelected=JuBrain+Cytoarchitectonic+Atlas') - await atlasPage.wait(MAT_SIDENAV_TIMEOUT) - await atlasPage.dismissModal() - - do { - - } while( - await atlasPage.wait(100), - !(await atlasPage.viewerIsPopulated()) - ) - }) - - afterEach(() => { - atlasPage = null - }) - - it('> on init, status panel should not be visible', async () => { - - const init = await atlasPage.statusPanelIsVisible() - expect(init).toEqual(false) - }) - - it('> on toggling side panel, status panel should become visible', async () => { - await atlasPage.clickSideNavTab() - await atlasPage.wait(MAT_SIDENAV_TIMEOUT) - - const expectVisible = await atlasPage.statusPanelIsVisible() - expect(expectVisible).toEqual(true) - }) - - it('> on click status panel, side nav become visible, status panel become invisible', async () => { - - await atlasPage.clickSideNavTab() - await atlasPage.wait(MAT_SIDENAV_TIMEOUT) - - await atlasPage.clickStatusPanel() - await atlasPage.wait(MAT_SIDENAV_TIMEOUT) - - const expectHidden = await atlasPage.statusPanelIsVisible() - expect(expectHidden).toEqual(false) - - const expectVisible = await atlasPage.sideNavIsVisible() - expect(expectVisible).toEqual(true) - }) -}) - -describe('> double mat drawer', () => { - describe('> on user interaction', () => { - describe('> when user closes region chip', () => { - it('> mat drawers should remain closed') - }) - }) -}) diff --git a/e2e/src/layout/pluginInfo.e2e-spec.js b/e2e/src/layout/pluginInfo.e2e-spec.js deleted file mode 100644 index 50bc4e83a8fed67fc087ef06559a2112474447c5..0000000000000000000000000000000000000000 --- a/e2e/src/layout/pluginInfo.e2e-spec.js +++ /dev/null @@ -1,35 +0,0 @@ -const { LayoutPage } = require("../util") - -describe('> plugin dropdown', () => { - let layoutPage - - beforeEach(async () => { - layoutPage = new LayoutPage() - await layoutPage.init() - await layoutPage.goto() - await layoutPage.dismissModal() - }) - - it('> click on drop down btn shows drop down menu', async () => { - await layoutPage.showToolsMenu() - await layoutPage.wait(500) - const tools = await layoutPage.getVisibleTools() - expect(tools.length).toBeGreaterThan(0) - }) - - it('> click on info btn shows info', async () => { - await layoutPage.showToolsMenu() - await layoutPage.wait(500) - const tools = await layoutPage.getVisibleTools() - const exampleIndex = tools.findIndex(tool => /Example\ Plugin/.test(tool)) - expect(exampleIndex).toBeGreaterThanOrEqual(0) - await layoutPage.clickOnNthTool(exampleIndex, '[aria-label="About this plugin"]') - await layoutPage.wait(500) - const txt = await layoutPage.getModalText() - expect(txt).toContain('About Example Plugin (v0.0.1)') - expect(txt).toContain('description of example plugin') - expect(txt).toContain('http://HOSTNAME/home.html') - expect(txt).toContain('Xiaoyun Gui <x.gui@fz-juelich.de>') - - }) -}) diff --git a/e2e/src/layout/scrollDatasetContainer.prod.e2e-spec.js b/e2e/src/layout/scrollDatasetContainer.prod.e2e-spec.js deleted file mode 100644 index 97c457c1c34d849f36269c631c283d532616d42e..0000000000000000000000000000000000000000 --- a/e2e/src/layout/scrollDatasetContainer.prod.e2e-spec.js +++ /dev/null @@ -1,36 +0,0 @@ -const { AtlasPage } = require('../util') -const { ARIA_LABELS } = require('../../../common/constants') -describe('> scroll dataset container', () => { - let iavPage - - beforeEach(async () => { - iavPage = new AtlasPage() - await iavPage.init() - - }) - - it('> can scroll to the end', async () => { - await iavPage.goto() - await iavPage.selectTitleCard('ICBM 2009c Nonlinear Asymmetric') - await iavPage.wait(1000) - await iavPage.waitForAsync() - - await iavPage.click(`[aria-label="${ARIA_LABELS.TOGGLE_EXPLORE_PANEL}"]`) - - await iavPage.clearAlerts() - - let countdown = 100 - do { - await iavPage.scrollElementBy(`[aria-label="${ARIA_LABELS.LIST_OF_DATASETS}"]`, { - delta: [0, 100] - }) - await iavPage.wait(100) - countdown -- - }while(countdown > 0) - - await iavPage.wait(500) - - const val = await iavPage.getScrollStatus(`[aria-label="${ARIA_LABELS.LIST_OF_DATASETS}"]`) - expect(val).toBeGreaterThanOrEqual(9900) - }) -}) \ No newline at end of file diff --git a/e2e/src/layout/statusbar.prod.e2e-spec.js b/e2e/src/layout/statusbar.prod.e2e-spec.js deleted file mode 100644 index facf6b01c61327e12946de0f04fdc67f6a43eb72..0000000000000000000000000000000000000000 --- a/e2e/src/layout/statusbar.prod.e2e-spec.js +++ /dev/null @@ -1,75 +0,0 @@ -const { AtlasPage } = require('../util') -const { ARIA_LABELS } = require('../../../common/constants') -const { retry } = require('../../../common/util') -describe('> statusbar', () => { - let atlasPage = new AtlasPage() - beforeEach(async () => { - atlasPage = new AtlasPage() - await atlasPage.init() - }) - - it('> on init, should not be visible', async () => { - await atlasPage.goto() - try { - const visible = await atlasPage.isVisible(`[aria-label="${ARIA_LABELS.STATUS_PANEL}"]`) - expect(visible).toBeFalsy() - } catch (e) { - - } - }) - - describe('> on template selection', () => { - beforeEach(async () => { - await atlasPage.goto() - await atlasPage.selectTitleCard('MNI Colin 27') - await retry(async () => { - const populated = await atlasPage.viewerIsPopulated() - if (!populated) throw new Error(`viewer not yet populated`) - }, { retries: 10, timeout: 500 }) - - }) - it('> on template selection, should be visible', async () => { - - const visible = await atlasPage.isVisible(`[aria-label="${ARIA_LABELS.STATUS_PANEL}"]`) - expect(visible).toBeTruthy() - }) - - it('> on template selection, minimised status panel should be visible', async () => { - const maximaizeVisible = await atlasPage.isVisible(`[aria-label="${ARIA_LABELS.SHOW_FULL_STATUS_PANEL}"]`) - expect(maximaizeVisible).toBeTruthy() - try { - const minimizeVisible = await atlasPage.isVisible(`[aria-label="${ARIA_LABELS.HIDE_FULL_STATUS_PANEL}"]`) - expect(minimizeVisible).toBeFalsy() - } catch (e) { - - } - }) - - it('> clicking maximise btn should maximise the status panel', async () => { - await atlasPage.click(`[aria-label="${ARIA_LABELS.SHOW_FULL_STATUS_PANEL}"]`) - await atlasPage.wait(500) - const minimizeVisible = await atlasPage.isVisible(`[aria-label="${ARIA_LABELS.HIDE_FULL_STATUS_PANEL}"]`) - expect(minimizeVisible).toBeTruthy() - try { - const maxVisible = await atlasPage.isVisible(`[aria-label="${ARIA_LABELS.SHOW_FULL_STATUS_PANEL}"]`) - expect(maxVisible).toBeFalsy() - } catch (e) { - - } - }) - - it('> click min btn should minimize', async () => { - await atlasPage.click(`[aria-label="${ARIA_LABELS.SHOW_FULL_STATUS_PANEL}"]`) - await atlasPage.wait(500) - await atlasPage.click(`[aria-label="${ARIA_LABELS.HIDE_FULL_STATUS_PANEL}"]`) - await atlasPage.wait(500) - try { - const minimizeVisible = await atlasPage.isVisible(`[aria-label="${ARIA_LABELS.HIDE_FULL_STATUS_PANEL}"]`) - expect(minimizeVisible).toBeFalsy() - } catch (e) { - - } - }) - }) - -}) \ No newline at end of file diff --git a/e2e/src/layout/viewerCtxMenu.prod.e2e-spec.js b/e2e/src/layout/viewerCtxMenu.prod.e2e-spec.js deleted file mode 100644 index 78ffbd9410cd826e6bc9ba846f2a59a56248ea6c..0000000000000000000000000000000000000000 --- a/e2e/src/layout/viewerCtxMenu.prod.e2e-spec.js +++ /dev/null @@ -1,94 +0,0 @@ -const { AtlasPage } = require('../util') -const { ARIA_LABELS } = require('../../../common/constants') -const dict = { - "ICBM 2009c Nonlinear Asymmetric": { - "JuBrain Cytoarchitectonic Atlas": { - tests:[ - { - position: [550, 270], - expectedLabelName: 'Fastigial Nucleus (Cerebellum) - right hemisphere', - } - ] - } - }, - "Big Brain (Histology)": { - "Cytoarchitectonic Maps": { - tests:[ - { - position: [440,200], - expectedLabelName: 'Area hOc1 (V1, 17, CalcS)', - expectedLabelStatus: '(fully mapped)' - } - ] - } - } -} - -describe('> viewerCtxMenu', () => { - - for (const templateName in dict) { - for (const parcellationName in dict[templateName]) { - describe(`> on ${templateName} / ${parcellationName}`, () => { - beforeAll(async () => { - iavPage = new AtlasPage() - await iavPage.init() - await iavPage.goto() - await iavPage.selectTitleTemplateParcellation(templateName, parcellationName) - await iavPage.wait(500) - await iavPage.waitForAsync() - }) - - it('> does not appear on init', async () => { - const visible = await iavPage.isVisible(`[aria-label="${ARIA_LABELS.CONTEXT_MENU}"]`) - expect(visible).toBeFalse() - }) - - it('> appears on click', async () => { - const { tests } = dict[templateName][parcellationName] - const { position } = tests[0] - await iavPage.cursorMoveToAndClick({ position }) - await iavPage.wait(500) - const visible = await iavPage.isVisible(`[aria-label="${ARIA_LABELS.CONTEXT_MENU}"]`) - expect(visible).toBeTrue() - }) - - it('> Title includes region status', async () => { - const { tests } = dict[templateName][parcellationName] - const { expectedLabelStatus, expectedLabelName } = tests[0] - await iavPage.wait(500) - if (expectedLabelStatus) { - const fullMenuText = await iavPage.getText(`[aria-label="${ARIA_LABELS.CONTEXT_MENU}"]`) - expect(fullMenuText.includes(`${expectedLabelName} ${expectedLabelStatus}`)).toEqual(true) - } - }) - - it('> Title do not includes region status', async () => { - const { tests } = dict[templateName][parcellationName] - const { expectedLabelStatus, expectedLabelName } = tests[0] - await iavPage.wait(500) - if (!expectedLabelStatus) { - const fullMenuText = await iavPage.getText(`[aria-label="${ARIA_LABELS.CONTEXT_MENU}"]`) - expect(fullMenuText.includes(expectedLabelName)).toEqual(true) - } - }) - - it('> pos does not change when click inside', async () => { - const { x: xBefore, y: yBefore, height: hBefore } = await iavPage.isAt(`[aria-label="${ARIA_LABELS.CONTEXT_MENU}"]`) - await iavPage.click(`[aria-label="${ARIA_LABELS.SHOW_IN_OTHER_REF_SPACE}"]`) - await iavPage.wait(500) - const { x: xAfter, y: yAfter, height: hAfter } = await iavPage.isAt(`[aria-label="${ARIA_LABELS.CONTEXT_MENU}"]`) - expect(xBefore).toEqual(xAfter) - expect(yBefore).toEqual(yAfter) - expect(hAfter).toBeGreaterThan(hBefore) - }) - - it('> disappear again on click of anywhere else', async () => { - await iavPage.cursorMoveToAndClick({ position: [10, 10] }) - await iavPage.wait(500) - const visible = await iavPage.isVisible(`[aria-label="${ARIA_LABELS.CONTEXT_MENU}"]`) - expect(visible).toBeFalse() - }) - }) - } - } -}) diff --git a/e2e/src/material-util.js b/e2e/src/material-util.js deleted file mode 100644 index 04f9c994fac5310b6d1c50ab915ec3f1ddcc215f..0000000000000000000000000000000000000000 --- a/e2e/src/material-util.js +++ /dev/null @@ -1,19 +0,0 @@ -const { By } = require('selenium-webdriver') - -async function polyFillClick(cssSelector){ - if (!cssSelector) throw new Error(`click method needs to define a css selector`) - const webEl = this._browser.findElement( By.css(cssSelector) ) - try { - await webEl.click() - } catch (e) { - const id = await webEl.getAttribute('id') - const newId = id.replace(/-input$/, '') - await this._browser.findElement( - By.id(newId) - ).click() - } -} - -module.exports = { - polyFillClick -} diff --git a/e2e/src/navigating/btnZoomInOut.prod.e2e-spec.js b/e2e/src/navigating/btnZoomInOut.prod.e2e-spec.js deleted file mode 100644 index d8349964da698991f33631ca33365f6b4f0fbacb..0000000000000000000000000000000000000000 --- a/e2e/src/navigating/btnZoomInOut.prod.e2e-spec.js +++ /dev/null @@ -1,138 +0,0 @@ -const { AtlasPage } = require('../util') -const { width, height } = require('../../opts') -const { ARIA_LABELS } = require('../../../common/constants') - -describe('> zoom in btns on panels', () => { - - let iavPage - const url = '/?templateSelected=MNI+152+ICBM+2009c+Nonlinear+Asymmetric&parcellationSelected=JuBrain+Cytoarchitectonic+Atlas' - - describe('> on hover overlay elements', () => { - beforeEach(async () => { - iavPage = new AtlasPage() - await iavPage.init() - await iavPage.goto(url) - }) - it('> panel btns do not show', async () => { - - await iavPage.cursorMoveToElement(`[aria-label="${ARIA_LABELS.SELECT_ATLAS}"]`) - - await iavPage.wait(500) - - const visibleFlags = await iavPage.areVisible(`[aria-label="${ARIA_LABELS.ZOOM_IN}"]`) - expect(visibleFlags.length).toBe(4) - expect(visibleFlags).toEqual([false, false, false, false]) - }) - }) - - const delta = 30 - const arr = [ - [ width / 2 - delta, height / 2 - delta ], - [ width / 2 + delta, height / 2 - delta ], - [ width / 2 - delta, height / 2 + delta ], - [ width / 2 + delta, height / 2 + delta ], - ] - - for (const key of [ ARIA_LABELS.ZOOM_IN, ARIA_LABELS.ZOOM_OUT ]) { - describe(`> testing ${key}`, () => { - - for (const idx in arr) { - describe(`> panel ${idx}`, () => { - beforeAll(async () => { - iavPage = new AtlasPage() - await iavPage.init() - await iavPage.goto(url) - }) - it('> mouse over should show zoom btns', async () => { - - await iavPage.cursorMoveTo({ - position: arr[idx] - }) - - await iavPage.wait(500) - const visibleFlags = await iavPage.areVisible(`[aria-label="${key}"]`) - expect(visibleFlags.length).toBe(4) - - const expectedFlags = [false, false, false, false] - expectedFlags[idx] = true - expect(visibleFlags).toEqual(expectedFlags) - }) - - - describe(`> "${key}" btns btn works`, () => { - let o, po, pz, z, p, - no2, npo2, npz2, nz2, np2 - beforeAll(async () => { - - const navState = await iavPage.getNavigationState() - - o = navState.orientation - po = navState.perspectiveOrientation - pz = navState.perspectiveZoom - z = navState.zoom - p = navState.position - - const arrOut = await iavPage.areAt(`[aria-label="${key}"]`) - - const positionOut = [ - arrOut[idx].x + arrOut[idx].width / 2, - arrOut[idx].y + arrOut[idx].height / 2 - ] - await iavPage.cursorMoveToAndClick({ - position: positionOut - }) - await iavPage.wait(2000) - const newNavState2 = await iavPage.getNavigationState() - no2 = newNavState2.orientation - npo2 = newNavState2.perspectiveOrientation - npz2 = newNavState2.perspectiveZoom - nz2 = newNavState2.zoom - np2 = newNavState2.position - - }) - - it('> expect orientation to be unchanged', () => { - expect(o).toEqual(no2) - }) - - it('> expects perspective orientation to be unchanged', () => { - expect(po).toEqual(npo2) - }) - - it('> expect position to be unchanged', () => { - expect(p).toEqual(np2) - }) - - /** - * when iterating over array accessor, the key are actually string - */ - if (Number(idx) === 3) { - it('> expects zoom to be unchanged', () => { - expect(z).toEqual(nz2) - }) - it('> expects perspectivezoom to increase with zoom out btn', () => { - if (key === ARIA_LABELS.ZOOM_OUT) { - expect(pz).toBeLessThan(npz2) - } else { - expect(pz).toBeGreaterThan(npz2) - } - }) - } else { - it('> expects perspective zoom to be unchanged', () => { - expect(pz).toEqual(npz2) - }) - - it('> expect zoom to increase with zoom out btn', () => { - if (key === ARIA_LABELS.ZOOM_OUT) { - expect(z).toBeLessThan(nz2) - } else { - expect(z).toBeGreaterThan(nz2) - } - }) - } - }) - }) - } - }) - } -}) diff --git a/e2e/src/navigating/changeTemplate.prod.e2e-spec.js b/e2e/src/navigating/changeTemplate.prod.e2e-spec.js deleted file mode 100644 index df74a6cbdc3326ff0640abe1e7ae9d8d49998fff..0000000000000000000000000000000000000000 --- a/e2e/src/navigating/changeTemplate.prod.e2e-spec.js +++ /dev/null @@ -1,65 +0,0 @@ -const { AtlasPage } = require('../util') - -describe('trans template navigation', () => { - let iavPage - - beforeEach(async () => { - iavPage = new AtlasPage() - await iavPage.init() - - }) - - it('when user moves from template a -> template b, a xhr call is made', async () => { - - const searchParam = new URLSearchParams() - searchParam.set('templateSelected', 'MNI 152 ICBM 2009c Nonlinear Asymmetric') - searchParam.set('parcellationSelected', 'JuBrain Cytoarchitectonic Atlas') - await iavPage.goto(`/?${searchParam.toString()}`, { interceptHttp: true, doNotAutomate: true }) - await iavPage.wait(200) - await iavPage.dismissModal() - - await iavPage.waitUntilAllChunksLoaded() - - await iavPage.selectDropdownTemplate('Big Brain (Histology)') - await iavPage.wait(2000) - const interceptedCalls = await iavPage.getInterceptedHttpCalls() - - expect(interceptedCalls).toBeTruthy() - - const found = interceptedCalls && interceptedCalls.find(({ method, url }) => { - return method === 'POST' && /transform-points/.test(url) - }) - expect(!!found).toBe(true) - }) - - it('Check region color after template change when region was selected', async () => { - - const url = '/?templateSelected=MNI+152+ICBM+2009c+Nonlinear+Asymmetric&parcellationSelected=JuBrain+Cytoarchitectonic+Atlas' - const area = 'Area TE 3 (STG) - right hemisphere' - const expectedPosition = [630, 510] - const expectedColor = {red: 70, green: 139, blue: 57} - - await iavPage.goto(url) - - await iavPage.searchRegionWithText(area) - await iavPage.wait(1000) - - await iavPage.selectSearchRegionAutocompleteWithText() - await iavPage.dismissModal() - await iavPage.wait(500) - await iavPage.selectDropdownTemplate('MNI Colin 27') - /** - * wait for template translate & js execution - */ - await iavPage.wait(1000) - await iavPage.waitUntilAllChunksLoaded() - const actualColor = await iavPage.getRgbAt({ position: expectedPosition }) - - for (const key in actualColor) { - expect(Math.abs(actualColor[key] - expectedColor[key])).toBeLessThan(5) - } - - }) - - // TODO test that nav/zoom/orientation are actually preserved -}) diff --git a/e2e/src/navigating/loadingOrder.prod.e2e-spec.js b/e2e/src/navigating/loadingOrder.prod.e2e-spec.js deleted file mode 100644 index dc62278d79d3ef39bf926952d4f8eec73e0a30cb..0000000000000000000000000000000000000000 --- a/e2e/src/navigating/loadingOrder.prod.e2e-spec.js +++ /dev/null @@ -1,120 +0,0 @@ -const { AtlasPage } = require('../util') -const { IDS } = require('../../../common/constants') -const { width, height } = require('../../opts') -const { hrtime } = process - -const templates = [ - ["Big Brain (Histology)", "Cytoarchitectonic Maps"], - ["Waxholm Space rat brain MRI/DTI", "Waxholm Space rat brain atlas v3"] -] - -describe('> when loading an atlas', () => { - let iavPage = new AtlasPage() - - const getNumOfSpinners = async () => { - - try { - return await iavPage.execScript(` - const els = document.querySelectorAll('.spinnerAnimationCircle') - return els && els.length - `) - } catch (e) { - return false - } - } - - const checkRoleStatus = async () => { - try { - const text = await iavPage.execScript(` - const el = document.getElementById('${IDS.MESH_LOADING_STATUS}') - return el && el.textContent - `) - return text && /Loading\s.*?chunks/.test(text) - } catch (e) { - return false - } - } - - beforeEach(async () => { - iavPage = new AtlasPage() - await iavPage.init() - await iavPage.goto() - }) - - for (const [template, parcelation] of templates) { - - const masterTimer = {moving: null, nonmoving: null} - - it(`> for ${template}, image will be loaded first`, async () => { - const timer = hrtime() - await iavPage.selectTitleTemplateParcellation(template, parcelation) - await iavPage.wait(500) - const preSpinners = await getNumOfSpinners() - expect(preSpinners).toBe(4) - while( await checkRoleStatus() ) { - await iavPage.wait(200) - } - - const finishedTimer = hrtime(timer) - - const postSpinners = await getNumOfSpinners() - /** - * There is currently a known bug that spinner in IDS.MESH_LOADING_STATUS is hidden with opacity 0 rather than unload from DOM - * TODO fix bug - */ - expect(postSpinners).toBeLessThanOrEqual(2) - expect(postSpinners).toBeGreaterThanOrEqual(1) - - const sec = finishedTimer[0] + finishedTimer[1] / 1e9 - masterTimer.nonmoving = sec - }) - - it('> if user was panning, it should take longer as loading takes priority', async () => { - const timer = hrtime() - await iavPage.selectTitleTemplateParcellation(template, parcelation) - await iavPage.wait(500) - - await iavPage.cursorMoveToAndDrag({ - position: [ Math.round(width / 4 * 3), Math.round(height / 4) ], - delta: [ Math.round(width / 8), Math.round(height / 8)] - }) - - await iavPage.wait(500) - - await iavPage.cursorMoveToAndDrag({ - position: [ Math.round(width / 4 * 3), Math.round(height / 4) ], - delta: [ 1, Math.round(height / -4)] - }) - - while( await checkRoleStatus() ) { - await iavPage.wait(200) - } - - const finishedTimer = hrtime(timer) - - const sec = finishedTimer[0] + finishedTimer[1] / 1e9 - masterTimer.moving = sec - - expect(masterTimer.moving).toBeGreaterThan(masterTimer.nonmoving) - }) - - it('> if the meshes are already loading, do not show overlay', async () => { - - await iavPage.selectTitleTemplateParcellation(template, parcelation) - await iavPage.wait(500) - - while( await checkRoleStatus() ) { - await iavPage.wait(200) - } - - await iavPage.cursorMoveToAndDrag({ - position: [ Math.round(width / 4 * 3), Math.round(height / 4) ], - delta: [ Math.round(width / 8), Math.round(height / 8)] - }) - - const roleStatus = await checkRoleStatus() - - expect(roleStatus).toBeFalsy() - }) - } -}) diff --git a/e2e/src/navigating/mouseOverNehuba.prod.e2e-spec.js b/e2e/src/navigating/mouseOverNehuba.prod.e2e-spec.js deleted file mode 100644 index d446ea1ed137df9132c2b1a62ecc1781c0e42df8..0000000000000000000000000000000000000000 --- a/e2e/src/navigating/mouseOverNehuba.prod.e2e-spec.js +++ /dev/null @@ -1,193 +0,0 @@ -const { AtlasPage } = require('../util') - -const dictionary = { - "Allen Mouse Common Coordinate Framework v3": { - "Allen Mouse Common Coordinate Framework v3 2017": { - tests: [ - { - position: [530, 530], - expectedLabelName: 'Primary somatosensory area, barrel field, layer 4', - }, - { - position: [590, 120], - expectedLabelName: 'Retrosplenial area, ventral part, layer 2/3', - } - ] - }, - "Allen Mouse Common Coordinate Framework v3 2015": { - tests: [ - { - position: [520, 530], - expectedLabelName: 'Primary somatosensory area, barrel field', - }, - { - position: [588, 115], - expectedLabelName: 'Retrosplenial area, ventral part', - } - ] - } - }, - "Waxholm Space rat brain MRI/DTI": { - "Waxholm Space rat brain atlas v3": { - tests: [ - { - position: [350, 170], - expectedLabelName: 'neocortex', - }, - { - position: [320, 560], - expectedLabelName: 'corpus callosum and associated subcortical white matter', - } - ] - }, - "Waxholm Space rat brain atlas v2": { - tests: [ - { - position: [500, 630], - expectedLabelName: 'lateral entorhinal cortex', - }, - { - position: [300, 200], - expectedLabelName: 'dentate gyrus', - } - ] - }, - "Waxholm Space rat brain atlas v1": { - tests: [ - { - position: [480, 680], - expectedLabelName: 'inner ear', - }, - { - position: [550, 550], - expectedLabelName: 'corpus callosum and associated subcortical white matter', - } - ] - } - }, - "ICBM 2009c Nonlinear Asymmetric": { - "JuBrain Cytoarchitectonic Atlas": { - tests:[ - { - position: [550, 270], - expectedLabelName: 'Fastigial Nucleus (Cerebellum) - right hemisphere', - }, - { - position: [600, 490], - expectedLabelName: 'Area 6ma (preSMA, mesial SFG) - left hemisphere', - } - ] - }, - "Fibre Bundle Atlas - Long Bundle": { - tests: [ - { - position: [300, 210], - expectedLabelName: 'InferiorFrontoOccipital - Right', - }, - { - position: [680, 590], - expectedLabelName: 'InferiorLongitudinal - Left', - } - ] - }, - "Fibre Bundle Atlas - Short Bundle": { - tests: [ - { - position: [300, 100], - expectedLabelName: 'rh_SP-SM_0', - }, - { - /** - * Changed from [677, 579] as it is extremely unfortunate in that - * it is literally the connecting point between lh_CAC-PrCu_0 and lh_PoCi-PrCu_0 - */ - position: [677, 579], - expectedLabelName: 'lh_ST-TT_0', - } - ] - } - }, - // TODO big brain cytomap occassionally resets center position to -20mm. investigate why - "Big Brain (Histology)": { - "Cytoarchitectonic Maps": { - url: "/?templateSelected=Big+Brain+%28Histology%29&parcellationSelected=Cytoarchitectonic+Maps&cNavigation=0.0.0.-W000.._eCwg.2-FUe3._-s_W.2_evlu..7LIx..1n5q~.1FYC.2Is-..1B9C", - tests: [ - { - position: [686, 677], - expectedLabelName: 'Area STS1 (STS)' - }, - { - position: [617,682], - expectedLabelName: 'Entorhinal Cortex' - } - ] - }, - "BigBrain Cortical Layers Segmentation": { - url: "/?templateSelected=Big+Brain+%28Histology%29&parcellationSelected=BigBrain+Cortical+Layers+Segmentation&cNavigation=0.0.0.-W000.._eCwg.2-FUe3._-s_W.2_evlu..7LIx..2c8U8.1FYC.wfmi..91G", - tests: [ - { - position: [330, 550], - expectedLabelName: 'cortical layer 6', - }, - { - position: [475, 244], - expectedLabelName: 'cortical layer 1', - } - ] - }, - "Grey/White matter": { - url: "/?templateSelected=Big+Brain+%28Histology%29&parcellationSelected=Grey%2FWhite+matter&cNavigation=0.0.0.-W000.._eCwg.2-FUe3._-s_W.2_evlu..7LIx..3cX1m.1FYC.Cr8t..5Jn", - tests: [ - { - position: [210, 238], - expectedLabelName: 'White matter' - }, - { - position: [600, 150], - expectedLabelName: 'Grey matter' - } - ] - } - } -} - -describe('> mouse over viewer show area name', () => { - let iavPage - beforeAll(async () => { - iavPage = new AtlasPage() - await iavPage.init() - }) - - for (const templateName in dictionary) { - for (const parcellationName in dictionary[templateName]) { - describe(`> testing template: ${templateName} & parcellation: ${parcellationName}`, () => { - - const {url, tests} = dictionary[templateName][parcellationName] - beforeAll(async () => { - if (url) { - await iavPage.goto(url) - } else { - await iavPage.goto() - await iavPage.selectTitleTemplateParcellation(templateName, parcellationName) - } - - const tag = await iavPage.getSideNavTag() - await tag.click() - await iavPage.wait(1000) - await iavPage.waitUntilAllChunksLoaded() - }) - for (const { position, expectedLabelName } of tests ) { - it(`> at cursor position: ${JSON.stringify(position)}, expect label name: ${expectedLabelName}`, async () => { - - await iavPage.cursorMoveTo({ position }) - await iavPage.wait(2000) - const text = await iavPage.getFloatingCtxInfoAsText() - expect( - text.indexOf(expectedLabelName) - ).toBeGreaterThanOrEqual(0) - }) - } - }) - } - } -}) diff --git a/e2e/src/navigating/navigateFromRegion.prod.e2e-spec.js b/e2e/src/navigating/navigateFromRegion.prod.e2e-spec.js deleted file mode 100644 index 3c90b7ceb5e394c5074a10b63947ac871f66e99b..0000000000000000000000000000000000000000 --- a/e2e/src/navigating/navigateFromRegion.prod.e2e-spec.js +++ /dev/null @@ -1,175 +0,0 @@ -const { AtlasPage } = require('../util') -const { ARIA_LABELS } = require('../../../common/constants') -const { SHOW_IN_OTHER_REF_SPACE, AVAILABILITY_IN_OTHER_REF_SPACE } = ARIA_LABELS - -const TEST_DATA = [ - { - url: "/?templateSelected=MNI+152+ICBM+2009c+Nonlinear+Asymmetric&parcellationSelected=JuBrain+Cytoarchitectonic+Atlas", - templateName: 'MNI 152 ICBM 2009c Nonlinear Asymmetric', - position: [450, 200], - expectedRegion: 'Area hOc1 (V1, 17, CalcS) - left hemisphere', - expectedTemplateLabels: [ - { - name: 'Big Brain (Histology)', - expectedPosition: [3187941, -50436480, 3430986] - }, - { - name: 'MNI Colin 27', - expectedPosition: [ - -8533787, - -84646549, - 1855106 - ] - }, - ], - }, - { - url: "/?templateSelected=Big+Brain+%28Histology%29&parcellationSelected=Cytoarchitectonic+Maps&cNavigation=0.0.0.-W000.._eCwg.2-FUe3._-s_W.2_evlu..7LIx..1n5q~.1FYC.2Is-..1B9C", - templateName: 'Big Brain (Histology)', - position: [691,678], // [370, 150], - expectedRegion: 'Area STS1 (STS)', - expectedTemplateLabels: [ - { - name: 'MNI Colin 27', - hemisphere: 'left hemisphere', - expectedPosition: [-54514755, -16753913, -5260713] - }, - { - name: 'MNI Colin 27', - hemisphere: 'right hemisphere', - expectedPosition: [54536567, -17992636, -5712544] - }, - { - name: 'MNI 152 ICBM 2009c Nonlinear Asymmetric', - hemisphere: 'left hemisphere', - expectedPosition: [-55442669, -18314601, -6381831] - }, - { - name: 'MNI 152 ICBM 2009c Nonlinear Asymmetric', - hemisphere: 'right hemisphere', - expectedPosition: [52602966, -18339402, -5666868] - }, - ], - }, -] - -const getBeforeEachFn = iavPage => ({ - url, - templateName, - position, - }) => async () => { - - if (url) { - await iavPage.goto(url) - } else { - await iavPage.goto() - await iavPage.selectTitleTemplateParcellation(templateName) - await iavPage.wait(500) - await iavPage.waitForAsync() - } - - const tag = await iavPage.getSideNavTag() - await tag.click() - await iavPage.wait(1000) - await iavPage.waitUntilAllChunksLoaded() - await iavPage.cursorMoveToAndClick({ position }) - - await iavPage.click(`[aria-label="${SHOW_IN_OTHER_REF_SPACE}"]`) - await iavPage.wait(500) -} - -describe('> explore same region in different templates', () => { - - let iavPage - beforeEach(async () => { - iavPage = new AtlasPage() - await iavPage.init() - }) - - describe('> moving to different reference template works', () => { - for (const template of TEST_DATA) { - const { - url, - templateName, - position, - expectedRegion, - expectedTemplateLabels, - } = template - - describe(`> testing ${templateName}`, () => { - beforeEach(async () => { - await getBeforeEachFn(iavPage)(template)() - }) - - for (const tmplLabel of expectedTemplateLabels) { - const { expectedPosition, name, hemisphere } = tmplLabel - describe(`> moving to ${name}`, () => { - it('> works as expected', async () => { - - const otherTemplate = await iavPage.getText(`[aria-label="${SHOW_IN_OTHER_REF_SPACE}: ${name}${hemisphere ? (' - ' + hemisphere) : ''}"]`) - const trimmedTemplate = otherTemplate.replace(/^\s+/, '').replace(/\s+$/, '').replace(/\s+/g, ' ') - if (hemisphere) { - expect(trimmedTemplate).toEqual(`${name} (${hemisphere})`) - } else { - expect(trimmedTemplate).toEqual(name) - } - - await iavPage.click(`[aria-label="${SHOW_IN_OTHER_REF_SPACE}: ${name}${hemisphere ? (' - ' + hemisphere) : ''}"]`) - await iavPage.wait(500) - await iavPage.waitUntilAllChunksLoaded() - - const navState = await iavPage.getNavigationState() - - // somehow there are slight deviations (1nm in most cases) - // giving a tolerance of 0.1um - for (const idx in navState.position) { - expect( - Math.abs(navState.position[idx] - expectedPosition[idx]) - ).toBeLessThanOrEqual(100) - } - }) - }) - } - }) - } - }) - - describe('> menu UI', () => { - const data = TEST_DATA[0] - - beforeEach(async () => { - }) - - it('> dismisses when user clicks/drags outside', async () => { - await getBeforeEachFn(iavPage)(data)() - const { expectedRegion, expectedTemplateLabels, position, url, templateName } = data - - await iavPage.cursorMoveToAndDrag({ - position: [position[0], position[1] - 100], - delta: [50, 1] - }) - - await iavPage.wait(1000) - - // should throw - try { - const otherTemplates = await iavPage.getAllOtherTemplates() - expect(true).toBe(false) - } catch(e) { - expect(true).toBe(true) - } - }) - - it('> Tooltip visible if overflowed', async () => { - const data2 = TEST_DATA[1] - await getBeforeEachFn(iavPage)(data2)() - const {expectedTemplateLabels} = data2 - const desiredTemplateButton = await expectedTemplateLabels.find(el => el.name.length > 30) - if (desiredTemplateButton) { - await iavPage.cursorMoveToElement(`[aria-label="${SHOW_IN_OTHER_REF_SPACE}: ${desiredTemplateButton.name}${desiredTemplateButton.hemisphere ? (' - ' + desiredTemplateButton.hemisphere) : ''}"]`) - const tooltipText = await iavPage.getText('mat-tooltip-component') - expect(tooltipText.trim()).toContain(desiredTemplateButton.name) - } - }) - }) -}) diff --git a/e2e/src/navigating/originDataset.prod.e2e-spec.js b/e2e/src/navigating/originDataset.prod.e2e-spec.js deleted file mode 100644 index db6c60dd2e698ed814424910419918e778e30412..0000000000000000000000000000000000000000 --- a/e2e/src/navigating/originDataset.prod.e2e-spec.js +++ /dev/null @@ -1,80 +0,0 @@ -const { AtlasPage } = require("../util") -const { ARIA_LABELS } = require('../../../common/constants') -const { SHOW_ORIGIN_DATASET } = ARIA_LABELS - -const cssSelector = `[aria-label="${SHOW_ORIGIN_DATASET}"]` - -const dict = { - 'ICBM 2009c Nonlinear Asymmetric': { - 'JuBrain Cytoarchitectonic Atlas': { - tests: [ - { - position: [600, 490], - expectedLabelName: 'Area 6ma (preSMA, mesial SFG) - left hemisphere', - } - ] - } - } -} - -describe('origin dataset pmap', () => { - let iavPage - - beforeAll(async () => { - iavPage = new AtlasPage() - await iavPage.init() - }) - - for (const templateName in dict) { - for (const parcellationName in dict[templateName]) { - describe(`testing template: ${templateName}, parcellation name: ${parcellationName}`, () => { - - const {url, tests} = dict[templateName][parcellationName] - beforeAll(async () => { - if (url) { - await iavPage.goto(url) - } else { - await iavPage.goto() - await iavPage.selectTitleTemplateParcellation(templateName, parcellationName) - } - - const tag = await iavPage.getSideNavTag() - await tag.click() - await iavPage.wait(5000) - await iavPage.waitUntilAllChunksLoaded() - }) - - for (const test of tests) { - it('> original pmap btn exists, and on click, show pmap', async () => { - - const { position, expectedLabelName } = test - await iavPage.cursorMoveToAndClick({ position }) - - await iavPage.click(cssSelector) - await iavPage.wait(5000) - await iavPage.waitForAsync() - - const additionalLayerControlIsExpanded = await iavPage.additionalLayerControlIsExpanded() - expect(additionalLayerControlIsExpanded).toEqual(false) - - const checked = await iavPage.switchIsChecked(cssSelector) - expect(checked).toEqual(true) - }) - - it('> on second click, dismisses the pmap', async () => { - - await iavPage.click(cssSelector) - await iavPage.wait(5000) - await iavPage.waitForAsync() - - const additionalLayerControlIsShown = await iavPage.isVisible(`[aria-label="${ARIA_LABELS.ADDITIONAL_VOLUME_CONTROL}"]`) - expect(additionalLayerControlIsShown).toEqual(false) - - const checked = await iavPage.switchIsChecked(cssSelector) - expect(checked).toEqual(false) - }) - } - }) - } - } -}) \ No newline at end of file diff --git a/e2e/src/selecting/atlas.prod.e2e-spec.js b/e2e/src/selecting/atlas.prod.e2e-spec.js deleted file mode 100644 index 370fb3e17de25d3c70a4003776184178963a559c..0000000000000000000000000000000000000000 --- a/e2e/src/selecting/atlas.prod.e2e-spec.js +++ /dev/null @@ -1,93 +0,0 @@ -const { AtlasPage } = require('../../util/helper') - -const atlases = [ - 'Waxholm Space atlas of the Sprague Dawley rat brain', - 'Multilevel Human Atlas', - 'Allen Mouse Common Coordinate Framework v3' -] - -describe('> atlases are generally available', () => { - let atlasPage = new AtlasPage() - beforeEach(async () => { - atlasPage = new AtlasPage() - await atlasPage.init() - }) - it('> on startup, there should be three atlases', async () => { - await atlasPage.goto() - const texts = await atlasPage.getAllCardsText() - expect(texts.sort()).toEqual(atlases.sort()) - }) -}) - -// describe('> generic atlas behaviours', () => { -// let atlasPage = new AtlasPage() -// beforeEach(async () => { -// atlasPage = new AtlasPage() -// await atlasPage.init() -// }) -// for (const atlas of atlases) { -// describe(`> of ${atlas}`, () => { -// it('> on launch, shows atlas name as a pill', async () => { -// await atlasPage.goto() -// await atlasPage.clearAlerts() -// await atlasPage.setAtlasSpecifications(atlas) -// await atlasPage.wait(500) -// await atlasPage.waitUntilAllChunksLoaded() -// const txtArr = await atlasPage.getAllChipsText() -// expect( -// txtArr.filter(v => v.replace(/\s/g, '').length > 0).length -// ).toBeGreaterThan(0) -// console.log(`chip shows: ${txtArr.join(', ')}`) -// }) -// }) -// } -// }) - -// describe('> in human multi level', () => { -// let atlasPage = new AtlasPage() -// beforeAll(async () => { -// atlasPage = new AtlasPage() -// await atlasPage.init() -// await atlasPage.goto() -// await atlasPage.clearAlerts() -// }) -// describe('> removal of additional layers should restore base layer', () => { -// it('> in mni152', async () => { -// await atlasPage.setAtlasSpecifications(atlases[1], [`Fibre tracts`, `Short Bundle`]) -// await atlasPage.wait(500) -// await atlasPage.waitForAsync() - -// const txtArr = await atlasPage.getAllChipsText() -// expect( -// txtArr.find(txt => /short bundle/i.test(txt)) -// ).toBeTruthy() - -// await atlasPage.clickChip(/short bundle/i, '.fa-times') - -// const txtArr2 = await atlasPage.getAllChipsText() -// expect( -// txtArr2.find(txt => /short bundle/i.test(txt)) -// ).toBeFalsy() - -// }) - -// it('> in bigbrain', async () => { -// await atlasPage.setAtlasSpecifications(atlases[1], [/isocortex/i]) -// await atlasPage.wait(500) -// await atlasPage.waitForAsync() - -// const txtArr = await atlasPage.getAllChipsText() -// expect( -// txtArr.find(txt => /isocortex/i.test(txt)) -// ).toBeTruthy() - -// await atlasPage.clickChip(/isocortex/i, '.fa-times') - -// const txtArr2 = await atlasPage.getAllChipsText() -// expect( -// txtArr2.find(txt => /isocortex/i.test(txt)) -// ).toBeFalsy() - -// }) -// }) -// }) diff --git a/e2e/src/selecting/region.prod.e2e-spec.js b/e2e/src/selecting/region.prod.e2e-spec.js deleted file mode 100644 index 9b6e0d535042a9346c0891fe2a5da75d06daee4c..0000000000000000000000000000000000000000 --- a/e2e/src/selecting/region.prod.e2e-spec.js +++ /dev/null @@ -1,78 +0,0 @@ -const { AtlasPage } = require('../../src/util') -const { height, width } = require('../../opts') -const { CONST } = require('../../../common/constants') - -describe('> selecting regions', () => { - - const duplicatedRegion = { - atlas: 'Multilevel Human Atlas', - template: `ICBM 152 2009c Nonlinear Asymmetric`, - parcVersion: 'v1.18', - position: [-0.256, 26.028, -11.678] - } - describe(`> when selecting duplicated regions at ${duplicatedRegion.atlas} / ${duplicatedRegion.template} / ${JSON.stringify(duplicatedRegion.position)}`, () => { - it(`> when click, should only select a single region`, async () => { - const newPage = new AtlasPage() - await newPage.init() - await newPage.goto() - await newPage.setAtlasSpecifications(duplicatedRegion.atlas, [ duplicatedRegion.template ], duplicatedRegion.parcVersion) - await newPage.wait(500) - await newPage.waitForAsync() - await newPage.execScript(`interactiveViewer.viewerHandle.setNavigationLoc(${JSON.stringify(duplicatedRegion.position.map(v => v*1e6))}, true)`) - await newPage.wait(500) - await newPage.cursorMoveTo({ - position: [ width * 3 / 4, height / 4 ] - }) - await newPage.wait(500) - const txt = await newPage.getText(`[floatingMouseContextualContainerDirective]`) - expect(txt.indexOf(`left`)).toBeGreaterThanOrEqual(0) - expect(txt.indexOf(`right`)).toBeGreaterThanOrEqual(0) - - await newPage.cursorMoveToAndClick({ - position: [width * 3 / 4, height / 4] - }) - await newPage.wait(500) - await newPage.waitForAsync() - const visible = await newPage.areVisible(`region-menu`) - expect(visible.length).toEqual(1) - - }) - }) - - 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` - - 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.setAtlasSpecifications(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/src/selecting/share.e2e-screenshot.js b/e2e/src/selecting/share.e2e-screenshot.js deleted file mode 100644 index 35d8872c4b53002c9053eb4831bd394775ac6e40..0000000000000000000000000000000000000000 --- a/e2e/src/selecting/share.e2e-screenshot.js +++ /dev/null @@ -1,66 +0,0 @@ -const { AtlasPage } = require('../util') -const { ARIA_LABELS } = require('../../../common/constants') -const fs = require('fs') -const path = require('path') - -const outputDir = path.join(__dirname, '../../../docs/autogen_images') -const exists = fs.existsSync(outputDir) -if (!exists) fs.mkdirSync(outputDir) - -describe('> share', () => { - let iavPage - beforeAll(async () => { - iavPage = new AtlasPage() - await iavPage.init() - await iavPage.goto() - await iavPage.wait(1000) - await iavPage.selectTitleTemplateParcellation('Big Brain (Histology)', 'Grey/White matter') - await iavPage.wait(1000) - await iavPage.waitUntilAllChunksLoaded() - }) - - afterEach(async () => { - await iavPage.clearAlerts() - }) - - it('> generating highlight share btn', async () => { - const b64 = await iavPage.takeScreenshot(`[aria-label="${ARIA_LABELS.SHARE_BTN}"]`) - - const outputPath = path.join(outputDir, 'share_highlightShareBtn.png') - fs.writeFileSync(outputPath, b64, 'base64') - }) - - it('> generating highlight shareUrl btn', async () => { - await iavPage.click(`[aria-label="${ARIA_LABELS.SHARE_BTN}"]`) - await iavPage.wait(1000) - - const b64 = await iavPage.takeScreenshot(`[aria-label="${ARIA_LABELS.SHARE_COPY_URL_CLIPBOARD}"]`) - - const outputPath = path.join(outputDir, 'share_highlightShareURL.png') - fs.writeFileSync(outputPath, b64, 'base64') - }) - - it('> generating highlight custom URL', async () => { - - await iavPage.click(`[aria-label="${ARIA_LABELS.SHARE_BTN}"]`) - await iavPage.wait(1000) - - const b64 = await iavPage.takeScreenshot(`[aria-label="${ARIA_LABELS.SHARE_CUSTOM_URL}"]`) - - const outputPath = path.join(outputDir, 'share_highlightShareCustomURL.png') - fs.writeFileSync(outputPath, b64, 'base64') - }) - - it('> generating custom URL dialog', async () => { - - await iavPage.click(`[aria-label="${ARIA_LABELS.SHARE_BTN}"]`) - await iavPage.wait(1000) - await iavPage.click(`[aria-label="${ARIA_LABELS.SHARE_CUSTOM_URL}"]`) - await iavPage.wait(1000) - - const b64 = await iavPage.takeScreenshot(`[aria-label="${ARIA_LABELS.SHARE_CUSTOM_URL_DIALOG}"]`) - - const outputPath = path.join(outputDir, 'share_shareCustomURLDialog.png') - fs.writeFileSync(outputPath, b64, 'base64') - }) -}) diff --git a/e2e/src/selecting/template.prod.e2e-spec.js b/e2e/src/selecting/template.prod.e2e-spec.js deleted file mode 100644 index 23e378a03c1bc12ceb1994a4bbb5ea7ffe256450..0000000000000000000000000000000000000000 --- a/e2e/src/selecting/template.prod.e2e-spec.js +++ /dev/null @@ -1,108 +0,0 @@ -const { isatty } = require("tty") -const { AtlasPage } = require("../util") - -const atlasName = 'Multilevel Human Atlas' -const tNameIcbm152 = 'ICBM 152 2009c Nonlinear Asymmetric' -// colin has temporarily been disabled -// const tNameColin = 'MNI Colin 27' -const tNameBB = 'Big Brain (Histology)' - -describe('templates > ', () => { - - let iavPage - beforeEach(async () => { - iavPage = new AtlasPage() - await iavPage.init() - }) - - describe('selecting template', () => { - - it('can select template by clicking main card', async () => { - await iavPage.goto() - await iavPage.setAtlasSpecifications(atlasName) - await iavPage.wait(1000) - - const viewerIsPopulated = await iavPage.viewerIsPopulated() - expect(viewerIsPopulated).toBe(true) - }) - - - it('switching template after template init by clicking select should work', async () => { - - await iavPage.goto() - - await iavPage.setAtlasSpecifications(atlasName, [ tNameIcbm152 ]) - await iavPage.wait(1000) - - await iavPage.setAtlasSpecifications(atlasName, [ tNameBB ]) - await iavPage.wait(7000) - - const viewerIsPopulated = await iavPage.viewerIsPopulated() - expect(viewerIsPopulated).toBe(true) - }) - - it('MNI152 should return desc', async () => { - - const expectedDesc = `An unbiased non-linear average of multiple subjects from the MNI152 database, which provides high-spatial resolution and signal-to-noise while not being biased towards a single brain (Fonov et al., 2011). This template space is widely used as a reference space in neuroimaging. HBP provides the JuBrain probabilistic cytoarchitectonic atlas (Amunts/Zilles, 2015) as well as a probabilistic atlas of large fibre bundles (Guevara, Mangin et al., 2017) in this space.` - - await iavPage.goto() - - await iavPage.setAtlasSpecifications(atlasName, [ tNameIcbm152 ]) - await iavPage.wait(1000) - - const info = await iavPage.getAtlasTileInfo(tNameIcbm152) - - expect( - info.indexOf(expectedDesc) - ).toBeGreaterThanOrEqual(0) - }) - }) - - describe('> switching template', () => { - beforeEach(async () => { - - await iavPage.goto() - await iavPage.setAtlasSpecifications(atlasName, [ tNameIcbm152 ]) - await iavPage.wait(500) - await iavPage.waitUntilAllChunksLoaded() - }) - it('> activeFlag works', async () => { - const isActive = await iavPage.atlasTileIsActive(tNameIcbm152) - expect(isActive.toString()).toEqual('true') - const isNotActive = await iavPage.atlasTileIsActive(tNameBB) - expect(isNotActive.toString()).toEqual('false') - - }) - it('> works in regular navigation', async () => { - - await iavPage.setAtlasSpecifications(atlasName, [ tNameIcbm152 ]) - await iavPage.wait(500) - await iavPage.waitUntilAllChunksLoaded() - await iavPage.wait(500) - - const isActive = await iavPage.atlasTileIsActive(tNameIcbm152) - expect(isActive.toString()).toEqual('true') - - const isNotActive = await iavPage.atlasTileIsActive(tNameBB) - expect(isNotActive.toString()).toEqual('false') - - }) - - it('> works in history navigation', async () => { - - await iavPage.setAtlasSpecifications(atlasName, [ tNameBB ]) - await iavPage.wait(500) - await iavPage.waitUntilAllChunksLoaded() - - await iavPage.historyBack() - await iavPage.wait(500) - await iavPage.waitForAsync() - - const isActive = await iavPage.atlasTileIsActive(tNameIcbm152) - expect(isActive.toString()).toEqual('true') - const isNotActive = await iavPage.atlasTileIsActive(tNameBB) - expect(isNotActive.toString()).toEqual('false') - }) - }) - -}) \ No newline at end of file diff --git a/e2e/src/util.js b/e2e/src/util.js deleted file mode 100644 index f837b8ce9285bb77d0416738d39c6c79e1efb13e..0000000000000000000000000000000000000000 --- a/e2e/src/util.js +++ /dev/null @@ -1,10 +0,0 @@ - -const { - BasePage, - AtlasPage, - LayoutPage, -} = require('../util/helper') - -exports.AtlasPage = AtlasPage -exports.LayoutPage = LayoutPage -exports.BasePage = BasePage diff --git a/e2e/util/helper.js b/e2e/util/helper.js deleted file mode 100644 index 10a7176ad2c2428057a87561e0e1427f76e5ea84..0000000000000000000000000000000000000000 --- a/e2e/util/helper.js +++ /dev/null @@ -1,11 +0,0 @@ -const { - WdIavPage, - WdLayoutPage, - WdBase, -} = require('./selenium/iav') - -module.exports = { - BasePage: WdBase, - LayoutPage: WdLayoutPage, - AtlasPage: WdIavPage -} diff --git a/e2e/util/selenium/base.js b/e2e/util/selenium/base.js deleted file mode 100644 index 88312daf3cd2eadb52f2b47a390e9d1e6d33c89b..0000000000000000000000000000000000000000 --- a/e2e/util/selenium/base.js +++ /dev/null @@ -1,413 +0,0 @@ -const CITRUS_LIGHT_URL = `https://unpkg.com/citruslight@0.1.0/citruslight.js` -const { By, Key, until } = require('selenium-webdriver') -const { retry } = require('../../../common/util') -const chromeOpts = require('../../chromeOpts') -const ATLAS_URL = (process.env.ATLAS_URL || 'http://localhost:3000').replace(/\/$/, '') - -function getActualUrl(url) { - return /^http\:\/\//.test(url) ? url : `${ATLAS_URL}/${url.replace(/^\//, '')}` -} - -async function polyFillClick(cssSelector){ - if (!cssSelector) throw new Error(`click method needs to define a css selector`) - const webEl = this._browser.findElement( By.css(cssSelector) ) - try { - await webEl.click() - } catch (e) { - const id = await webEl.getAttribute('id') - const newId = id.replace(/-input$/, '') - await this._browser.findElement( - By.id(newId) - ).click() - } -} - -const verifyPosition = position => { - - if (!position) throw new Error(`cursorGoto: position must be defined!`) - const x = Array.isArray(position) ? position[0] : position.x - const y = Array.isArray(position) ? position[1] : position.y - 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 { - x, - y - } -} - -class WdBase{ - constructor() { - browser.waitForAngularEnabled(false) - globalThis.IAVBase = this - } - get _browser(){ - return browser - } - get _driver(){ - return this._browser.driver - } - - async highlightElement(cssSelector) { - - await this._browser.executeAsyncScript(async () => { - const cb = arguments[arguments.length - 1] - const moduleUrl = arguments[0] - const cssSelector = arguments[1] - - const el = document.querySelector(cssSelector) - if (!el) throw new Error(`css selector not fetching anything`) - import(moduleUrl) - .then(async m => { - m.citruslight(el) - cb() - }) - }, CITRUS_LIGHT_URL, cssSelector) - - await this.wait(1000) - - return async () => { - await this._browser.executeAsyncScript(async () => { - const cb = arguments[arguments.length - 1] - const moduleUrl = arguments[0] - - import(moduleUrl) - .then(async m => { - m.clearAll() - cb() - }) - }, CITRUS_LIGHT_URL) - } - } - - // without image header - // output as b64 png - async takeScreenshot(cssSelector){ - - let cleanUp - if(cssSelector) { - cleanUp= await this.highlightElement(cssSelector) - } - - const result = await this._browser.takeScreenshot() - - if (cleanUp) { - await cleanUp() - } - - await this.wait(1000) - return result - } - - async getLog() { - const browserLog = await this._browser.manage().logs().get('browser') - return browserLog - } - - async getRgbAt({ position } = {}, cssSelector = null){ - if (!position) throw new Error(`position is required for getRgbAt`) - const { x, y } = verifyPosition(position) - const screenshotData = await this.takeScreenshot(cssSelector) - const [ red, green, blue ] = await this._driver.executeAsyncScript(() => { - - const dataUri = arguments[0] - const pos = arguments[1] - const dim = arguments[2] - const cb = arguments[arguments.length - 1] - - const img = new Image() - img.onload = () => { - const canvas = document.createElement('canvas') - canvas.width = dim[0] - canvas.height = dim[1] - - const ctx = canvas.getContext('2d') - ctx.drawImage(img, 0, 0) - const imgData = ctx.getImageData(0, 0, dim[0], dim[1]) - - const idx = (dim[0] * pos[1] + pos[0]) * 4 - const red = imgData.data[idx] - const green = imgData.data[idx + 1] - const blue = imgData.data[idx + 2] - cb([red, green, blue]) - } - img.src = dataUri - - }, `data:image/png;base64,${screenshotData}`, [x, y], [800, 796]) - - return { red, green, blue } - } - - async switchIsChecked(cssSelector){ - if (!cssSelector) throw new Error(`switchChecked method requies css selector`) - const checked = await this._browser - .findElement( By.css(cssSelector) ) - .getAttribute('aria-checked') - return checked === 'true' - } - - async click(cssSelector){ - return await polyFillClick.bind(this)(cssSelector) - } - - async getText(cssSelector){ - if (!cssSelector) throw new Error(`getText needs to define css selector`) - const el = await this._browser.findElement( By.css(cssSelector) ) - - const text = await el.getText() - return text - } - - async isVisible(cssSelector) { - - if (!cssSelector) throw new Error(`getText needs to define css selector`) - const el = await this._browser.findElement( By.css(cssSelector) ) - const isDisplayed = await el.isDisplayed() - - return isDisplayed - } - - async areVisible(cssSelector){ - if (!cssSelector) throw new Error(`getText needs to define css selector`) - const els = await this._browser.findElements( By.css( cssSelector ) ) - const returnArr = [] - - for (const el of els) { - returnArr.push(await el.isDisplayed()) - } - return returnArr - } - - async isAt(cssSelector){ - if (!cssSelector) throw new Error(`getText needs to define css selector`) - const { x, y, width, height } = await this._browser.findElement( By.css(cssSelector) ).getRect() - return { x, y, width, height } - } - - async areAt(cssSelector){ - - if (!cssSelector) throw new Error(`getText needs to define css selector`) - const els = await this._browser.findElements( By.css( cssSelector ) ) - const returnArr = [] - - for (const el of els) { - const { x, y, width, height } = await el.getRect() - returnArr.push({ x, y, width, height }) - } - return returnArr - } - - historyBack() { - return this._browser.navigate().back() - } - - historyForward() { - return this._browser.navigate().forward() - } - - 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 () => { - return [ - window.outerWidth - window.innerWidth + (+ arguments[0]), - window.outerHeight - window.innerHeight + (+ arguments[1]), - ] - }, width, height) - - await this._browser.manage() - .window() - .setRect({ - width: newDim[0], - height: newDim[1] - }) - } - - async waitForAsync(){ - - await this._browser.wait(async () => { - const els = await this._browser.findElements( - By.css('div.loadingIndicator') - ) - const els2 = await this._browser.findElements( - By.css('.spinnerAnimationCircle') - ) - return [...els, ...els2].length === 0 - }, 1e3 * 60 * 10) - } - - async cursorMoveTo({ position }) { - const { x, y } = verifyPosition(position) - return this._driver.actions() - .move() - .move({ - x, - y, - duration: 1000 - }) - .perform() - } - - async cursorMoveToElement(cssSelector) { - if (!cssSelector) throw new Error(`cursorMoveToElement needs to define css selector`) - const el = await this._browser.findElement( By.css(cssSelector) ) - await this._driver.actions() - .move() - .move({ - origin: el, - duration: 1000 - }) - .perform() - } - - async scrollElementBy(cssSelector, options) { - const { delta } = options - await this._browser.executeScript(() => { - const { delta } = arguments[1] - const el = document.querySelector(arguments[0]) - el.scrollBy(...delta) - }, cssSelector, { delta }) - } - - async getScrollStatus(cssSelector) { - const val = await this._browser.executeScript(() => { - const el = document.querySelector(arguments[0]) - return el.scrollTop - }, cssSelector) - return val - } - - async cursorMoveToAndClick({ position }) { - const { x, y } = verifyPosition(position) - return this._driver.actions() - .move() - .move({ - x, - y, - duration: 1000 - }) - .click() - .perform() - } - - async cursorMoveToAndDrag({ position, delta }) { - const { x, y } = verifyPosition(position) - const { x: deltaX, y: deltaY } = verifyPosition(delta) - return this._driver.actions() - .move() - .move({ - x, - y, - duration: 1000 - }) - .press() - .move({ - x: x + deltaX, - y: y + deltaY, - duration: 1000 - }) - .release() - .perform() - } - - async initHttpInterceptor(){ - await this._browser.executeScript(() => { - if (window.__isIntercepting__) return - window.__isIntercepting__ = true - const open = window.XMLHttpRequest.prototype.open - window.__interceptedXhr__ = [] - window.XMLHttpRequest.prototype.open = function () { - window.__interceptedXhr__.push({ - method: arguments[0], - url: arguments[1] - }) - return open.apply(this, arguments) - } - }) - } - - async isHttpIntercepting(){ - return await this._browser.executeScript(() => { - return window.__isIntercepting__ - }) - } - - async getInterceptedHttpCalls(){ - return await this._browser.executeScript(() => { - return window['__interceptedXhr__'] - }) - } - - // it seems if you set intercept http to be true, you might also want ot set do not automat to be true - async goto(url = '/', { interceptHttp, doNotAutomate, forceTimeout = 20 * 1000 } = {}){ - this.__trackingNavigationState__ = false - const actualUrl = getActualUrl(url) - if (interceptHttp) { - this._browser.get(actualUrl) - await this.initHttpInterceptor() - } else { - await this._browser.get(actualUrl) - } - - // if doNotAutomate is not set - // should wait for async operations to end - if (!doNotAutomate) { - await this.wait(200) - await this.clearAlerts() - await this.wait(200) - - if (forceTimeout) { - await Promise.race([ - this.waitForAsync(), - this.wait(forceTimeout) - ]) - } else { - await this.waitForAsync() - } - } - } - - async wait(ms) { - if (!ms) throw new Error(`wait duration must be specified!`) - return new Promise(rs => { - setTimeout(rs, ms) - }) - } - - async waitForCss(cssSelector) { - if (!cssSelector) throw new Error(`css selector must be defined`) - await this._browser.wait( - until.elementLocated( By.css(cssSelector) ), - 1e3 * 60 * 10 - ) - } - - async waitFor(animation = false, async = false){ - if (animation) await this.wait(500) - if (async) await this.waitForAsync() - } - - async clearAlerts() { - await this._driver - .actions() - .sendKeys( - Key.ESCAPE, - Key.ESCAPE, - Key.ESCAPE, - Key.ESCAPE - ) - .perform() - - await this.wait(500) - } - - async execScript(fn, ...arg){ - const result = await this._driver.executeScript(fn) - return result - } -} - -module.exports = { - WdBase -} diff --git a/e2e/util/selenium/iav.js b/e2e/util/selenium/iav.js deleted file mode 100644 index 6d75eaa5b7b3ed38e1310d7460fdd24ef874aac2..0000000000000000000000000000000000000000 --- a/e2e/util/selenium/iav.js +++ /dev/null @@ -1,200 +0,0 @@ -const { WdLayoutPage, WdBase } = require('./layout') -const { ARIA_LABELS, CONST } = require('../../../common/constants') -const { _getTextFromWebElement, _getIndexFromArrayOfWebElements } = require('./util') -const { Key } = require('selenium-webdriver') - -class WdIavPage extends WdLayoutPage{ - constructor(){ - super() - } - - async clearAllSelectedRegions() { - const clearAllRegionBtn = await this._browser.findElement( - By.css(`[aria-label="${ARIA_LABELS.CLEAR_SELECTED_REGION}"]`) - ) - await clearAllRegionBtn.click() - await this.wait(500) - } - - async waitUntilAllChunksLoaded(){ - await this.waitForCss(`iav-cmp-viewer-nehuba-glue`) - await this.waitForAsync() - } - - async getFloatingCtxInfoAsText(){ - const floatingContainer = await this._browser.findElement( - By.css('div[floatingMouseContextualContainerDirective]') - ) - - const text = await floatingContainer.getText() - return text - } - - async selectDropdownTemplate(title) { - throw new Error(`selectDropdownTemplate has been deprecated. use setAtlasSpecifications instead`) - } - - async _getSearchRegionInput(){ - await this._setSideNavPrimaryExpanded(true) - await this.wait(500) - const secondaryOpen = await this._getSideNavSecondaryExpanded() - if (secondaryOpen) { - return this._getSideNavSecondary().findElement( By.css(`[aria-label="${ARIA_LABELS.TEXT_INPUT_SEARCH_REGION}"]`) ) - } else { - return this._getSideNavPrimary().findElement( By.css(`[aria-label="${ARIA_LABELS.TEXT_INPUT_SEARCH_REGION}"]`) ) - } - } - - async searchRegionWithText(text=''){ - const searchRegionInput = await this._getSearchRegionInput() - await searchRegionInput - .sendKeys( - Key.chord(Key.CONTROL, 'a'), - text - ) - } - - async clearSearchRegionWithText() { - const searchRegionInput = await this._getSearchRegionInput() - await searchRegionInput - .sendKeys( - Key.chord(Key.CONTROL, 'a'), - Key.BACK_SPACE, - Key.ESCAPE - ) - } - - 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 options = await this._getAutcompleteOptions() - - const idx = await _getIndexFromArrayOfWebElements(text, options) - if (idx >= 0) { - await options[idx].click() - } else { - throw new Error(`_getIndexFromArrayOfWebElements ${text} option not founds`) - } - } - - _getModalityListView(){ - return this._browser - .findElement( By.css('modality-picker') ) - .findElements( By.css('mat-checkbox') ) - } - - async getModalities(){ - const els = await this._getModalityListView() - const returnArr = [] - for (const el of els) { - returnArr.push( - await el.getText() - ) - } - return returnArr - } - - _getSingleDatasetListView(){ - throw new Error(`data-browser has been deprecated. rewrite selector`) - return this._browser - .findElement( By.css('data-browser') ) - .findElements( By.css('single-dataset-list-view') ) - } - - async getVisibleDatasets() { - const singleDatasetListView = await this._getSingleDatasetListView() - - const returnArr = [] - for (const item of singleDatasetListView) { - returnArr.push( await item.getText() ) - } - return returnArr - } - - async clickNthDataset(index){ - if (!Number.isInteger(index)) throw new Error(`index needs to be an integer`) - const list = await this._getSingleDatasetListView() - await list[index].click() - } - - async togglePinNthDataset(index) { - if (!Number.isInteger(index)) throw new Error(`index needs to be an integer`) - const list = await this._getSingleDatasetListView() - if (!list[index]) throw new Error(`out of bound ${index} in list with length ${list.length}`) - await list[index] - .findElement( By.css('[aria-label="Toggle pinning this dataset"]') ) - .click() - } - - async viewerIsPopulated() { - try { - const ngContainer = await this._browser.findElement( - By.id('neuroglancer-container') - ) - if (! (await ngContainer.isDisplayed())) { - return false - } - const canvas = await ngContainer.findElement( - By.tagName('canvas') - ) - if (!(await canvas.isDisplayed())) { - return false - } - return true - } catch (e) { - return false - } - } - - async getNavigationState() { - if (!this.__trackingNavigationState__) { - await this._browser.executeScript(async () => { - window.__iavE2eNavigationState__ = {} - - const getPr = () => new Promise(rs => { - - window.__iavE2eNavigationStateSubptn__ = nehubaViewer.navigationState.all - .subscribe(({ orientation, perspectiveOrientation, perspectiveZoom, position, zoom }) => { - window.__iavE2eNavigationState__ = { - orientation: Array.from(orientation), - perspectiveOrientation: Array.from(perspectiveOrientation), - perspectiveZoom, - zoom, - position: Array.from(position) - } - rs() - }) - }) - - await getPr() - }) - - this.__trackingNavigationState__ = true - } - - const returnVal = await this._browser.executeScript(() => window.__iavE2eNavigationState__) - return returnVal - } - -} - -module.exports = { - WdIavPage, - WdLayoutPage, - WdBase, -} \ No newline at end of file diff --git a/e2e/util/selenium/layout.js b/e2e/util/selenium/layout.js deleted file mode 100644 index 27f1f6e15d88cb4afa500609f1c49e62c7ad586b..0000000000000000000000000000000000000000 --- a/e2e/util/selenium/layout.js +++ /dev/null @@ -1,665 +0,0 @@ -const { WdBase } = require('./base') -const { - _getIndexFromArrayOfWebElements, - _getTextFromWebElement, - _compareText -} = require('./util') -const { ARIA_LABELS } = require('../../../common/constants') - -class WdLayoutPage extends WdBase{ - constructor(){ - 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 - */ - async getSnackbarMessage(){ - const txt = await this._driver - .findElement( By.css('simple-snack-bar') ) - .findElement( By.css('span') ) - .getText() - return txt - } - - async clickSnackbarAction(){ - await this._driver - .findElement( By.css('simple-snack-bar') ) - .findElement( By.css('button') ) - .click() - } - - /** - * Bottomsheet - */ - _getBottomSheet() { - return this._driver.findElement( By.css('mat-bottom-sheet-container') ) - } - - _getBottomSheetList(){ - return this._getBottomSheet().findElements( By.css('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() - } - } - - /** - * Modal - */ - _getModal(){ - return this._browser.findElement( By.css('mat-dialog-container') ) - } - - async dismissModal() { - try { - const okBtn = await this._getModal() - .findElement( By.css('mat-dialog-actions') ) - .findElement( By.css('button[color="primary"]') ) - await okBtn.click() - } catch (e) { - - } - } - - _getModalBtns(){ - return this._getModal().findElements( By.tagName('button') ) - } - - async getModalText(){ - const el = await this._getModal() - const txt = await _getTextFromWebElement(el) - return txt - } - - async getModalActions(){ - const btns = await this._getModalBtns() - - const arr = [] - for (const btn of btns){ - arr.push(await _getTextFromWebElement(btn)) - } - return arr - } - - /** - * - * @param {string|RegExp} text - * @description search criteria for the btn to click - */ - async clickModalBtnByText(text){ - const btns = await this._getModalBtns() - const arr = await this.getModalActions() - if (typeof text === 'string') { - const idx = arr.indexOf(text) - if (idx < 0) throw new Error(`clickModalBtnByText: ${text} not found.`) - await btns[idx].click() - return - } - if (text instanceof RegExp) { - const idx = arr.findIndex(item => text.test(item)) - if (idx < 0) throw new Error(`clickModalBtnByText: regexp ${text.toString()} not found`) - await btns[idx].click() - return - } - - throw new Error(`clickModalBtnByText arg must be instance of string or regexp`) - } - - /** - * ExpansionPanel - */ - - /** - * - * @param {string|RegExp} text - * @description search criteria for the expansion panel title - */ - async _getExpansionPanel(text){ - const expPanels = await this._browser.findElements( - By.css(`mat-expansion-panel`) - ) - - const expPanelHdrs = [] - for (const expPanel of expPanels) { - expPanelHdrs.push( - await expPanel.findElement( - By.css(`mat-expansion-panel-header`) - ) - ) - } - - const idx = await _getIndexFromArrayOfWebElements(text, expPanelHdrs) - return idx >= 0 && expPanels[idx] - } - - /** - * - * @param {Object} expPanel webelement of the mat expansion panel - * @returns {Promise<boolean>} - */ - async _expansionPanelIsOpen(expPanel){ - const classString = await expPanel.getAttribute('class') - /** - * mat-expanded gets appended when mat-expansion panel is set to open - */ - return classString.indexOf('mat-expanded') >= 0 - } - - /** - * - * @param {string|RegExp} name Text of the expansion panel header - * @param {boolean} flag @optional State to set the expansion panel. Leave empty for toggle. - */ - async toggleExpansionPanelState(name, flag){ - const expPanel = await this._getExpansionPanel(name) - if (!expPanel) throw new Error(`expansionPanel ${name} could not be found`) - if (typeof flag === 'undefined') { - await expPanel.findElement( - By.css(`mat-expansion-panel-header`) - ).click() - return - } - - const currentOpen = await this._expansionPanelIsOpen(expPanel) - if (currentOpen !== flag) { - await expPanel.findElement( - By.css(`mat-expansion-panel-header`) - ).click() - } - } - - /** - * Chips - */ - async _getChips(){ - return await this._browser.findElements( - By.css('mat-chip') - ) - } - - async getAllChipsText(){ - const texts = [] - const webEls = await this._getChips() - for (const el of webEls) { - texts.push( - await _getTextFromWebElement(el) - ) - } - return texts - } - - async getAllChipsVisibility(){ - const visibility = [] - const webEls = await this._getChips() - for (const el of webEls) { - visibility.push( - await el.isDisplayed() - ) - } - return visibility - } - - async clickChip(search, cssSelector) { - const allChips = await this._getChips() - const idx = await _getIndexFromArrayOfWebElements(search, allChips) - if (idx < 0) throw new Error(`clickChip ${search.toString()} not found`) - if (!cssSelector) { - return await allChips[idx].click() - } - const el = await allChips[idx].findElement( - By.css(cssSelector) - ) - if (!el) throw new Error(`clickChip css selector ${cssSelector} not found`) - return await el.click() - } - - /** - * Cards - */ - - async _getAllCards(){ - return await this._browser.findElements( - By.css('mat-card') - ) - } - - async getAllCardsText(){ - const allCardsEl = await this._getAllCards() - const txtArr = [] - for (const el of allCardsEl) { - txtArr.push( - await _getTextFromWebElement(el) - ) - } - return txtArr - } - - /** - * Badge - */ - async getBadgeContentByDesc(description){ - const els = await this._browser.findElements( - By.css(`.mat-badge-content`) - ) - for (const el of els) { - const descById = await el.getAttribute('aria-describedby') - if (!!descById) { - const descEl = await this._browser.findElement( - By.id(`${descById}`) - ) - /** - * getText() will not return elements that are hidden - * which aria descriptions are. - * so use getInnerHtml instead - */ - const descElText = await descEl.getAttribute('innerHTML') - if (descElText === description) { - const elText = await el.getText() - return elText - } - } - } - return null - } - - /** - * Other - */ - async _findTitleCard(title) { - const titleCards = await this._browser - .findElement( By.css('ui-splashscreen') ) - .findElements( By.css('mat-card') ) - 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) - await titleCard.click() - } - - async selectTitleTemplateParcellation(templateName, parcellationName){ - throw new Error(`selectTitleTemplateParcellation has been deprecated. use setAtlasSpecifications`) - } - - /** - * _setAtlasSelectorExpanded - * toggle/set the open state of the atlas-layer-selector element - * If the only argument (flag) is not provided, it will toggle the atlas-layer-selector - * - * Will throw if atlas-layer-selector is not in the DOM - * - * @param {boolean} flag - * - */ - async _setAtlasSelectorExpanded(flag) { - const atlasLayerSelectorEl = this._browser.findElement( - By.css('atlas-layer-selector') - ) - const openedFlag = (await atlasLayerSelectorEl.getAttribute('data-opened')) === 'true' - if (typeof flag === 'undefined' || flag !== openedFlag) { - await atlasLayerSelectorEl.findElement(By.css(`button[aria-label="${ARIA_LABELS.TOGGLE_ATLAS_LAYER_SELECTOR}"]`)).click() - } - } - - /** - * - * @param {WebElement} webEl - * @description Look for child element fas.fa-info, click, then get modal text - */ - async _getInfo(webEl) { - const infoBtn = await webEl.findElement( - By.css(`.fas.fa-info`) - ) - if (!infoBtn) { - return null - } - await infoBtn.click() - await this.wait(500) - await this.waitForAsync() - const text = await this.getModalText() - await this.clearAlerts() - await this.wait(500) - return text - } - - async _getAtlasSelectorTile(tileName) { - - if (!tileName) throw new Error(`tileName needs to be provided`) - await this._setAtlasSelectorExpanded(true) - await this.wait(1000) - const allTiles = await this._browser.findElements( By.css(`mat-grid-tile`) ) - - const idx = await _getIndexFromArrayOfWebElements(tileName, allTiles) - - if (idx < 0) throw new Error(`#selectTile: tileName ${tileName} cannot be found.`) - return allTiles[idx] - } - - async selectTile(tileName){ - const el = await this._getAtlasSelectorTile(tileName) - await el.click() - } - - async getAtlasTileInfo(tileName){ - const el = await this._getAtlasSelectorTile(tileName) - return this._getInfo(el) - } - - async atlasTileIsActive(tileName) { - const el = await this._getAtlasSelectorTile(tileName) - return await el.getAttribute('aria-checked') - } - - async changeParc(parcName) { - throw new Error(`changeParc NYI`) - } - - async changeParcVersion(parcVersion) { - await this._browser.findElement( - By.css(`[aria-label="${ARIA_LABELS.PARC_VER_SELECT}"]`) - ).click() - await this.wait(500) - this._browser.findElement( - By.css(`[aria-label="${ARIA_LABELS.PARC_VER_CONTAINER}"] [aria-label="${parcVersion}"]`) - ).click() - await this.wait(500) - } - - async setAtlasSpecifications(atlasName, atlasSpecifications = [], parcVersion = null) { - if (!atlasName) throw new Error(`atlasName needs to be provided`) - try { - /** - * if at title screen - */ - await (await this._findTitleCard(atlasName)).click() - } catch (e) { - /** - * if not at title screen - * select from dropdown - */ - console.log(`selecting from ui-splash screen errored, try selecting from dropdown`) - await this.selectDropdownOption(`[aria-label="${ARIA_LABELS.SELECT_ATLAS}"]`, atlasName) - } - - for (const spec of atlasSpecifications) { - await this.wait(1000) - await this.waitUntilAllChunksLoaded() - await this.selectTile(spec) - } - - if (parcVersion) { - await this.wait(1000) - await this.waitUntilAllChunksLoaded() - await this.changeParcVersion(parcVersion) - } - - try { - await this._setAtlasSelectorExpanded(false) - } catch (e) { - /** - * atlas selector may not be found - */ - } - } - - /** - * Sidenav - */ - _getSideNavPrimary(){ - return this._browser.findElement( - By.css('mat-drawer[data-mat-drawer-top-open]') - ) - } - - async _getSideNavPrimaryExpanded(){ - return (await this._getSideNavPrimary() - .getAttribute('data-mat-drawer-top-open')) === 'true' - } - - _getSideNavSecondary(){ - return this._browser.findElement( - By.css('mat-drawer[data-mat-drawer-fullleft-open]') - ) - } - - async _getSideNavSecondaryExpanded(){ - return (await this._getSideNavSecondary() - .getAttribute('data-mat-drawer-fullleft-open')) === 'true' - } - - async _setSideNavPrimaryExpanded(flag) { - const openedFlag = await this._getSideNavPrimaryExpanded() - if (typeof flag === 'undefined' || flag !== openedFlag) { - await this._browser.findElement(By.css(`button[aria-label="${ARIA_LABELS.TOGGLE_SIDE_PANEL}"]`)).click() - } - } - - async getSideNavTag(){ - return await this._browser - .findElement( By.css('[mat-drawer-trigger]') ) - .findElement( By.css('i') ) - } - - sideNavIsVisible(){ - throw new Error(`sideNavIsVisible is deprecated`) - } - - _getSideNavTab(){ - return this._browser - .findElement( By.css('[mat-drawer-trigger]') ) - .findElement( By.css('i') ) - } - - 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() - } - - // will throw if additional layer control is not visible - additionalLayerControlIsExpanded() { - throw new Error(`additionalLayerControlIsExpanded is deprecated`) - } - - /** - * TODO? deprecate - */ - async toggleNthLayerControl(idx) { - const els = await this._browser - .findElement( - By.css(`[aria-label="${ARIA_LABELS.ADDITIONAL_VOLUME_CONTROL}"]`) - ) - .findElements( By.css(`[aria-label="${ARIA_LABELS.TOGGLE_SHOW_LAYER_CONTROL}"]`)) - if (!els[idx]) throw new Error(`toggleNthLayerControl index out of bound: accessor ${idx} with length ${els.length}`) - await els[idx].click() - } - - // Signin banner - _getToolsIcon(){ - return this._driver - .findElement( By.css('[aria-label="Show tools and plugins"]') ) - } - - async showToolsMenu(){ - await this._getToolsIcon().click() - } - - _getToolsMenu(){ - return this._driver - .findElement( By.css('[aria-label="Tools and plugins menu"]') ) - } - - _getAllTools(){ - return this._getToolsMenu().findElements( By.css('[role="menuitem"]') ) - } - - async getVisibleTools(){ - // may throw if tools menu not visible - const menuItems = await this._getAllTools() - const returnArr = [] - for (const menuItem of menuItems){ - returnArr.push( - await _getTextFromWebElement(menuItem) - ) - } - return returnArr - } - - async clickOnNthTool(index, cssSelector){ - const menuItems = await this._getAllTools() - if (!menuItems[index]) throw new Error(`index out of bound: accessing index ${index} of length ${menuItems.length}`) - if (cssSelector) await menuItems[index].findElement( By.css(cssSelector) ).click() - else await menuItems[index].click() - } - - _getFavDatasetIcon(){ - return this._driver - .findElement( By.css('[aria-label="Show pinned datasets"]') ) - } - - async showPinnedDatasetPanel(){ - 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() - } - - _getWidgetPanel(title){ - return this._driver.findElement( By.css(`[aria-label="Widget for ${title}"]`) ) - } - - async widgetPanelIsDispalyed(title){ - try { - const isDisplayed = await this._getWidgetPanel(title).isDisplayed() - return isDisplayed - } catch (e) { - console.warn(`widgetPanelIsDisplayed error`, e) - return false - } - } - - async closeWidgetByname(title){ - await this._getWidgetPanel(title) - .findElement( By.css(`[aria-label="close"]`) ) - .click() - } -} - -module.exports = { - WdLayoutPage, - WdBase, -} \ No newline at end of file diff --git a/e2e/util/selenium/util.js b/e2e/util/selenium/util.js deleted file mode 100644 index 07aadf6a27365d35aa076a368b12e66583c6d760..0000000000000000000000000000000000000000 --- a/e2e/util/selenium/util.js +++ /dev/null @@ -1,25 +0,0 @@ - -function _getTextFromWebElement(webElement) { - return webElement.getText() -} - -async function _getIndexFromArrayOfWebElements(search, webElements) { - const texts = await Promise.all( - webElements.map(_getTextFromWebElement) - ) - return texts.findIndex(text => search instanceof RegExp - ? search.test(text) - : text.indexOf(search) >= 0) -} - -function _compareText(textString, testStrRegExp){ - return testStrRegExp instanceof RegExp - ? testStrRegExp.test(textString) - : textString.indexOf(testStrRegExp) >= 0 -} - -module.exports = { - _getTextFromWebElement, - _getIndexFromArrayOfWebElements, - _compareText -} \ No newline at end of file diff --git a/features/_convert.py b/features/_convert.py index ecd36cac48cae44824bf21a6b990ffb5ae94eb3b..8b22a9e06c2f19b6afb30d27da8bc42cfbe16146 100644 --- a/features/_convert.py +++ b/features/_convert.py @@ -101,7 +101,7 @@ def gherkin_to_markdown(gherkin_text): ) -def main(output: str="./e2e/checklist.md"): +def main(output: str="./checklist.md"): path_to_feature = Path("features") markdown_txt = """# Staging Checklist diff --git a/mkdocs.yml b/mkdocs.yml index dfd714d8026d57c4f6afbcb0ecc131a6a720663f..d1561a7764aef3917555ae88ffb04c9c3ffb6e44 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -45,6 +45,7 @@ nav: - Differential gene expression analysis: "advanced/differential_gene_expression_analysis.md" - Release notes: + - v2.14.7: 'releases/v2.14.7.md' - v2.14.6: 'releases/v2.14.6.md' - v2.14.5: 'releases/v2.14.5.md' - v2.14.4: 'releases/v2.14.4.md' diff --git a/package-lock.json b/package-lock.json index 01873b6c7ddecd1bbe5a1fcf921258e0d1dd944d..1f5725874bc3a1d6f01a7865f2270ff31ab25d3e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "siibra-explorer", - "version": "2.14.5", + "version": "2.14.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "siibra-explorer", - "version": "2.14.5", + "version": "2.14.6", "license": "apache-2.0", "dependencies": { "@angular/animations": "^15.2.10", @@ -23,7 +23,7 @@ "@ngrx/effects": "^15.4.0", "@ngrx/store": "^15.4.0", "acorn": "^8.4.1", - "export-nehuba": "^0.1.8", + "export-nehuba": "^0.1.9", "file-loader": "^6.2.0", "jszip": "^3.6.0", "postcss": "^8.3.6", @@ -7646,9 +7646,9 @@ "dev": true }, "node_modules/export-nehuba": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/export-nehuba/-/export-nehuba-0.1.8.tgz", - "integrity": "sha512-A5RijEUDqhv09yAOeVb2AxS36YmJNyWXRmcImPFSGgLq9bP8bcjrHIbmBOsEX9ntAKwwaHNvlVVmDSwHnGqFug==", + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/export-nehuba/-/export-nehuba-0.1.9.tgz", + "integrity": "sha512-59vm+BlB1zuD2ftDWUGUv6Jt0WGHjzB6egGGuD+JRR9oW4D7m9DNuOwheymSvlUxJ2GEOjMBe3I460T51m6W/A==", "dependencies": { "pako": "^1.0.6" } diff --git a/package.json b/package.json index dfe5f4708b9d5482f9bcd70604ef75eb7bc75b6c..4654168aff06b996f84488df25690b5c3223feab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "siibra-explorer", - "version": "2.14.6", + "version": "2.14.7", "description": "siibra-explorer - explore brain atlases. Based on humanbrainproject/nehuba & google/neuroglancer. Built with angular", "scripts": { "lint": "eslint src --ext .ts", @@ -12,10 +12,7 @@ "test": "ng test", "test-ci": "ng test --progress false --watch false --browsers=ChromeHeadless", "sapi-schema": "curl 'https://siibra-api-stable.apps.hbp.eu/v3_0/openapi.json' | jq > ./src/atlasComponents/sapi/openapi.json && npx openapi-typescript@6.1.0 ./src/atlasComponents/sapi/openapi.json --output ./src/atlasComponents/sapi/schemaV3.ts && eslint ./src/atlasComponents/sapi/schemaV3.ts --no-ignore --fix", - "api-schema": "node src/api/generateSchema.mjs", - "docs:json": "compodoc -p ./tsconfig.json -e json -d .", - "storybook": "npm run docs:json && start-storybook -p 6006", - "build-storybook": "npm run docs:json && build-storybook" + "api-schema": "node src/api/generateSchema.mjs" }, "keywords": [], "author": "FZJ-INM1-BDA <inm1-bda@fz-juelich.de>", @@ -55,7 +52,7 @@ "@ngrx/effects": "^15.4.0", "@ngrx/store": "^15.4.0", "acorn": "^8.4.1", - "export-nehuba": "^0.1.8", + "export-nehuba": "^0.1.9", "file-loader": "^6.2.0", "jszip": "^3.6.0", "postcss": "^8.3.6", diff --git a/src/index.html b/src/index.html index 95d9da0bf8f5a092b4ac37a3aa42cc3a5ffb4596..89bed597be4739486f6374d6a5a365a3630021a4 100644 --- a/src/index.html +++ b/src/index.html @@ -16,6 +16,7 @@ <script type="module" src="https://unpkg.com/ng-layer-tune@0.0.26/dist/ng-layer-tune/ng-layer-tune.esm.js"></script> <script type="module" src="https://unpkg.com/hbp-connectivity-component@0.6.6/dist/connectivity-component/connectivity-component.js" ></script> <script src="https://cdn.plot.ly/plotly-2.24.1.min.js" charset="utf-8"></script> + <script src="main.bundle.js" charset="utf-8"></script> <!-- export_nehuba --> <title>Siibra Explorer</title> </head> <body> diff --git a/src/ui/ui.module.ts b/src/ui/ui.module.ts index 98efd3854b801b7cffe5d1720ffc32fab5ea32d7..dbacdadf9c546f69ffacf94b45c1b5dd8abbefb5 100644 --- a/src/ui/ui.module.ts +++ b/src/ui/ui.module.ts @@ -9,8 +9,6 @@ import { UtilModule } from "src/util"; import { ShareModule } from "src/share"; import { AuthModule } from "src/auth"; import { ActionDialog } from "./actionDialog/actionDialog.component"; -import { APPEND_SCRIPT_TOKEN, appendScriptFactory } from "src/util/constants"; -import { DOCUMENT } from "@angular/common"; import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; import { HANDLE_SCREENSHOT_PROMISE, TypeHandleScrnShotPromise } from "../screenshot"; @@ -32,11 +30,6 @@ import { HANDLE_SCREENSHOT_PROMISE, TypeHandleScrnShotPromise } from "../screens ActionDialog, ], providers: [ - { - provide: APPEND_SCRIPT_TOKEN, - useFactory: appendScriptFactory, - deps: [DOCUMENT] - }, { provide: HANDLE_SCREENSHOT_PROMISE, useValue: ((param) => { diff --git a/src/viewerModule/nehuba/module.ts b/src/viewerModule/nehuba/module.ts index 76b1be3db1e3a5046702286313b63e6e6ebe3edc..d6d5906e9741ddfbf7a469e2eecbd82a49f8b629 100644 --- a/src/viewerModule/nehuba/module.ts +++ b/src/viewerModule/nehuba/module.ts @@ -1,9 +1,8 @@ import { APP_INITIALIZER, NgModule } from "@angular/core"; import { NehubaViewerContainerDirective } from './nehubaViewerInterface/nehubaViewerInterface.directive' -import { IMPORT_NEHUBA_INJECT_TOKEN, NehubaViewerUnit } from "./nehubaViewer/nehubaViewer.component"; +import { NehubaViewerUnit } from "./nehubaViewer/nehubaViewer.component"; import { CommonModule } from "@angular/common"; -import { APPEND_SCRIPT_TOKEN } from "src/util/constants"; -import { importNehubaFactory, NEHUBA_INSTANCE_INJTKN } from "./util"; +import { NEHUBA_INSTANCE_INJTKN } from "./util"; import { NehubaViewerTouchDirective } from "./nehubaViewerInterface/nehubaViewerTouch.directive"; import { StoreModule } from "@ngrx/store"; import { NEHUBA_VIEWER_FEATURE_KEY } from "./constants"; @@ -18,7 +17,7 @@ import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { BehaviorSubject } from "rxjs"; import { StateModule } from "src/state"; import { AuthModule } from "src/auth"; -import {QuickTourModule} from "src/ui/quickTour/module"; +import { QuickTourModule } from "src/ui/quickTour/module"; import { WindowResizeModule } from "src/util/windowResize"; import { EffectsModule } from "@ngrx/effects"; import { MeshEffects } from "./mesh.effects/mesh.effects"; @@ -81,12 +80,6 @@ import { MediaQueryDirective } from "src/util/directives/mediaQuery.directive"; StatusCardComponent, ], providers: [ - - { - provide: IMPORT_NEHUBA_INJECT_TOKEN, - useFactory: importNehubaFactory, - deps: [ APPEND_SCRIPT_TOKEN ] - }, { provide: NEHUBA_INSTANCE_INJTKN, useValue: new BehaviorSubject(null) diff --git a/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.spec.ts b/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.spec.ts index 89b3a42f99d93c8222d314784bfa9b6057de5aa1..bee657a551771449ef3fca3599aea69be8983412 100644 --- a/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.spec.ts +++ b/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.spec.ts @@ -1,6 +1,6 @@ import { TestBed, fakeAsync, tick, ComponentFixture } from "@angular/core/testing" import { CommonModule } from "@angular/common" -import { NehubaViewerUnit, IMPORT_NEHUBA_INJECT_TOKEN, scanFn } from "./nehubaViewer.component" +import { NehubaViewerUnit, scanFn } from "./nehubaViewer.component" import { LoggingModule, LoggingService } from "src/logging" import { IMeshesToLoad, SET_MESHES_TO_LOAD } from "../constants" import { Subject } from "rxjs" @@ -90,10 +90,6 @@ describe('> nehubaViewer.component.ts', () => { NehubaViewerUnit ], providers:[ - { - provide: IMPORT_NEHUBA_INJECT_TOKEN, - useValue: () => Promise.resolve(), - }, { provide: SET_MESHES_TO_LOAD, useFactory: () => setMeshToLoadCtl$ diff --git a/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.ts b/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.ts index 6e2f8251fa76b4d8910b3d3f7d012542a95024fb..99ec8489b9f043e862a3caf14c751df95227d859 100644 --- a/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.ts +++ b/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.ts @@ -24,7 +24,6 @@ function translateUnit(unit: Unit) { throw new Error(`Cannot translate unit: ${unit}`) } -export const IMPORT_NEHUBA_INJECT_TOKEN = `IMPORT_NEHUBA_INJECT_TOKEN` interface LayerLabelIndex { layer: { @@ -123,7 +122,6 @@ export class NehubaViewerUnit implements OnDestroy { public elementRef: ElementRef, private log: LoggingService, private periodicSvc: PeriodicSvc, - @Inject(IMPORT_NEHUBA_INJECT_TOKEN) getImportNehubaPr: () => Promise<any>, @Optional() @Inject(NEHUBA_INSTANCE_INJTKN) private nehubaViewer$: Subject<NehubaViewerUnit>, @Optional() @Inject(SET_MESHES_TO_LOAD) private injSetMeshesToLoad$: Observable<IMeshesToLoad>, @Optional() @Inject(SET_COLORMAP_OBS) private setColormap$: Observable<IColorMap>, @@ -194,8 +192,7 @@ export class NehubaViewerUnit implements OnDestroy { this.nehubaViewer$.next(this) } - getImportNehubaPr() - .then(() => getExportNehuba()) + getExportNehuba() .then(exportNehuba => { this.nehubaLoaded = true this.exportNehuba = exportNehuba @@ -417,9 +414,7 @@ export class NehubaViewerUnit implements OnDestroy { this.log.error(err) }); - (window as any).nehubaViewer = this.nehubaViewer - - const viewer = window['viewer'] + const viewer = this.nehubaViewer.ngviewer /** * Hide all layers except the base layer (template) diff --git a/src/viewerModule/nehuba/util.ts b/src/viewerModule/nehuba/util.ts index 0af076efd9c18e061e1e9f539c2911445aae4c77..8091d50beb6b4974bf7afe4d1eccc6b1d6a30d14 100644 --- a/src/viewerModule/nehuba/util.ts +++ b/src/viewerModule/nehuba/util.ts @@ -178,18 +178,6 @@ export const isIdentityQuat = (ori: number[]): boolean => Math.abs(ori[0]) < 1e- && Math.abs(ori[2]) < 1e-6 && Math.abs(ori[3] - 1) < 1e-6 -export const importNehubaFactory = (appendSrc: (src: string) => Promise<void>): () => Promise<void> => { - let pr: Promise<void> - return async () => { - if (!!(window as any).export_nehuba) return - - if (pr) return pr - pr = appendSrc('main.bundle.js') - - return pr - } -} - export const takeOnePipe = () => { return pipe(