diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index ca06d06d1..6345b8272 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -5,23 +5,59 @@ on: pull_request: branches: [main, master] jobs: - test: - timeout-minutes: 120 + playwright-tests: + 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 steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: lts/* + node-version: 18 - name: Install dependencies - run: npm install -g yarn && yarn - - name: Install Playwright Browsers - run: yarn playwright install --with-deps - - name: Run Playwright tests - run: yarn test:e2e:ci - - uses: actions/upload-artifact@v4 - if: always() + run: yarn install --frozen-lockfile + + - name: Download blob reports from GitHub Actions Artifacts + uses: actions/download-artifact@v4 with: - name: playwright-report - path: tests/playwright-report - retention-days: 30 + path: all-blob-reports + pattern: blob-report-* + 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 diff --git a/extensions/cornerstone/src/types/AppTypes.ts b/extensions/cornerstone/src/types/AppTypes.ts index 45c523079..90997eb27 100644 --- a/extensions/cornerstone/src/types/AppTypes.ts +++ b/extensions/cornerstone/src/types/AppTypes.ts @@ -6,6 +6,8 @@ import SyncGroupServiceType from '../services/SyncGroupService'; import ToolGroupServiceType from '../services/ToolGroupService'; import ViewportActionCornersServiceType from '../services/ViewportActionCornersService/ViewportActionCornersService'; import ColorbarServiceType from '../services/ColorbarService'; +import * as cornerstone from '@cornerstonejs/core'; +import * as cornerstoneTools from '@cornerstonejs/tools'; declare global { namespace AppTypes { @@ -25,5 +27,11 @@ declare global { viewportActionCornersService?: ViewportActionCornersServiceType; colorbarService?: ColorbarServiceType; } + + export interface Test { + services?: Services; + cornerstone?: typeof cornerstone; + cornerstoneTools?: typeof cornerstoneTools; + } } } diff --git a/package.json b/package.json index 82541bffd..a648fe74f 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "test:unit:ci": "lerna run test:unit:ci --parallel --stream", "test:e2e": "lerna run test:e2e --stream", "test:e2e:ci": "npx playwright test", + "test:e2e:ui": "npx playwright test --ui", "test:e2e:headed": "npx playwright test --headed", "test:e2e:dist": "lerna run test:e2e:dist --stream", "test:e2e:serve": "yarn test:data && lerna run test:e2e:serve --stream", diff --git a/platform/core/src/types/AppTypes.ts b/platform/core/src/types/AppTypes.ts index c7f953e8a..644f9335d 100644 --- a/platform/core/src/types/AppTypes.ts +++ b/platform/core/src/types/AppTypes.ts @@ -120,6 +120,13 @@ declare global { dataSources?: any; oidc?: any; } + + export interface Test { + services?: Services; + commandsManager?: CommandsManager; + extensionManager?: ExtensionManager; + config?: Config; + } } export type withAppTypes = T & diff --git a/platform/docs/docs/development/playwright-testing.md b/platform/docs/docs/development/playwright-testing.md index 8e0e9fc98..d55ec1198 100644 --- a/platform/docs/docs/development/playwright-testing.md +++ b/platform/docs/docs/development/playwright-testing.md @@ -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. +## 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 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). diff --git a/playwright.config.ts b/playwright.config.ts index 29385061a..b31696188 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -8,7 +8,12 @@ export default defineConfig({ workers: process.env.CI ? 1 : undefined, snapshotPathTemplate: './tests/screenshots{/projectName}/{testFilePath}/{arg}{ext}', outputDir: './tests/test-results', - reporter: [['html', { outputFolder: './tests/playwright-report' }]], + reporter: [ + [ + process.env.CI ? 'blob' : 'html', + { outputFolder: './tests/playwright-report' }, + ], + ], timeout: 720 * 1000, use: { baseURL: 'http://localhost:3000', diff --git a/tests/3DFourUp.spec.ts b/tests/3DFourUp.spec.ts index 333ef675c..e196856d9 100644 --- a/tests/3DFourUp.spec.ts +++ b/tests/3DFourUp.spec.ts @@ -1,8 +1,8 @@ import { test } from '@playwright/test'; -import { visitStudy, checkForScreenshot, screenShotPaths } from './utils'; +import { visitStudy, checkForScreenshot, screenShotPaths, reduce3DViewportSize } from './utils'; 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'; await visitStudy(page, studyInstanceUID, mode, 2000); }); @@ -15,6 +15,7 @@ test.describe('3D four up Test', async () => { .filter({ hasText: /^3D four up$/ }) .first() .click(); + await reduce3DViewportSize(page); await checkForScreenshot( page, page, diff --git a/tests/3DMain.spec.ts b/tests/3DMain.spec.ts index e30fffbea..f0ce18f34 100644 --- a/tests/3DMain.spec.ts +++ b/tests/3DMain.spec.ts @@ -1,8 +1,8 @@ import { test } from '@playwright/test'; -import { visitStudy, checkForScreenshot, screenShotPaths } from './utils'; +import { visitStudy, checkForScreenshot, screenShotPaths, reduce3DViewportSize } from './utils'; 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'; await visitStudy(page, studyInstanceUID, mode, 2000); }); @@ -15,6 +15,7 @@ test.describe('3D main Test', async () => { .filter({ hasText: /^3D main$/ }) .first() .click(); + await reduce3DViewportSize(page); await checkForScreenshot( page, page, diff --git a/tests/3DOnly.spec.ts b/tests/3DOnly.spec.ts index 115823f0c..28489d024 100644 --- a/tests/3DOnly.spec.ts +++ b/tests/3DOnly.spec.ts @@ -1,8 +1,8 @@ import { test } from '@playwright/test'; -import { visitStudy, checkForScreenshot, screenShotPaths } from './utils'; +import { visitStudy, checkForScreenshot, screenShotPaths, reduce3DViewportSize } from './utils'; 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'; await visitStudy(page, studyInstanceUID, mode, 2000); }); @@ -15,6 +15,7 @@ test.describe('3D only Test', async () => { .filter({ hasText: /^3D only$/ }) .first() .click(); + await reduce3DViewportSize(page); await checkForScreenshot( page, page, diff --git a/tests/3DPrimary.spec.ts b/tests/3DPrimary.spec.ts index 73e853223..f38481588 100644 --- a/tests/3DPrimary.spec.ts +++ b/tests/3DPrimary.spec.ts @@ -1,8 +1,8 @@ import { test } from '@playwright/test'; -import { visitStudy, checkForScreenshot, screenShotPaths } from './utils'; +import { visitStudy, checkForScreenshot, screenShotPaths, reduce3DViewportSize } from './utils'; 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'; await visitStudy(page, studyInstanceUID, mode, 2000); }); @@ -16,6 +16,7 @@ test.describe('3D primary Test', async () => { .first() .click(); + await reduce3DViewportSize(page); await checkForScreenshot( page, page, diff --git a/tests/AxialPrimary.spec.ts b/tests/AxialPrimary.spec.ts index 0458ac19d..8826ed031 100644 --- a/tests/AxialPrimary.spec.ts +++ b/tests/AxialPrimary.spec.ts @@ -2,7 +2,7 @@ import { test } from '@playwright/test'; import { visitStudy, checkForScreenshot, screenShotPaths } from './utils'; 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'; await visitStudy(page, studyInstanceUID, mode, 2000); }); diff --git a/tests/MPR.spec.ts b/tests/MPR.spec.ts index 57eb3068e..4119ccaa0 100644 --- a/tests/MPR.spec.ts +++ b/tests/MPR.spec.ts @@ -2,7 +2,7 @@ import { test } from '@playwright/test'; import { visitStudy, checkForScreenshot, screenShotPaths } from './utils/index'; 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'; await visitStudy(page, studyInstanceUID, mode, 2000); }); diff --git a/tests/screenshots/chromium/3DFourUp.spec.ts/threeDFourUpDisplayedCorrectly.png b/tests/screenshots/chromium/3DFourUp.spec.ts/threeDFourUpDisplayedCorrectly.png index 9386de049..ddf13a29e 100644 Binary files a/tests/screenshots/chromium/3DFourUp.spec.ts/threeDFourUpDisplayedCorrectly.png and b/tests/screenshots/chromium/3DFourUp.spec.ts/threeDFourUpDisplayedCorrectly.png differ diff --git a/tests/screenshots/chromium/3DMain.spec.ts/threeDMainDisplayedCorrectly.png b/tests/screenshots/chromium/3DMain.spec.ts/threeDMainDisplayedCorrectly.png index cf1a2bf3d..10f72b0fa 100644 Binary files a/tests/screenshots/chromium/3DMain.spec.ts/threeDMainDisplayedCorrectly.png and b/tests/screenshots/chromium/3DMain.spec.ts/threeDMainDisplayedCorrectly.png differ diff --git a/tests/screenshots/chromium/3DOnly.spec.ts/threeDOnlyDisplayedCorrectly.png b/tests/screenshots/chromium/3DOnly.spec.ts/threeDOnlyDisplayedCorrectly.png index 542c59b26..60dc71550 100644 Binary files a/tests/screenshots/chromium/3DOnly.spec.ts/threeDOnlyDisplayedCorrectly.png and b/tests/screenshots/chromium/3DOnly.spec.ts/threeDOnlyDisplayedCorrectly.png differ diff --git a/tests/screenshots/chromium/3DPrimary.spec.ts/threeDPrimaryDisplayedCorrectly.png b/tests/screenshots/chromium/3DPrimary.spec.ts/threeDPrimaryDisplayedCorrectly.png index d58dd2f6f..8d1fb1df3 100644 Binary files a/tests/screenshots/chromium/3DPrimary.spec.ts/threeDPrimaryDisplayedCorrectly.png and b/tests/screenshots/chromium/3DPrimary.spec.ts/threeDPrimaryDisplayedCorrectly.png differ diff --git a/tests/screenshots/chromium/AxialPrimary.spec.ts/axialPrimaryDisplayedCorrectly.png b/tests/screenshots/chromium/AxialPrimary.spec.ts/axialPrimaryDisplayedCorrectly.png index ac725b88e..babca6641 100644 Binary files a/tests/screenshots/chromium/AxialPrimary.spec.ts/axialPrimaryDisplayedCorrectly.png and b/tests/screenshots/chromium/AxialPrimary.spec.ts/axialPrimaryDisplayedCorrectly.png differ diff --git a/tests/screenshots/chromium/MPR.spec.ts/mprDisplayedCorrectly.png b/tests/screenshots/chromium/MPR.spec.ts/mprDisplayedCorrectly.png index 52cadb0af..01a5cd4e2 100644 Binary files a/tests/screenshots/chromium/MPR.spec.ts/mprDisplayedCorrectly.png and b/tests/screenshots/chromium/MPR.spec.ts/mprDisplayedCorrectly.png differ diff --git a/tests/utils/index.ts b/tests/utils/index.ts index f9ee5a7a0..cea8ef009 100644 --- a/tests/utils/index.ts +++ b/tests/utils/index.ts @@ -2,5 +2,7 @@ import { visitStudy } from './visitStudy'; import { checkForScreenshot } from './checkForScreenshot'; import { screenShotPaths } from './screenShotPaths'; import { simulateClicksOnElement } from './simulateClicksOnElement'; +import { reduce3DViewportSize } from './reduce3DviewportSize'; -export { visitStudy, checkForScreenshot, screenShotPaths, simulateClicksOnElement }; + +export { visitStudy, checkForScreenshot, screenShotPaths, simulateClicksOnElement, reduce3DViewportSize }; diff --git a/tests/utils/reduce3DviewportSize.ts b/tests/utils/reduce3DviewportSize.ts new file mode 100644 index 000000000..2ce072c5d --- /dev/null +++ b/tests/utils/reduce3DviewportSize.ts @@ -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')); +} diff --git a/tsconfig.json b/tsconfig.json index 3c2bf2cbf..ee01dec9e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -25,7 +25,7 @@ "platform/**/public/**/*", "extensions/**/src/**/*", "modes/**/src/**/*", - "custom.d.ts" + "tests/**/*", ], "exclude": ["node_modules", "dist"] }