mirror of
https://github.com/Kong/insomnia.git
synced 2026-11-08 14:03:29 -05:00
- align dependency versions with the rest of the monorepo (express ^4, zod ^3, graphql ^16, @types/node ^24, @modelcontextprotocol/sdk ^1.17.5) and regenerate package-lock.json - make CI coverage on-demand: always on for develop pushes, opt-in via the workflow_dispatch `coverage` input otherwise - drop video recording (and the ffmpeg install); start Electron window tracing explicitly and attach trace.zip on failure instead Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
447 lines
18 KiB
YAML
447 lines
18 KiB
YAML
name: Insomnia Test
|
|
|
|
on:
|
|
merge_group:
|
|
workflow_dispatch:
|
|
inputs:
|
|
coverage:
|
|
description: Collect and merge V8 coverage (slower)
|
|
type: boolean
|
|
default: false
|
|
push:
|
|
branches:
|
|
- develop
|
|
pull_request:
|
|
types:
|
|
- opened
|
|
- synchronize
|
|
|
|
env:
|
|
# Coverage is on-demand: always on for develop pushes (the baseline), and
|
|
# for manual runs only when the `coverage` input is ticked. PRs and merge
|
|
# queue runs skip it.
|
|
COVERAGE: ${{ (github.event_name == 'push' || inputs.coverage) && 'true' || 'false' }}
|
|
|
|
concurrency:
|
|
group: insomnia-test-nonblocking-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
# ---------------------------------------------------------------------------
|
|
# Build the Insomnia binary once and upload it as an artifact. All shards
|
|
# download the same binary instead of each building it.
|
|
# ---------------------------------------------------------------------------
|
|
build:
|
|
timeout-minutes: 30
|
|
runs-on: ubuntu-24.04
|
|
permissions:
|
|
contents: read
|
|
packages: read
|
|
steps:
|
|
- name: Harden Runner
|
|
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
|
with:
|
|
egress-policy: audit
|
|
|
|
- name: Checkout repo
|
|
uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
|
|
with:
|
|
node-version-file: .nvmrc
|
|
registry-url: 'https://npm.pkg.github.com'
|
|
scope: '@kong'
|
|
|
|
- name: Expand swap space
|
|
run: |
|
|
sudo dd if=/dev/zero of=/mnt/swapfile bs=1M count=8192 status=none
|
|
sudo chmod 600 /mnt/swapfile
|
|
sudo mkswap /mnt/swapfile
|
|
sudo swapon /mnt/swapfile
|
|
|
|
# node_modules is installed once here and cached by lockfile hash; the
|
|
# test shards and result job restore it instead of running `npm ci`.
|
|
# Restore must come before install; the save runs right after install so
|
|
# later build steps can't alter what gets cached.
|
|
- name: Restore node_modules
|
|
id: node-modules-cache
|
|
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5
|
|
with:
|
|
path: |
|
|
node_modules
|
|
packages/*/node_modules
|
|
key: node-modules-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
|
|
|
|
- name: Install dependencies
|
|
if: steps.node-modules-cache.outputs.cache-hit != 'true'
|
|
run: npm ci
|
|
env:
|
|
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Save node_modules
|
|
if: steps.node-modules-cache.outputs.cache-hit != 'true'
|
|
uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25 # v5
|
|
with:
|
|
path: |
|
|
node_modules
|
|
packages/*/node_modules
|
|
key: node-modules-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
|
|
|
|
- name: Type-check insomnia-test
|
|
run: npm run type-check -w insomnia-test
|
|
|
|
- name: Build Insomnia
|
|
working-directory: packages/insomnia
|
|
env:
|
|
NODE_OPTIONS: --max-old-space-size=8192
|
|
run: |
|
|
npm run build:react-router -- --minify=false
|
|
npx esr --cache ./scripts/build.ts --noErrorTruncation
|
|
echo "=== build/ contents ==="
|
|
ls -la build/ 2>/dev/null || echo "ERROR: build/ not found"
|
|
test -f build/entry.main.min.js || { echo "ERROR: entry.main.min.js missing after build"; exit 1; }
|
|
|
|
- name: Package Insomnia (Linux unpacked)
|
|
working-directory: packages/insomnia
|
|
env:
|
|
USE_HARD_LINKS: 'false'
|
|
# Package .map files so coverage reports show original (pre-compile) sources
|
|
KEEP_SOURCEMAPS: 'true'
|
|
run: npx electron-builder build --config ../insomnia-test/electron-builder.config.ts --linux --dir --publish never
|
|
|
|
- name: Upload Insomnia binary
|
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
|
with:
|
|
name: insomnia-linux-unpacked
|
|
path: packages/insomnia/dist/linux-unpacked
|
|
retention-days: 1
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Counts the test cases with `playwright test --list` and derives the shard
|
|
# count as ceil(total / TESTS_PER_SHARD), capped at MAX_SHARDS, then generates
|
|
# the matrix indices (1..N). Needs `build` only for the cached node_modules.
|
|
# ---------------------------------------------------------------------------
|
|
shards:
|
|
name: Shard Matrix
|
|
needs: build
|
|
runs-on: ubuntu-24.04
|
|
permissions:
|
|
contents: read
|
|
packages: read
|
|
env:
|
|
TESTS_PER_SHARD: 10
|
|
MAX_SHARDS: 200
|
|
outputs:
|
|
indices: ${{ steps.matrix.outputs.indices }}
|
|
total: ${{ steps.matrix.outputs.total }}
|
|
steps:
|
|
- name: Harden Runner
|
|
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
|
with:
|
|
egress-policy: audit
|
|
|
|
- name: Checkout repo
|
|
uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
|
|
with:
|
|
node-version-file: .nvmrc
|
|
|
|
- name: Restore node_modules
|
|
id: node-modules-cache
|
|
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5
|
|
with:
|
|
path: |
|
|
node_modules
|
|
packages/*/node_modules
|
|
key: node-modules-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
|
|
|
|
# The build job's cache save can lose a reservation race (or be left
|
|
# reserved by a cancelled run), so fall back to a fresh install.
|
|
- name: Install dependencies
|
|
if: steps.node-modules-cache.outputs.cache-hit != 'true'
|
|
run: npm ci
|
|
env:
|
|
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- id: matrix
|
|
working-directory: packages/insomnia-test
|
|
run: |
|
|
list_output=$(npx playwright test --list 2>&1) || true
|
|
count=$(echo "$list_output" | grep -oE '^Total: [0-9]+' | grep -oE '[0-9]+' || true)
|
|
if [ -z "$count" ] || [ "$count" -lt 1 ]; then
|
|
echo "$list_output"
|
|
echo "ERROR: could not determine test count"; exit 1
|
|
fi
|
|
total=$(( (count + TESTS_PER_SHARD - 1) / TESTS_PER_SHARD ))
|
|
if [ "$total" -gt "$MAX_SHARDS" ]; then total=$MAX_SHARDS; fi
|
|
echo "$count tests -> $total shards ($TESTS_PER_SHARD tests per shard, max $MAX_SHARDS)"
|
|
echo "total=$total" >> "$GITHUB_OUTPUT"
|
|
echo "indices=$(seq 1 $total | jq -sc .)" >> "$GITHUB_OUTPUT"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Run the whole suite across the shards computed by the `shards` job (about
|
|
# TESTS_PER_SHARD tests each, at most MAX_SHARDS) in parallel. Each shard restores the
|
|
# downloaded binary and runs a slice of the suite, retrying failures in-process
|
|
# (see playwright.config.ts `retries`).
|
|
# ---------------------------------------------------------------------------
|
|
parallel-test:
|
|
name: Parallel Test
|
|
needs: [build, shards]
|
|
timeout-minutes: 60
|
|
runs-on: ubuntu-24.04
|
|
permissions:
|
|
contents: read
|
|
packages: read
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
shardIndex: ${{ fromJSON(needs.shards.outputs.indices) }}
|
|
shardTotal: ${{ fromJSON(format('[{0}]', needs.shards.outputs.total)) }}
|
|
steps:
|
|
- name: Harden Runner
|
|
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
|
with:
|
|
egress-policy: audit
|
|
|
|
- name: Checkout repo
|
|
uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
|
|
with:
|
|
node-version-file: .nvmrc
|
|
|
|
- name: Download Insomnia binary
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
with:
|
|
name: insomnia-linux-unpacked
|
|
path: packages/insomnia/dist/linux-unpacked
|
|
|
|
# upload/download-artifact go through zip and drop Unix file modes, so
|
|
# the binary and its helper executables (e.g. chrome_crashpad_handler)
|
|
# would otherwise fail to spawn with EACCES.
|
|
- name: Make Insomnia binary executable
|
|
run: |
|
|
cd packages/insomnia/dist/linux-unpacked
|
|
chmod +x insomnia
|
|
for f in chrome_crashpad_handler chrome-sandbox; do
|
|
if [ -f "$f" ]; then chmod +x "$f"; fi
|
|
done
|
|
|
|
- name: Restore node_modules
|
|
id: node-modules-cache
|
|
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5
|
|
with:
|
|
path: |
|
|
node_modules
|
|
packages/*/node_modules
|
|
key: node-modules-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
|
|
|
|
- name: Install dependencies
|
|
if: steps.node-modules-cache.outputs.cache-hit != 'true'
|
|
run: npm ci
|
|
env:
|
|
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Install Electron system dependencies
|
|
working-directory: packages/insomnia-test
|
|
run: npx playwright install-deps chromium
|
|
|
|
- name: Run Playwright tests (shard ${{ matrix.shardIndex }}/${{ matrix.shardTotal }})
|
|
working-directory: packages/insomnia-test
|
|
env:
|
|
INSOMNIA_BINARY: ${{ github.workspace }}/packages/insomnia/dist/linux-unpacked/insomnia
|
|
PLAYWRIGHT_BLOB_OUTPUT_NAME: blob-report-${{ matrix.shardIndex }}.zip
|
|
run: |
|
|
xvfb-run --auto-servernum npx playwright test --reporter=list,html,blob --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
|
|
|
|
# Two paths here (not just coverage/raw/) because v8-report.json (see
|
|
# misc/coverage.ts) must live as a sibling of raw/, not inside it — the
|
|
# upload computes a common ancestor across both, so raw/'s own
|
|
# contents now land one level deeper in the artifact, under `raw/`.
|
|
- name: Upload coverage (raw)
|
|
if: ${{ !cancelled() && env.COVERAGE == 'true' }}
|
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
|
with:
|
|
name: coverage-raw-${{ matrix.shardIndex }}
|
|
path: |
|
|
packages/insomnia-test/coverage/raw/
|
|
packages/insomnia-test/coverage/v8-report.json
|
|
retention-days: 1
|
|
if-no-files-found: ignore
|
|
|
|
- name: Upload Playwright report
|
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
|
if: ${{ !cancelled() }}
|
|
with:
|
|
name: playwright-report-${{ matrix.shardIndex }}
|
|
path: packages/insomnia-test/playwright-report/
|
|
retention-days: 1
|
|
if-no-files-found: ignore
|
|
|
|
- name: Upload blob report
|
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
|
if: ${{ !cancelled() }}
|
|
with:
|
|
name: blob-report-${{ matrix.shardIndex }}
|
|
path: packages/insomnia-test/blob-report/blob-report-${{ matrix.shardIndex }}.zip
|
|
retention-days: 1
|
|
if-no-files-found: ignore
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# This job doesn't gate the workflow — parallel-test (no continue-on-error)
|
|
# already fails the run on its own if any shard fails. This job only
|
|
# merges every shard's raw V8 coverage data (collected only when the
|
|
# workflow-level COVERAGE env is 'true') into one coverage
|
|
# report, and every shard's blob report into one full-suite Playwright
|
|
# report — both run on every trigger this workflow has (push and
|
|
# pull_request are the only two, so no `if` gate is needed on either).
|
|
# Each merge step is its own `continue-on-error: true` so a merge failure
|
|
# never fails this job. It finishes by deleting every per-shard
|
|
# intermediate (coverage-raw-*, playwright-report-*, blob-report-*),
|
|
# leaving only the merged artifact(s).
|
|
# ---------------------------------------------------------------------------
|
|
insomnia-test-result:
|
|
name: Insomnia Test Result
|
|
needs: parallel-test
|
|
if: ${{ !cancelled() }}
|
|
runs-on: ubuntu-24.04
|
|
permissions:
|
|
contents: read
|
|
packages: read
|
|
actions: write
|
|
steps:
|
|
- name: Harden Runner
|
|
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
|
|
with:
|
|
egress-policy: audit
|
|
|
|
- name: Checkout repo
|
|
continue-on-error: true
|
|
uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Setup Node.js
|
|
continue-on-error: true
|
|
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
|
|
with:
|
|
node-version-file: .nvmrc
|
|
|
|
# Full install (not just monocart-coverage-reports) so `npx playwright
|
|
# merge-reports` below is the exact same Playwright version the shards
|
|
# generated their blob reports with.
|
|
- name: Restore node_modules
|
|
continue-on-error: true
|
|
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5
|
|
with:
|
|
path: |
|
|
node_modules
|
|
packages/*/node_modules
|
|
key: node-modules-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
|
|
fail-on-cache-miss: true
|
|
|
|
# Coverage raw data can embed `file:` sourcemap URLs pointing into this
|
|
# build output (see parallel-test's own restore step). Without it
|
|
# here, sourcemap resolution silently fails for those
|
|
# scripts during the merge below, deflating line/statement/branch
|
|
# coverage relative to what each shard reports locally.
|
|
- name: Download Insomnia binary
|
|
continue-on-error: true
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
with:
|
|
name: insomnia-linux-unpacked
|
|
path: packages/insomnia/dist/linux-unpacked
|
|
|
|
- name: Download raw coverage from all shards
|
|
if: ${{ env.COVERAGE == 'true' }}
|
|
continue-on-error: true
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
with:
|
|
path: coverage-raw
|
|
pattern: coverage-raw-*
|
|
|
|
# Uses our own line/statement/branch/function union across each shard's
|
|
# own (already-correct) v8-json report, instead of monocart's built-in
|
|
# multi-shard raw-coverage merge (misc/merge-coverage.ts) — that merge
|
|
# has a bug where combining a script's coverage across shards with very
|
|
# different coverage levels can produce a result *lower* than any
|
|
# individual shard reported on its own. See misc/merge-coverage-union.ts
|
|
# for the full writeup.
|
|
- name: Merge coverage reports
|
|
id: merge-coverage
|
|
if: ${{ env.COVERAGE == 'true' }}
|
|
continue-on-error: true
|
|
working-directory: packages/insomnia-test
|
|
run: node misc/merge-coverage-union.ts ../../coverage-raw
|
|
|
|
- name: Upload merged coverage report
|
|
if: ${{ env.COVERAGE == 'true' }}
|
|
continue-on-error: true
|
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
|
with:
|
|
name: coverage-report
|
|
path: packages/insomnia-test/coverage-merged/
|
|
retention-days: 30
|
|
|
|
- name: Download blob reports from all shards
|
|
continue-on-error: true
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
with:
|
|
path: all-blob-reports
|
|
pattern: blob-report-*
|
|
merge-multiple: true
|
|
|
|
- name: Merge Playwright reports
|
|
id: merge-report
|
|
continue-on-error: true
|
|
working-directory: packages/insomnia-test
|
|
run: npx playwright merge-reports --reporter=html ../../all-blob-reports
|
|
|
|
- name: Upload merged Playwright report
|
|
continue-on-error: true
|
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
|
with:
|
|
name: playwright-report
|
|
path: packages/insomnia-test/playwright-report/
|
|
retention-days: 30
|
|
|
|
# Runs only after every shard passed: a failed run keeps all its
|
|
# intermediates so "Re-run failed jobs" still has the binary and the
|
|
# other shards' blob/coverage data to merge with. `gh api` instead of
|
|
# a third-party action keeps this within the repo's pinned-action set.
|
|
- name: Delete per-shard intermediate artifacts
|
|
if: ${{ always() && needs.parallel-test.result == 'success' }}
|
|
continue-on-error: true
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: |
|
|
gh api --paginate "repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts" \
|
|
--jq '.artifacts[] | select(.name | test("^(coverage-raw-|playwright-report-|blob-report-)") or . == "insomnia-linux-unpacked") | "\(.id) \(.name)"' |
|
|
while read -r id name; do
|
|
echo "Deleting artifact $name ($id)"
|
|
gh api -X DELETE "repos/${{ github.repository }}/actions/artifacts/$id" || echo "::warning::Failed to delete $name"
|
|
done
|
|
|
|
- name: Warn if a merge step failed
|
|
if: ${{ always() && (steps.merge-coverage.outcome == 'failure' || steps.merge-report.outcome == 'failure') }}
|
|
run: |
|
|
{
|
|
echo "### :warning: Insomnia Test report merge failed"
|
|
echo "- Merge coverage reports: ${{ steps.merge-coverage.outcome }}"
|
|
echo "- Merge Playwright reports: ${{ steps.merge-report.outcome }}"
|
|
echo "The merged artifacts may be missing; per-shard artifacts are still available."
|
|
} >> "$GITHUB_STEP_SUMMARY"
|