Skip to content

Commit

Permalink
4245 - E2E Testing framework and test runner in Github Actions (#4246)
Browse files Browse the repository at this point in the history
* 4245 - dont start reporter server

* 4245 - run tests inside container

* 4245 - partial-backup: support excluding schemas and tables outside script, support custom name

* 4245 - workflow: test: partial db copy

* 4245 - workflow: test: cleanup

* 4245 - Dockerfile.playwright remove unnecessary ls

* 4245 - debug

* 4245 - use exact name

* 4245 - Disable whisper

* 4245 - Google authentication env var placeholder

* 4245 - token_secret env var placeholder

* 4245 - Remove unknown opt

* 4245 - Disable tmate

* 4245 - use latest cycle

* 4245 - Mount test results folder and upload artifact

* debug

* 4245 - Zipped results and one drive db

* 4245 - Backup from s3

* 4245 - Fix failing title test

* 4245 - Disable tmate

* 4245 - add db caching

* 4245 - Fix indentation

* Empty-Commit

* Empty-Commit

* 4245 - split CI workflows into build, test, and e2e

* 4245 - separate unit and integration test configs

* 4245 - run unit and integration tests parallel

* 4245 - remove deprecated workflow

* 4245 - fix typo

* 4245 - Cache and parallel

* 4245 - fix typo

* 4245 - Remove separate build wf

* 4245 - Fix typo

* 4245 - cache only db

* 4245 - run migrations

* 4245 - default false

* 4245 - boolean

* 4245 - remove jest prefix

* 4245 - e2e: run integration and unit tests

* 4245 - test: ignore only development

* 4245 - Rename workflows

---------

Co-authored-by: Heroku-Deploy <>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
sorja and mergify[bot] authored Jan 30, 2025
1 parent 1c0c69d commit 5881cfe
Show file tree
Hide file tree
Showing 14 changed files with 228 additions and 124 deletions.
96 changes: 96 additions & 0 deletions .github/workflows/test-all.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
name: Run test all (unit, integration and e2e)

on:
pull_request:
branches:
- 'development'
workflow_dispatch:
inputs:
force_refresh:
description: 'Force database refresh'
required: false
default: false
type: boolean

jobs:
tests:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_DEV }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_DEV }}
aws-region: eu-west-1

- name: Cache test database
id: cache-db
uses: actions/cache@v3
with:
path: ./db/backup
key: test-db-${{ runner.os }}-v1-${{ hashFiles('src/test/e2e/docker-compose.test.yml') }}
restore-keys: |
test-db-${{ runner.os }}-v1-
test-db-${{ runner.os }}-
- name: Download and decrypt test database
if: steps.cache-db.outputs.cache-hit != 'true' || ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.force_refresh == true }}
run: |
mkdir -p ./db
aws s3 cp s3://fra-platform-s3-developer-assets/test-assets/database/backup.gpg ./db/backup.gpg
./src/tools/heroku/decrypt.sh ./db/backup.gpg
env:
BACKUP_PASSPHRASE: ${{ secrets.BACKUP_PASSPHRASE }}

- name: Build and start containers
run: docker compose -f src/test/e2e/docker-compose.test.yml up -d
env:
NPM_GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}

- name: Wait for services to be ready
run: |
timeout 300 bash -c 'until docker compose -f src/test/e2e/docker-compose.test.yml ps web | grep -q "healthy"; do sleep 5; done'
- name: Create test results directory
run: mkdir -p playwright-report

- name: Run database migrations
run: docker compose -f src/test/e2e/docker-compose.test.yml exec -T web yarn migration-steps:run

- name: Run unit and integration tests
run: docker compose -f src/test/e2e/docker-compose.test.yml exec -T web yarn test
env:
NPM_GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}

- name: Run E2E tests
if: always()
run: |
docker compose -f src/test/e2e/docker-compose.test.yml run \
playwright npm run test:e2e
env:
NPM_GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}

- name: Zip test results
if: always()
run: |
cd src/test/e2e
zip -r ../../../playwright-results.zip test-results/
- name: Upload test results
if: always() && !env.ACT
uses: actions/upload-artifact@v4
with:
name: playwright-results
path: playwright-results.zip
retention-days: 30

- name: Stop containers
if: always()
run: docker compose -f src/test/e2e/docker-compose.test.yml down -v

- name: Cleanup database backup
if: always()
run: |
rm -rf ./db
71 changes: 71 additions & 0 deletions .github/workflows/test-unit-integration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
name: Run test partial (unit and integration)

on:
pull_request:
branches-ignore:
- 'development'
workflow_dispatch:
inputs:
force_refresh:
description: 'Force database refresh'
required: false
default: false
type: boolean

jobs:
tests:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_DEV }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_DEV }}
aws-region: eu-west-1

- name: Cache test database
id: cache-db
uses: actions/cache@v3
with:
path: ./db/backup
key: test-db-${{ runner.os }}-v1-${{ hashFiles('src/test/e2e/docker-compose.test.yml') }}
restore-keys: |
test-db-${{ runner.os }}-v1-
test-db-${{ runner.os }}-
- name: Download and decrypt test database
if: steps.cache-db.outputs.cache-hit != 'true' || ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.force_refresh == 'true' }}
run: |
mkdir -p ./db
aws s3 cp s3://fra-platform-s3-developer-assets/test-assets/database/backup.gpg ./db/backup.gpg
./src/tools/heroku/decrypt.sh ./db/backup.gpg
env:
BACKUP_PASSPHRASE: ${{ secrets.BACKUP_PASSPHRASE }}

- name: Build and start containers
run: docker compose -f src/test/e2e/docker-compose.test.yml up -d
env:
NPM_GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}

- name: Wait for services to be ready
run: |
timeout 300 bash -c 'until docker compose -f src/test/e2e/docker-compose.test.yml ps web | grep -q "healthy"; do sleep 5; done'
- name: Run database migrations
run: docker compose -f src/test/e2e/docker-compose.test.yml exec -T web yarn migration-steps:run

- name: Run unit and integration tests
run: docker compose -f src/test/e2e/docker-compose.test.yml exec -T web yarn test
env:
NPM_GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}

- name: Stop containers
if: always()
run: docker compose -f src/test/e2e/docker-compose.test.yml down -v

- name: Cleanup database backup
if: always()
run: |
rm -rf ./db
86 changes: 0 additions & 86 deletions .github/workflows/test.js.yml

This file was deleted.

2 changes: 0 additions & 2 deletions jest.config.js → jest.config.base.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,5 @@ module.exports = {
rootDir: 'src',
roots: ['<rootDir>'],
testEnvironment: 'node',
testMatch: ['**/*.test.ts'],
testPathIgnorePatterns: ['/node_modules/'],
verbose: true,
}
7 changes: 7 additions & 0 deletions jest.config.integration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const baseConfig = require('./jest.config.base')

module.exports = {
...baseConfig,
testMatch: ['**/integration.test.ts'],
}
8 changes: 8 additions & 0 deletions jest.config.unit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const baseConfig = require('./jest.config.base')

module.exports = {
...baseConfig,
testMatch: ['**/?(*.)+(test).ts'],
testPathIgnorePatterns: ['/node_modules/', '/dist/', '/src/test/integration/', '/src/test/e2e/'],
}
13 changes: 7 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,13 @@
"run:prod:server": "node dist/server/start",
"start": "run-s migration-public:run run:prod:server",
"//test": "mochapack --webpack-config webpack.config.babel.test.js",
"test": "run-s test:integration",
"test:integration": "yarn jest --no-cache --detectOpenHandles --setupFiles dotenv/config",
"test:e2e": "playwright test --config ./src/test/e2e/jest-playwright.config.ts",
"test:e2e:dev": "playwright test --config ./src/test/e2e/jest-playwright.config.local.ts --debug --headed --ui",
"test": "run-p test:unit test:integration",
"test:unit": "yarn jest --no-cache --detectOpenHandles --setupFiles dotenv/config --config jest.config.unit.js",
"test:integration": "yarn jest --no-cache --detectOpenHandles --setupFiles dotenv/config --config jest.config.integration.js src/test/integration/integration.test.ts",
"test:e2e": "playwright test --config ./src/test/e2e/playwright.config.ts",
"test:e2e:dev": "playwright test --config ./src/test/e2e/playwright.config.local.ts --debug --headed --ui",
"test:e2e:docker": "docker-compose -f src/test/e2e/docker-compose.test.yml up --build --exit-code-from playwright",
"test:watch": "yarn jest --no-cache --detectOpenHandles --watchAll --setupFiles dotenv/config",
"test:watch": "yarn jest --no-cache --detectOpenHandles --watchAll --setupFiles dotenv/config --config jest.config.unit.js",
"preversion": "git diff --quiet || { echo \"Working directory is dirty\"; exit 1; };",
"postversion": "git push --tags && echo \"Successfully released version $npm_package_version!\"",
"prepare": "husky install",
Expand Down Expand Up @@ -295,4 +296,4 @@
"prettier --write"
]
}
}
}
2 changes: 0 additions & 2 deletions src/test/e2e/Dockerfile.playwright
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ RUN yarn playwright install --with-deps chromium

COPY . .

RUN ls -la src/test/e2e

EXPOSE 9323

CMD ["yarn", "test:e2e"]
4 changes: 4 additions & 0 deletions src/test/e2e/docker-compose.test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ services:
- REDIS_QUEUE_URL=redis://redis-queue:6379
- REDIS_DATA_URL=redis://redis-data:6379
- PORT=9001
- WWWHISPER_DISABLE=true
- FRA_GOOGLE_CLIENT_ID=google-client-id
- FRA_GOOGLE_CLIENT_SECRET=goggle-client-secret
- TOKEN_SECRET=1234567890
ports:
- '9001:9001'
healthcheck:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { PlaywrightTestConfig } from '@playwright/test'

import baseConfig from './jest-playwright.config'
import baseConfig from './playwright.config'

const config: PlaywrightTestConfig = {
...baseConfig,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,7 @@ const config: PlaywrightTestConfig = {
},
],

reporter: [
['list'],
[
'html',
{
outputFolder: 'test-results',
port: 9323,
host: '0.0.0.0',
open: 'always', // Remove this or change to 'on-failure'
},
],
],
reporter: [['list'], ['html', { outputFolder: 'test-results', open: 'never' }]],
}

export default config
4 changes: 2 additions & 2 deletions src/test/e2e/tests/01-example.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { expect, test } from '@playwright/test'

test('homepage has title and links to intro page', async ({ page }) => {
await page.goto('/')

await expect(page).toHaveTitle(/FRA platform/, { timeout: 10000 })
const title = /FRA Platform | Global Forest Resources Data | Food and Agriculture Organization of the United Nations/
await expect(page).toHaveTitle(title, { timeout: 10000 })
const headerLogo = await page.getByRole('img', { name: 'FAO' })
await expect(headerLogo).toBeVisible()
const headerTitle = await page.getByText('Global Forest Resources Assessment').first()
Expand Down
6 changes: 3 additions & 3 deletions src/test/e2e/tests/03-login.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { expect, test } from '@playwright/test'

test.describe('Login', () => {
test('should login with test user credentials', async ({ page }) => {
await page.goto('/assessments/fra/2025/login')
await page.goto('/assessments/fra/latest/login')

await page.click('button:has-text("Sign in with FRA")')

Expand All @@ -11,13 +11,13 @@ test.describe('Login', () => {

await page.click('button.btn:has-text("Login")')

await expect(page).toHaveURL('/assessments/fra/2025')
await expect(page).toHaveURL('/assessments/fra/latest')

await expect(page.getByText('Test User')).toBeVisible()
})

test('should show error with invalid credentials', async ({ page }) => {
await page.goto('/assessments/fra/2025/login')
await page.goto('/assessments/fra/latest/login')

await page.click('button:has-text("Sign in with FRA")')

Expand Down
Loading

0 comments on commit 5881cfe

Please sign in to comment.