Skip to content
Merged
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
39 changes: 39 additions & 0 deletions docs/generated-app-ci.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Generated App CI

When you run `th generate <schema> --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.
Original file line number Diff line number Diff line change
@@ -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
11 changes: 11 additions & 0 deletions packages/templates/next-export-ui/test-scaffold/tests/README.md
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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.
8 changes: 8 additions & 0 deletions test/testCliGenerateUi.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand All @@ -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');
});
});
Loading