-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add ability to sort statistics results (#78)
* #76 Add new sort parameter to `getIndividualUserStatistics` * #76 Add full test coverage to the statistics service * #76 Document, refactor and provide test coverage for `quizService.quizScorePercentagesForUser`
- Loading branch information
1 parent
625c08e
commit 9b44d32
Showing
8 changed files
with
439 additions
and
115 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,115 +3,181 @@ import { QuizPersistence } from './quiz.persistence'; | |
import { S3FileService } from '../file/s3.service'; | ||
import { Decimal } from '@prisma/client/runtime/library'; | ||
|
||
jest.mock('./quiz.persistence'); | ||
|
||
const mockPersistence = { | ||
getQuizzesWithUserResults: jest.fn(), | ||
getCompletionScoreWithQuizTypesForUser: jest.fn(), | ||
}; | ||
const mockFileService = {}; | ||
|
||
const sut = new QuizService(mockPersistence as unknown as QuizPersistence, mockFileService as S3FileService); | ||
|
||
describe('QuizService', () => { | ||
beforeEach(() => { | ||
jest.resetAllMocks(); | ||
}); | ||
describe('getQuizzesWithUserResults', () => { | ||
it('must call getQuizzesWithUserResults on persistence with correct arguments and transform the result', async () => { | ||
const persistenceResult = [ | ||
{ | ||
id: 'fake-id-one', | ||
type: 'SHARK', | ||
date: new Date('2023-01-01'), | ||
uploadedAt: new Date('2023-01-02'), | ||
uploadedByUserId: 'fake-user-id', | ||
completions: [], | ||
uploadedByUser: { | ||
id: 'fake-user-id', | ||
email: '[email protected]', | ||
name: 'Joe Blogs', | ||
}, | ||
}, | ||
{ | ||
id: 'fake-id-two', | ||
type: 'BRAINWAVES', | ||
date: new Date('2023-02-01'), | ||
uploadedAt: new Date('2023-03-02'), | ||
uploadedByUserId: 'fake-user-id', | ||
completions: [ | ||
{ | ||
completedAt: new Date('2023-03-10'), | ||
completedBy: [ | ||
{ | ||
user: { | ||
id: 'fake-completion-user-id', | ||
email: '[email protected]', | ||
name: 'Completer', | ||
}, | ||
}, | ||
], | ||
score: new Decimal(10), | ||
}, | ||
], | ||
uploadedByUser: { | ||
id: 'fake-user-id', | ||
email: '[email protected]', | ||
name: 'Joe Blogs', | ||
}, | ||
}, | ||
]; | ||
mockPersistence.getQuizzesWithUserResults.mockImplementationOnce(() => | ||
Promise.resolve({ data: persistenceResult, hasMoreRows: false }), | ||
); | ||
|
||
const actual = await sut.getQuizzesWithUsersResults('[email protected]', 10); | ||
|
||
expect(mockPersistence.getQuizzesWithUserResults).toHaveBeenCalledTimes(1); | ||
expect(mockPersistence.getQuizzesWithUserResults).toHaveBeenCalledWith({ | ||
userEmail: '[email protected]', | ||
limit: 10, | ||
}); | ||
|
||
expect(actual).toEqual({ | ||
data: [ | ||
describe('quiz', () => { | ||
describe('quiz.service', () => { | ||
beforeEach(() => { | ||
jest.restoreAllMocks(); | ||
}); | ||
describe('getQuizzesWithUserResults', () => { | ||
it('must call getQuizzesWithUserResults on persistence with correct arguments and transform the result', async () => { | ||
const persistenceResult = [ | ||
{ | ||
id: 'fake-id-one', | ||
type: 'SHARK', | ||
date: new Date('2023-01-01'), | ||
uploadedAt: new Date('2023-01-02'), | ||
uploadedBy: { | ||
email: '[email protected]', | ||
uploadedByUserId: 'fake-user-id', | ||
completions: [], | ||
uploadedByUser: { | ||
id: 'fake-user-id', | ||
email: '[email protected]', | ||
name: 'Joe Blogs', | ||
}, | ||
myCompletions: [], | ||
}, | ||
{ | ||
id: 'fake-id-two', | ||
type: 'BRAINWAVES', | ||
date: new Date('2023-02-01'), | ||
uploadedAt: new Date('2023-03-02'), | ||
uploadedBy: { | ||
email: '[email protected]', | ||
id: 'fake-user-id', | ||
name: 'Joe Blogs', | ||
}, | ||
myCompletions: [ | ||
uploadedByUserId: 'fake-user-id', | ||
completions: [ | ||
{ | ||
completedAt: new Date('2023-03-10'), | ||
completedBy: [ | ||
{ | ||
id: 'fake-completion-user-id', | ||
email: '[email protected]', | ||
name: 'Completer', | ||
user: { | ||
id: 'fake-completion-user-id', | ||
email: '[email protected]', | ||
name: 'Completer', | ||
}, | ||
}, | ||
], | ||
score: 10, | ||
score: new Decimal(10), | ||
}, | ||
], | ||
uploadedByUser: { | ||
id: 'fake-user-id', | ||
email: '[email protected]', | ||
name: 'Joe Blogs', | ||
}, | ||
}, | ||
], | ||
hasMoreRows: false, | ||
]; | ||
mockPersistence.getQuizzesWithUserResults.mockImplementationOnce(() => | ||
Promise.resolve({ data: persistenceResult, hasMoreRows: false }), | ||
); | ||
|
||
const actual = await sut.getQuizzesWithUsersResults('[email protected]', 10); | ||
|
||
expect(mockPersistence.getQuizzesWithUserResults).toHaveBeenCalledTimes(1); | ||
expect(mockPersistence.getQuizzesWithUserResults).toHaveBeenCalledWith({ | ||
userEmail: '[email protected]', | ||
limit: 10, | ||
}); | ||
|
||
expect(actual).toEqual({ | ||
data: [ | ||
{ | ||
id: 'fake-id-one', | ||
type: 'SHARK', | ||
date: new Date('2023-01-01'), | ||
uploadedAt: new Date('2023-01-02'), | ||
uploadedBy: { | ||
email: '[email protected]', | ||
id: 'fake-user-id', | ||
name: 'Joe Blogs', | ||
}, | ||
myCompletions: [], | ||
}, | ||
{ | ||
id: 'fake-id-two', | ||
type: 'BRAINWAVES', | ||
date: new Date('2023-02-01'), | ||
uploadedAt: new Date('2023-03-02'), | ||
uploadedBy: { | ||
email: '[email protected]', | ||
id: 'fake-user-id', | ||
name: 'Joe Blogs', | ||
}, | ||
myCompletions: [ | ||
{ | ||
completedAt: new Date('2023-03-10'), | ||
completedBy: [ | ||
{ | ||
id: 'fake-completion-user-id', | ||
email: '[email protected]', | ||
name: 'Completer', | ||
}, | ||
], | ||
score: 10, | ||
}, | ||
], | ||
}, | ||
], | ||
hasMoreRows: false, | ||
}); | ||
}); | ||
}); | ||
describe('quizScorePercentagesForUser', () => { | ||
it('must call getCompletionScoreWithQuizTypesForUser on persistence with correct arguments and calculate percentages for the results', async () => { | ||
mockPersistence.getCompletionScoreWithQuizTypesForUser.mockResolvedValueOnce({ | ||
data: [ | ||
{ | ||
id: '1', | ||
quiz: { | ||
type: 'SHARK', | ||
}, | ||
score: new Decimal(10), | ||
}, | ||
{ | ||
id: '2', | ||
quiz: { | ||
type: 'BRAINWAVES', | ||
}, | ||
score: new Decimal(12.5), | ||
}, | ||
], | ||
hasMoreRows: false, | ||
}); | ||
|
||
const actual = await sut.quizScorePercentagesForUser('[email protected]', 2, 'test-cursor'); | ||
|
||
expect(mockPersistence.getCompletionScoreWithQuizTypesForUser).toHaveBeenCalledTimes(1); | ||
expect(mockPersistence.getCompletionScoreWithQuizTypesForUser).toHaveBeenCalledWith({ | ||
email: '[email protected]', | ||
limit: 2, | ||
afterId: 'test-cursor', | ||
}); | ||
|
||
expect(actual).toEqual({ | ||
stats: [0.5, 0.25], | ||
cursor: undefined, | ||
}); | ||
}); | ||
it('must provide the correct cursor if more data is available', async () => { | ||
mockPersistence.getCompletionScoreWithQuizTypesForUser.mockResolvedValueOnce({ | ||
data: [ | ||
{ | ||
id: '1', | ||
quiz: { | ||
type: 'SHARK', | ||
}, | ||
score: new Decimal(10), | ||
}, | ||
{ | ||
id: '2', | ||
quiz: { | ||
type: 'BRAINWAVES', | ||
}, | ||
score: new Decimal(12.5), | ||
}, | ||
], | ||
hasMoreRows: true, | ||
}); | ||
|
||
const actual = await sut.quizScorePercentagesForUser('[email protected]'); | ||
|
||
expect(actual).toEqual({ | ||
stats: [0.5, 0.25], | ||
cursor: '2', | ||
}); | ||
}); | ||
}); | ||
}); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.