Test backend#16
Conversation
- Set up Jest + Supertest for Express + TypeScript backend - Refactored app/index separation to enable testing - Mocked Firebase auth middleware to inject req.user.uid - Added isolated MongoDB testing using mongodb-memory-server - Implemented integration tests for health, user, and history endpoints - Verified ownership-based delete with proper 204 response - Added coverage reporting and validated test scope
There was a problem hiding this comment.
Pull request overview
This PR sets up automated testing infrastructure for the backend with Jest/Supertest, performs code cleanup including formatting improvements and removal of unused code, and configures GitHub Actions for continuous integration.
Changes:
- Added comprehensive test suite with Jest, Supertest, and MongoDB memory server for isolated testing
- Extracted Express app configuration into a separate
app.tsfile for better testability - Improved code quality with trailing commas, formatting fixes, and typo corrections
- Added GitHub Actions workflow for automated test execution on pull requests
Reviewed changes
Copilot reviewed 25 out of 27 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| server/src/app.ts | New file extracting Express app configuration from index.ts for testability |
| server/src/index.ts | Simplified to only handle database connection and server startup |
| server/src/tests/*.test.ts | Added test suites for health, history, and user endpoints |
| server/src/tests/setup/*.ts | Test utilities for database setup and authentication mocking |
| server/jest.config.js | Jest configuration with ts-jest preset and coverage settings |
| server/package.json | Added testing dependencies and npm scripts for test execution |
| .github/workflows/test.yml | CI workflow for running backend tests (contains syntax error) |
| server/src/middlewares/auth.ts | Removed whitespace inconsistencies and unused variable assignment |
| server/src/controllers/history.controller.ts | Changed DELETE response to 204 (No Content) and removed unused import |
| server/src/controllers/health.controller.ts | Changed response format from plain text to JSON |
| server/src/controllers/upload.controller.ts | Improved error message and removed history from response payload |
| server/src/controllers/user.controller.ts | Renamed function from getUserRecords to getUserRecord for accuracy |
| server/src/routes/user.routes.ts | Updated import to match renamed controller function |
| server/src/routes/history.routes.ts | Removed commented code and corrected file path in comment |
| server/src/validators/history.schema.ts | Deleted file containing unused validation schema |
| server/src/validators/prediction.schema.ts | Added missing trailing semicolon |
| server/src/models/User.models.ts | Added trailing commas for consistency |
| client/src/pages/UserAccount.jsx | Fixed typos in comments and added % symbol to confidence display |
| client/src/components/Result.jsx | Added % symbol to confidence display |
| client/src/components/UploadBox.jsx | Reduced max file size from 10MB to 5MB |
| server/.gitignore | Added coverage directory |
| .gitignore | Added images directory |
| revision.md | Updated documentation about testing and CI |
Comments suppressed due to low confidence (1)
server/src/controllers/upload.controller.ts:95
- The upload controller now lacks test coverage while other controllers (health, history, user) have tests. Consider adding tests for the uploadImage function to ensure proper validation, error handling, and integration with the ML prediction service.
export const uploadImage = async (req: AuthRequest, res: Response) => {
try {
if (!req.file) {
res.status(400).json({ error: "No file uploaded" });
return;
}
// S1. SEND IMAGE TO MODEL
// Create formData for predict request to FastAPI
const formData = new FormData();
const modelType = req.body.modelType;
const image = req.file.buffer;
if (modelType !== "bird" &&
modelType !== "animal" &&
modelType !== "plant"
) {
res.status(400).json({ error: "Invalid modelType" });
return;
}
// append image & modelType
formData.append("image", image, {
filename: req.file.originalname,
contentType: req.file.mimetype,
});
formData.append("modelType", modelType);
// Send req to fastapi microservice
const FAST_URL = process.env.FAST_API_URL ||
`http://localhost:5000/predict`;
// S2. GET PREDICTION RESULTS
const result = await axios.post(
FAST_URL,
formData,
{ headers: formData.getHeaders() }
);
// axios calls are auto res.json()-ed
// result.data = {
// "label": label,
// "confidence": confidence,
// "info": species_info
// }
const response = result.data;
if (response.error) {
res.status(500).json({ error: response.error });
return;
}
// S3. ADD PREDICTION RECORD TO HISTORY
// parse req.body safely (zod validates req body)
const validateResponse = MLPredictionSchema.safeParse(response);
if (!validateResponse.success) {
res.status(500).json({ error: "Prediction validation failed" });
return;
}
const prediction = {
label: response.label,
confidence: response.confidence,
};
const { uid, name } = req.user!;
const history = await History.create({
uid,
modelType,
prediction
});
res.json({
name,
label: response.label,
confidence: response.confidence,
info: response.info,
});
} catch (err) {
// console.error(err);
if (!res.headersSent) {
res.status(500).json({ error: "Server error" });
}
return;
}
};
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| name: Backend Tests | ||
|
|
||
| on: | ||
| pull_request |
There was a problem hiding this comment.
The workflow trigger is missing a colon after 'pull_request'. This will cause a YAML syntax error and the workflow will not run. Change 'pull_request' to 'pull_request:' or add specific activity types if needed (e.g., 'pull_request: [opened, synchronize]').
| pull_request | |
| pull_request: |
| await User.create({ | ||
| uid, | ||
| name: 'test', | ||
| email: 'abc@test.com', | ||
| }); |
There was a problem hiding this comment.
Test isolation issue: the user test creates a User record but doesn't clean it up between tests. This can cause tests to interfere with each other or fail on subsequent runs. Add a cleanup step using afterEach or beforeEach to clear the User collection.
Just testing CI....