|
1 | | -import {beforeEach, describe, expect, it} from 'vitest'; |
| 1 | +import {afterEach, beforeEach, describe, expect, it} from 'vitest'; |
| 2 | +import {provideHttpClient, withInterceptorsFromDi, withXhr} from '@angular/common/http'; |
| 3 | +import {HttpTestingController, provideHttpClientTesting} from '@angular/common/http/testing'; |
2 | 4 | import {TestBed} from '@angular/core/testing'; |
3 | | -import { |
4 | | - DISABLED_STATE, |
5 | | - NORMAL_STATE, |
6 | | - STALE_STATE, |
7 | | - SUPPRESSED_STATE, |
8 | | - UNAVAILABLE_STATE, |
9 | | - ZERO_PERCENT_STATE, |
10 | | -} from '../mock/peer-progress-indicator.mock'; |
| 5 | +import {PeerProgressIndicator} from 'src/app/api/models/peer-progress-indicator'; |
| 6 | +import API_URL from 'src/app/config/constants/apiUrl'; |
| 7 | +import {DISABLED_STATE, NORMAL_STATE, SUPPRESSED_STATE} from '../mock/peer-progress-indicator.mock'; |
11 | 8 | import {PeerProgressIndicatorService} from '../peer-progress-indicator.service'; |
12 | 9 |
|
13 | 10 | describe('PeerProgressIndicatorService', () => { |
14 | 11 | let service: PeerProgressIndicatorService; |
| 12 | + let httpMock: HttpTestingController; |
15 | 13 |
|
16 | 14 | beforeEach(() => { |
17 | 15 | TestBed.configureTestingModule({ |
18 | | - providers: [PeerProgressIndicatorService], |
| 16 | + providers: [ |
| 17 | + PeerProgressIndicatorService, |
| 18 | + provideHttpClient(withXhr(), withInterceptorsFromDi()), |
| 19 | + provideHttpClientTesting(), |
| 20 | + ], |
19 | 21 | }); |
20 | 22 |
|
21 | 23 | service = TestBed.inject(PeerProgressIndicatorService); |
| 24 | + httpMock = TestBed.inject(HttpTestingController); |
22 | 25 | }); |
23 | 26 |
|
24 | | - it('should return normal state', () => { |
25 | | - service.getIndicator(1, 10, 2, 'normal').subscribe((result) => { |
26 | | - expect(result.submittedPercentage).toBe(NORMAL_STATE.submittedPercentage); |
27 | | - expect(result.isSuppressed).toBe(NORMAL_STATE.isSuppressed); |
28 | | - expect(result.isFeatureEnabled).toBe(NORMAL_STATE.isFeatureEnabled); |
29 | | - |
30 | | - // overwritten fields |
31 | | - expect(result.taskDefinitionId).toBe(1); |
32 | | - expect(result.unitId).toBe(10); |
33 | | - expect(result.targetGrade).toBe(2); |
34 | | - }); |
| 27 | + afterEach(() => { |
| 28 | + httpMock.verify({ignoreCancelled: true}); |
35 | 29 | }); |
36 | 30 |
|
37 | | - it('should return zero percent state', () => { |
38 | | - service.getIndicator(2, 20, 1, 'zero').subscribe((result) => { |
39 | | - expect(result.submittedPercentage).toBe(ZERO_PERCENT_STATE.submittedPercentage); |
40 | | - expect(result.isSuppressed).toBe(ZERO_PERCENT_STATE.isSuppressed); |
| 31 | + it('requests the authorised project/task route without client-supplied cohort parameters', () => { |
| 32 | + service.getIndicator(7, 99).subscribe(); |
41 | 33 |
|
42 | | - expect(result.taskDefinitionId).toBe(2); |
43 | | - expect(result.unitId).toBe(20); |
44 | | - expect(result.targetGrade).toBe(1); |
45 | | - }); |
46 | | - }); |
| 34 | + const request = httpMock.expectOne(`${API_URL}/projects/7/task_def_id/99/peer_progress`); |
47 | 35 |
|
48 | | - it('should return suppressed state', () => { |
49 | | - service.getIndicator(3, 30, 0, 'suppressed').subscribe((result) => { |
50 | | - expect(result.submittedPercentage).toBe(SUPPRESSED_STATE.submittedPercentage); |
51 | | - expect(result.isSuppressed).toBe(true); |
52 | | - expect(result.unavailableMessage).toBe(SUPPRESSED_STATE.unavailableMessage); |
| 36 | + expect(request.request.method).toBe('GET'); |
| 37 | + expect(request.request.params.keys()).toEqual([]); |
53 | 38 |
|
54 | | - expect(result.taskDefinitionId).toBe(3); |
55 | | - expect(result.unitId).toBe(30); |
56 | | - expect(result.targetGrade).toBe(0); |
| 39 | + request.flush({ |
| 40 | + task_definition_id: 99, |
| 41 | + unit_id: 1, |
| 42 | + target_grade: 2, |
| 43 | + submitted_percentage: 40, |
| 44 | + is_suppressed: false, |
| 45 | + is_stale: false, |
| 46 | + is_feature_enabled: true, |
| 47 | + last_updated_at: '2026-08-23T00:00:00Z', |
| 48 | + unavailable_message: '', |
57 | 49 | }); |
58 | 50 | }); |
59 | 51 |
|
60 | | - it('should return unavailable state', () => { |
61 | | - service.getIndicator(4, 40, 3, 'unavailable').subscribe((result) => { |
62 | | - expect(result.submittedPercentage).toBe(UNAVAILABLE_STATE.submittedPercentage); |
63 | | - expect(result.unavailableMessage).toBe(UNAVAILABLE_STATE.unavailableMessage); |
| 52 | + it('maps the complete snake-case response and preserves nullable fields', () => { |
| 53 | + let result: PeerProgressIndicator | undefined; |
64 | 54 |
|
65 | | - expect(result.taskDefinitionId).toBe(4); |
66 | | - expect(result.unitId).toBe(40); |
67 | | - expect(result.targetGrade).toBe(3); |
| 55 | + service.getIndicator(7, 99).subscribe((value) => { |
| 56 | + result = value; |
68 | 57 | }); |
69 | | - }); |
70 | 58 |
|
71 | | - it('should return stale state', () => { |
72 | | - service.getIndicator(5, 50, 2, 'stale').subscribe((result) => { |
73 | | - expect(result.submittedPercentage).toBe(STALE_STATE.submittedPercentage); |
74 | | - expect(result.isStale).toBe(true); |
75 | | - expect(result.unavailableMessage).toBe(STALE_STATE.unavailableMessage); |
76 | | - |
77 | | - expect(result.taskDefinitionId).toBe(5); |
78 | | - expect(result.unitId).toBe(50); |
79 | | - expect(result.targetGrade).toBe(2); |
| 59 | + httpMock.expectOne(`${API_URL}/projects/7/task_def_id/99/peer_progress`).flush({ |
| 60 | + task_definition_id: 99, |
| 61 | + unit_id: 1, |
| 62 | + target_grade: null, |
| 63 | + submitted_percentage: null, |
| 64 | + is_suppressed: false, |
| 65 | + is_stale: false, |
| 66 | + is_feature_enabled: true, |
| 67 | + last_updated_at: null, |
| 68 | + unavailable_message: 'Peer progress is currently unavailable.', |
80 | 69 | }); |
81 | | - }); |
82 | | - |
83 | | - it('should return disabled state', () => { |
84 | | - service.getIndicator(6, 60, 1, 'disabled').subscribe((result) => { |
85 | | - expect(result.submittedPercentage).toBe(DISABLED_STATE.submittedPercentage); |
86 | | - expect(result.isFeatureEnabled).toBe(false); |
87 | | - expect(result.unavailableMessage).toBe(DISABLED_STATE.unavailableMessage); |
88 | 70 |
|
89 | | - expect(result.taskDefinitionId).toBe(6); |
90 | | - expect(result.unitId).toBe(60); |
91 | | - expect(result.targetGrade).toBe(1); |
| 71 | + expect(result).toEqual({ |
| 72 | + taskDefinitionId: 99, |
| 73 | + unitId: 1, |
| 74 | + targetGrade: null, |
| 75 | + submittedPercentage: null, |
| 76 | + isSuppressed: false, |
| 77 | + isStale: false, |
| 78 | + isFeatureEnabled: true, |
| 79 | + lastUpdatedAt: null, |
| 80 | + unavailableMessage: 'Peer progress is currently unavailable.', |
92 | 81 | }); |
93 | 82 | }); |
94 | 83 |
|
95 | | - it('should fall back to unavailable state for unknown keys', () => { |
96 | | - service.getIndicator(99, 99, 0, 'unknown' as 'normal').subscribe((result) => { |
97 | | - expect(result.unavailableMessage).toBe(UNAVAILABLE_STATE.unavailableMessage); |
98 | | - expect(result.submittedPercentage).toBeNull(); |
| 84 | + it('cancels the live HTTP request when the caller unsubscribes', () => { |
| 85 | + const subscription = service.getIndicator(7, 99).subscribe(); |
| 86 | + const request = httpMock.expectOne(`${API_URL}/projects/7/task_def_id/99/peer_progress`); |
99 | 87 |
|
100 | | - expect(result.taskDefinitionId).toBe(99); |
101 | | - expect(result.unitId).toBe(99); |
102 | | - expect(result.targetGrade).toBe(0); |
103 | | - }); |
| 88 | + subscription.unsubscribe(); |
| 89 | + |
| 90 | + expect(request.cancelled).toBe(true); |
104 | 91 | }); |
105 | 92 |
|
106 | 93 | describe('getMockUnitSummary', () => { |
|
0 commit comments