mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
Replace the fake resized-desktop mobile specs with real Playwright device projects (Pixel 7, iPhone 14, iPad gen 7, Galaxy Tab S9) that exercise real touch, mobile UA, DPR, and WebKit engine. Device projects in playwright.config.ts: - mobile-chromium (Pixel 7, 412x839, Chromium) - mobile-webkit (iPhone 14, 390x664, WebKit) - tablet-webkit (iPad gen 7, 810x1080, WebKit) - tablet-chromium (Galaxy Tab S9, 640x1024, Chromium) Device specs (16 mobile, 10 tablet): - Core flow: navigate to tool, upload, process, download - Responsive chrome: bottom-nav, sidebar hidden, search, overflow - Touch interactions: before-after slider, crop canvas - Editor gate: phone asserts "Desktop Recommended" message - Editor tablet: iPad (810px) renders canvas, Galaxy Tab (640px) shows gate - SSE visibility-recovery regression guard - RTL Arabic locale responsive check Key finding: Galaxy Tab S9 viewport (640px) is below the 768px mobile breakpoint, so useMobile() returns true and the editor shows the mobile gate. Only iPad gen 7 (810px) is classified as non-mobile. Component tests (17 tests, Vitest/jsdom): - use-mobile hook: breakpoint behavior across all 4 device widths - mobile-bottom-nav: render, navigation links, settings callback, icons CI wiring: - ci.yml: mobile-chromium smoke job (PR gate) - nightly.yml: full device matrix with webkit - update-visual-baselines.yml: webkit + device projects for goldens Parity: 13218 passed, 0 dropped (PARITY OK)
271 lines
9.7 KiB
YAML
271 lines
9.7 KiB
YAML
name: CI
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
push:
|
|
branches: [main]
|
|
paths-ignore:
|
|
- "README.md"
|
|
- "CONTRIBUTING.md"
|
|
- "branding/**"
|
|
- "apps/docs/**"
|
|
- "apps/landing/**"
|
|
- "docs/**"
|
|
pull_request:
|
|
branches: [main]
|
|
paths-ignore:
|
|
- "README.md"
|
|
- "CONTRIBUTING.md"
|
|
- "branding/**"
|
|
- "apps/docs/**"
|
|
- "apps/landing/**"
|
|
- "docs/**"
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
lint:
|
|
name: Lint
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
- uses: ./.github/actions/setup
|
|
- run: pnpm lint
|
|
- name: License boundary check (D15)
|
|
run: pnpm check:license-boundary
|
|
|
|
typecheck:
|
|
name: Typecheck
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
- uses: ./.github/actions/setup
|
|
- run: pnpm typecheck
|
|
|
|
test-unit:
|
|
name: Unit Tests
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 5
|
|
steps:
|
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
|
|
- name: Install system dependencies (HEIC + ExifTool + ImageMagick + exotic format tools)
|
|
run: sudo apt-get update -qq && sudo apt-get install -y --no-install-recommends libheif-examples libheif-plugin-x265 libheif-plugin-libde265 libimage-exiftool-perl imagemagick ghostscript libjxl-tools libopenjp2-tools
|
|
|
|
- uses: ./.github/actions/setup
|
|
- run: pnpm vitest run tests/unit/ --reporter=verbose
|
|
|
|
test-integration:
|
|
name: Integration (${{ matrix.shard }}/4)
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
shard: [1, 2, 3, 4]
|
|
steps:
|
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
|
|
- name: Install system dependencies (image formats + doc-engine qpdf/pandoc/LibreOffice)
|
|
run: sudo apt-get update -qq && sudo apt-get install -y --no-install-recommends libheif-examples libheif-plugin-x265 libheif-plugin-libde265 libimage-exiftool-perl imagemagick ghostscript libjxl-tools libopenjp2-tools qpdf pandoc libreoffice-calc libreoffice-impress libreoffice-writer
|
|
|
|
- name: Install pdfcpu (doc-engine PDF layout binary; matches docker/Dockerfile v0.13.0)
|
|
run: |
|
|
curl -fsSL https://github.com/pdfcpu/pdfcpu/releases/download/v0.13.0/pdfcpu_0.13.0_Linux_x86_64.tar.xz -o /tmp/pdfcpu.tar.xz
|
|
tar -xJf /tmp/pdfcpu.tar.xz -C /tmp
|
|
sudo install "$(find /tmp -type f -name pdfcpu | head -1)" /usr/local/bin/pdfcpu
|
|
pdfcpu version
|
|
|
|
- name: Allow ImageMagick to read EPS/PS via Ghostscript delegate
|
|
run: |
|
|
POLICY_FILE=$(find /etc/ImageMagick* -name policy.xml 2>/dev/null | head -1)
|
|
if [ -n "$POLICY_FILE" ]; then
|
|
sudo sed -i 's/<policy domain="coder" rights="none" pattern="EPS"/<policy domain="coder" rights="read" pattern="EPS"/' "$POLICY_FILE"
|
|
sudo sed -i 's/<policy domain="coder" rights="none" pattern="PS"/<policy domain="coder" rights="read" pattern="PS"/' "$POLICY_FILE"
|
|
fi
|
|
|
|
- uses: ./.github/actions/setup
|
|
- run: pnpm vitest run tests/integration/ --reporter=verbose --shard=${{ matrix.shard }}/4
|
|
|
|
test-e2e-smoke:
|
|
name: E2E Smoke (Chromium)
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 15
|
|
services:
|
|
postgres:
|
|
image: postgres:17-alpine
|
|
env:
|
|
POSTGRES_USER: snapotter
|
|
POSTGRES_PASSWORD: snapotter
|
|
POSTGRES_DB: snapotter
|
|
ports:
|
|
- 5432:5432
|
|
options: >-
|
|
--health-cmd "pg_isready -U snapotter"
|
|
--health-interval 5s
|
|
--health-timeout 3s
|
|
--health-retries 10
|
|
redis:
|
|
image: redis:8-alpine
|
|
ports:
|
|
- 6379:6379
|
|
options: >-
|
|
--health-cmd "redis-cli ping"
|
|
--health-interval 5s
|
|
--health-timeout 3s
|
|
--health-retries 10
|
|
steps:
|
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
- uses: ./.github/actions/setup
|
|
- name: Get Playwright version
|
|
id: pw-version
|
|
run: echo "version=$(node -p "require('@playwright/test/package.json').version")" >> "$GITHUB_OUTPUT"
|
|
- name: Cache Playwright browsers
|
|
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
|
with:
|
|
path: ~/.cache/ms-playwright
|
|
key: playwright-${{ runner.os }}-${{ steps.pw-version.outputs.version }}
|
|
- name: Install Playwright Chromium
|
|
run: pnpm playwright install --with-deps chromium
|
|
- name: Run smoke specs
|
|
# tools-all.spec.ts is the full 157-tool per-tool render matrix (~170 tests)
|
|
# -- a comprehensive check, not a PR-gate smoke test. It runs in the nightly
|
|
# e2e-full bucket, which executes the whole suite sharded. Keep this gate to
|
|
# genuinely fast sanity specs so it finishes well inside the timeout.
|
|
run: pnpm playwright test tests/e2e/smoke.spec.ts tests/e2e/navigation.spec.ts tests/e2e/home-page.spec.ts --project=chromium
|
|
env:
|
|
PW_WORKERS: "2"
|
|
- name: Upload report on failure
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
if: failure()
|
|
with:
|
|
name: e2e-smoke-report
|
|
path: playwright-report/
|
|
retention-days: 7
|
|
|
|
test-e2e-mobile-smoke:
|
|
name: E2E Mobile Smoke (Chromium)
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 15
|
|
services:
|
|
postgres:
|
|
image: postgres:17-alpine
|
|
env:
|
|
POSTGRES_USER: snapotter
|
|
POSTGRES_PASSWORD: snapotter
|
|
POSTGRES_DB: snapotter
|
|
ports:
|
|
- 5432:5432
|
|
options: >-
|
|
--health-cmd "pg_isready -U snapotter"
|
|
--health-interval 5s
|
|
--health-timeout 3s
|
|
--health-retries 10
|
|
redis:
|
|
image: redis:8-alpine
|
|
ports:
|
|
- 6379:6379
|
|
options: >-
|
|
--health-cmd "redis-cli ping"
|
|
--health-interval 5s
|
|
--health-timeout 3s
|
|
--health-retries 10
|
|
steps:
|
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
- uses: ./.github/actions/setup
|
|
- name: Get Playwright version
|
|
id: pw-version
|
|
run: echo "version=$(node -p "require('@playwright/test/package.json').version")" >> "$GITHUB_OUTPUT"
|
|
- name: Cache Playwright browsers
|
|
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
|
with:
|
|
path: ~/.cache/ms-playwright
|
|
key: playwright-${{ runner.os }}-${{ steps.pw-version.outputs.version }}
|
|
- name: Install Playwright Chromium
|
|
run: pnpm playwright install --with-deps chromium
|
|
- name: Run mobile device specs (Pixel 7)
|
|
run: pnpm playwright test --project=mobile-chromium --grep @mobile
|
|
env:
|
|
PW_WORKERS: "2"
|
|
- name: Upload report on failure
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
if: failure()
|
|
with:
|
|
name: e2e-mobile-smoke-report
|
|
path: playwright-report/
|
|
retention-days: 7
|
|
|
|
pip-audit:
|
|
name: Python Dependency Audit
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
|
|
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
with:
|
|
python-version: "3.11"
|
|
|
|
- run: pip install "pip-audit==2.10.0"
|
|
- name: Run pip-audit (ignoring CVEs blocked by dependency constraints)
|
|
# CVE-2025-3000: torch 2.12.0, no fixed release available as of 2026-06-11
|
|
run: >-
|
|
pip-audit -r packages/ai/python/requirements.txt
|
|
--ignore-vuln CVE-2024-27763
|
|
--ignore-vuln CVE-2025-3000
|
|
--ignore-vuln CVE-2026-40086
|
|
--ignore-vuln CVE-2026-25990
|
|
--ignore-vuln CVE-2026-40192
|
|
--ignore-vuln GHSA-55v6-g8pm-pw4c
|
|
--ignore-vuln CVE-2026-42308
|
|
--ignore-vuln CVE-2026-42310
|
|
--ignore-vuln CVE-2026-42311
|
|
--ignore-vuln PYSEC-2025-189
|
|
--ignore-vuln PYSEC-2025-190
|
|
--ignore-vuln PYSEC-2025-191
|
|
--ignore-vuln PYSEC-2025-192
|
|
--ignore-vuln PYSEC-2025-193
|
|
--ignore-vuln PYSEC-2025-194
|
|
--ignore-vuln PYSEC-2025-195
|
|
--ignore-vuln PYSEC-2025-196
|
|
--ignore-vuln PYSEC-2025-197
|
|
--ignore-vuln PYSEC-2025-210
|
|
--ignore-vuln PYSEC-2026-139
|
|
--ignore-vuln PYSEC-2024-277
|
|
--ignore-vuln PYSEC-2026-89
|
|
|
|
build:
|
|
name: Build
|
|
runs-on: ubuntu-latest
|
|
needs: [lint, typecheck, test-unit, test-integration, test-e2e-smoke, test-e2e-mobile-smoke]
|
|
steps:
|
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
- uses: ./.github/actions/setup
|
|
- run: pnpm build
|
|
|
|
# docker:
|
|
# name: Docker Build Test
|
|
# runs-on: ubuntu-latest
|
|
# steps:
|
|
# - uses: actions/checkout@v4
|
|
# - uses: docker/setup-buildx-action@v3
|
|
# - name: Log in to GHCR (for registry cache)
|
|
# uses: docker/login-action@v3
|
|
# with:
|
|
# registry: ghcr.io
|
|
# username: ${{ github.repository_owner }}
|
|
# password: ${{ secrets.GHCR_TOKEN }}
|
|
# - uses: docker/build-push-action@v6
|
|
# with:
|
|
# context: .
|
|
# file: docker/Dockerfile
|
|
# push: false
|
|
# tags: snapotter:ci
|
|
# build-args: SKIP_MODEL_DOWNLOADS=true
|
|
# cache-from: type=registry,ref=ghcr.io/snapotter-hq/snapotter:cache-linux-amd64
|
|
# cache-to: type=registry,ref=ghcr.io/snapotter-hq/snapotter:cache-ci,mode=max
|