Skip to content

Commit 23188b3

Browse files
committed
add tests
1 parent 24a5da2 commit 23188b3

11 files changed

Lines changed: 907 additions & 10 deletions

File tree

backend/packages/Upgrade/src/api/controllers/ExperimentController.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1948,6 +1948,6 @@ export class ExperimentController {
19481948
if (!env.mooclets?.enabled) {
19491949
throw new BadRequestError('Mooclet is not enabled in the environment');
19501950
}
1951-
return this.moocletRewardService.getRewardsSummaryForExperiment(id, request);
1951+
return this.moocletRewardService.getRewardsSummaryForExperiment(id, request.logger);
19521952
}
19531953
}

backend/packages/Upgrade/src/api/services/MoocletRewardsService.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import {
1717
} from '../../types/Mooclet';
1818
import { RewardValidator } from '../controllers/validators/RewardValidator';
1919
import { ExperimentRewardsByCondition, ExperimentRewardsSummary } from 'upgrade_types';
20-
import { AppRequest } from 'src/types';
2120
import { MoocletExperimentService } from './MoocletExperimentService';
2221

2322
export interface IRewardResponse {
@@ -215,16 +214,16 @@ export class MoocletRewardsService {
215214

216215
public async getRewardsSummaryForExperiment(
217216
experimentId: string,
218-
request: AppRequest
217+
logger: UpgradeLogger
219218
): Promise<ExperimentRewardsSummary> {
220219
try {
221220
const moocletExperimentRef = await this.moocletExperimentService.getMoocletExperimentRefByUpgradeExperimentId(
222221
experimentId
223222
);
224-
const moocletRewardsResponse = await this.fetchRewardsForExperiment(moocletExperimentRef, request.logger);
225-
return this.createExperimentRewardsSummary(moocletExperimentRef, moocletRewardsResponse, request.logger);
223+
const moocletRewardsResponse = await this.fetchRewardsForExperiment(moocletExperimentRef, logger);
224+
return this.createExperimentRewardsSummary(moocletExperimentRef, moocletRewardsResponse, logger);
226225
} catch (error) {
227-
request.logger.error({ message: 'Error fetching rewards summary for experiment', experimentId, error });
226+
logger.error({ message: 'Error fetching rewards summary for experiment', experimentId, error });
228227
throw error;
229228
}
230229
}

backend/packages/Upgrade/test/unit/controllers/ExperimentController.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import { ExperimentAssignmentService } from '../../../src/api/services/Experimen
1111
import ExperimentAssignmentServiceMock from './mocks/ExperimentAssignmentServiceMock';
1212
import { MoocletExperimentService } from '../../../src/api/services/MoocletExperimentService';
1313
import MoocletExperimentServiceMock from './mocks/MoocletExperimentServiceMock';
14+
import { MoocletRewardsService } from '../../../src/api/services/MoocletRewardsService';
15+
import MoocletRewardsServiceMock from './mocks/MoocletRewardsServiceMock';
1416
import { ImportExportService } from '../../../src/api/services/ImportExportService';
1517
import ImportExportServiceMock from './mocks/ImportExportServiceMock';
1618
import { env } from './../../../src/env';
@@ -37,6 +39,7 @@ describe('Experiment Controller Testing', () => {
3739
Container.set(ExperimentService, new ExperimentServiceMock());
3840
Container.set(ExperimentAssignmentService, new ExperimentAssignmentServiceMock());
3941
Container.set(MoocletExperimentService, new MoocletExperimentServiceMock());
42+
Container.set(MoocletRewardsService, new MoocletRewardsServiceMock());
4043
Container.set(ImportExportService, new ImportExportServiceMock());
4144
});
4245

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { Service } from 'typedi';
2+
3+
@Service()
4+
export default class MoocletRewardsServiceMock {
5+
public async getRewardsSummaryForExperiment(experimentId: string, logger: any): Promise<any> {
6+
return [
7+
{
8+
conditionCode: 'Control',
9+
successes: 10,
10+
failures: 5,
11+
total: 15,
12+
successRate: '66.7%',
13+
order: 0,
14+
},
15+
{
16+
conditionCode: 'Treatment',
17+
successes: 8,
18+
failures: 7,
19+
total: 15,
20+
successRate: '53.3%',
21+
order: 1,
22+
},
23+
];
24+
}
25+
}

backend/packages/Upgrade/test/unit/services/MoocletDataService.test.ts

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,4 +459,109 @@ describe('#MoocletDataService', () => {
459459
);
460460
});
461461
});
462+
463+
describe('#getRewardsForExperiment', () => {
464+
it('should successfully fetch rewards for an experiment', async () => {
465+
const requestBody = {
466+
moocletId: 456,
467+
variableName: 'outcome_var',
468+
};
469+
470+
const mockResponse = {
471+
count: 5,
472+
next: null,
473+
previous: null,
474+
results: [
475+
{ id: '1', version: 100, value: 1.0, variable: 'outcome_var', learner: 'user-1', mooclet: 456 },
476+
{ id: '2', version: 100, value: 0.0, variable: 'outcome_var', learner: 'user-2', mooclet: 456 },
477+
{ id: '3', version: 200, value: 1.0, variable: 'outcome_var', learner: 'user-3', mooclet: 456 },
478+
],
479+
};
480+
481+
jest.spyOn(moocletDataService, 'fetchExternalMoocletsData').mockResolvedValue(mockResponse);
482+
483+
const result = await moocletDataService.getRewardsForExperiment(requestBody, logger);
484+
485+
expect(result).toEqual(mockResponse);
486+
expect(moocletDataService.fetchExternalMoocletsData).toHaveBeenCalledWith(
487+
expect.objectContaining({
488+
method: 'GET',
489+
url: expect.stringContaining('/value?mooclet=456&variable__name=outcome_var'),
490+
}),
491+
logger
492+
);
493+
});
494+
495+
it('should construct correct query parameters with moocletId and variableName', async () => {
496+
const requestBody = {
497+
moocletId: 789,
498+
variableName: 'test_variable',
499+
};
500+
501+
const mockResponse = {
502+
count: 0,
503+
next: null,
504+
previous: null,
505+
results: [],
506+
};
507+
508+
jest.spyOn(moocletDataService, 'fetchExternalMoocletsData').mockResolvedValue(mockResponse);
509+
510+
await moocletDataService.getRewardsForExperiment(requestBody, logger);
511+
512+
expect(moocletDataService.fetchExternalMoocletsData).toHaveBeenCalledWith(
513+
expect.objectContaining({
514+
method: 'GET',
515+
url: expect.stringContaining('mooclet=789'),
516+
}),
517+
logger
518+
);
519+
expect(moocletDataService.fetchExternalMoocletsData).toHaveBeenCalledWith(
520+
expect.objectContaining({
521+
method: 'GET',
522+
url: expect.stringContaining('variable__name=test_variable'),
523+
}),
524+
logger
525+
);
526+
});
527+
528+
it('should handle paginated responses with next page', async () => {
529+
const requestBody = {
530+
moocletId: 456,
531+
variableName: 'outcome_var',
532+
};
533+
534+
const mockResponse = {
535+
count: 100,
536+
next: 'http://api.mooclet.com/next-page',
537+
previous: null,
538+
results: [{ id: '1', version: 100, value: 1.0 }],
539+
};
540+
541+
jest.spyOn(moocletDataService, 'fetchExternalMoocletsData').mockResolvedValue(mockResponse);
542+
543+
const result = await moocletDataService.getRewardsForExperiment(requestBody, logger);
544+
545+
expect(result.next).toBe('http://api.mooclet.com/next-page');
546+
expect(result.count).toBe(100);
547+
});
548+
549+
it('should throw error when fetchExternalMoocletsData fails', async () => {
550+
const requestBody = {
551+
moocletId: 456,
552+
variableName: 'outcome_var',
553+
};
554+
555+
const mockError = new Error('API connection failed');
556+
jest.spyOn(moocletDataService, 'fetchExternalMoocletsData').mockRejectedValue(mockError);
557+
558+
await expect(moocletDataService.getRewardsForExperiment(requestBody, logger)).rejects.toThrow(
559+
'API connection failed'
560+
);
561+
});
562+
563+
afterAll(() => {
564+
jest.restoreAllMocks();
565+
});
566+
});
462567
});

0 commit comments

Comments
 (0)