Skip to content

Commit e7a9748

Browse files
committed
feat: add tests
1 parent 56c1dc5 commit e7a9748

27 files changed

+3343
-85
lines changed

.claude/settings.local.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"permissions": {
3-
"allow": ["Bash(pnpm run lint*)"],
3+
"allow": ["Bash(pnpm run test:*)", "Bash(pnpm run lint:*)"],
44
"deny": [],
55
"ask": []
66
}

.github/workflows/test.yml

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
name: Test Suite
2+
3+
on:
4+
pull_request:
5+
branches: [main]
6+
workflow_dispatch:
7+
8+
jobs:
9+
test:
10+
runs-on: ubuntu-latest
11+
timeout-minutes: 15
12+
13+
services:
14+
mysql:
15+
image: mysql:8
16+
env:
17+
MYSQL_ROOT_PASSWORD: password
18+
MYSQL_DATABASE: catalog_test
19+
ports:
20+
- 3307:3306
21+
options: >-
22+
--health-cmd="mysqladmin ping"
23+
--health-interval=10s
24+
--health-timeout=5s
25+
--health-retries=3
26+
27+
opensearch:
28+
image: opensearchproject/opensearch:3
29+
env:
30+
cluster.name: test-opensearch-cluster
31+
node.name: test-opensearch
32+
discovery.type: single-node
33+
bootstrap.memory_lock: true
34+
OPENSEARCH_JAVA_OPTS: -Xms256m -Xmx256m
35+
DISABLE_SECURITY_PLUGIN: true
36+
ports:
37+
- 9201:9200
38+
options: >-
39+
--health-cmd="curl -f http://localhost:9200/_cluster/health || exit 1"
40+
--health-interval=30s
41+
--health-timeout=10s
42+
--health-retries=3
43+
44+
steps:
45+
- name: Checkout code
46+
uses: actions/checkout@v4
47+
48+
- name: Setup pnpm
49+
uses: pnpm/action-setup@v4
50+
51+
- name: Setup Node.js
52+
uses: actions/setup-node@v4
53+
with:
54+
node-version: 'lts/*'
55+
cache: pnpm
56+
57+
- name: Install dependencies
58+
run: pnpm install --frozen-lockfile
59+
60+
- name: Generate Prisma client
61+
run: pnpm run generate
62+
63+
- name: Wait for services to be ready
64+
run: |
65+
# Wait for MySQL
66+
for i in {1..30}; do
67+
if mysqladmin ping -h 127.0.0.1 -P 3307 -u root -ppassword &> /dev/null; then
68+
echo "MySQL is ready"
69+
break
70+
fi
71+
echo "Waiting for MySQL..."
72+
sleep 2
73+
done
74+
75+
# Wait for OpenSearch
76+
for i in {1..30}; do
77+
if curl -f http://localhost:9201/_cluster/health &> /dev/null; then
78+
echo "OpenSearch is ready"
79+
break
80+
fi
81+
echo "Waiting for OpenSearch..."
82+
sleep 2
83+
done
84+
85+
- name: Run database migrations
86+
run: pnpm run db:migrate
87+
env:
88+
DATABASE_URL: mysql://root:password@localhost:3307/catalog_test
89+
90+
- name: Run linting
91+
run: |
92+
pnpm run lint:biome
93+
pnpm run lint:types
94+
95+
- name: Run unit tests
96+
run: pnpm run test
97+
env:
98+
DATABASE_URL: mysql://root:password@localhost:3307/catalog_test
99+
OPENSEARCH_URL: http://localhost:9201
100+
NODE_ENV: test
101+
102+
- name: Run tests with coverage
103+
run: pnpm run test:coverage
104+
env:
105+
DATABASE_URL: mysql://root:password@localhost:3307/catalog_test
106+
OPENSEARCH_URL: http://localhost:9201
107+
NODE_ENV: test
108+
109+
- name: Check coverage threshold
110+
run: |
111+
# Extract coverage percentage from coverage report
112+
COVERAGE=$(pnpm run test:coverage --reporter=json | jq -r '.total.lines.pct')
113+
echo "Coverage: $COVERAGE%"
114+
115+
# Fail if coverage is below 95%
116+
if (( $(echo "$COVERAGE < 95" | bc -l) )); then
117+
echo "Coverage $COVERAGE% is below required 95%"
118+
exit 1
119+
fi
120+
echo "Coverage check passed: $COVERAGE%"
121+
122+
- name: Upload coverage reports
123+
uses: codecov/codecov-action@v4
124+
if: always()
125+
with:
126+
file: ./coverage/coverage-final.json
127+
fail_ci_if_error: false
128+
129+
- name: Comment PR with test results
130+
uses: actions/github-script@v7
131+
if: github.event_name == 'pull_request' && always()
132+
with:
133+
script: |
134+
const fs = require('fs');
135+
136+
// Read coverage report if it exists
137+
let coverageComment = '';
138+
try {
139+
const coverage = JSON.parse(fs.readFileSync('./coverage/coverage-final.json', 'utf8'));
140+
const total = coverage.total;
141+
coverageComment = `
142+
## 📊 Test Coverage
143+
144+
| Metric | Percentage | Status |
145+
|--------|------------|--------|
146+
| Lines | ${total.lines.pct}% | ${total.lines.pct >= 95 ? '✅' : '❌'} |
147+
| Functions | ${total.functions.pct}% | ${total.functions.pct >= 95 ? '✅' : '❌'} |
148+
| Branches | ${total.branches.pct}% | ${total.branches.pct >= 95 ? '✅' : '❌'} |
149+
| Statements | ${total.statements.pct}% | ${total.statements.pct >= 95 ? '✅' : '❌'} |
150+
151+
**Minimum required coverage: 95%**
152+
`;
153+
} catch (error) {
154+
coverageComment = '⚠️ Coverage report not available';
155+
}
156+
157+
const comment = `
158+
## 🧪 Test Results
159+
160+
The test suite has completed for this PR.
161+
162+
${coverageComment}
163+
164+
### ✅ Tests Included
165+
- Unit tests for routes and utilities
166+
- Integration tests with real database
167+
- OpenAPI schema validation
168+
- Error handling scenarios
169+
170+
Please review the test results above and ensure all checks are passing.
171+
`;
172+
173+
github.rest.issues.createComment({
174+
issue_number: context.issue.number,
175+
owner: context.repo.owner,
176+
repo: context.repo.repo,
177+
body: comment
178+
});
179+
180+
# Job to enforce that tests must pass
181+
test-status-check:
182+
runs-on: ubuntu-latest
183+
needs: test
184+
if: always()
185+
steps:
186+
- name: Test Status Check
187+
run: |
188+
if [ "${{ needs.test.result }}" != "success" ]; then
189+
echo "Tests failed or were cancelled"
190+
exit 1
191+
fi
192+
echo "All tests passed successfully"

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,5 @@ dist
1616

1717
# prisma
1818
src/generated/prisma/
19+
20+
coverage

.knip.jsonc

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,6 @@
11
{
22
"$schema": "https://unpkg.com/knip@5/schema-jsonc.json",
3-
"entry": [
4-
"src/index.ts"
5-
// // CDK
6-
// "bin/paragest.ts",
7-
// "lib/paragest-stack.ts",
8-
// "reset.d.ts",
9-
//
10-
// // Our scripts
11-
// "bin/list-failures.mts",
12-
// "bin/replay-s3-event.mts",
13-
//
14-
// // Lambdas
15-
// "src/tsconfig.json",
16-
// "src/*.ts",
17-
// "src/common/*.ts",
18-
// "src/cron/*.ts",
19-
// "src/audio/*.ts",
20-
// "src/image/*.ts",
21-
// "src/video/*.ts",
22-
// "src/other/*.ts",
23-
// "src/tsconfig.json"
24-
],
25-
"ignore": ["example/src/index.express.ts", "example/src/index.fastify.ts"],
3+
"ignore": ["example/src/index.express.ts", "example/src/index.fastify.ts", "scripts/loadEntities.ts"],
264
"ignoreDependencies": [
275
// Used in prisma.schema, not directly in code
286
"prisma-json-types-generator",

0 commit comments

Comments
 (0)