-
Notifications
You must be signed in to change notification settings - Fork 0
🧪 QA: Add missing test for ComparativeProgressService #350
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: staging
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,29 @@ | ||||||||||||||||||||||||||||||||||
| import { describe, it, expect, vi, beforeEach } from "vitest" | ||||||||||||||||||||||||||||||||||
| import { ComparativeProgressService } from "../ComparativeProgressService" | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| describe("ComparativeProgressService", () => { | ||||||||||||||||||||||||||||||||||
| let service: ComparativeProgressService | ||||||||||||||||||||||||||||||||||
| let mockLogger: any | ||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using SuggestionReplace let mockLogger: { info: ReturnType<typeof vi.fn>; error: ReturnType<typeof vi.fn> }
beforeEach(() => {
mockLogger = {
info: vi.fn(),
error: vi.fn()
}
service = new ComparativeProgressService(mockLogger)
})If the real logger type is available, prefer: const mockLogger = {
info: vi.fn(),
error: vi.fn()
} satisfies LoggerReply with "@CharlieHelps yes please" if you’d like me to add a commit with this change.
|
||||||||||||||||||||||||||||||||||
| let mockLogger: any | |
| let mockLogger: ConstructorParameters<typeof ComparativeProgressService>[0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spying on an internal method via (service as any) makes the test brittle and weakens refactoring safety (renames/visibility changes won’t be caught cleanly). This also introduces additional any usage, which can mask incorrect stubbing.
Suggestion
Prefer stubbing at an injected dependency boundary (ideal), or make the data-fetch method protected and override it in a test subclass.
Example (if you can change visibility to protected):
class TestComparativeProgressService extends ComparativeProgressService {
protected override fetchUserProgressData() {
return Promise.resolve([])
}
}
beforeEach(() => {
service = new TestComparativeProgressService(mockLogger)
})At minimum, also ensure spies don’t leak across tests:
afterEach(() => vi.restoreAllMocks())Reply with "@CharlieHelps yes please" if you’d like me to add a commit with a safer stubbing approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Validate no-snapshot path with a non-null benchmark
Using metricName: "test-metric" makes fetchBenchmarkData return null in ComparativeProgressService, so the current assertions can still pass even if the early-return branch for empty snapshots is removed: generateInsights would still produce insufficient_data. This means the test does not actually protect the intended regression scenario and gives false confidence about the no-user-data shortcut path.
Useful? React with 👍 / 👎.
Copilot
AI
Apr 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test uses service as any to spy on a private method. A narrower cast (e.g., to an object type that only exposes fetchUserProgressData) keeps TypeScript checking in place and reduces the chance of the test silently breaking if the method name/signature changes.
| vi.spyOn(service as any, "fetchUserProgressData").mockResolvedValue([]) | |
| const result = await service.analyzeProgress({ | |
| anonymizedUserId: "test-user", | |
| metricName: "test-metric", | |
| cohortId: "test-cohort", | |
| dateRange: { startDate: "2023-01-01", endDate: "2023-01-31" } | |
| }) | |
| const serviceWithFetch = service as Pick<ComparativeProgressService, "fetchUserProgressData"> | |
| vi.spyOn(serviceWithFetch, "fetchUserProgressData").mockResolvedValue([]) | |
| const result = await service.analyzeProgress({ | |
| anonymizedUserId: "test-user", | |
| metricName: "test-metric", | |
| cohortId: "test-cohort", | |
| dateRange: { startDate: "2023-01-01", endDate: "2023-01-31" } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test file uses double quotes, which is inconsistent with the repo’s standard single-quote formatting in TS/Vitest tests (e.g., AnalyticsService.test.ts). Running the repo formatter (oxfmt) / aligning to single quotes will keep formatting consistent and avoid churn in future formatting-only diffs.