diff --git a/.github/workflows/build-json-files-and-md-cache.yml b/.github/workflows/build-json-files-and-md-cache.yml index 083a416e25..a3e734a461 100644 --- a/.github/workflows/build-json-files-and-md-cache.yml +++ b/.github/workflows/build-json-files-and-md-cache.yml @@ -23,9 +23,23 @@ jobs: uses: actions/setup-node@v3 with: node-version: 18 - cache: 'npm' - - run: npm install + - name: Cache node modules + id: cache-npm + uses: actions/cache@v3 + env: + cache-name: cache-node-modules + with: + # npm cache files are stored in `~/.npm` on Linux/macOS + path: ~/.npm + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + - if: ${{ steps.cache-npm.outputs.cache-hit != 'true' }} + name: Install dependencies + run: npm ci - name: create pipeline.json run: npm run build-pipeline-json env: diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml new file mode 100644 index 0000000000..d711dac240 --- /dev/null +++ b/.github/workflows/playwright.yml @@ -0,0 +1,53 @@ +name: Playwright Tests +on: + pull_request: + +# Cancel if a newer run is started +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + run_test: + timeout-minutes: 30 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 18 + - name: Cache node modules + id: cache-npm + uses: actions/cache@v3 + env: + cache-name: cache-node-modules + with: + # npm cache files are stored in `~/.npm` on Linux/macOS + path: ~/.npm + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + + - if: ${{ steps.cache-npm.outputs.cache-hit != 'true' }} + name: Install dependencies + run: npm ci + - name: Install Playwright Browsers + run: npx playwright install --with-deps + - name: Waiting for 200 from the Netlify Preview + uses: jakepartusch/wait-for-netlify-action@v1.4 + id: waitFor200 + with: + site_name: 'nf-core' + max_timeout: 600 # 10 Minutes + - name: Run Playwright tests + run: npx playwright test + env: + PLAYWRIGHT_TEST_BASE_URL: 'https://deploy-preview-${{github.event.pull_request.number}}--nf-core.netlify.app' + - uses: actions/upload-artifact@v3 + if: always() + with: + name: playwright-report + path: playwright-report/ + retention-days: 1 diff --git a/.gitignore b/.gitignore index 1b08ac693d..b1ebacd37d 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,5 @@ pnpm-debug.log* # Local Netlify folder .netlify src/content/pipelines +playwright-report +test-results diff --git a/package-lock.json b/package-lock.json index 07f6d3af45..48ddf7f7e9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,13 +17,13 @@ "@astrojs/sitemap": "^2.0.2", "@astrojs/svelte": "^3.1.1", "@astropub/md": "^0.2.0", - "@aws-sdk/client-s3": "^3.395.0", - "@aws-sdk/credential-provider-node": "^3.395.0", + "@aws-sdk/client-s3": "^3.398.0", + "@aws-sdk/credential-provider-node": "^3.398.0", "@fontsource-variable/inter": "^5.0.8", "@fontsource-variable/maven-pro": "^5.0.8", "@fontsource-variable/open-sans": "^5.0.9", "@nanostores/persistent": "^0.9.1", - "astro": "^2.10.12", + "astro": "^2.10.13", "astro-icon": "^0.8.1", "bootstrap": "^5.3.1", "bootstrap-print-css": "^1.0.1", @@ -73,6 +73,7 @@ "youtube-player": "^5.6.0" }, "devDependencies": { + "@playwright/test": "^1.37.1", "@rollup/plugin-yaml": "^4.1.1", "@types/leaflet": "^1.9.3", "fontaine": "^0.4.0", @@ -2349,6 +2350,25 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/@playwright/test": { + "version": "1.37.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.37.1.tgz", + "integrity": "sha512-bq9zTli3vWJo8S3LwB91U0qDNQDpEXnw7knhxLM0nwDvexQAwx9tO8iKDZSqqneVq+URd/WIoz+BALMqUTgdSg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "playwright-core": "1.37.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, "node_modules/@popperjs/core": { "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", @@ -6039,9 +6059,9 @@ } }, "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "hasInstallScript": true, "optional": true, "os": [ @@ -9146,6 +9166,18 @@ "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", "dev": true }, + "node_modules/playwright-core": { + "version": "1.37.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.37.1.tgz", + "integrity": "sha512-17EuQxlSIYCmEMwzMqusJ2ztDgJePjrbttaefgdsiqeLWidjYz9BxXaTaZWxH1J95SHGk6tjE+dwgWILJoUZfA==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/postcss": { "version": "8.4.28", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.28.tgz", diff --git a/package.json b/package.json index 6117fb88a6..4edca02624 100644 --- a/package.json +++ b/package.json @@ -27,13 +27,13 @@ "@astrojs/sitemap": "^2.0.2", "@astrojs/svelte": "^3.1.1", "@astropub/md": "^0.2.0", - "@aws-sdk/client-s3": "^3.395.0", - "@aws-sdk/credential-provider-node": "^3.395.0", + "@aws-sdk/client-s3": "^3.398.0", + "@aws-sdk/credential-provider-node": "^3.398.0", "@fontsource-variable/inter": "^5.0.8", "@fontsource-variable/maven-pro": "^5.0.8", "@fontsource-variable/open-sans": "^5.0.9", "@nanostores/persistent": "^0.9.1", - "astro": "^2.10.12", + "astro": "^2.10.13", "astro-icon": "^0.8.1", "bootstrap": "^5.3.1", "bootstrap-print-css": "^1.0.1", @@ -83,6 +83,7 @@ "youtube-player": "^5.6.0" }, "devDependencies": { + "@playwright/test": "^1.37.1", "@rollup/plugin-yaml": "^4.1.1", "@types/leaflet": "^1.9.3", "fontaine": "^0.4.0", diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 0000000000..dca3958148 --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,65 @@ +import { defineConfig, devices } from '@playwright/test'; + + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// require('dotenv').config(); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: './tests', + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: 'html', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + baseURL: process.env.PLAYWRIGHT_TEST_BASE_URL || 'http://localhost:3000', + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] }, + }, + + { + name: 'webkit', + use: { ...devices['Desktop Safari'] }, + }, + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, + // }, + ], + + /* Run your local dev server before starting the tests */ + // webServer: { + // command: 'npm run dev', + // url: 'http://localhost:3000/', + // timeout: 120 * 1000, + // reuseExistingServer: !process.env.CI, + // }, +}); diff --git a/tests/nf-core.spec.ts b/tests/nf-core.spec.ts new file mode 100644 index 0000000000..c7e27a9449 --- /dev/null +++ b/tests/nf-core.spec.ts @@ -0,0 +1,33 @@ +import { test, expect } from '@playwright/test'; + + +test.describe.configure({ mode: 'parallel' }); +// @ts-check + +test('meta is correct', async ({ page }) => { + await page.goto('/'); + + await expect.soft(page).toHaveTitle('nf-core'); +}); + +test('pipeline redirect works for /$pipeliname', async ({ page }) => { + await page.goto('/rnaseq'); + await expect.soft(page).toHaveTitle('rnaseq: Introduction'); + // check if markdown is rendered correctly + await expect.soft(page.locator('.markdown-content')).toContainText('nf-core/rnaseq is a bioinformatics pipeline'); + // check if results redirect works + await page.goto('/rnaseq/results/'); + + await expect.soft(page.getByRole('link', { name: 'Results' })).toHaveClass('nav-link active'); + // check if SSR works correctly for results + await page.locator('.list-group-item').nth(1).click(); + await expect.soft(page.locator('.file-browser')).toContainText('fastqc'); +}); + +test('random pipeline page', async ({ page }) => { + // check if CTA button works and random (=the pipeline with the newest release) pipeline page is loaded + await page.goto('/'); + await page.getByRole('link', { name: 'View Pipelines' }).click(); + await page.locator('.card').locator('a').first().click(); + await expect.soft(page.locator('.markdown-content')).toContainText('Citations'); +});