Skip to content

Commit faabe6a

Browse files
authored
Merge pull request #24 from dacharyc/express-integration-tests
Add integration tests for Express server
2 parents dff7906 + 78206d3 commit faabe6a

13 files changed

Lines changed: 1658 additions & 70 deletions

.github/scripts/generate-test-summary-jest.sh

Lines changed: 95 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,122 @@
11
#!/bin/bash
22
set -e
33

4-
# Generate Test Summary from Jest JSON Output
5-
# Usage: ./generate-test-summary-jest.sh <path-to-jest-json-file>
4+
# Generate Detailed Test Summary from Multiple Jest JSON Output Files
5+
# Shows breakdown by test type (unit vs integration)
6+
# Usage: ./generate-test-summary-jest.sh <unit-json> <integration-json>
67

7-
JSON_FILE="${1:-test-results.json}"
8+
UNIT_JSON="${1:-}"
9+
INTEGRATION_JSON="${2:-}"
810

911
echo "## Test Results" >> $GITHUB_STEP_SUMMARY
1012
echo "" >> $GITHUB_STEP_SUMMARY
1113

12-
# Parse test results from Jest JSON output
13-
if [ -f "$JSON_FILE" ]; then
14-
# Extract test counts using jq or grep/sed
15-
# Jest JSON structure: { "numTotalTests": N, "numPassedTests": N, "numFailedTests": N, "numPendingTests": N, ... }
16-
14+
# Function to parse Jest JSON file
15+
parse_json() {
16+
local json_file="$1"
17+
local test_type="$2"
18+
19+
if [ ! -f "$json_file" ]; then
20+
echo "0 0 0 0"
21+
return
22+
fi
23+
1724
if command -v jq &> /dev/null; then
1825
# Use jq if available (preferred)
19-
total_tests=$(jq -r '.numTotalTests // 0' "$JSON_FILE")
20-
passed=$(jq -r '.numPassedTests // 0' "$JSON_FILE")
21-
failed=$(jq -r '.numFailedTests // 0' "$JSON_FILE")
22-
skipped=$(jq -r '.numPendingTests // 0' "$JSON_FILE")
23-
24-
# Extract failed test details
25-
failed_tests_file=$(mktemp)
26-
jq -r '.testResults[]? | select(.status == "failed") | .assertionResults[]? | select(.status == "failed") | "\(.ancestorTitles | join(" > ")) > \(.title)"' "$JSON_FILE" > "$failed_tests_file" 2>/dev/null || true
26+
total_tests=$(jq -r '.numTotalTests // 0' "$json_file")
27+
passed=$(jq -r '.numPassedTests // 0' "$json_file")
28+
failed=$(jq -r '.numFailedTests // 0' "$json_file")
29+
skipped=$(jq -r '.numPendingTests // 0' "$json_file")
2730
else
2831
# Fallback to grep/sed if jq is not available
29-
total_tests=$(grep -oP '"numTotalTests":\s*\K[0-9]+' "$JSON_FILE" | head -1)
30-
passed=$(grep -oP '"numPassedTests":\s*\K[0-9]+' "$JSON_FILE" | head -1)
31-
failed=$(grep -oP '"numFailedTests":\s*\K[0-9]+' "$JSON_FILE" | head -1)
32-
skipped=$(grep -oP '"numPendingTests":\s*\K[0-9]+' "$JSON_FILE" | head -1)
33-
34-
# Extract failed test names (basic extraction without jq)
35-
failed_tests_file=$(mktemp)
36-
grep -oP '"fullName":\s*"\K[^"]*' "$JSON_FILE" | while read -r line; do
37-
if echo "$line" | grep -q "failed"; then
38-
echo "$line" >> "$failed_tests_file"
39-
fi
40-
done 2>/dev/null || true
32+
total_tests=$(grep -oP '"numTotalTests":\s*\K[0-9]+' "$json_file" | head -1)
33+
passed=$(grep -oP '"numPassedTests":\s*\K[0-9]+' "$json_file" | head -1)
34+
failed=$(grep -oP '"numFailedTests":\s*\K[0-9]+' "$json_file" | head -1)
35+
skipped=$(grep -oP '"numPendingTests":\s*\K[0-9]+' "$json_file" | head -1)
4136
fi
42-
37+
4338
# Default to 0 if values are empty
4439
total_tests=${total_tests:-0}
4540
passed=${passed:-0}
4641
failed=${failed:-0}
4742
skipped=${skipped:-0}
4843

49-
echo "| Status | Count |" >> $GITHUB_STEP_SUMMARY
50-
echo "|--------|-------|" >> $GITHUB_STEP_SUMMARY
51-
echo "| ✅ Passed | $passed |" >> $GITHUB_STEP_SUMMARY
52-
echo "| ❌ Failed | $failed |" >> $GITHUB_STEP_SUMMARY
53-
echo "| ⏭️ Skipped | $skipped |" >> $GITHUB_STEP_SUMMARY
54-
echo "| **Total** | **$total_tests** |" >> $GITHUB_STEP_SUMMARY
44+
echo "$total_tests $passed $failed $skipped"
45+
}
46+
47+
# Parse both files
48+
read -r unit_tests unit_passed unit_failed unit_skipped <<< "$(parse_json "$UNIT_JSON" "Unit")"
49+
read -r int_tests int_passed int_failed int_skipped <<< "$(parse_json "$INTEGRATION_JSON" "Integration")"
50+
51+
# Calculate totals
52+
total_tests=$((unit_tests + int_tests))
53+
total_passed=$((unit_passed + int_passed))
54+
total_failed=$((unit_failed + int_failed))
55+
total_skipped=$((unit_skipped + int_skipped))
56+
57+
# Display detailed breakdown
58+
echo "### Summary by Test Type" >> $GITHUB_STEP_SUMMARY
59+
echo "" >> $GITHUB_STEP_SUMMARY
60+
echo "| Test Type | Passed | Failed | Skipped | Total |" >> $GITHUB_STEP_SUMMARY
61+
echo "|-----------|--------|--------|---------|-------|" >> $GITHUB_STEP_SUMMARY
62+
63+
if [ -f "$UNIT_JSON" ]; then
64+
echo "| 🔧 Unit Tests | $unit_passed | $unit_failed | $unit_skipped | $unit_tests |" >> $GITHUB_STEP_SUMMARY
65+
fi
66+
67+
if [ -f "$INTEGRATION_JSON" ]; then
68+
echo "| 🔗 Integration Tests | $int_passed | $int_failed | $int_skipped | $int_tests |" >> $GITHUB_STEP_SUMMARY
69+
fi
70+
71+
echo "| **Total** | **$total_passed** | **$total_failed** | **$total_skipped** | **$total_tests** |" >> $GITHUB_STEP_SUMMARY
72+
echo "" >> $GITHUB_STEP_SUMMARY
73+
74+
# Overall status
75+
echo "### Overall Status" >> $GITHUB_STEP_SUMMARY
76+
echo "" >> $GITHUB_STEP_SUMMARY
77+
echo "| Status | Count |" >> $GITHUB_STEP_SUMMARY
78+
echo "|--------|-------|" >> $GITHUB_STEP_SUMMARY
79+
echo "| ✅ Passed | $total_passed |" >> $GITHUB_STEP_SUMMARY
80+
echo "| ❌ Failed | $total_failed |" >> $GITHUB_STEP_SUMMARY
81+
echo "| ⏭️ Skipped | $total_skipped |" >> $GITHUB_STEP_SUMMARY
82+
echo "| **Total** | **$total_tests** |" >> $GITHUB_STEP_SUMMARY
83+
echo "" >> $GITHUB_STEP_SUMMARY
84+
85+
# List failed tests if any
86+
if [ $total_failed -gt 0 ]; then
87+
echo "### ❌ Failed Tests" >> $GITHUB_STEP_SUMMARY
5588
echo "" >> $GITHUB_STEP_SUMMARY
5689

57-
# List failed tests if any
58-
if [ "$failed" -gt 0 ]; then
59-
echo "### ❌ Failed Tests" >> $GITHUB_STEP_SUMMARY
60-
echo "" >> $GITHUB_STEP_SUMMARY
61-
62-
if [ -s "$failed_tests_file" ]; then
63-
while IFS= read -r test; do
64-
echo "- \`$test\`" >> $GITHUB_STEP_SUMMARY
65-
done < "$failed_tests_file"
66-
else
67-
echo "_Unable to parse individual test names_" >> $GITHUB_STEP_SUMMARY
90+
failed_tests_file=$(mktemp)
91+
92+
# Extract failed tests from both files
93+
for json_file in "$UNIT_JSON" "$INTEGRATION_JSON"; do
94+
if [ -f "$json_file" ]; then
95+
if command -v jq &> /dev/null; then
96+
jq -r '.testResults[]? | select(.status == "failed") | .assertionResults[]? | select(.status == "failed") | "\(.ancestorTitles | join(" > ")) > \(.title)"' "$json_file" >> "$failed_tests_file" 2>/dev/null || true
97+
else
98+
# Basic fallback without jq
99+
grep -oP '"fullName":\s*"\K[^"]*' "$json_file" | while read -r line; do
100+
if echo "$line" | grep -q "failed"; then
101+
echo "$line" >> "$failed_tests_file"
102+
fi
103+
done 2>/dev/null || true
104+
fi
68105
fi
69-
70-
echo "" >> $GITHUB_STEP_SUMMARY
71-
echo "❌ **Tests failed!**" >> $GITHUB_STEP_SUMMARY
72-
rm -f "$failed_tests_file"
73-
exit 1
106+
done
107+
108+
if [ -s "$failed_tests_file" ]; then
109+
while IFS= read -r test; do
110+
echo "- \`$test\`" >> $GITHUB_STEP_SUMMARY
111+
done < "$failed_tests_file"
74112
else
75-
echo "✅ **All tests passed!**" >> $GITHUB_STEP_SUMMARY
113+
echo "_Unable to parse individual test names_" >> $GITHUB_STEP_SUMMARY
76114
fi
77-
115+
116+
echo "" >> $GITHUB_STEP_SUMMARY
117+
echo "❌ **Tests failed!**" >> $GITHUB_STEP_SUMMARY
78118
rm -f "$failed_tests_file"
79-
else
80-
echo "⚠️ No test results found at: $JSON_FILE" >> $GITHUB_STEP_SUMMARY
81119
exit 1
120+
else
121+
echo "✅ **All tests passed!**" >> $GITHUB_STEP_SUMMARY
82122
fi
83-

.github/workflows/run-express-tests.yml

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@ on:
44
pull_request_target:
55
branches:
66
- development
7+
paths:
8+
- 'server/express/**'
79
push:
810
branches:
911
- development
12+
paths:
13+
- 'server/express/**'
1014

1115
jobs:
1216
test:
@@ -33,24 +37,34 @@ jobs:
3337
- name: Install dependencies
3438
run: npm install
3539

36-
- name: Run tests
37-
run: npm test -- --json --outputFile=test-results.json || true
40+
- name: Run unit tests
41+
run: npm run test:unit -- --json --outputFile=test-results-unit.json || true
3842
env:
3943
MONGODB_URI: ${{ secrets.MFLIX_URI }}
4044

45+
- name: Run integration tests
46+
run: npm run test:integration -- --json --outputFile=test-results-integration.json || true
47+
env:
48+
MONGODB_URI: ${{ secrets.MFLIX_URI }}
49+
ENABLE_SEARCH_TESTS: true
50+
VOYAGE_API_KEY: ${{ secrets.VOYAGE_AI }}
51+
4152
- name: Upload test results
4253
uses: actions/upload-artifact@v4
4354
if: always()
4455
with:
4556
name: test-results
4657
path: |
4758
server/express/coverage/
48-
server/express/test-results.json
59+
server/express/test-results-unit.json
60+
server/express/test-results-integration.json
4961
retention-days: 30
5062

5163
- name: Generate Test Summary
5264
if: always()
5365
working-directory: .
5466
run: |
5567
chmod +x .github/scripts/generate-test-summary-jest.sh
56-
.github/scripts/generate-test-summary-jest.sh server/express/test-results.json
68+
.github/scripts/generate-test-summary-jest.sh \
69+
server/express/test-results-unit.json \
70+
server/express/test-results-integration.json

server/express/.env.example

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,8 @@ PORT=3001
77
NODE_ENV=development
88

99
# CORS Configuration (frontend URL)
10-
CORS_ORIGIN=http://localhost:3000
10+
CORS_ORIGIN=http://localhost:3000
11+
12+
# Optional: Enable MongoDB Search tests
13+
# Uncomment the following line to enable Search tests
14+
# ENABLE_SEARCH_TESTS=true

server/express/jest.config.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
"**/__tests__/**/*.ts",
77
"**/?(*.)+(spec|test).ts"
88
],
9+
"testPathIgnorePatterns": [
10+
"/node_modules/",
11+
"/tests/integration/"
12+
],
913
"transform": {
1014
"^.+\\.ts$": "ts-jest"
1115
},
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"preset": "ts-jest",
3+
"testEnvironment": "node",
4+
"roots": ["<rootDir>/tests/integration"],
5+
"testMatch": [
6+
"**/integration/**/*.test.ts",
7+
"**/integration/**/*.spec.ts"
8+
],
9+
"transform": {
10+
"^.+\\.ts$": "ts-jest"
11+
},
12+
"setupFilesAfterEnv": ["<rootDir>/tests/integration/setup.ts"],
13+
"testTimeout": 60000
14+
}
15+

server/express/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"test:watch": "jest --watch",
1515
"test:coverage": "jest --coverage",
1616
"test:unit": "jest tests/controllers",
17+
"test:integration": "jest --config jest.integration.config.json",
1718
"test:verbose": "jest --verbose",
1819
"test:silent": "jest --silent"
1920
},
@@ -30,9 +31,11 @@
3031
"@types/express": "^4.17.21",
3132
"@types/jest": "^29.5.14",
3233
"@types/node": "^20.10.5",
34+
"@types/supertest": "^6.0.3",
3335
"@types/swagger-jsdoc": "^6.0.4",
3436
"@types/swagger-ui-express": "^4.1.8",
3537
"jest": "^29.7.0",
38+
"supertest": "^7.1.4",
3639
"ts-jest": "^29.1.1",
3740
"ts-node": "^10.9.2",
3841
"typescript": "^5.3.3"

server/express/src/app.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,5 +161,10 @@ process.on("SIGTERM", () => {
161161
process.exit(0);
162162
});
163163

164-
// Start the server
165-
startServer();
164+
// Export the app for testing
165+
export { app };
166+
167+
// Only start the server if this file is run directly (not imported for testing)
168+
if (require.main === module) {
169+
startServer();
170+
}

server/express/src/utils/errorHandler.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,16 @@ export function errorHandler(
3838
): void {
3939
// Log the error for debugging purposes
4040
// In production, we recommend using a logging service
41-
console.error("Error occurred:", {
42-
message: err.message,
43-
stack: err.stack,
44-
url: req.url,
45-
method: req.method,
46-
timestamp: new Date().toISOString(),
47-
});
41+
// Suppress error logging during tests to keep test output clean
42+
if (process.env.NODE_ENV !== "test") {
43+
console.error("Error occurred:", {
44+
message: err.message,
45+
stack: err.stack,
46+
url: req.url,
47+
method: req.method,
48+
timestamp: new Date().toISOString(),
49+
});
50+
}
4851

4952
// Determine the appropriate HTTP status code and error message
5053
const errorDetails = parseErrorDetails(err);

0 commit comments

Comments
 (0)