diff --git a/docs/generated-app-ci.md b/docs/generated-app-ci.md new file mode 100644 index 0000000..93ec1a0 --- /dev/null +++ b/docs/generated-app-ci.md @@ -0,0 +1,39 @@ +# Generated App CI + +When you run `th generate --with-tests`, the generated UI app includes: + +- `tests/contract/integration.mjs` +- `tests/ui/smoke.mjs` +- `.github/workflows/generated-app-ci.yml` + +The emitted workflow runs in GitHub Actions and is designed to work in a generated app repository with no manual CI authoring. + +## Default workflow behavior + +- Uses Node 20 and pnpm. +- Caches pnpm store using a lockfile-based key. +- Installs dependencies with `pnpm install --frozen-lockfile`. +- Installs Foundry/anvil. +- Runs generated contract tests with `pnpm run test:contract`. +- Runs generated UI tests with `pnpm run test:ui`. + +## Optional workflow knobs + +Use repository or environment variables to tune runtime cost: + +- `TH_SKIP_CONTRACT_TESTS=1` + - Skip Foundry installation and contract tests. +- `TH_SKIP_UI_TESTS=1` + - Skip UI smoke tests. +- `TH_INSTALL_BROWSER_DEPS=1` + - Install Playwright Chromium dependencies when Playwright exists in the generated app. + +## Canonical app validation in this builder repo + +This repo validates generated-app test scaffolds and canonical job-board behavior through integration tests under `test/integration/`: + +- generated contract scaffold execution +- generated UI scaffold execution against live preview +- end-to-end canonical job-board flow + +These checks back the required `integration-local` CI job in this repository. diff --git a/packages/templates/next-export-ui/test-scaffold/.github/workflows/generated-app-ci.yml b/packages/templates/next-export-ui/test-scaffold/.github/workflows/generated-app-ci.yml new file mode 100644 index 0000000..f911ee1 --- /dev/null +++ b/packages/templates/next-export-ui/test-scaffold/.github/workflows/generated-app-ci.yml @@ -0,0 +1,71 @@ +name: Generated App CI + +on: + push: + branches: + - main + - master + pull_request: + +jobs: + generated-app-tests: + runs-on: ubuntu-latest + timeout-minutes: 25 + env: + NEXT_TELEMETRY_DISABLED: '1' + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: '10.12.1' + + - name: Get pnpm store path + id: pnpm-store + shell: bash + run: echo "store_path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT" + + - name: Cache pnpm store + uses: actions/cache@v4 + with: + path: ${{ steps.pnpm-store.outputs.store_path }} + key: generated-app-pnpm-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} + restore-keys: | + generated-app-pnpm-${{ runner.os }}- + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Install Foundry (anvil) + if: ${{ env.TH_SKIP_CONTRACT_TESTS != '1' }} + uses: foundry-rs/foundry-toolchain@v1 + with: + version: stable + + - name: Confirm anvil + if: ${{ env.TH_SKIP_CONTRACT_TESTS != '1' }} + run: anvil --version + + - name: Install browser deps (optional) + if: ${{ env.TH_INSTALL_BROWSER_DEPS == '1' }} + run: | + if pnpm exec playwright --version >/dev/null 2>&1; then + pnpm exec playwright install --with-deps chromium + else + echo "Playwright is not installed; skipping browser dependency install." + fi + + - name: Run generated contract tests + if: ${{ env.TH_SKIP_CONTRACT_TESTS != '1' }} + run: pnpm run test:contract + + - name: Run generated UI tests + if: ${{ env.TH_SKIP_UI_TESTS != '1' }} + run: pnpm run test:ui diff --git a/packages/templates/next-export-ui/test-scaffold/tests/README.md b/packages/templates/next-export-ui/test-scaffold/tests/README.md index 38d0f15..7eb9947 100644 --- a/packages/templates/next-export-ui/test-scaffold/tests/README.md +++ b/packages/templates/next-export-ui/test-scaffold/tests/README.md @@ -1,6 +1,7 @@ Generated app test scaffold This directory is emitted by `th generate --with-tests`. +The same scaffold also emits `.github/workflows/generated-app-ci.yml`. - `contract/integration.mjs` runs schema-driven contract behavior tests against local anvil. - `contract/smoke.mjs` validates baseline generated app contract test preconditions. @@ -19,4 +20,14 @@ UI smoke test env vars: When `TH_UI_BASE_URL` is not set, `ui/smoke.mjs` runs static scaffold checks only. +Generated CI workflow defaults: +- Install dependencies with pnpm on Node 20. +- Install Foundry/anvil and run `pnpm run test:contract`. +- Run `pnpm run test:ui`. + +Generated CI workflow knobs: +- `TH_SKIP_CONTRACT_TESTS=1` skips Foundry install and contract tests. +- `TH_SKIP_UI_TESTS=1` skips UI tests. +- `TH_INSTALL_BROWSER_DEPS=1` installs Playwright Chromium deps if Playwright is present. + These tests are schema-driven and intended to be expanded further for app-specific assertions. diff --git a/test/testCliGenerateUi.js b/test/testCliGenerateUi.js index 30a1f9c..b1b3c66 100644 --- a/test/testCliGenerateUi.js +++ b/test/testCliGenerateUi.js @@ -125,6 +125,7 @@ describe('th generate (UI template)', function () { expect(fs.existsSync(path.join(uiDir, 'tests', 'contract', 'smoke.mjs'))).to.equal(true); expect(fs.existsSync(path.join(uiDir, 'tests', 'contract', 'integration.mjs'))).to.equal(true); expect(fs.existsSync(path.join(uiDir, 'tests', 'ui', 'smoke.mjs'))).to.equal(true); + expect(fs.existsSync(path.join(uiDir, '.github', 'workflows', 'generated-app-ci.yml'))).to.equal(true); const pkg = JSON.parse(fs.readFileSync(path.join(uiDir, 'package.json'), 'utf-8')); expect(pkg?.scripts?.test).to.equal('pnpm run test:contract && pnpm run test:ui'); @@ -138,5 +139,12 @@ describe('th generate (UI template)', function () { const uiSmoke = runCmd('node', ['tests/ui/smoke.mjs'], uiDir); expect(uiSmoke.status, uiSmoke.stderr || uiSmoke.stdout).to.equal(0); + + const workflow = fs.readFileSync(path.join(uiDir, '.github', 'workflows', 'generated-app-ci.yml'), 'utf-8'); + expect(workflow).to.include('pnpm run test:contract'); + expect(workflow).to.include('pnpm run test:ui'); + expect(workflow).to.include('TH_SKIP_CONTRACT_TESTS'); + expect(workflow).to.include('TH_SKIP_UI_TESTS'); + expect(workflow).to.include('TH_INSTALL_BROWSER_DEPS'); }); });