test(improve-setup): sharding configuration, allow accessing cornerstone methods and events in tests, and add types (#4255)
62
.github/workflows/playwright.yml
vendored
@ -5,23 +5,59 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
branches: [main, master]
|
branches: [main, master]
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
playwright-tests:
|
||||||
timeout-minutes: 120
|
timeout-minutes: 60
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
shardIndex: [1, 2, 3, 4, 5]
|
||||||
|
shardTotal: [5]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 18
|
||||||
|
- name: Install dependencies
|
||||||
|
run: yarn install --frozen-lockfile
|
||||||
|
- name: Install Playwright Browsers
|
||||||
|
run: npx playwright install --with-deps
|
||||||
|
- name: Run Playwright tests
|
||||||
|
run: export NODE_OPTIONS="--max_old_space_size=8192" && npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
|
||||||
|
|
||||||
|
- name: Upload blob report to GitHub Actions Artifacts
|
||||||
|
if: ${{ !cancelled() }}
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: blob-report-${{ matrix.shardIndex }}
|
||||||
|
path: blob-report
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
merge-reports:
|
||||||
|
if: ${{ !cancelled() }}
|
||||||
|
needs: [playwright-tests]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: lts/*
|
node-version: 18
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm install -g yarn && yarn
|
run: yarn install --frozen-lockfile
|
||||||
- name: Install Playwright Browsers
|
|
||||||
run: yarn playwright install --with-deps
|
- name: Download blob reports from GitHub Actions Artifacts
|
||||||
- name: Run Playwright tests
|
uses: actions/download-artifact@v4
|
||||||
run: yarn test:e2e:ci
|
|
||||||
- uses: actions/upload-artifact@v4
|
|
||||||
if: always()
|
|
||||||
with:
|
with:
|
||||||
name: playwright-report
|
path: all-blob-reports
|
||||||
path: tests/playwright-report
|
pattern: blob-report-*
|
||||||
retention-days: 30
|
merge-multiple: true
|
||||||
|
|
||||||
|
- name: Merge into HTML Report
|
||||||
|
run: npx playwright merge-reports --reporter html ./all-blob-reports
|
||||||
|
|
||||||
|
- name: Upload HTML report
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: html-report--attempt-${{ github.run_attempt }}
|
||||||
|
path: playwright-report
|
||||||
|
retention-days: 14
|
||||||
|
|||||||
@ -6,6 +6,8 @@ import SyncGroupServiceType from '../services/SyncGroupService';
|
|||||||
import ToolGroupServiceType from '../services/ToolGroupService';
|
import ToolGroupServiceType from '../services/ToolGroupService';
|
||||||
import ViewportActionCornersServiceType from '../services/ViewportActionCornersService/ViewportActionCornersService';
|
import ViewportActionCornersServiceType from '../services/ViewportActionCornersService/ViewportActionCornersService';
|
||||||
import ColorbarServiceType from '../services/ColorbarService';
|
import ColorbarServiceType from '../services/ColorbarService';
|
||||||
|
import * as cornerstone from '@cornerstonejs/core';
|
||||||
|
import * as cornerstoneTools from '@cornerstonejs/tools';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
namespace AppTypes {
|
namespace AppTypes {
|
||||||
@ -25,5 +27,11 @@ declare global {
|
|||||||
viewportActionCornersService?: ViewportActionCornersServiceType;
|
viewportActionCornersService?: ViewportActionCornersServiceType;
|
||||||
colorbarService?: ColorbarServiceType;
|
colorbarService?: ColorbarServiceType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Test {
|
||||||
|
services?: Services;
|
||||||
|
cornerstone?: typeof cornerstone;
|
||||||
|
cornerstoneTools?: typeof cornerstoneTools;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,6 +49,7 @@
|
|||||||
"test:unit:ci": "lerna run test:unit:ci --parallel --stream",
|
"test:unit:ci": "lerna run test:unit:ci --parallel --stream",
|
||||||
"test:e2e": "lerna run test:e2e --stream",
|
"test:e2e": "lerna run test:e2e --stream",
|
||||||
"test:e2e:ci": "npx playwright test",
|
"test:e2e:ci": "npx playwright test",
|
||||||
|
"test:e2e:ui": "npx playwright test --ui",
|
||||||
"test:e2e:headed": "npx playwright test --headed",
|
"test:e2e:headed": "npx playwright test --headed",
|
||||||
"test:e2e:dist": "lerna run test:e2e:dist --stream",
|
"test:e2e:dist": "lerna run test:e2e:dist --stream",
|
||||||
"test:e2e:serve": "yarn test:data && lerna run test:e2e:serve --stream",
|
"test:e2e:serve": "yarn test:data && lerna run test:e2e:serve --stream",
|
||||||
|
|||||||
@ -120,6 +120,13 @@ declare global {
|
|||||||
dataSources?: any;
|
dataSources?: any;
|
||||||
oidc?: any;
|
oidc?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Test {
|
||||||
|
services?: Services;
|
||||||
|
commandsManager?: CommandsManager;
|
||||||
|
extensionManager?: ExtensionManager;
|
||||||
|
config?: Config;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type withAppTypes<T = object> = T &
|
export type withAppTypes<T = object> = T &
|
||||||
|
|||||||
@ -128,6 +128,21 @@ yarn playwright show-report tests/playwright-report
|
|||||||
|
|
||||||
By default, when you run the tests, it will call the `yarn start` command to serve the viewer first, then run the tests, if you would like to serve the viewer manually, you can use the same command. The viewer will be available at `http://localhost:3000`. This could speed up your development process since playwright will skip this step and use the existing server on port 3000.
|
By default, when you run the tests, it will call the `yarn start` command to serve the viewer first, then run the tests, if you would like to serve the viewer manually, you can use the same command. The viewer will be available at `http://localhost:3000`. This could speed up your development process since playwright will skip this step and use the existing server on port 3000.
|
||||||
|
|
||||||
|
## Accessing services, managers, configs and cornerstone in your tests
|
||||||
|
|
||||||
|
If you would like to access the cornerstone3D, services, or command managers in your tests, you can use the `page.evaluate` function to access them. For example, if you would like to access the `services` so you can show a UI notifcation using the uiNotifcationService, you can use the following code snippet:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
await page.evaluate(({ services }: AppTypes.Test) => {
|
||||||
|
const { uiNotificationService } = services;
|
||||||
|
uiNotificationService.show({
|
||||||
|
title: 'Test',
|
||||||
|
message: 'This is a test',
|
||||||
|
type: 'info',
|
||||||
|
});
|
||||||
|
}, await page.evaluateHandle('window'));
|
||||||
|
```
|
||||||
|
|
||||||
## Playwright VSCode Extension and Recording Tests
|
## Playwright VSCode Extension and Recording Tests
|
||||||
|
|
||||||
If you are using VSCode, you can use the Playwright extension to help you write your tests. The extension provides a test runner and many great features such as picking a locator using your mouse, recording a new test, and more. You can install the extension by searching for `Playwright` in the extensions tab in VSCode or by visiting the [Playwright extension page](https://marketplace.visualstudio.com/items?itemName=ms-playwright.playwright).
|
If you are using VSCode, you can use the Playwright extension to help you write your tests. The extension provides a test runner and many great features such as picking a locator using your mouse, recording a new test, and more. You can install the extension by searching for `Playwright` in the extensions tab in VSCode or by visiting the [Playwright extension page](https://marketplace.visualstudio.com/items?itemName=ms-playwright.playwright).
|
||||||
|
|||||||
@ -8,7 +8,12 @@ export default defineConfig({
|
|||||||
workers: process.env.CI ? 1 : undefined,
|
workers: process.env.CI ? 1 : undefined,
|
||||||
snapshotPathTemplate: './tests/screenshots{/projectName}/{testFilePath}/{arg}{ext}',
|
snapshotPathTemplate: './tests/screenshots{/projectName}/{testFilePath}/{arg}{ext}',
|
||||||
outputDir: './tests/test-results',
|
outputDir: './tests/test-results',
|
||||||
reporter: [['html', { outputFolder: './tests/playwright-report' }]],
|
reporter: [
|
||||||
|
[
|
||||||
|
process.env.CI ? 'blob' : 'html',
|
||||||
|
{ outputFolder: './tests/playwright-report' },
|
||||||
|
],
|
||||||
|
],
|
||||||
timeout: 720 * 1000,
|
timeout: 720 * 1000,
|
||||||
use: {
|
use: {
|
||||||
baseURL: 'http://localhost:3000',
|
baseURL: 'http://localhost:3000',
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { test } from '@playwright/test';
|
import { test } from '@playwright/test';
|
||||||
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils';
|
import { visitStudy, checkForScreenshot, screenShotPaths, reduce3DViewportSize } from './utils';
|
||||||
|
|
||||||
test.beforeEach(async ({ page }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
const studyInstanceUID = '2.16.840.1.114362.1.11972228.22789312658.616067305.306.2';
|
const studyInstanceUID = '1.3.6.1.4.1.14519.5.2.1.1706.8374.643249677828306008300337414785';
|
||||||
const mode = 'Basic Viewer';
|
const mode = 'Basic Viewer';
|
||||||
await visitStudy(page, studyInstanceUID, mode, 2000);
|
await visitStudy(page, studyInstanceUID, mode, 2000);
|
||||||
});
|
});
|
||||||
@ -15,6 +15,7 @@ test.describe('3D four up Test', async () => {
|
|||||||
.filter({ hasText: /^3D four up$/ })
|
.filter({ hasText: /^3D four up$/ })
|
||||||
.first()
|
.first()
|
||||||
.click();
|
.click();
|
||||||
|
await reduce3DViewportSize(page);
|
||||||
await checkForScreenshot(
|
await checkForScreenshot(
|
||||||
page,
|
page,
|
||||||
page,
|
page,
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { test } from '@playwright/test';
|
import { test } from '@playwright/test';
|
||||||
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils';
|
import { visitStudy, checkForScreenshot, screenShotPaths, reduce3DViewportSize } from './utils';
|
||||||
|
|
||||||
test.beforeEach(async ({ page }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
const studyInstanceUID = '2.16.840.1.114362.1.11972228.22789312658.616067305.306.2';
|
const studyInstanceUID = '1.3.6.1.4.1.14519.5.2.1.1706.8374.643249677828306008300337414785';
|
||||||
const mode = 'Basic Viewer';
|
const mode = 'Basic Viewer';
|
||||||
await visitStudy(page, studyInstanceUID, mode, 2000);
|
await visitStudy(page, studyInstanceUID, mode, 2000);
|
||||||
});
|
});
|
||||||
@ -15,6 +15,7 @@ test.describe('3D main Test', async () => {
|
|||||||
.filter({ hasText: /^3D main$/ })
|
.filter({ hasText: /^3D main$/ })
|
||||||
.first()
|
.first()
|
||||||
.click();
|
.click();
|
||||||
|
await reduce3DViewportSize(page);
|
||||||
await checkForScreenshot(
|
await checkForScreenshot(
|
||||||
page,
|
page,
|
||||||
page,
|
page,
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { test } from '@playwright/test';
|
import { test } from '@playwright/test';
|
||||||
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils';
|
import { visitStudy, checkForScreenshot, screenShotPaths, reduce3DViewportSize } from './utils';
|
||||||
|
|
||||||
test.beforeEach(async ({ page }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
const studyInstanceUID = '2.16.840.1.114362.1.11972228.22789312658.616067305.306.2';
|
const studyInstanceUID = '1.3.6.1.4.1.14519.5.2.1.1706.8374.643249677828306008300337414785';
|
||||||
const mode = 'Basic Viewer';
|
const mode = 'Basic Viewer';
|
||||||
await visitStudy(page, studyInstanceUID, mode, 2000);
|
await visitStudy(page, studyInstanceUID, mode, 2000);
|
||||||
});
|
});
|
||||||
@ -15,6 +15,7 @@ test.describe('3D only Test', async () => {
|
|||||||
.filter({ hasText: /^3D only$/ })
|
.filter({ hasText: /^3D only$/ })
|
||||||
.first()
|
.first()
|
||||||
.click();
|
.click();
|
||||||
|
await reduce3DViewportSize(page);
|
||||||
await checkForScreenshot(
|
await checkForScreenshot(
|
||||||
page,
|
page,
|
||||||
page,
|
page,
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { test } from '@playwright/test';
|
import { test } from '@playwright/test';
|
||||||
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils';
|
import { visitStudy, checkForScreenshot, screenShotPaths, reduce3DViewportSize } from './utils';
|
||||||
|
|
||||||
test.beforeEach(async ({ page }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
const studyInstanceUID = '2.16.840.1.114362.1.11972228.22789312658.616067305.306.2';
|
const studyInstanceUID = '1.3.6.1.4.1.14519.5.2.1.1706.8374.643249677828306008300337414785';
|
||||||
const mode = 'Basic Viewer';
|
const mode = 'Basic Viewer';
|
||||||
await visitStudy(page, studyInstanceUID, mode, 2000);
|
await visitStudy(page, studyInstanceUID, mode, 2000);
|
||||||
});
|
});
|
||||||
@ -16,6 +16,7 @@ test.describe('3D primary Test', async () => {
|
|||||||
.first()
|
.first()
|
||||||
.click();
|
.click();
|
||||||
|
|
||||||
|
await reduce3DViewportSize(page);
|
||||||
await checkForScreenshot(
|
await checkForScreenshot(
|
||||||
page,
|
page,
|
||||||
page,
|
page,
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { test } from '@playwright/test';
|
|||||||
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils';
|
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils';
|
||||||
|
|
||||||
test.beforeEach(async ({ page }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
const studyInstanceUID = '2.16.840.1.114362.1.11972228.22789312658.616067305.306.2';
|
const studyInstanceUID = '1.3.6.1.4.1.14519.5.2.1.1706.8374.643249677828306008300337414785';
|
||||||
const mode = 'Basic Viewer';
|
const mode = 'Basic Viewer';
|
||||||
await visitStudy(page, studyInstanceUID, mode, 2000);
|
await visitStudy(page, studyInstanceUID, mode, 2000);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { test } from '@playwright/test';
|
|||||||
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils/index';
|
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils/index';
|
||||||
|
|
||||||
test.beforeEach(async ({ page }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
const studyInstanceUID = '2.16.840.1.114362.1.11972228.22789312658.616067305.306.2';
|
const studyInstanceUID = '1.3.6.1.4.1.14519.5.2.1.1706.8374.643249677828306008300337414785';
|
||||||
const mode = 'Basic Viewer';
|
const mode = 'Basic Viewer';
|
||||||
await visitStudy(page, studyInstanceUID, mode, 2000);
|
await visitStudy(page, studyInstanceUID, mode, 2000);
|
||||||
});
|
});
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 381 KiB After Width: | Height: | Size: 332 KiB |
|
Before Width: | Height: | Size: 366 KiB After Width: | Height: | Size: 288 KiB |
|
Before Width: | Height: | Size: 522 KiB After Width: | Height: | Size: 301 KiB |
|
Before Width: | Height: | Size: 660 KiB After Width: | Height: | Size: 295 KiB |
|
Before Width: | Height: | Size: 288 KiB After Width: | Height: | Size: 340 KiB |
|
Before Width: | Height: | Size: 232 KiB After Width: | Height: | Size: 212 KiB |
@ -2,5 +2,7 @@ import { visitStudy } from './visitStudy';
|
|||||||
import { checkForScreenshot } from './checkForScreenshot';
|
import { checkForScreenshot } from './checkForScreenshot';
|
||||||
import { screenShotPaths } from './screenShotPaths';
|
import { screenShotPaths } from './screenShotPaths';
|
||||||
import { simulateClicksOnElement } from './simulateClicksOnElement';
|
import { simulateClicksOnElement } from './simulateClicksOnElement';
|
||||||
|
import { reduce3DViewportSize } from './reduce3DviewportSize';
|
||||||
|
|
||||||
export { visitStudy, checkForScreenshot, screenShotPaths, simulateClicksOnElement };
|
|
||||||
|
export { visitStudy, checkForScreenshot, screenShotPaths, simulateClicksOnElement, reduce3DViewportSize };
|
||||||
|
|||||||
9
tests/utils/reduce3DviewportSize.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
export const reduce3DViewportSize = async (page: any) => {
|
||||||
|
await page.evaluate(({ cornerstone }: AppTypes.Test) => {
|
||||||
|
const enabledElement = cornerstone.getEnabledElements().filter(element => element.viewport.type === 'volume3d')[0]
|
||||||
|
const { viewport } = enabledElement;
|
||||||
|
viewport.setZoom(0.5);
|
||||||
|
viewport.render()
|
||||||
|
}, await page.evaluateHandle('window'));
|
||||||
|
}
|
||||||
@ -25,7 +25,7 @@
|
|||||||
"platform/**/public/**/*",
|
"platform/**/public/**/*",
|
||||||
"extensions/**/src/**/*",
|
"extensions/**/src/**/*",
|
||||||
"modes/**/src/**/*",
|
"modes/**/src/**/*",
|
||||||
"custom.d.ts"
|
"tests/**/*",
|
||||||
],
|
],
|
||||||
"exclude": ["node_modules", "dist"]
|
"exclude": ["node_modules", "dist"]
|
||||||
}
|
}
|
||||||
|
|||||||