diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ce310f0c1dc..3e5a361ae10 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -165,3 +165,9 @@ jobs: needs: build uses: ./.github/workflows/e2e.yml secrets: inherit + + playwright: + if: github.ref_name != 'i18n/crowdin' + needs: build + uses: ./.github/workflows/playwright.yml + secrets: inherit diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 90b6b700d4f..663798fb1f7 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -1,27 +1,204 @@ -name: Playwright Tests +name: Playwright E2E + on: - push: - branches: [ main, master ] - pull_request: - branches: [ main, master ] + workflow_call: + +env: + TZ: UTC + OC_ENV: ci + NODE_ENV: test + WEBSITE_URL: http://localhost:3000 + API_URL: http://localhost:3060 + API_KEY: dvl-1510egmf4a23d80342403fb599qd + CI: true + + E2E_TEST: 1 + PGHOST: localhost + PGUSER: postgres + IMAGES_URL: http://localhost:3001 + GITHUB_CLIENT_ID: ${{ secrets.GH_CLIENT_ID }} + GITHUB_CLIENT_SECRET: ${{ secrets.GH_CLIENT_SECRET }} + FRONTEND_FOLDER: /home/runner/work/opencollective-frontend/opencollective-frontend + API_FOLDER: /home/runner/work/opencollective-frontend/opencollective-frontend/opencollective-api + IMAGES_FOLDER: /home/runner/work/opencollective-frontend/opencollective-frontend/opencollective-images + TERM: xterm + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + STRIPE_WEBHOOK_KEY: ${{ secrets.STRIPE_WEBHOOK_KEY }} + STRIPE_WEBHOOK_SIGNING_SECRET: ${{ secrets.STRIPE_WEBHOOK_SIGNING_SECRET }} + AWS_KEY: ${{ secrets.AWS_KEY }} + AWS_SECRET: ${{ secrets.AWS_SECRET }} + jobs: - test: - timeout-minutes: 60 + e2e-playwright: + if: github.ref_name != 'i18n/crowdin' + runs-on: ubuntu-latest + + timeout-minutes: 30 + + strategy: + fail-fast: false + matrix: + files: ['0*.js', '1*.js', '2*.js', '3*.js'] + + services: + redis: + image: redis + ports: + - 6379:6379 + options: --entrypoint redis-server + postgres: + image: postgres:13.13 + env: + POSTGRES_USER: postgres + POSTGRES_DB: postgres + POSTGRES_HOST_AUTH_METHOD: trust + ports: + - 5432:5432 + # needed because the postgres container does not provide a healthcheck + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: 18 - - name: Install dependencies - run: npm ci - - name: Install Playwright Browsers - run: npx playwright install --with-deps - - name: Run Playwright tests - run: npx playwright test - - uses: actions/upload-artifact@v3 - if: always() - with: - name: playwright-report - path: playwright-report/ - retention-days: 30 + - name: Update apt + run: sudo apt-get update || exit 0 + + - name: Install postgresql-client + run: sudo apt-get install -y postgresql-client + + - name: Install graphicsmagick + run: sudo apt-get install -y graphicsmagick + + - name: Install stripe-cli + run: | + sudo apt-get install -y wget + wget https://github.com/stripe/stripe-cli/releases/download/v1.13.9/stripe_1.13.9_linux_x86_64.tar.gz -O /tmp/stripe_1.13.9_linux_x86_64.tar.gz + sudo tar xzvf /tmp/stripe_1.13.9_linux_x86_64.tar.gz -C /bin/ + + - name: Checkout (frontend) + uses: actions/checkout@v4 + + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version-file: 'package.json' + cache: 'npm' + + # Checkouts + + - name: Set REF in env, removing the `refs/` part + run: | + echo "MATCHING_BRANCH_REF=${GITHUB_HEAD_REF-${GITHUB_REF##*/}}" >> $GITHUB_ENV + + - name: Check matching branch (api) + id: check-matching-branch + uses: octokit/request-action@v2.x + with: + route: GET /repos/{owner}/{repo}/git/ref/{ref} + owner: opencollective + repo: opencollective-api + ref: heads/${{ env.MATCHING_BRANCH_REF }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + continue-on-error: true + + - name: Checkout (api - matching branch) + if: steps.check-matching-branch.outputs.status == 200 + uses: actions/checkout@v4 + with: + repository: opencollective/opencollective-api + path: opencollective-api + ref: ${{ env.MATCHING_BRANCH_REF }} + + - name: Checkout (api - main) + if: steps.check-matching-branch.outputs.status != 200 + uses: actions/checkout@v4 + with: + repository: opencollective/opencollective-api + path: opencollective-api + + - name: Checkout (images) + uses: actions/checkout@v4 + with: + repository: opencollective/opencollective-images + path: opencollective-images + + # Prepare API + + - name: Restore node_modules (api) + uses: actions/cache@v3 + id: api-node-modules + with: + path: opencollective-api/node_modules + key: ${{ runner.os }}-api-node-modules-${{ hashFiles('opencollective-api/package-lock.json') }} + + - name: Install dependencies (api) + working-directory: opencollective-api + if: steps.api-node-modules.outputs.cache-hit != 'true' + run: npm ci --prefer-offline --no-audit + + - name: Build (api) + working-directory: opencollective-api + run: npm run build + + # Prepare Images + + - name: Restore node_modules (images) + uses: actions/cache@v3 + id: images-node-modules + with: + path: opencollective-images/node_modules + key: ${{ runner.os }}-images-node-modules-${{ hashFiles('opencollective-images/package-lock.json') }} + + - name: Install dependencies (images) + working-directory: opencollective-images + if: steps.images-node-modules.outputs.cache-hit != 'true' + run: npm ci --prefer-offline --no-audit + + - name: Build (images) + working-directory: opencollective-images + run: npm run build + + # Prepare Frontend + + - name: Restore node_modules (frontend) + uses: actions/cache@v3 + id: node-modules + with: + path: node_modules + key: ${{ runner.os }}-node-modules-${{ hashFiles('package-lock.json') }}-${{ secrets.CACHE_VERSION }} + + - name: Install dependencies (frontend) + if: steps.node-modules.outputs.cache-hit != 'true' + run: CYPRESS_INSTALL_BINARY=0 npm ci --prefer-offline --no-audit + + - name: Install Playwright + run: npx playwright install --with-deps + + - name: Restore .next build (frontend) + uses: actions/cache@v3 + id: next-build + with: + path: .next + key: ${{ runner.os }}-next-build-${{ github.sha }} + + - name: Restore .next cache (frontend) + if: steps.next-build.outputs.cache-hit != 'true' + uses: actions/cache@v3 + with: + path: .next/cache + key: ${{ runner.os }}-next-cache-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-next-cache-${{ github.sha }} + ${{ runner.os }}-next-cache- + + - name: Build (frontend) + if: steps.next-build.outputs.cache-hit != 'true' + run: npm run build + + - name: Setup DB + run: ./scripts/setup_db.sh + + - name: Run E2E with Playwright + run: ./scripts/run_e2e_tests.sh + env: + USE_PLAYWRIGHT: true diff --git a/playwright-tests/playwright-script.py b/playwright-tests/playwright-script.py deleted file mode 100644 index f8c6ce06af2..00000000000 --- a/playwright-tests/playwright-script.py +++ /dev/null @@ -1,27 +0,0 @@ -import subprocess - -t1p = [] -t2p = [] -currentWorkingDirectory = "/Users/atharvchandratre/IdeaProjects/opencollective-frontend/" -for i in range(10): - commandstr = "npx playwright test playwright-tests/16-tiers-page.spec.ts --reporter=json --workers=1 | grep duration" - result = subprocess.run(commandstr.split(" "), capture_output=True, text=True, cwd=currentWorkingDirectory).stdout - splitresult = result.split("\"duration\": ") - t1p.append(int(splitresult[1].split(",")[0])) - t2p.append(int(splitresult[2].split(",")[0])) - -# t1 -> Test 1 of the spec file -# t2 -> Test 2 of the spec file -# c -> Cypress -# p -> Playwright - -# t1c = [2486, 2116, 2156, 2017, 2018, 2106, 2060, 1899, 2108, 2283] -# t2c = [2018, 2120, 2037, 2031, 2135, 2074, 2292, 2225, 2141, 2031] -# -# t1p = [1483, 1402, 1395, 1426, 1570, 2019, 1873, 1443, 1516, 1438] -# t2p = [1356, 1416, 1344, 1356, 1662, 1852, 1434, 1388, 1485, 1460] -# -# print(sum(t1c)/10) = 2124.9 -# print(sum(t2c)/10) = 2110.4 -# print(sum(t1p)/10) = 1556.5 -# print(sum(t2p)/10) = 1475.3 diff --git a/playwright.config.ts b/playwright.config.ts index bc154a17fd7..d90e887caf2 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -10,7 +10,7 @@ import { defineConfig, devices } from '@playwright/test'; * See https://playwright.dev/docs/test-configuration. */ export default defineConfig({ - testDir: './playwright-tests', + testDir: './test/playwright', /* Run tests in files in parallel */ fullyParallel: true, /* Fail the build on CI if you accidentally left test.only in the source code. */ diff --git a/scripts/run_e2e_tests.sh b/scripts/run_e2e_tests.sh index 25cc255ad5e..659f2c3be9b 100755 --- a/scripts/run_e2e_tests.sh +++ b/scripts/run_e2e_tests.sh @@ -85,9 +85,13 @@ echo "" wait_for_service PDF 127.0.0.1 3002 echo "" -echo "> Running cypress tests" - -npm run cypress:run -- ${CYPRESS_RECORD} --env OC_ENV=$OC_ENV --spec "test/cypress/integration/${CYPRESS_TEST_FILES}" +if [ "$USE_PLAYWRIGHT" = "true" ]; then + echo "> Running playwright tests" + npx playwright test test/playwright/e2e.test.js +else + echo "> Running cypress tests" + npm run cypress:run -- ${CYPRESS_RECORD} --env OC_ENV=$OC_ENV --spec "test/cypress/integration/${CYPRESS_TEST_FILES}" +fi RETURN_CODE=$? if [ $RETURN_CODE -ne 0 ]; then @@ -103,5 +107,6 @@ kill $API_PID kill $FRONTEND_PID kill $IMAGES_PID kill $PDF_PID + echo "Exiting with code $RETURN_CODE" exit $RETURN_CODE diff --git a/playwright-tests/16-tiers-page.spec.ts b/test/playwright/16-tiers-page.spec.ts similarity index 57% rename from playwright-tests/16-tiers-page.spec.ts rename to test/playwright/16-tiers-page.spec.ts index 71cc8085a1c..2bd4d53e254 100644 --- a/playwright-tests/16-tiers-page.spec.ts +++ b/test/playwright/16-tiers-page.spec.ts @@ -1,15 +1,15 @@ -import { test, expect } from '@playwright/test' +import { expect, test } from '@playwright/test'; -const baseUrl:String = 'http://localhost:3000' +const baseUrl: String = 'http://localhost:3000'; test('Can be accessed from "/collective/contribute" (default)', async ({ page }) => { - await page.goto(baseUrl+'/apex/contribute') - await expect(page).toHaveTitle('Contribute to APEX - Open Collective') - await expect(page.locator('link[rel="canonical"]')).toHaveAttribute('href',baseUrl+'/apex/contribute') -}) + await page.goto(`${baseUrl}/apex/contribute`); + await expect(page).toHaveTitle('Contribute to APEX - Open Collective'); + await expect(page.locator('link[rel="canonical"]')).toHaveAttribute('href', `${baseUrl}/apex/contribute`); +}); test('Can be accessed from "/collective/tiers"', async ({ page }) => { - await page.goto(baseUrl+'/apex/tiers') - await expect(page).toHaveTitle('Contribute to APEX - Open Collective') - await expect(page.locator('link[rel="canonical"]')).toHaveAttribute('href',baseUrl+'/apex/contribute') -}) + await page.goto(`${baseUrl}/apex/tiers`); + await expect(page).toHaveTitle('Contribute to APEX - Open Collective'); + await expect(page.locator('link[rel="canonical"]')).toHaveAttribute('href', `${baseUrl}/apex/contribute`); +});