Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 11 additions & 55 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,7 @@ jobs:
# ==========================================================================

test-e2e:
name: E2E Tests (Shard ${{ matrix.shard }})
name: E2E Tests (Endform)
timeout-minutes: 60
runs-on: ubuntu-latest
needs:
Expand All @@ -555,12 +555,9 @@ jobs:
packages: read
checks: write
pull-requests: write
id-token: write
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
strategy:
fail-fast: false
matrix:
shard: [1, 2, 3, 4]
services:
db:
image: pgvector/pgvector:pg14
Expand Down Expand Up @@ -609,7 +606,7 @@ jobs:
with:
node-version: "24"
cache: "yarn"
cache-dependency-path: "e2e-tests/yarn.lock"
cache-dependency-path: "yarn.lock"

- name: Log in to GitHub Container Registry
if: needs.build-backend.outputs.is_fork != 'true'
Expand Down Expand Up @@ -747,11 +744,6 @@ jobs:
run: |
cd e2e-tests
yarn install
# System Chrome handles browsing, but retry videos need Playwright's ffmpeg.
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=0 yarn playwright install ffmpeg

- name: Verify Google Chrome
run: google-chrome --version

- name: Wait for services
env:
Expand All @@ -778,11 +770,14 @@ jobs:
echo "=== Container status ==="
docker ps -a

- name: Run E2E tests (shard ${{ matrix.shard }})
- name: Run E2E tests with Endform
env:
PUBLIC_BACKEND_URL: http://localhost:8000
PUBLIC_WEB_FRONTEND_URL: http://localhost:3000
BASE_URL: http://localhost:3000
PRIVATE_BACKEND_URL: http://backend:8000
ENDFORM_GIT_BRANCH: ${{ github.head_ref || github.ref_name }}
ENDFORM_GIT_COMMIT_SHA: ${{ env.REAL_GITHUB_SHA }}
# The CI web-frontend runs with the default (empty) cookie prefix, so
# tests that read/set cookies (e.g. the user_source_token) must use the
# same empty prefix rather than playwright.config's baserow_e2e_ default.
Expand All @@ -799,15 +794,15 @@ jobs:
E2E_BUTTON_RATE_LIMIT: "3"
CI: 1
run: |
cd e2e-tests
npx playwright test --timeout=30000 --grep-invert=@slow --shard=${{ matrix.shard }}/4 --project=chrome
npx endform@latest --version
npx endform@latest test --config=playwright.endform.config.ts --organization-id 2G1ZCj7X --timeout=30000 --grep-invert=@slow --project=chrome

- name: Upload E2E test results
uses: actions/upload-artifact@v4
if: always()
with:
name: e2e-test-results-shard-${{ matrix.shard }}
path: e2e-tests/blob-report/
name: e2e-test-report-endform
path: playwright-report/
retention-days: 7
include-hidden-files: true

Expand All @@ -829,43 +824,6 @@ jobs:
docker stop backend web-frontend celery || true
docker rm backend web-frontend celery || true

collect-e2e-reports:
name: Collect E2E Test Reports
runs-on: ubuntu-latest
needs: [test-e2e]
permissions:
contents: read
checks: read
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "24"

- name: Download all E2E test results
uses: actions/download-artifact@v4
with:
pattern: e2e-test-results-shard-*
path: e2e-tests/blob-report
merge-multiple: true

- name: Merge Playwright reports
run: |
cd e2e-tests
yarn install
npx playwright merge-reports --reporter html blob-report/

- name: Upload merged E2E report
uses: actions/upload-artifact@v4
if: always()
with:
name: e2e-test-report-merged
path: e2e-tests/playwright-report/
retention-days: 30

# ==========================================================================
# COVERAGE STAGE - Collect and report test coverage
# ==========================================================================
Expand Down Expand Up @@ -1296,7 +1254,6 @@ jobs:
- check-mjml-compiled
# E2E tests (can be skipped based on path changes)
- test-e2e
- collect-e2e-reports
# Coverage (depends on test-backend)
- collect-coverage
steps:
Expand All @@ -1314,7 +1271,6 @@ jobs:
test-zapier=${{ needs.test-zapier.result }}
check-mjml-compiled=${{ needs.check-mjml-compiled.result }}
test-e2e=${{ needs.test-e2e.result }}
collect-e2e-reports=${{ needs.collect-e2e-reports.result }}
collect-coverage=${{ needs.collect-coverage.result }}
run: |
echo "=================================="
Expand Down
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,8 @@ web-frontend/storybook-static

.agent
MEMORY.md

# Endform reports from the repository-root Playwright wrapper
/playwright-report/
/test-results/
/blob-report/
2 changes: 1 addition & 1 deletion e2e-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"dependencies": {
"@faker-js/faker": "10.5.0",
"@nuxt/test-utils": "^3.21.0",
"@playwright/test": "^1.48.0",
"@playwright/test": "1.63.0",
"axios": "1.18.0",
"dotenv": "16.0.3"
}
Expand Down
16 changes: 10 additions & 6 deletions e2e-tests/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
import type { PlaywrightTestConfig } from "@playwright/test";
import { devices } from "@playwright/test";
import path from "path";
import dotenv from "dotenv";

// Resolve relative to this file so paths are correct regardless of cwd
// (VS Code Playwright extension runs from the workspace root, not e2e-tests/).
require("dotenv").config({ path: path.join(__dirname, ".env") });
dotenv.config({ path: path.join(__dirname, ".env") });

const defaultBackendPort = process.env.E2E_BACKEND_PORT || "8070";
const defaultFrontendPort = process.env.E2E_FRONTEND_PORT || "3070";

export const baserowConfig = {
PUBLIC_WEB_FRONTEND_URL: process.env.PUBLIC_WEB_FRONTEND_URL
? process.env.PUBLIC_WEB_FRONTEND_URL
: `http://localhost:${defaultFrontendPort}`,
PUBLIC_WEB_FRONTEND_URL:
process.env.BASE_URL ??
process.env.PUBLIC_WEB_FRONTEND_URL ??
`http://localhost:${defaultFrontendPort}`,
PUBLIC_BACKEND_URL: process.env.PUBLIC_BACKEND_URL
? process.env.PUBLIC_BACKEND_URL
: `http://localhost:${defaultBackendPort}`,
BUILDER_PREVIEW_URL:
process.env.BASEROW_BUILDER_PREVIEW_URL ??
process.env.BASE_URL ??
process.env.PUBLIC_WEB_FRONTEND_URL ??
`http://localhost:${defaultFrontendPort}`,
BASEROW_FRONTEND_COOKIE_PREFIX:
Expand Down Expand Up @@ -54,8 +57,9 @@ const config: PlaywrightTestConfig = {
/* 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('/')`. */
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: "on-first-retry",
baseURL: baserowConfig.PUBLIC_WEB_FRONTEND_URL,
/* Keep traces for failed tests. See https://playwright.dev/docs/trace-viewer */
trace: "retain-on-failure",
video: "on-first-retry",
nuxt: {
host: baserowConfig.PUBLIC_WEB_FRONTEND_URL,
Expand Down
35 changes: 14 additions & 21 deletions e2e-tests/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -175,12 +175,12 @@
vitest-environment-nuxt "^1.0.1"
vue "^3.5.25"

"@playwright/test@^1.48.0":
version "1.48.0"
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.48.0.tgz#4b81434a3ca75e2a6f82a645287784223a45434c"
integrity sha512-W5lhqPUVPqhtc/ySvZI5Q8X2ztBOUgZ8LbAFy0JQgrXZs2xaILrUcNO3rQjwbLPfGK13+rZsDa1FpG+tqYkT5w==
"@playwright/test@1.63.0":
version "1.63.0"
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.63.0.tgz#808020c46e8b6b91f9d628cd0ebcbb32bdfd8b6c"
integrity sha512-oxMK4vllB9RK5NQ2l1pq1IfOf2AvnEuj/vYGDj0H2nMtmtZpKtCwt/l00GEO6xjGfpBNAvjovvYdCm50dRQkpQ==
dependencies:
playwright "1.48.0"
playwright "1.63.0"

"@types/estree@^1.0.0":
version "1.0.8"
Expand Down Expand Up @@ -499,11 +499,6 @@ form-data@^4.0.5:
hasown "^2.0.2"
mime-types "^2.1.12"

fsevents@2.3.2:
version "2.3.2"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==

function-bind@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
Expand Down Expand Up @@ -754,19 +749,17 @@ pkg-types@^2.3.0:
exsolve "^1.0.7"
pathe "^2.0.3"

playwright-core@1.48.0:
version "1.48.0"
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.48.0.tgz#34d209dd4aba8fccd4a96116f1c4f7630f868722"
integrity sha512-RBvzjM9rdpP7UUFrQzRwR8L/xR4HyC1QXMzGYTbf1vjw25/ya9NRAVnXi/0fvFopjebvyPzsmoK58xxeEOaVvA==
playwright-core@1.63.0:
version "1.63.0"
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.63.0.tgz#e57665bc32846c213ac39a1e4d5bc6228e76b376"
integrity sha512-rYCsBF/M5HjUch52bbtVONEFjv6Xu8sm8h72dNlR5bzIE1fvC/bxgspzkjSfU+MweEMmPM8KJebG6nnyxo5mCg==

playwright@1.48.0:
version "1.48.0"
resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.48.0.tgz#00855d9a25f1991d422867f1c32af5d90f457b48"
integrity sha512-qPqFaMEHuY/ug8o0uteYJSRfMGFikhUysk8ZvAtfKmUK3kc/6oNl/y3EczF8OFGYIi/Ex2HspMfzYArk6+XQSA==
playwright@1.63.0:
version "1.63.0"
resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.63.0.tgz#99b56f9f69b1b70c44f00bf84b2fe52348ae2511"
integrity sha512-+7ziBLidS4NaNCdt57SUDT+wYmmd5fmiQejUic/kb+YsYSCPyOOE9sebzMjNmQrsnNpDJqd4WHvV/8lfKfUDUg==
dependencies:
playwright-core "1.48.0"
optionalDependencies:
fsevents "2.3.2"
playwright-core "1.63.0"

postcss@^8.5.6:
version "8.5.6"
Expand Down
29 changes: 29 additions & 0 deletions endform.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { defineEndformConfig } from "endform";
import { baserowConfig } from "./e2e-tests/playwright.config";

const applicationPorts = [
baserowConfig.PUBLIC_WEB_FRONTEND_URL,
baserowConfig.PUBLIC_BACKEND_URL,
baserowConfig.BUILDER_PREVIEW_URL,
]
.map((address) => new URL(address))
.filter(
({ hostname }) =>
["localhost", "127.0.0.1", "[::1]"].includes(hostname) ||
hostname.endsWith(".localhost")
)
.map(({ port, protocol }) => Number(port || (protocol === "https:" ? 443 : 80)));

export default defineEndformConfig({
// Transfer only the runtime-read image and the frontend protocol module.
// The root Playwright wrapper keeps both inside the upload root.
additionalFiles: [
"e2e-tests/assets/testuploadimage.png",
"web-frontend/modules/core/plugins/realtimeProtocol.js",
],
// The Axios API setup stalls with HTTP interception. Forward only the
// application URLs plus MailHog, barrier, and S3Mock loopback ports.
proxyNetworkPorts: [...new Set([...applicationPorts, 8025, 8102, 9090])],
// One shared application stack: avoid overwhelming its three API workers.
concurrentTestLimits: [{ scope: "within-suite-run", limit: 4 }],
});
11 changes: 11 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "baserow-endform",
"private": true,
"devDependencies": {
"@playwright/test": "1.63.0",
"endform": "0.81.3"
},
"workspaces": [
"e2e-tests"
]
}
5 changes: 5 additions & 0 deletions playwright.endform.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Keep both e2e-tests and its frontend source import inside Endform's upload root.
// The existing config still owns test selection, fixtures, projects, and retries.
import config from "./e2e-tests/playwright.config";

export default config;
Loading
Loading