Skip to content

feat(lenses): Leviticus 1-10 lens content, batch 1 of Pentateuch-rest pilot (#820, #1782) #1446

feat(lenses): Leviticus 1-10 lens content, batch 1 of Pentateuch-rest pilot (#820, #1782)

feat(lenses): Leviticus 1-10 lens content, batch 1 of Pentateuch-rest pilot (#820, #1782) #1446

Workflow file for this run

name: Tests
on:
pull_request:
branches: [master]
push:
branches: [master]
permissions:
contents: read
pull-requests: write
jobs:
test:
runs-on: ubuntu-latest
defaults:
run:
working-directory: app
steps:
- uses: actions/checkout@v4
with:
lfs: false # scripture.db is not needed for tests
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: app/package-lock.json
- run: npm ci
- name: TypeScript check
run: npx tsc --noEmit
- name: Run tests with coverage
id: tests
run: |
npx jest --coverage --ci --verbose --json --outputFile=test-results.json 2>&1 | tail -20
echo "TESTS_EXIT_CODE=${PIPESTATUS[0]:-$?}" >> $GITHUB_ENV
continue-on-error: true
- name: Generate test summary
if: always()
id: summary
working-directory: app
run: |
if [ ! -f test-results.json ]; then
echo "body=⚠️ **Tests**: Could not parse results" >> $GITHUB_OUTPUT
exit 0
fi
PASSED=$(node -e "const r=require('./test-results.json'); console.log(r.numPassedTests)")
FAILED=$(node -e "const r=require('./test-results.json'); console.log(r.numFailedTests)")
TOTAL=$(node -e "const r=require('./test-results.json'); console.log(r.numTotalTests)")
SUITES_PASSED=$(node -e "const r=require('./test-results.json'); console.log(r.numPassedTestSuites)")
SUITES_FAILED=$(node -e "const r=require('./test-results.json'); console.log(r.numFailedTestSuites)")
SUITES_TOTAL=$(node -e "const r=require('./test-results.json'); console.log(r.numTotalTestSuites)")
DURATION=$(node -e "const r=require('./test-results.json'); const s=((Date.now()-r.startTime)/1000).toFixed(1); console.log(s+'s')")
# Extract coverage percentages from coverage-summary.json
COV_STMTS="—"
COV_BRANCH="—"
COV_FUNCS="—"
COV_LINES="—"
if [ -f coverage/coverage-summary.json ]; then
COV_STMTS=$(node -e "const c=require('./coverage/coverage-summary.json').total.statements.pct; console.log(c+'%')")
COV_BRANCH=$(node -e "const c=require('./coverage/coverage-summary.json').total.branches.pct; console.log(c+'%')")
COV_FUNCS=$(node -e "const c=require('./coverage/coverage-summary.json').total.functions.pct; console.log(c+'%')")
COV_LINES=$(node -e "const c=require('./coverage/coverage-summary.json').total.lines.pct; console.log(c+'%')")
fi
# Build the summary body
if [ "$FAILED" = "0" ]; then
STATUS="✅ All tests passed"
else
STATUS="❌ $FAILED test(s) failed"
fi
BODY="## Test Results
${STATUS}
| | Passed | Failed | Total |
|---|---|---|---|
| **Tests** | ✅ ${PASSED} | ❌ ${FAILED} | ${TOTAL} |
| **Suites** | ✅ ${SUITES_PASSED} | ❌ ${SUITES_FAILED} | ${SUITES_TOTAL} |
### Coverage
| Statements | Branches | Functions | Lines |
|---|---|---|---|
| ${COV_STMTS} | ${COV_BRANCH} | ${COV_FUNCS} | ${COV_LINES} |
⏱️ Duration: ${DURATION}"
# Also write to GitHub Actions job summary
echo "$BODY" >> $GITHUB_STEP_SUMMARY
# Save for PR comment (use delimiter for multiline)
EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64)
echo "body<<$EOF" >> $GITHUB_OUTPUT
echo "$BODY" >> $GITHUB_OUTPUT
echo "$EOF" >> $GITHUB_OUTPUT
- name: Post results to PR
if: always() && github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const body = `${{ steps.summary.outputs.body }}`;
if (!body) return;
// Find existing bot comment to update (avoid spam)
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const botComment = comments.find(c =>
c.user.type === 'Bot' && c.body.includes('## Test Results')
);
if (botComment) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
});
}
- name: Upload coverage report
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: app/coverage/
retention-days: 14
- name: Fail if tests failed
if: env.TESTS_EXIT_CODE != '0'
run: exit 1
# ── Preflight bundle checks ──────────────────────────────────────
# These catch issues that unit tests can't see: dep version drift
# and Metro bundle-level resolution failures. They run only after
# tests pass — no point bundling a red build.
#
# Added after we shipped a TestFlight binary whose JS bundle
# couldn't resolve react-native-reanimated transitively; tests
# passed, EAS build failed during bundling. expo-doctor + expo
# export in CI would have caught both issues before merge.
- name: Expo doctor — dep version check
run: npx expo-doctor@latest
- name: Expo export — iOS bundle resolution check
run: npx expo export --platform ios --output-dir /tmp/expo-export-check