feature(database-connection): Add tests for timetracking and add fallback value to max season for fetching stats
This commit is contained in:
@@ -1,13 +1,25 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { seasons } from '@prisma/client';
|
||||
import { DatabaseService } from './database.service';
|
||||
import { mockReset, MockProxy, mockDeep } from 'jest-mock-extended';
|
||||
import { SeasonInfo } from '../models/aliases';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { TimeTrackerPredicate } from './timetracking.predicate';
|
||||
import { mocked } from 'ts-jest';
|
||||
|
||||
describe('DatabaseService', () => {
|
||||
let service: DatabaseService;
|
||||
const mockedPrismaService: MockProxy<PrismaService> = mockDeep<PrismaService>();
|
||||
|
||||
beforeEach(async () => {
|
||||
mockReset(mockedPrismaService);
|
||||
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [DatabaseService],
|
||||
}).compile();
|
||||
providers: [DatabaseService, PrismaService, TimeTrackerPredicate],
|
||||
})
|
||||
.overrideProvider(PrismaService)
|
||||
.useValue(mockedPrismaService)
|
||||
.compile();
|
||||
|
||||
service = module.get<DatabaseService>(DatabaseService);
|
||||
});
|
||||
@@ -15,4 +27,43 @@ describe('DatabaseService', () => {
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
|
||||
// TODO This will be skipped as Prisma__#client can barely be mocked.
|
||||
// it('fetch season info with season ID given', async () => {
|
||||
// const seasonIdToBeTested = 1;
|
||||
// const mockedValue: seasons = {
|
||||
// season_id: 2,
|
||||
// start_date: new Date('1995-12-17T03:24:00'),
|
||||
// end_date: null
|
||||
// };
|
||||
// const mockedMaxSeasonId = {
|
||||
// max: {
|
||||
// season_id: 2
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// mockedPrismaService.seasons.findUnique.calledWith({
|
||||
// where: {
|
||||
// season_id: Number(seasonIdToBeTested)
|
||||
// }
|
||||
// }).mockImplementation((subset) => {
|
||||
// return new Promise(resolve => resolve(mockedValue));
|
||||
// });
|
||||
//
|
||||
// mockedPrismaService.seasons.aggregate.calledWith({
|
||||
// max: {
|
||||
// season_id: true
|
||||
// }
|
||||
// }).mockImplementation(() => Promise.resolve(mockedMaxSeasonId));
|
||||
//
|
||||
// const expected: SeasonInfo = {
|
||||
// season_id: 2,
|
||||
// maxSeasonId: 2,
|
||||
// start_date: new Date('1995-12-17T03:24:00'),
|
||||
// end_date: null
|
||||
// }
|
||||
// const actual = service.fetchSeasonInfos();
|
||||
//
|
||||
// await expect(actual).resolves.toEqual(expected);
|
||||
// });
|
||||
});
|
||||
|
||||
@@ -6,40 +6,35 @@ import {
|
||||
UserStatsResponse,
|
||||
} from '../models/aliases';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { seasons } from '@prisma/client';
|
||||
|
||||
@Injectable()
|
||||
export class DatabaseService {
|
||||
// private host = process.env.MYSQL_HOST
|
||||
// private port = process.env.MYSQL_PORT
|
||||
// private credentials = {
|
||||
// username: process.env.MYSQL_USERNAME,
|
||||
// password: process.env.MYSQL_PASSWORD
|
||||
// }
|
||||
// private database = process.env.MYSQL_DATABASE
|
||||
|
||||
constructor(
|
||||
private readonly prismaClient: PrismaService,
|
||||
private readonly timetrackerPredicate: TimeTrackerPredicate,
|
||||
) {}
|
||||
|
||||
public fetchSeasonInfos = async (seasonId: string): Promise<SeasonInfo> => {
|
||||
let seasons;
|
||||
return this.prismaClient.seasons
|
||||
.findOne({
|
||||
where: {
|
||||
// eslint-disable-next-line @typescript-eslint/camelcase
|
||||
season_id: Number(seasonId),
|
||||
},
|
||||
})
|
||||
.then(result => (seasons = result))
|
||||
.then(this.fetchMaxSeasonId)
|
||||
.then(result => {
|
||||
seasons.maxSeasonId = result;
|
||||
return seasons;
|
||||
});
|
||||
public fetchSeasonInfos = async (seasonId?: string): Promise<SeasonInfo> => {
|
||||
let maxSeasonId: number;
|
||||
|
||||
return this.fetchMaxSeasonId().then(value => {
|
||||
maxSeasonId = value;
|
||||
return value;
|
||||
})
|
||||
.then(value => this.prismaClient.seasons.findUnique({
|
||||
where: {
|
||||
season_id: (!seasonId ? value : seasonId)
|
||||
}
|
||||
}) as Promise<seasons>)
|
||||
.then((result: SeasonInfo) => {
|
||||
result.maxSeasonId = maxSeasonId;
|
||||
return result;
|
||||
});
|
||||
};
|
||||
|
||||
public fetchStats = async (seasonId: string): Promise<UserStatsResponse> => {
|
||||
public fetchStats = async (seasonId?: string): Promise<UserStatsResponse> => {
|
||||
let response;
|
||||
return this.fetchSeasonInfos(seasonId)
|
||||
.then(result => {
|
||||
@@ -61,18 +56,6 @@ export class DatabaseService {
|
||||
});
|
||||
};
|
||||
|
||||
// public fetchStats = async (seasonId: string): Promise<TableEntry[]> => this.prismaClient.timetracker.findMany({
|
||||
// include: {
|
||||
// user: true,
|
||||
// ranks: true
|
||||
// },
|
||||
// where: {
|
||||
// // eslint-disable-next-line @typescript-eslint/camelcase
|
||||
// season_id: Number(seasonId)
|
||||
// }
|
||||
// })
|
||||
// .then(this.timetrackerPredicate.process);
|
||||
|
||||
fetchTimeTrackerStats: (string) => Promise<TimeTrackerStats[]> = (
|
||||
seasonId: string,
|
||||
) =>
|
||||
|
||||
71
backend/src/database/timetracking.predicate.spec.ts
Normal file
71
backend/src/database/timetracking.predicate.spec.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { TimeTrackerPredicate } from './timetracking.predicate';
|
||||
import { TimeTrackerStats } from '../models/aliases';
|
||||
|
||||
describe('TimeTrackerPredicate', () => {
|
||||
let timeTrackerPredicate: TimeTrackerPredicate;
|
||||
|
||||
beforeEach(() => {
|
||||
timeTrackerPredicate = new TimeTrackerPredicate();
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(timeTrackerPredicate).toBeDefined();
|
||||
});
|
||||
|
||||
it('should process UserStats properly to TableEntry', () => {
|
||||
const input: TimeTrackerStats[] = [
|
||||
{
|
||||
entry_id: 1,
|
||||
user_uid: 'TEST_UUID1',
|
||||
season_id: 1,
|
||||
rank_id: 1,
|
||||
time: 12345,
|
||||
user: {
|
||||
uid: 'TEST_UUID1',
|
||||
name: 'Test User 1'
|
||||
},
|
||||
ranks: {
|
||||
entry_id: 1,
|
||||
season_id: 1,
|
||||
rank_id: 1,
|
||||
rank_name: 'Test Rank 1'
|
||||
}
|
||||
},
|
||||
{
|
||||
entry_id: 2,
|
||||
user_uid: 'TEST_UUID2',
|
||||
season_id: 1,
|
||||
rank_id: 2,
|
||||
time: 123455,
|
||||
user: {
|
||||
uid: 'TEST_UUID2',
|
||||
name: 'Test User 2'
|
||||
},
|
||||
ranks: {
|
||||
entry_id: 1,
|
||||
season_id: 1,
|
||||
rank_id: 2,
|
||||
rank_name: 'Test Rank 2'
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
const expected = [
|
||||
{
|
||||
name: 'Test User 2',
|
||||
onlineTime: "1d 10h 17m 35s",
|
||||
rank: 'Test Rank 2',
|
||||
rawTime: 123455
|
||||
},
|
||||
{
|
||||
name: 'Test User 1',
|
||||
onlineTime: "0d 3h 25m 45s",
|
||||
rank: 'Test Rank 1',
|
||||
rawTime: 12345
|
||||
}
|
||||
];
|
||||
|
||||
const actual = timeTrackerPredicate.process(input);
|
||||
expect(actual).toEqual(expected);
|
||||
})
|
||||
});
|
||||
@@ -1,19 +1,17 @@
|
||||
import { ranks, seasons, timetracker, user } from '@prisma/client';
|
||||
import { Predicate } from 'src/api/predicate';
|
||||
import { Sort } from 'src/api/sort';
|
||||
import { TimeUtil } from 'src/api/timeutil';
|
||||
import { TableEntry } from 'src/models/TableEntry';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
type UserStats = timetracker & { user: user; ranks: ranks };
|
||||
import { TimeTrackerStats } from '../models/aliases';
|
||||
import { Predicate } from '../api/predicate';
|
||||
import { TableEntry } from '../models/TableEntry';
|
||||
import { TimeUtil } from '../api/timeutil';
|
||||
import { Sort } from '../api/sort';
|
||||
|
||||
@Injectable()
|
||||
export class TimeTrackerPredicate
|
||||
implements Predicate<UserStats[], TableEntry[]> {
|
||||
process(input: UserStats[]): TableEntry[] {
|
||||
implements Predicate<TimeTrackerStats[], TableEntry[]> {
|
||||
process(input: TimeTrackerStats[]): TableEntry[] {
|
||||
return input
|
||||
.filter((userStats: UserStats) => userStats.time != null)
|
||||
.map((userStats: UserStats) => {
|
||||
.filter((userStats: TimeTrackerStats) => userStats.time != null)
|
||||
.map((userStats: TimeTrackerStats) => {
|
||||
return {
|
||||
name: userStats.user.name,
|
||||
rawTime: userStats.time,
|
||||
|
||||
Reference in New Issue
Block a user