diff --git a/.github/workflows/build-nextjs.yml b/.github/workflows/build-nextjs.yml index 5001ffce7..ea9912da2 100644 --- a/.github/workflows/build-nextjs.yml +++ b/.github/workflows/build-nextjs.yml @@ -12,18 +12,21 @@ jobs: steps: - uses: actions/checkout@v2 - - uses: actions/cache@v2 - id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "::set-output name=dir::$(yarn cache dir)" + + - uses: actions/cache@v3 with: path: | - node_modules - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + ${{ steps.yarn-cache-dir-path.outputs.dir }} + **/.next/cache + key: ${{ runner.os }}-build-yarn-${{ hashFiles('**/yarn.lock') }} restore-keys: | - ${{ runner.os }}-yarn- + ${{ runner.os }}-build-yarn- - name: Install dependencies run: yarn - if: steps.yarn-cache.outputs.cache-hit != 'true' - name: Build frontend run: | diff --git a/.github/workflows/check-pr.yml b/.github/workflows/check-pr.yml index d66b67c64..cd10fa0c9 100644 --- a/.github/workflows/check-pr.yml +++ b/.github/workflows/check-pr.yml @@ -80,3 +80,7 @@ jobs: service_account_credentials: ${{ secrets.MONDOO_SECRET }} scan_type: k8s path: prod-manifests.yaml + + run-playwright: + name: Run Playwright + uses: ./.github/workflows/playwright.yml \ No newline at end of file diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml new file mode 100644 index 000000000..07768bcd2 --- /dev/null +++ b/.github/workflows/playwright.yml @@ -0,0 +1,75 @@ +name: Playwright tests +on: + workflow_call: + +jobs: + run-playwright: + name: Run Playwright + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + path: './frontend' + + - name: Checkout + uses: actions/checkout@v3 + with: + repository: podkrepi-bg/api + ref: master + path: './api' + + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "::set-output name=dir::$(yarn cache dir)" + + - uses: actions/cache@v3 + with: + path: | + ${{ steps.yarn-cache-dir-path.outputs.dir }} + **/.next/cache + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - name: Run db + working-directory: ./api + run: docker compose up -d pg-db + + - name: Run api + working-directory: ./api + run: docker compose up -d --force-recreate --no-build migrate-db seed-db api keycloak + + - uses: actions/setup-node@v2 + with: + node-version: '14.x' + + - name: Install dependencies + working-directory: ./frontend + run: yarn + + - name: Build frontend + working-directory: ./frontend + run: yarn run next build + + - name: Setup env + working-directory: ./frontend + run: cp .env.local.example .env.local + + - name: Start frontend + working-directory: ./frontend + run: yarn start & + + - name: Install Playwright Browsers + working-directory: ./frontend + run: npx playwright install --with-deps + + - name: Run Playwright tests + working-directory: ./frontend + run: yarn playwright test e2e/local + + - uses: actions/upload-artifact@v2 + if: always() + with: + name: playwright-report + path: ./frontend/playwright-report/ + retention-days: 30 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 989344810..469c36f1e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -113,10 +113,14 @@ jobs: scan_type: k8s path: prod-manifests.yaml + run-playwright: + name: Run Playwright + uses: ./.github/workflows/playwright.yml + release-dev: name: Release to dev runs-on: ubuntu-latest - needs: [build-frontend-image, build-maintenance-image, scan-manifests] + needs: [build-frontend-image, build-maintenance-image, scan-manifests, run-playwright] environment: name: dev url: https://dev.podkrepi.bg diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cb2b4c1c7..87fbdd872 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,11 +22,15 @@ jobs: with: node-version: ${{ matrix.node-version }} - - uses: actions/cache@v2 - id: yarn-cache + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "::set-output name=dir::$(yarn cache dir)" + + - uses: actions/cache@v3 with: path: | - node_modules + ${{ steps.yarn-cache-dir-path.outputs.dir }} + **/.next/cache key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} restore-keys: | ${{ runner.os }}-yarn- diff --git a/.gitignore b/.gitignore index bac89f28c..ee3999fcd 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,6 @@ build/ bld/ [Bb]in/ [Oo]bj/ +/test-results/ +/playwright-report/ +/playwright/.cache/ diff --git a/README.md b/README.md index cd52fc3be..d715591f5 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@

Lint Build Build docker image

- +

@@ -25,6 +25,8 @@ - [Formik](https://formik.org/) / [MobX](https://mobx.js.org/) - [ESlint](https://eslint.org/) / [Prettier](https://prettier.io/) / [Husky](https://github.com/typicode/husky) / [Stylelint](https://stylelint.io/) / [Lint Staged](https://github.com/okonet/lint-staged) - [Sentry](https://sentry.io/organizations/podkrepibg/) +- Testing + - [Playwright](https://playwright.dev/) ## Initial setup @@ -59,6 +61,12 @@ In order to use the frontend together with the API and be able to test donations Follow the instructions at +## Testing + +End to end testing is done on every PR with [Playwright](https://playwright.dev/). Github Workflows start the whole stack and run tests in headless mode. + +Read more at [End-2-End Testing](https://github.com/podkrepi-bg/frontend/blob/master/e2e/README.md) + ## Contributors ✨ diff --git a/e2e/README.md b/e2e/README.md new file mode 100644 index 000000000..444b53d23 --- /dev/null +++ b/e2e/README.md @@ -0,0 +1,58 @@ +# End-to-end testing + +## Playwright + +- + +## Running tests + +E2e tests are automated and running on every PR in Github Actions. [Link to the workflow](https://github.com/podkrepi-bg/frontend/blob/29b49f438541fa9254829a494e388202034b274d/.github/workflows/playwright.yml) + +```shell +$ yarn test:e2e --help + +Run tests with Playwright Test + +Options: +--browser Browser to use for tests, one of "all", "chromium", "firefox" or "webkit" (default: "chromium") +--headed Run tests in headed browsers (default: headless) +--debug Run tests with Playwright Inspector. Shortcut for "PWDEBUG=1" environment variable and "--timeout=0 --maxFailures=1 --headed --workers=1" options +-c, --config Configuration file, or a test directory with optional "playwright.config.ts"/"playwright.config.js"/"playwright.config.mjs" +--forbid-only Fail if test.only is called (default: false) +--fully-parallel Run all tests in parallel (default: false) +-g, --grep Only run tests matching this regular expression (default: ".*") +-gv, --grep-invert Only run tests that do not match this regular expression +--global-timeout Maximum time this test suite can run in milliseconds (default: unlimited) +-j, --workers Number of concurrent workers, use 1 to run in a single worker (default: number of CPU cores / 2) +--list Collect all the tests and report them, but do not run +--max-failures Stop after the first N failures +--output Folder for output artifacts (default: "test-results") +--quiet Suppress stdio +--repeat-each Run each test N times (default: 1) +--reporter Reporter to use, comma-separated, can be "list", "line", "dot", "json", "junit", "null", "github", "html" (default: "list") +--retries Maximum retry count for flaky tests, zero for no retries (default: no retries) +--shard Shard tests and execute only the selected shard, specify in the form "current/all", 1-based, for example "3/5" +--project Only run tests from the specified list of projects (default: run all projects) +--timeout Specify test timeout threshold in milliseconds, zero for unlimited (default: 30000) +-u, --update-snapshots Update snapshots with actual results (default: only create missing snapshots) +-x Stop after the first failure +-h, --help display help for command +``` + +### Run all test suites + +```shell +yarn test:e2e +``` + +### Run only local test suites + +```shell +yarn test:e2e local +``` + +### Run local test suites in headed mode with enabled debug + +```shell +yarn test:e2e local --headed --debug -x -g support +``` diff --git a/e2e/local/homepage.spec.ts b/e2e/local/homepage.spec.ts new file mode 100644 index 000000000..08bd673b7 --- /dev/null +++ b/e2e/local/homepage.spec.ts @@ -0,0 +1,80 @@ +import { test, expect } from '@playwright/test' + +test.beforeEach(async ({ page }) => { + await page.goto('http://localhost:3040/') +}) + +test('test homepage', async ({ page }) => { + // Click text=Това е бета версията на платформата на Подкрепи.бг преди предстоящия наесен офиц + await expect( + page.locator( + 'text=Това е бета версията на платформата на Подкрепи.бг преди предстоящия наесен офиц', + ), + ).toBeDefined() + + // Click text=Затвори + await page.locator('text=Затвори').click() + + // Click text=Текущи кампании + await page.locator('text=Текущи кампании').click() + + // Click text=Как работи Подкрепи.бг? + await page.locator('text=Как работи Подкрепи.бг?').click() + + // Click text=Кой стои зад Подкрепи.бг? + await page.locator('text=Кой стои зад Подкрепи.бг?').click() + + // Click text=Какво ни обединява? + await page.locator('text=Какво ни обединява?').click() + + // Click text=Искам да помогна на Подкрепи.бг + await page.locator('text=Искам да помогна на Подкрепи.бг').click() + + // Click h2:has-text("Често задавани въпроси") + await page.locator('h2:has-text("Често задавани въпроси")').click() + + // Click text=Какво представлява Подкрепи.бг?Подкрепи.бг е платформа за среща между хора, коит >> [data-testid="ExpandMoreIcon"] + await page + .locator( + 'text=Какво представлява Подкрепи.бг?Подкрепи.бг е платформа за среща между хора, коит >> [data-testid="ExpandMoreIcon"]', + ) + .click() + + // Click text=Подкрепи.бг е платформа за среща между хора, които искат да съберат средства за + await page + .locator( + 'text=Подкрепи.бг е платформа за среща между хора, които искат да съберат средства за ', + ) + .click() + + // Click text=Защо направихте нова платформа, когато вече има и други? + await page.locator('text=Защо направихте нова платформа, когато вече има и други?').click() + + // Click text=Накратко - целта ни е да увеличим доверието на обществото в дарителските организ + await page + .locator( + 'text=Накратко - целта ни е да увеличим доверието на обществото в дарителските организ', + ) + .click() + + // Click text=Как гарантирате прозрачност и какво значи “софтуер с отворен код”? + await page + .locator('text=Как гарантирате прозрачност и какво значи “софтуер с отворен код”?') + .click() + + // Click text=Софтуер с отворен код е установена практика, при която всеки, без ограничение, м + await page + .locator( + 'text=Софтуер с отворен код е установена практика, при която всеки, без ограничение, м', + ) + .click() + + // Click text=Виж всички >> nth=1 + await page.locator('text=Виж всички').nth(1).click() + await expect(page).toHaveURL('http://localhost:3040/faq') + + // Click text=Моделът ни на работа се основава на Принципите, които ни обединяват + await page + .locator('text=Моделът ни на работа се основава на Принципите, които ни обединяват') + .click() +}) diff --git a/e2e/local/support.spec.ts b/e2e/local/support.spec.ts new file mode 100644 index 000000000..09f8aeecf --- /dev/null +++ b/e2e/local/support.spec.ts @@ -0,0 +1,144 @@ +import { expect, test } from '@playwright/test' + +test.beforeEach(async ({ page }) => { + await page.goto('http://localhost:3040/') +}) + +test('test support page', async ({ page }) => { + // Click text=Това е бета версията на платформата на Подкрепи.бг преди предстоящия наесен офиц + await expect( + page.locator( + 'text=Това е бета версията на платформата на Подкрепи.бг преди предстоящия наесен офиц', + ), + ).toBeDefined() + + // Click text=Затвори + await page.locator('text=Затвори').click() + + // Click text=Станете доброволец >> nth=0 + await page.locator('text=Станете доброволец').first().click() + + // Go to http://localhost:3040/support + await page.goto('http://localhost:3040/support') + + // Click h1:has-text("Станете доброволец") + await page.locator('h1:has-text("Станете доброволец")').click() + + // Click text=Как искате да ни подкрепите? + await page.locator('text=Как искате да ни подкрепите?').click() + + // Click text=Включете се в организацията като: + await page.locator('text=Включете се в организацията като:').click() + + // Check input[name="roles\.benefactor"] + await page.locator('input[name="roles\\.benefactor"]').check() + + // Check input[name="roles\.associationMember"] + await page.locator('input[name="roles\\.associationMember"]').check() + + // Click text=Напред + await page.locator('text=Напред').click() + + // Click text=В каква роля искате да ни подкрепите? + await page.locator('text=В каква роля искате да ни подкрепите?').click() + + // Click text=Назад + await page.locator('text=Назад').click() + + // Click text=Как искате да ни подкрепите? + await page.locator('text=Как искате да ни подкрепите?').click() + + // Click text=Напред + await page.locator('text=Напред').click() + + // Check input[name="benefactor\.campaignBenefactor"] + await page.locator('input[name="benefactor\\.campaignBenefactor"]').check() + + // Click text=Дарител в бъдещи кампании + await page.locator('text=Дарител в бъдещи кампании').click() + + // Click text=Моля, изберете си роля + await page.locator('text=Моля, изберете си роля').click() + + // Click text=Дарител в бъдещи кампании + await page.locator('text=Дарител в бъдещи кампании').click() + + // Click text=Напред + await page.locator('text=Напред').click() + + // Click text=Изпратете + await page.locator('text=Изпратете').click() + + // Click text=Изпратете + await page.locator('text=Изпратете').click() + + // Click #mui-3-helper-text + await page.locator('#mui-1-helper-text').click() + + // Click #mui-4-helper-text + await page.locator('#mui-2-helper-text').click() + + // Click #mui-3-helper-text + await page.locator('#mui-3-helper-text').click() + + // Click #mui-4-helper-text + await page.locator('#mui-4-helper-text').click() + + // Click text=Моля, приемете oбщите условия + await page.locator('text=Моля, приемете oбщите условия').click() + + // Click text=Моля, приемете политиката за защита на личните данни + await page.locator('text=Моля, приемете политиката за защита на личните данни').click() + + // Click input[name="person\.firstName"] + await page.locator('input[name="person\\.firstName"]').click() + + // Fill input[name="person\.firstName"] + await page.locator('input[name="person\\.firstName"]').fill('test') + + // Click input[name="person\.lastName"] + await page.locator('input[name="person\\.lastName"]').click() + + // Fill input[name="person\.lastName"] + await page.locator('input[name="person\\.lastName"]').fill('test') + + // Click input[name="person\.email"] + await page.locator('input[name="person\\.email"]').click() + + // Fill input[name="person\.email"] + await page.locator('input[name="person\\.email"]').fill('test@test.com') + + // Click input[name="person\.phone"] + await page.locator('input[name="person\\.phone"]').click() + + // Fill input[name="person\.phone"] + await page.locator('input[name="person\\.phone"]').fill('0987654321') + + // Click textarea[name="person\.comment"] + await page.locator('textarea[name="person\\.comment"]').click() + + // Fill textarea[name="person\.comment"] + await page.locator('textarea[name="person\\.comment"]').fill('test test test') + + // Check input[name="person\.terms"] + await page.locator('input[name="person\\.terms"]').check() + + // Check input[name="person\.gdpr"] + await page.locator('input[name="person\\.gdpr"]').check() + + // Check input[name="person\.newsletter"] + await page.locator('input[name="person\\.newsletter"]').check() + + // Click text=Изпратете + await page.locator('text=Изпратете').click() + + // Click text=Благодарим Ви, че ни подкрепихте! + await page.locator('text=Благодарим Ви, че ни подкрепихте!').click() + + // Click text=Очаквайте представител на Подкрепи.бг да се свърже с Вас на посочения имейл адре + await page + .locator( + 'text=Очаквайте представител на Подкрепи.бг да се свърже с Вас на посочения имейл адре', + ) + .click() +}) diff --git a/e2e/staging/anon-donation-custom.spec.ts b/e2e/staging/anon-donation-custom.spec.ts new file mode 100644 index 000000000..ad03f3751 --- /dev/null +++ b/e2e/staging/anon-donation-custom.spec.ts @@ -0,0 +1,106 @@ +import { test, expect } from '@playwright/test' + +test('test anonymous donation on staging - custom amount', async ({ page }) => { + // Go to https://dev.podkrepi.bg/ + await page.goto('https://dev.podkrepi.bg/') + + // Click text=Училище за деца с нарушено зрение гр. Варна - стая за ерготерапия + await page + .locator('text=Училище за деца с нарушено зрение гр. Варна - стая за ерготерапия') + .click() + await expect(page).toHaveURL( + 'https://dev.podkrepi.bg/campaigns/uchilishe-za-deca-s-narusheno-zrenie-gr-varna-staya-za-ergoterapiya', + ) + + // Click button:has-text("Подкрепи") + await page.locator('button:has-text("Подкрепи")').click() + + await expect(page).toHaveURL( + 'https://dev.podkrepi.bg/campaigns/donation/uchilishe-za-deca-s-narusheno-zrenie-gr-varna-staya-za-ergoterapiya', + ) + + // Click label:has-text("Друга сума") + await page.locator('label:has-text("Друга сума")').click() + + // Click input[name="otherAmount"] + await page.locator('input[name="otherAmount"]').click() + + // Fill input[name="otherAmount"] + await page.locator('input[name="otherAmount"]').fill('7.50') + + // Check input[name="cardIncludeFees"] + await page.locator('input[name="cardIncludeFees"]').check() + + // Click text=8,11 лв. + await page.locator('text=8,11 лв.').click() + + // Click text=0,61 лв. + await page.locator('text=0,61 лв.').click() + + // Click text=7,50 лв. + await page.locator('text=7,50 лв.').click() + + // Click text=Напред + await page.locator('text=Напред').click() + + // Click text=Дарете анонимно + await page.locator('text=Дарете анонимно').click() + + // Click input[name="personsEmail"] + await page.locator('input[name="personsEmail"]').click() + + // Fill input[name="personsEmail"] + await page.locator('input[name="personsEmail"]').fill('test@example.com') + + // Click text=Напред + await page.locator('text=Напред').click() + + // Click textarea[name="message"] + await page.locator('textarea[name="message"]').click() + + // Fill textarea[name="message"] + await page.locator('textarea[name="message"]').fill('e2e tester 2') + + // Click text=Премини към плащане + await page.locator('text=Премини към плащане').click() + + await page.waitForURL((url) => + url.toString().startsWith('https://checkout.stripe.com/pay/cs_test_'), + ) + + await expect(page.url()).toContain('https://checkout.stripe.com/pay/cs_test_') + + // Click [placeholder="\31 234 1234 1234 1234"] + await page.locator('[placeholder="\\31 234 1234 1234 1234"]').click() + + // Fill [placeholder="\31 234 1234 1234 1234"] + await page.locator('[placeholder="\\31 234 1234 1234 1234"]').fill('4242 4242 4242 4242') + + // Click [placeholder="MM \/ YY"] + await page.locator('[placeholder="MM \\/ YY"]').click() + + // Fill [placeholder="MM \/ YY"] + await page.locator('[placeholder="MM \\/ YY"]').fill('04 / 242') + + // Click [placeholder="CVC"] + await page.locator('[placeholder="CVC"]').click() + + // Fill [placeholder="CVC"] + await page.locator('[placeholder="CVC"]').fill('424') + + // Click input[name="billingName"] + await page.locator('input[name="billingName"]').click() + + // Fill input[name="billingName"] + await page.locator('input[name="billingName"]').fill('tester') + + // Click [data-testid="hosted-payment-submit-button"] + await page.locator('[data-testid="hosted-payment-submit-button"]').click() + + await page.waitForURL( + 'https://dev.podkrepi.bg/campaigns/donation/uchilishe-za-deca-s-narusheno-zrenie-gr-varna-staya-za-ergoterapiya?success=true', + ) + + // Click text=Благодарим за доверието и подкрепата! + await page.locator('text=Благодарим за доверието и подкрепата!').click() +}) diff --git a/e2e/staging/anon-donation-fixed.spec.ts b/e2e/staging/anon-donation-fixed.spec.ts new file mode 100644 index 000000000..32d9d4366 --- /dev/null +++ b/e2e/staging/anon-donation-fixed.spec.ts @@ -0,0 +1,95 @@ +import { test, expect } from '@playwright/test' + +test('test anonymous donation on staging - fixed amount', async ({ page }) => { + // Go to https://dev.podkrepi.bg/ + await page.goto('https://dev.podkrepi.bg/') + + // Click text=Затвори + await page.locator('text=Затвори').click() + + // Click text=Дарете сега >> nth=0 + await page.locator('text=Дарете сега').first().click() + await expect(page).toHaveURL( + 'https://dev.podkrepi.bg/campaigns/donation/krizisen-centur-za-postradali-ot-nasilie-shans-za-nov-zhivot', + ) + + // Click label:has-text("10 лв.") + await page.locator('label:has-text("10 лв.")').click() + + // Click text=Искам да покрия таксите за плащане с карта издадена в: + await page.locator('text=Искам да покрия таксите за плащане с карта издадена в:').click() + + // Click text=10,65 лв. + await page.locator('text=10,65 лв.').click() + + // Click text=0,65 лв. >> nth=1 + await page.locator('text=0,65 лв.').nth(1).click() + + // Click text=10,00 лв. + await page.locator('text=10,00 лв.').click() + + // Click text=Напред + await page.locator('text=Напред').click() + + // Click text=Дарете анонимно + await page.locator('text=Дарете анонимно').click() + + // Click input[name="personsEmail"] + await page.locator('input[name="personsEmail"]').click() + + // Fill input[name="personsEmail"] + await page.locator('input[name="personsEmail"]').fill('test@example.com') + + // Click text=Напред + await page.locator('text=Напред').click() + + // Click textarea[name="message"] + await page.locator('textarea[name="message"]').click() + + // Fill textarea[name="message"] + await page.locator('textarea[name="message"]').fill('e2e test') + + // Click text=Премини към плащане + await page.locator('text=Премини към плащане').click() + + await page.waitForURL((url) => + url.toString().startsWith('https://checkout.stripe.com/pay/cs_test_'), + ) + + await expect(page.url()).toContain('https://checkout.stripe.com/pay/cs_test_') + + // Click [placeholder="\31 234 1234 1234 1234"] + await page.locator('[placeholder="\\31 234 1234 1234 1234"]').click() + + // Fill [placeholder="\31 234 1234 1234 1234"] + await page.locator('[placeholder="\\31 234 1234 1234 1234"]').fill('4242 4242 4242 4242') + + // Click [placeholder="MM \/ YY"] + await page.locator('[placeholder="MM \\/ YY"]').click() + + // Fill [placeholder="MM \/ YY"] + await page.locator('[placeholder="MM \\/ YY"]').fill('04 / 242') + + // Click [placeholder="CVC"] + await page.locator('[placeholder="CVC"]').click() + + // Fill [placeholder="CVC"] + await page.locator('[placeholder="CVC"]').fill('4242') + + // Click [data-testid="hosted-payment-submit-button"] + await page.locator('[data-testid="hosted-payment-submit-button"]').click() + + // Fill input[name="billingName"] + await page.locator('input[name="billingName"]').fill('e2e tester') + + // Click [data-testid="hosted-payment-submit-button"] + await page.locator('[data-testid="hosted-payment-submit-button"]').click() + + // Go to https://dev.podkrepi.bg/campaigns/donation/krizisen-centur-za-postradali-ot-nasilie-shans-za-nov-zhivot?success=true + await page.goto( + 'https://dev.podkrepi.bg/campaigns/donation/krizisen-centur-za-postradali-ot-nasilie-shans-za-nov-zhivot?success=true', + ) + + // Click text=Благодарим за доверието и подкрепата! + await expect(page.locator('text=Благодарим за доверието и подкрепата!')).toBeDefined() +}) diff --git a/e2e/staging/homepage.spec.ts b/e2e/staging/homepage.spec.ts new file mode 100644 index 000000000..f1865ae35 --- /dev/null +++ b/e2e/staging/homepage.spec.ts @@ -0,0 +1,85 @@ +import { test, expect } from '@playwright/test' + +test.beforeEach(async ({ page }) => { + await page.goto('https://dev.podkrepi.bg/') +}) + +test('test homepage on staging', async ({ page }) => { + // Go to http://dev.podkrepi.bg/ + + // Click text=Текущи кампании + await page.locator('text=Текущи кампании').click() + + // Click text=Това е бета версията на платформата на Подкрепи.бг преди предстоящия наесен офиц + await page + .locator( + 'text=Това е бета версията на платформата на Подкрепи.бг преди предстоящия наесен офиц', + ) + .click() + + // Check input[type="checkbox"] + await page.locator('input[type="checkbox"]').check() + + // Click text=Затвори + await page.locator('text=Затвори').click() + + // Click text=Как работи Подкрепи.бг? + await page.locator('text=Как работи Подкрепи.бг?').click() + + // Click text=Кой стои зад Подкрепи.бг? + await page.locator('text=Кой стои зад Подкрепи.бг?').click() + + // Click text=Какво ни обединява? + await page.locator('text=Какво ни обединява?').click() + + // Click text=Искам да помогна на Подкрепи.бг + await page.locator('text=Искам да помогна на Подкрепи.бг').click() + + // Click h2:has-text("Често задавани въпроси") + await page.locator('h2:has-text("Често задавани въпроси")').click() + + // Click text=Какво представлява Подкрепи.бг?Подкрепи.бг е платформа за среща между хора, коит >> [data-testid="ExpandMoreIcon"] + await page + .locator( + 'text=Какво представлява Подкрепи.бг?Подкрепи.бг е платформа за среща между хора, коит >> [data-testid="ExpandMoreIcon"]', + ) + .click() + + // Click text=Подкрепи.бг е платформа за среща между хора, които искат да съберат средства за + await page + .locator( + 'text=Подкрепи.бг е платформа за среща между хора, които искат да съберат средства за ', + ) + .click() + + // Click text=Защо направихте нова платформа, когато вече има и други? + await page.locator('text=Защо направихте нова платформа, когато вече има и други?').click() + + // Click text=Накратко - целта ни е да увеличим доверието на обществото в дарителските организ + await page + .locator( + 'text=Накратко - целта ни е да увеличим доверието на обществото в дарителските организ', + ) + .click() + + // Click text=Как гарантирате прозрачност и какво значи “софтуер с отворен код”? + await page + .locator('text=Как гарантирате прозрачност и какво значи “софтуер с отворен код”?') + .click() + + // Click text=Софтуер с отворен код е установена практика, при която всеки, без ограничение, м + await page + .locator( + 'text=Софтуер с отворен код е установена практика, при която всеки, без ограничение, м', + ) + .click() + + // Click text=Виж всички >> nth=1 + await page.locator('text=Виж всички').nth(1).click() + await expect(page).toHaveURL('https://dev.podkrepi.bg/faq') + + // Click text=Моделът ни на работа се основава на Принципите, които ни обединяват + await page + .locator('text=Моделът ни на работа се основава на Принципите, които ни обединяват') + .click() +}) diff --git a/jest.config.js b/jest.config.js index 361345318..5d707f141 100644 --- a/jest.config.js +++ b/jest.config.js @@ -14,6 +14,7 @@ const customJestConfig = { // if using TypeScript with a baseUrl set to the root directory then you need the below for alias' to work moduleDirectories: ['node_modules', '/src/'], testEnvironment: 'jest-environment-jsdom', + testPathIgnorePatterns: ['node_modules', '/e2e/'], } // createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async diff --git a/package.json b/package.json index 33e78f5d9..e1540661f 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "build": "yarn format && next build", "start": "next start -p 3040", "test": "jest --env=jsdom", + "test:e2e": "playwright test", "test:debug": "node --inspect-brk ./node_modules/jest/bin/jest.js --runInBand", "test:watch": "jest --env=jsdom --watch --silent=false", "lint": "eslint . --fix --ext=ts,tsx", @@ -78,6 +79,7 @@ "yup": "0.32.9" }, "devDependencies": { + "@playwright/test": "^1.24.2", "@testing-library/jest-dom": "^5.16.1", "@testing-library/react": "^12.1.2", "@types/cookie": "^0.4.1", diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 000000000..7f7362acd --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,107 @@ +import type { PlaywrightTestConfig } from '@playwright/test' +import { devices } from '@playwright/test' + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// require('dotenv').config(); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +const config: PlaywrightTestConfig = { + testDir: './e2e', + /* Maximum time one test can run for. */ + timeout: 30 * 1000, + expect: { + /** + * Maximum time expect() should wait for the condition to be met. + * For example in `await expect(locator).toHaveText();` + */ + timeout: 5000, + }, + /* 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: { + /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */ + actionTimeout: 0, + /* Base URL to use in actions like `await page.goto('/')`. */ + // baseURL: '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 Chrome', + // use: { + // ...devices['Pixel 5'], + // }, + // }, + // { + // name: 'Mobile Safari', + // use: { + // ...devices['iPhone 12'], + // }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { + // channel: 'msedge', + // }, + // }, + // { + // name: 'Google Chrome', + // use: { + // channel: 'chrome', + // }, + // }, + ], + + /* Folder for test artifacts such as screenshots, videos, traces, etc. */ + // outputDir: 'test-results/', + + /* Run your local dev server before starting the tests */ + // webServer: { + // command: 'npm run start', + // port: 3000, + // }, +} + +export default config diff --git a/yarn.lock b/yarn.lock index bd4b412aa..95d811c63 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1185,6 +1185,14 @@ resolved "https://registry.yarnpkg.com/@panva/hkdf/-/hkdf-1.0.2.tgz#bab0f09d09de9fd83628220d496627681bc440d6" integrity sha512-MSAs9t3Go7GUkMhpKC44T58DJ5KGk2vBo+h1cqQeqlMfdGkxaVB78ZWpv9gYi/g2fa4sopag9gJsNvS8XGgWJA== +"@playwright/test@^1.24.2": + version "1.24.2" + resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.24.2.tgz#283ea8cc497f9742037458659bf235f4776cf1f0" + integrity sha512-Q4X224pRHw4Dtkk5PoNJplZCokLNvVbXD9wDQEMrHcEuvWpJWEQDeJ9gEwkZ3iCWSFSWBshIX177B231XW4wOQ== + dependencies: + "@types/node" "*" + playwright-core "1.24.2" + "@polka/url@^1.0.0-next.20": version "1.0.0-next.21" resolved "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz" @@ -6284,6 +6292,11 @@ pkg-up@^2.0.0: dependencies: find-up "^2.1.0" +playwright-core@1.24.2: + version "1.24.2" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.24.2.tgz#47bc5adf3dcfcc297a5a7a332449c9009987db26" + integrity sha512-zfAoDoPY/0sDLsgSgLZwWmSCevIg1ym7CppBwllguVBNiHeixZkc1AdMuYUPZC6AdEYc4CxWEyLMBTw2YcmRrA== + please-upgrade-node@^3.2.0: version "3.2.0" resolved "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz"