diff --git a/.github/workflows/e2e-datasets.yml b/.github/workflows/e2e-datasets.yml new file mode 100644 index 000000000..4d6f01351 --- /dev/null +++ b/.github/workflows/e2e-datasets.yml @@ -0,0 +1,28 @@ +# A cache saved by a pull request run is only visible to that pull request. +# One saved on main is visible to all of them, so this keeps it there. +name: E2E dataset cache +on: + push: + branches: + - main + workflow_dispatch: + +jobs: + warm: + runs-on: ubuntu-latest + name: Warm the dataset cache + steps: + - uses: actions/checkout@v4 + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version: 22 + # Keep in step with the cache step in e2e.yml. + - name: Cache test datasets + uses: actions/cache@v4 + with: + path: .tmp/datasets + key: e2e-datasets-${{ hashFiles('tests/datasets.ts') }} + restore-keys: e2e-datasets- + - name: Download missing datasets + run: node tests/downloadDatasets.ts diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 4993780ad..f540f0e1b 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -29,6 +29,12 @@ jobs: run: npm ci env: DETECT_CHROMEDRIVER_VERSION: true + - name: Cache test datasets + uses: actions/cache@v4 + with: + path: .tmp/datasets + key: e2e-datasets-${{ hashFiles('tests/datasets.ts') }} + restore-keys: e2e-datasets- - name: Install xvfb (linux) if: matrix.os == 'ubuntu-latest' run: sudo apt-get install xvfb diff --git a/eslint.config.js b/eslint.config.js index 287844321..78aaaeafc 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -84,6 +84,38 @@ const featureBoundaries = (features) => { ]; }; +// Files that still pass their own time limits. Remove a file once it is +// clean; never add one. +const E2E_TIMEOUT_DEBT = [ + 'tests/pageobjects/volview.page.ts', + 'tests/specs/annotationTestUtils.ts', + 'tests/specs/automatic-layering.e2e.ts', + 'tests/specs/bug-report.e2e.ts', + 'tests/specs/cine-drag-onto-slot.e2e.ts', + 'tests/specs/cine-rendering.e2e.ts', + 'tests/specs/cine-ruler-session.e2e.ts', + 'tests/specs/crosshairs-multi-image.e2e.ts', + 'tests/specs/delete-selected-annotation.e2e.ts', + 'tests/specs/dicom-dimension-mismatch.e2e.ts', + 'tests/specs/different-direction-labelmap.e2e.ts', + 'tests/specs/imageCacheUtils.ts', + 'tests/specs/layer-source-lifetime.e2e.ts', + 'tests/specs/layers-and-rendering.e2e.ts', + 'tests/specs/multi-series-load.e2e.ts', + 'tests/specs/paint-tool-rendering.e2e.ts', + 'tests/specs/polygon-nested-interaction.e2e.ts', + 'tests/specs/sample-rendering.e2e.ts', + 'tests/specs/save-large-labelmap.e2e.ts', + 'tests/specs/seg-nrrd-export.e2e.ts', + 'tests/specs/select-annotation-at-press.e2e.ts', + 'tests/specs/select-tool-annotation-press.e2e.ts', + 'tests/specs/session-large-uri-base.e2e.ts', + 'tests/specs/sparse-manifest-prostate-rectangle.e2e.ts', + 'tests/specs/sparse-manifest.e2e.ts', + 'tests/specs/ultrasound-spacing.e2e.ts', + 'tests/specs/vtk-interactor-lifecycle.e2e.ts', +]; + export default tseslint.config( { ignores: [ @@ -142,6 +174,27 @@ export default tseslint.config( 'class-methods-use-this': 'off', }, }, + // A wait with its own time limit stands in for a state the app should + // publish, and fails on a slow machine. Wait on the state instead. + { + files: ['**/tests/specs/**/*.ts', '**/tests/pageobjects/**/*.ts'], + ignores: E2E_TIMEOUT_DEBT, + rules: { + 'no-restricted-syntax': [ + 'error', + { + selector: "Property[key.name='timeout']", + message: + 'Wait for a state the page publishes rather than passing a timeout.', + }, + { + selector: + "CallExpression[callee.object.name='browser'][callee.property.name='pause']", + message: 'Wait for a state the page publishes rather than pausing.', + }, + ], + }, + }, { files: ['**/__tests__/*.{js,ts}', '**/tests/unit/**/*.spec.{js,ts}'], languageOptions: { diff --git a/index.html b/index.html index eda9801e8..d460585dc 100644 --- a/index.html +++ b/index.html @@ -6,14 +6,6 @@ VolView - -