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 @@
-
+
@@ -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"