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
151 changes: 95 additions & 56 deletions .github/scripts/generate-test-summary-jest.sh
Original file line number Diff line number Diff line change
@@ -1,83 +1,122 @@
#!/bin/bash
set -e

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

JSON_FILE="${1:-test-results.json}"
UNIT_JSON="${1:-}"
INTEGRATION_JSON="${2:-}"

echo "## Test Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY

# Parse test results from Jest JSON output
if [ -f "$JSON_FILE" ]; then
# Extract test counts using jq or grep/sed
# Jest JSON structure: { "numTotalTests": N, "numPassedTests": N, "numFailedTests": N, "numPendingTests": N, ... }

# Function to parse Jest JSON file
parse_json() {
local json_file="$1"
local test_type="$2"

if [ ! -f "$json_file" ]; then
echo "0 0 0 0"
return
fi

if command -v jq &> /dev/null; then
# Use jq if available (preferred)
total_tests=$(jq -r '.numTotalTests // 0' "$JSON_FILE")
passed=$(jq -r '.numPassedTests // 0' "$JSON_FILE")
failed=$(jq -r '.numFailedTests // 0' "$JSON_FILE")
skipped=$(jq -r '.numPendingTests // 0' "$JSON_FILE")

# Extract failed test details
failed_tests_file=$(mktemp)
jq -r '.testResults[]? | select(.status == "failed") | .assertionResults[]? | select(.status == "failed") | "\(.ancestorTitles | join(" > ")) > \(.title)"' "$JSON_FILE" > "$failed_tests_file" 2>/dev/null || true
total_tests=$(jq -r '.numTotalTests // 0' "$json_file")
passed=$(jq -r '.numPassedTests // 0' "$json_file")
failed=$(jq -r '.numFailedTests // 0' "$json_file")
skipped=$(jq -r '.numPendingTests // 0' "$json_file")
else
# Fallback to grep/sed if jq is not available
total_tests=$(grep -oP '"numTotalTests":\s*\K[0-9]+' "$JSON_FILE" | head -1)
passed=$(grep -oP '"numPassedTests":\s*\K[0-9]+' "$JSON_FILE" | head -1)
failed=$(grep -oP '"numFailedTests":\s*\K[0-9]+' "$JSON_FILE" | head -1)
skipped=$(grep -oP '"numPendingTests":\s*\K[0-9]+' "$JSON_FILE" | head -1)

# Extract failed test names (basic extraction without jq)
failed_tests_file=$(mktemp)
grep -oP '"fullName":\s*"\K[^"]*' "$JSON_FILE" | while read -r line; do
if echo "$line" | grep -q "failed"; then
echo "$line" >> "$failed_tests_file"
fi
done 2>/dev/null || true
total_tests=$(grep -oP '"numTotalTests":\s*\K[0-9]+' "$json_file" | head -1)
passed=$(grep -oP '"numPassedTests":\s*\K[0-9]+' "$json_file" | head -1)
failed=$(grep -oP '"numFailedTests":\s*\K[0-9]+' "$json_file" | head -1)
skipped=$(grep -oP '"numPendingTests":\s*\K[0-9]+' "$json_file" | head -1)
fi

# Default to 0 if values are empty
total_tests=${total_tests:-0}
passed=${passed:-0}
failed=${failed:-0}
skipped=${skipped:-0}

echo "| Status | Count |" >> $GITHUB_STEP_SUMMARY
echo "|--------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| ✅ Passed | $passed |" >> $GITHUB_STEP_SUMMARY
echo "| ❌ Failed | $failed |" >> $GITHUB_STEP_SUMMARY
echo "| ⏭️ Skipped | $skipped |" >> $GITHUB_STEP_SUMMARY
echo "| **Total** | **$total_tests** |" >> $GITHUB_STEP_SUMMARY
echo "$total_tests $passed $failed $skipped"
}

# Parse both files
read -r unit_tests unit_passed unit_failed unit_skipped <<< "$(parse_json "$UNIT_JSON" "Unit")"
read -r int_tests int_passed int_failed int_skipped <<< "$(parse_json "$INTEGRATION_JSON" "Integration")"

# Calculate totals
total_tests=$((unit_tests + int_tests))
total_passed=$((unit_passed + int_passed))
total_failed=$((unit_failed + int_failed))
total_skipped=$((unit_skipped + int_skipped))

# Display detailed breakdown
echo "### Summary by Test Type" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Test Type | Passed | Failed | Skipped | Total |" >> $GITHUB_STEP_SUMMARY
echo "|-----------|--------|--------|---------|-------|" >> $GITHUB_STEP_SUMMARY

if [ -f "$UNIT_JSON" ]; then
echo "| 🔧 Unit Tests | $unit_passed | $unit_failed | $unit_skipped | $unit_tests |" >> $GITHUB_STEP_SUMMARY
fi

if [ -f "$INTEGRATION_JSON" ]; then
echo "| 🔗 Integration Tests | $int_passed | $int_failed | $int_skipped | $int_tests |" >> $GITHUB_STEP_SUMMARY
fi

echo "| **Total** | **$total_passed** | **$total_failed** | **$total_skipped** | **$total_tests** |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY

# Overall status
echo "### Overall Status" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Status | Count |" >> $GITHUB_STEP_SUMMARY
echo "|--------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| ✅ Passed | $total_passed |" >> $GITHUB_STEP_SUMMARY
echo "| ❌ Failed | $total_failed |" >> $GITHUB_STEP_SUMMARY
echo "| ⏭️ Skipped | $total_skipped |" >> $GITHUB_STEP_SUMMARY
echo "| **Total** | **$total_tests** |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY

# List failed tests if any
if [ $total_failed -gt 0 ]; then
echo "### ❌ Failed Tests" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY

# List failed tests if any
if [ "$failed" -gt 0 ]; then
echo "### ❌ Failed Tests" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY

if [ -s "$failed_tests_file" ]; then
while IFS= read -r test; do
echo "- \`$test\`" >> $GITHUB_STEP_SUMMARY
done < "$failed_tests_file"
else
echo "_Unable to parse individual test names_" >> $GITHUB_STEP_SUMMARY
failed_tests_file=$(mktemp)

# Extract failed tests from both files
for json_file in "$UNIT_JSON" "$INTEGRATION_JSON"; do
if [ -f "$json_file" ]; then
if command -v jq &> /dev/null; then
jq -r '.testResults[]? | select(.status == "failed") | .assertionResults[]? | select(.status == "failed") | "\(.ancestorTitles | join(" > ")) > \(.title)"' "$json_file" >> "$failed_tests_file" 2>/dev/null || true
else
# Basic fallback without jq
grep -oP '"fullName":\s*"\K[^"]*' "$json_file" | while read -r line; do
if echo "$line" | grep -q "failed"; then
echo "$line" >> "$failed_tests_file"
fi
done 2>/dev/null || true
fi
fi

echo "" >> $GITHUB_STEP_SUMMARY
echo "❌ **Tests failed!**" >> $GITHUB_STEP_SUMMARY
rm -f "$failed_tests_file"
exit 1
done

if [ -s "$failed_tests_file" ]; then
while IFS= read -r test; do
echo "- \`$test\`" >> $GITHUB_STEP_SUMMARY
done < "$failed_tests_file"
else
echo "✅ **All tests passed!**" >> $GITHUB_STEP_SUMMARY
echo "_Unable to parse individual test names_" >> $GITHUB_STEP_SUMMARY
fi


echo "" >> $GITHUB_STEP_SUMMARY
echo "❌ **Tests failed!**" >> $GITHUB_STEP_SUMMARY
rm -f "$failed_tests_file"
else
echo "⚠️ No test results found at: $JSON_FILE" >> $GITHUB_STEP_SUMMARY
exit 1
else
echo "✅ **All tests passed!**" >> $GITHUB_STEP_SUMMARY
fi

22 changes: 18 additions & 4 deletions .github/workflows/run-express-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@ on:
pull_request_target:
branches:
- development
paths:
- 'server/express/**'
push:
branches:
- development
paths:
- 'server/express/**'

jobs:
test:
Expand All @@ -33,24 +37,34 @@ jobs:
- name: Install dependencies
run: npm install

- name: Run tests
run: npm test -- --json --outputFile=test-results.json || true
- name: Run unit tests
run: npm run test:unit -- --json --outputFile=test-results-unit.json || true
env:
MONGODB_URI: ${{ secrets.MFLIX_URI }}

- name: Run integration tests
run: npm run test:integration -- --json --outputFile=test-results-integration.json || true
env:
MONGODB_URI: ${{ secrets.MFLIX_URI }}
ENABLE_SEARCH_TESTS: true
VOYAGE_API_KEY: ${{ secrets.VOYAGE_AI }}

- name: Upload test results
uses: actions/upload-artifact@v4
if: always()
with:
name: test-results
path: |
server/express/coverage/
server/express/test-results.json
server/express/test-results-unit.json
server/express/test-results-integration.json
retention-days: 30

- name: Generate Test Summary
if: always()
working-directory: .
run: |
chmod +x .github/scripts/generate-test-summary-jest.sh
.github/scripts/generate-test-summary-jest.sh server/express/test-results.json
.github/scripts/generate-test-summary-jest.sh \
server/express/test-results-unit.json \
server/express/test-results-integration.json
6 changes: 5 additions & 1 deletion server/express/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,8 @@ PORT=3001
NODE_ENV=development

# CORS Configuration (frontend URL)
CORS_ORIGIN=http://localhost:3000
CORS_ORIGIN=http://localhost:3000

# Optional: Enable MongoDB Search tests
# Uncomment the following line to enable Search tests
# ENABLE_SEARCH_TESTS=true
4 changes: 4 additions & 0 deletions server/express/jest.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
"**/__tests__/**/*.ts",
"**/?(*.)+(spec|test).ts"
],
"testPathIgnorePatterns": [
"/node_modules/",
"/tests/integration/"
],
"transform": {
"^.+\\.ts$": "ts-jest"
},
Expand Down
15 changes: 15 additions & 0 deletions server/express/jest.integration.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"preset": "ts-jest",
"testEnvironment": "node",
"roots": ["<rootDir>/tests/integration"],
"testMatch": [
"**/integration/**/*.test.ts",
"**/integration/**/*.spec.ts"
],
"transform": {
"^.+\\.ts$": "ts-jest"
},
"setupFilesAfterEnv": ["<rootDir>/tests/integration/setup.ts"],
"testTimeout": 60000
}

3 changes: 3 additions & 0 deletions server/express/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"test:watch": "jest --watch",
"test:coverage": "jest --coverage",
"test:unit": "jest tests/controllers",
"test:integration": "jest --config jest.integration.config.json",
"test:verbose": "jest --verbose",
"test:silent": "jest --silent"
},
Expand All @@ -30,9 +31,11 @@
"@types/express": "^4.17.21",
"@types/jest": "^29.5.14",
"@types/node": "^20.10.5",
"@types/supertest": "^6.0.3",
"@types/swagger-jsdoc": "^6.0.4",
"@types/swagger-ui-express": "^4.1.8",
"jest": "^29.7.0",
"supertest": "^7.1.4",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.2",
"typescript": "^5.3.3"
Expand Down
9 changes: 7 additions & 2 deletions server/express/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,5 +161,10 @@ process.on("SIGTERM", () => {
process.exit(0);
});

// Start the server
startServer();
// Export the app for testing
export { app };

// Only start the server if this file is run directly (not imported for testing)
if (require.main === module) {
startServer();
}
17 changes: 10 additions & 7 deletions server/express/src/utils/errorHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,16 @@ export function errorHandler(
): void {
// Log the error for debugging purposes
// In production, we recommend using a logging service
console.error("Error occurred:", {
message: err.message,
stack: err.stack,
url: req.url,
method: req.method,
timestamp: new Date().toISOString(),
});
// Suppress error logging during tests to keep test output clean
if (process.env.NODE_ENV !== "test") {
console.error("Error occurred:", {
message: err.message,
stack: err.stack,
url: req.url,
method: req.method,
timestamp: new Date().toISOString(),
});
}

// Determine the appropriate HTTP status code and error message
const errorDetails = parseErrorDetails(err);
Expand Down
Loading