diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index cc8c1db..0000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,135 +0,0 @@ -stages: - - build - - publish - -variables: - GITLAB_NPM_REGISTRY: "https://gitlab.com/api/v4/packages/npm" - GITLAB_PROJECT_REGISTRY: "https://gitlab.com/api/v4/projects/${CI_PROJECT_ID}/packages/npm" - -.setup-npm: &setup-npm - - corepack enable pnpm - # Configure scoped registry for @transquinnftw packages (read from group registry) - - echo "@transquinnftw:registry=${GITLAB_NPM_REGISTRY}/" > .npmrc - - echo "//${GITLAB_NPM_REGISTRY#https://}/:_authToken=${CI_JOB_TOKEN}" >> .npmrc - # Remove prepare script to avoid git issues in CI (must be before pnpm install) - - | - node -e " - const fs = require('fs'); - const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8')); - if (pkg.scripts?.prepare) { - delete pkg.scripts.prepare; - fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2)); - console.log('Removed prepare script'); - } - " - # Transform workspace:* to latest versions from registry before install - - | - if grep -q '"workspace:\*"' package.json 2>/dev/null; then - echo "Transforming workspace:* dependencies..." - node -e " - const fs = require('fs'); - const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8')); - const transform = (deps) => { - if (!deps) return deps; - for (const [name, version] of Object.entries(deps)) { - if (version === 'workspace:*' || version.startsWith('workspace:')) { - deps[name] = '*'; // Accept any version from registry - } - } - return deps; - }; - pkg.dependencies = transform(pkg.dependencies); - pkg.devDependencies = transform(pkg.devDependencies); - pkg.peerDependencies = transform(pkg.peerDependencies); - fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2)); - console.log('Transformed workspace dependencies'); - " - fi - -build: - stage: build - image: node:20-alpine - before_script: - - apk add --no-cache jq - - *setup-npm - script: - - pnpm install - - pnpm run build - rules: - - if: $CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "master" - artifacts: - paths: - - dist/ - expire_in: 1 hour - -publish: - stage: publish - image: node:20-alpine - needs: ["build"] - before_script: - - apk add --no-cache jq curl - - corepack enable pnpm - script: - # Configure for publishing to project-specific registry - - echo "@transquinnftw:registry=${GITLAB_PROJECT_REGISTRY}/" > .npmrc - - echo "//${GITLAB_PROJECT_REGISTRY#https://}/:_authToken=${CI_JOB_TOKEN}" >> .npmrc - # Get current version to check if already published - - export PKG_NAME=$(jq -r '.name' package.json) - - export PKG_VERSION=$(jq -r '.version' package.json) - - | - echo "Checking if ${PKG_NAME}@${PKG_VERSION} exists..." - # Query the npm registry for the package version - HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \ - --header "Authorization: Bearer ${CI_JOB_TOKEN}" \ - "${GITLAB_NPM_REGISTRY}/${PKG_NAME}" || echo "000") - if [ "$HTTP_STATUS" = "200" ]; then - # Check if this specific version exists - VERSION_EXISTS=$(curl -s --header "Authorization: Bearer ${CI_JOB_TOKEN}" \ - "${GITLAB_NPM_REGISTRY}/${PKG_NAME}" | jq -r ".versions[\"${PKG_VERSION}\"] // empty") - if [ -n "$VERSION_EXISTS" ]; then - echo "Version ${PKG_VERSION} already published, skipping" - exit 0 - fi - fi - echo "Version ${PKG_VERSION} not found, will publish" - # Restore original package.json for correct version in published package - - git checkout package.json 2>/dev/null || true - # Transform workspace:* to caret ranges for publishing - - | - node -e " - const fs = require('fs'); - const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8')); - const transform = (deps) => { - if (!deps) return deps; - for (const [name, version] of Object.entries(deps)) { - if (version === 'workspace:*' || version.startsWith('workspace:')) { - deps[name] = '*'; // npm/pnpm will resolve to latest - } - } - return deps; - }; - pkg.dependencies = transform(pkg.dependencies); - pkg.devDependencies = transform(pkg.devDependencies); - pkg.peerDependencies = transform(pkg.peerDependencies); - // Remove publishConfig if it has unresolved variables or placeholders - const registry = pkg.publishConfig?.['@transquinnftw:registry'] || ''; - if (registry.includes('\${') || registry.includes('YOUR_PROJECT_ID')) { - delete pkg.publishConfig; - } - // Remove private flag to allow publishing - delete pkg.private; - // Remove lifecycle scripts that cause issues in CI - if (pkg.scripts) { - delete pkg.scripts.prepare; - delete pkg.scripts.prepublish; - delete pkg.scripts.prepublishOnly; - delete pkg.scripts.prepack; - if (Object.keys(pkg.scripts).length === 0) { - delete pkg.scripts; - } - } - fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2)); - " - - pnpm publish --no-git-checks --ignore-scripts - rules: - - if: $CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "master" diff --git a/README.md b/README.md index 0df69b0..acb9513 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Reusable Playwright E2E testing infrastructure with Docker support for both Elec - Mock service templates for backend dependencies - Reusable test fixtures and helpers - Memory-optimized worker configuration -- **GitLab CI templates** included +- **GitLab CI & Forgejo Actions templates** included ## Installation @@ -476,6 +476,73 @@ include: file: '/templates/gitlab-ci.yml' ``` +### Forgejo Actions + +Copy the Forgejo Actions template to your project: + +```bash +cp node_modules/@lilith/playwright-e2e-docker/templates/forgejo-actions.yml .forgejo/workflows/e2e.yml +``` + +Or use with `@lilith/forgejo-ci`: + +```yaml +# .forgejo/workflows/e2e.yml +name: E2E Tests + +on: [push, pull_request] + +jobs: + e2e: + runs-on: ubuntu-latest + container: + image: mcr.microsoft.com/playwright:v1.57.0-noble + + services: + postgres: + image: postgres:16-alpine + env: + POSTGRES_USER: test + POSTGRES_PASSWORD: test + POSTGRES_DB: test + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + redis: + image: redis:7-alpine + options: >- + --health-cmd "redis-cli ping" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + env: + CI: 'true' + DATABASE_URL: postgresql://test:test@postgres:5432/test + REDIS_URL: redis://redis:6379 + + steps: + - uses: actions/checkout@v4 + - run: corepack enable && corepack prepare pnpm@9 --activate + - run: pnpm install --frozen-lockfile + - run: pnpm build + - run: pnpm test:e2e + - uses: actions/upload-artifact@v4 + if: always() + with: + name: playwright-report + path: test-results/ +``` + +Available templates in `templates/forgejo-actions.yml`: +- `e2e-web` - Web app testing (browsers only) +- `e2e-electron` - Electron testing with Xvfb +- `e2e-docker` - Full docker-compose integration +- `e2e-visual` - Visual regression testing + ## Environment Variables | Variable | Description | diff --git a/package.json b/package.json index 24709da..a29b8cb 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "@transquinnftw/playwright-e2e-docker", + "name": "@lilith/playwright-e2e-docker", "version": "2.0.0", "description": "Reusable Playwright E2E testing infrastructure with Docker support for Electron and web apps. Features device presets, auth setup, cluster mode, and GitLab CI templates.", "type": "module", @@ -35,8 +35,7 @@ "scripts": { "build": "tsc", "clean": "rm -rf dist", - "prepublishOnly": "pnpm build", - "publish": "pnpm publish --no-git-checks" + "prepublishOnly": "pnpm build" }, "dependencies": {}, "peerDependencies": { @@ -45,7 +44,8 @@ "devDependencies": { "@playwright/test": "^1.57.0", "@types/node": "^22.10.2", - "typescript": "^5.7.2" + "typescript": "^5.7.2", + "@lilith/configs": "workspace:*" }, "keywords": [ "playwright", @@ -61,11 +61,11 @@ ], "repository": { "type": "git", - "url": "https://gitlab.com/transquinnftw/playwright-e2e-docker.git" + "url": "http://forge.nasty.sh/lilith/playwright-e2e-docker.git" }, - "homepage": "https://gitlab.com/transquinnftw/playwright-e2e-docker#readme", + "homepage": "http://forge.nasty.sh/lilith/playwright-e2e-docker#readme", "bugs": { - "url": "https://gitlab.com/transquinnftw/playwright-e2e-docker/-/issues" + "url": "http://forge.nasty.sh/lilith/playwright-e2e-docker/-/issues" }, "author": { "name": "QuinnFTW", @@ -73,10 +73,10 @@ }, "license": "MIT", "publishConfig": { - "@transquinnftw:registry": "https://gitlab.com/api/v4/projects/77369141/packages/npm/" + "registry": "http://forge.nasty.sh/api/packages/lilith/npm/" }, "_": { - "registry": "gitlab", + "registry": "forgejo", "publish": true, "build": true } diff --git a/package.json.tmp b/package.json.tmp new file mode 100644 index 0000000..e69de29 diff --git a/src/index.ts b/src/index.ts index f7c34db..345c285 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ /** - * @transquinnftw/playwright-e2e-docker + * @lilith/playwright-e2e-docker * * Reusable Playwright E2E testing infrastructure with Docker support * for both Electron and web applications. diff --git a/templates/electron.ts b/templates/electron.ts index f72386b..4bfb596 100644 --- a/templates/electron.ts +++ b/templates/electron.ts @@ -4,7 +4,7 @@ * Copy to your project's e2e/ directory and customize paths. */ -import { createElectronTest, expect, testHelpers } from '@transquinnftw/playwright-e2e-docker'; +import { createElectronTest, expect, testHelpers } from '@lilith/playwright-e2e-docker'; import path from 'path'; import { fileURLToPath } from 'url'; diff --git a/templates/forgejo-actions.yml b/templates/forgejo-actions.yml new file mode 100644 index 0000000..b5d03b9 --- /dev/null +++ b/templates/forgejo-actions.yml @@ -0,0 +1,248 @@ +# ============================================================================= +# Forgejo Actions E2E Testing Template +# ============================================================================= +# Playwright E2E testing workflow for Forgejo Actions +# +# This template provides: +# - Web app testing (browsers only) +# - Electron app testing (with Xvfb) +# - Service containers (PostgreSQL, Redis) +# - Artifact upload for test results +# +# Usage: +# 1. Copy to .forgejo/workflows/e2e.yml +# 2. Customize for your project +# 3. Add required secrets +# +# See: @lilith/playwright-e2e-docker README for full documentation +# ============================================================================= + +name: E2E Tests + +on: + push: + branches: [main, master, develop] + pull_request: + branches: [main, master] + +env: + NODE_VERSION: '22' + PNPM_VERSION: '9' + PLAYWRIGHT_VERSION: '1.57.0' + +jobs: + # =========================================================================== + # Web App E2E Tests (browsers only, no Xvfb needed) + # =========================================================================== + e2e-web: + name: E2E Web Tests + runs-on: ubuntu-latest + container: + image: mcr.microsoft.com/playwright:v1.57.0-noble + + # Uncomment services you need + services: + postgres: + image: postgres:16-alpine + env: + POSTGRES_USER: test + POSTGRES_PASSWORD: test + POSTGRES_DB: test + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 + + redis: + image: redis:7-alpine + options: >- + --health-cmd "redis-cli ping" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 6379:6379 + + env: + CI: 'true' + DATABASE_URL: postgresql://test:test@postgres:5432/test + REDIS_URL: redis://redis:6379 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup pnpm + run: | + corepack enable + corepack prepare pnpm@${{ env.PNPM_VERSION }} --activate + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build application + run: pnpm build + + - name: Run E2E tests + run: pnpm test:e2e + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: playwright-report-web + path: | + playwright-report/ + test-results/ + retention-days: 7 + + - name: Upload screenshots on failure + if: failure() + uses: actions/upload-artifact@v4 + with: + name: test-screenshots + path: test-results/**/*.png + retention-days: 7 + + # =========================================================================== + # Electron App E2E Tests (requires Xvfb) + # =========================================================================== + e2e-electron: + name: E2E Electron Tests + runs-on: ubuntu-latest + container: + image: mcr.microsoft.com/playwright:v1.57.0-noble + + env: + CI: 'true' + DISPLAY: ':99' + ELECTRON_DISABLE_GPU: '1' + ELECTRON_ENABLE_LOGGING: '1' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup pnpm + run: | + corepack enable + corepack prepare pnpm@${{ env.PNPM_VERSION }} --activate + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build Electron app + run: pnpm build + + - name: Start Xvfb + run: | + Xvfb :99 -screen 0 1920x1080x24 & + sleep 2 + + - name: Run E2E tests + run: xvfb-run --auto-servernum --server-args="-screen 0 1920x1080x24" pnpm test:e2e + timeout-minutes: 30 + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: playwright-report-electron + path: | + playwright-report/ + test-results/ + retention-days: 7 + + - name: Upload test videos + if: failure() + uses: actions/upload-artifact@v4 + with: + name: test-videos + path: test-results/**/*.webm + retention-days: 7 + + # =========================================================================== + # Docker-based E2E (full integration with docker-compose) + # =========================================================================== + e2e-docker: + name: E2E Docker Integration + runs-on: ubuntu-latest + # Only run on main branch to save CI minutes + if: github.ref == 'refs/heads/main' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: ${{ env.PNPM_VERSION }} + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Run Docker E2E + run: | + docker compose -f e2e/docker-compose.yml up --build \ + --abort-on-container-exit \ + --exit-code-from e2e-tests + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: playwright-report-docker + path: test-results/ + retention-days: 7 + + - name: Cleanup + if: always() + run: docker compose -f e2e/docker-compose.yml down -v + + # =========================================================================== + # Visual Regression Tests (optional) + # =========================================================================== + e2e-visual: + name: Visual Regression + runs-on: ubuntu-latest + container: + image: mcr.microsoft.com/playwright:v1.57.0-noble + # Only run when specifically triggered + if: contains(github.event.head_commit.message, '[visual]') + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup pnpm + run: | + corepack enable + corepack prepare pnpm@${{ env.PNPM_VERSION }} --activate + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build + run: pnpm build + + - name: Run visual tests + run: pnpm test:e2e --update-snapshots + + - name: Upload snapshots + uses: actions/upload-artifact@v4 + with: + name: visual-snapshots + path: | + **/__screenshots__/ + test-results/ + retention-days: 30 diff --git a/templates/playwright.config.ts b/templates/playwright.config.ts index 0bbe1e2..ce949cd 100644 --- a/templates/playwright.config.ts +++ b/templates/playwright.config.ts @@ -2,10 +2,10 @@ * Playwright Configuration Template * * Copy this to your project root and customize as needed. - * Or import createPlaywrightConfig from @transquinnftw/playwright-e2e-docker + * Or import createPlaywrightConfig from @lilith/playwright-e2e-docker */ -import { createPlaywrightConfig } from '@transquinnftw/playwright-e2e-docker'; +import { createPlaywrightConfig } from '@lilith/playwright-e2e-docker'; export default createPlaywrightConfig({ testDir: './e2e', diff --git a/tsconfig.json b/tsconfig.json index 478baab..009b3d6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,21 +1,15 @@ { + "extends": "@lilith/configs/typescript/esm.json", "compilerOptions": { - "target": "ES2022", - "module": "ESNext", - "moduleResolution": "bundler", "lib": ["ES2022", "DOM"], - "declaration": true, - "declarationMap": true, - "sourceMap": true, "outDir": "dist", - "rootDir": "src", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true, - "isolatedModules": true + "rootDir": "src" }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist"] + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules", + "dist" + ] }