From 7b772e188ad36ebdc37658b93bc3c0372d654a3e Mon Sep 17 00:00:00 2001 From: Aaro Koivukangas Date: Wed, 26 Aug 2026 10:17:44 +0300 Subject: [PATCH] [Tests][Backend] Fix remaining tests and use better courseCodeToGroupId format --- .../attemptStatistics/mat21003.test.ts | 10 +- .../studentStatistics/mat11002.test.ts | 6 +- .../studentStatistics/mat21003.test.ts | 12 +- .../studentStatistics/tkt10002.test.ts | 8 +- .../populationStatisticsByCourse.test.ts | 19 +- .../tests/services/courses/index.test.ts | 17 +- .../courses/getCreditsForCourses.test.ts | 175 +++++++++++------- .../unit/services/courses/parseCredit.test.ts | 6 +- services/shared/test/utils/formatted.ts | 9 +- 9 files changed, 147 insertions(+), 115 deletions(-) diff --git a/services/backend/tests/api/courses/courseYearlyStats/attemptStatistics/mat21003.test.ts b/services/backend/tests/api/courses/courseYearlyStats/attemptStatistics/mat21003.test.ts index 08d2e32e5..88ade3eb5 100644 --- a/services/backend/tests/api/courses/courseYearlyStats/attemptStatistics/mat21003.test.ts +++ b/services/backend/tests/api/courses/courseYearlyStats/attemptStatistics/mat21003.test.ts @@ -5,9 +5,7 @@ import { yearToYearCode } from '@oodikone/shared/util' import { initTests } from '../../../../utils' import { getCourseYearlyStats, CourseYearlyStats } from '../helpers' -const courseCodeToGroupId = { - MAT21003: 'hy-CU-117375829', -} +const MAT21003 = 'hy-CU-117375829' void describe('Course yearly attempt statistics - MAT21003 (hy-CU-117375394, no substitutions)', () => { let app: Express @@ -18,7 +16,7 @@ void describe('Course yearly attempt statistics - MAT21003 (hy-CU-117375394, no describe('duplicate failed attempts across a large timespan are counted separately', () => { let body: CourseYearlyStats beforeAll(async () => { - body = await getCourseYearlyStats(app, `courses=${courseCodeToGroupId.MAT21003}&substitutions=false`) + body = await getCourseYearlyStats(app, `courses=${MAT21003}&substitutions=false`) }) it('2017-2018 should include a single failed attempt (539036)', () => { @@ -65,7 +63,7 @@ void describe('Course yearly attempt statistics - MAT21003 (hy-CU-117375394, no it('2017-2018 should include a failed attempt (539036)', async () => { const body = await getCourseYearlyStats( app, - `courses=${courseCodeToGroupId.MAT21003}&substitutions=false&fromYearCode=${yearToYearCode(2017)}&toYearCode=${yearToYearCode(2017)}` + `courses=${MAT21003}&substitutions=false&fromYearCode=${yearToYearCode(2017)}&toYearCode=${yearToYearCode(2017)}` ) const year = body.unifyStats.statistics.find(year => year.name === '2017-2018') assert(year && 'enrollments' in year, 'Missing stats for 2017-2018') @@ -79,7 +77,7 @@ void describe('Course yearly attempt statistics - MAT21003 (hy-CU-117375394, no it('2018-2019 should include a failed attempt (539036)', async () => { const body = await getCourseYearlyStats( app, - `courses=${courseCodeToGroupId.MAT21003}&substitutions=false&fromYearCode=${yearToYearCode(2018)}&toYearCode=${yearToYearCode(2018)}` + `courses=${MAT21003}&substitutions=false&fromYearCode=${yearToYearCode(2018)}&toYearCode=${yearToYearCode(2018)}` ) const year = body.unifyStats.statistics.find(year => year.name === '2018-2019') assert(year && 'enrollments' in year, 'Missing stats for 2018-2019') diff --git a/services/backend/tests/api/courses/courseYearlyStats/studentStatistics/mat11002.test.ts b/services/backend/tests/api/courses/courseYearlyStats/studentStatistics/mat11002.test.ts index e0fad7d32..86a165972 100644 --- a/services/backend/tests/api/courses/courseYearlyStats/studentStatistics/mat11002.test.ts +++ b/services/backend/tests/api/courses/courseYearlyStats/studentStatistics/mat11002.test.ts @@ -4,16 +4,14 @@ import { describe, it, beforeAll, assert } from 'vitest' import { initTests } from '../../../../utils' import { calculatePassedAndFailed, getCourseYearlyStats, CourseYearlyStats } from '../helpers' -const courseCodeToGroupId = { - MAT11002: 'hy-CU-117375394', -} +const MAT11002 = 'hy-CU-117375394' void describe('Course yearly statistics - MAT11002 (hy-CU-117375394, no substitutions)', () => { let app: Express let body: CourseYearlyStats beforeAll(async () => { app = await initTests() - body = await getCourseYearlyStats(app, `courses=${courseCodeToGroupId.MAT11002}&combineSubstitutions=false`) + body = await getCourseYearlyStats(app, `courses=${MAT11002}&combineSubstitutions=false`) }) it('should not include students for AY code', () => { diff --git a/services/backend/tests/api/courses/courseYearlyStats/studentStatistics/mat21003.test.ts b/services/backend/tests/api/courses/courseYearlyStats/studentStatistics/mat21003.test.ts index 8dca09c9d..4455d246e 100644 --- a/services/backend/tests/api/courses/courseYearlyStats/studentStatistics/mat21003.test.ts +++ b/services/backend/tests/api/courses/courseYearlyStats/studentStatistics/mat21003.test.ts @@ -5,9 +5,7 @@ import { yearToYearCode } from '@oodikone/shared/util' import { initTests } from '../../../../utils' import { calculatePassedAndFailed, getCourseYearlyStats, CourseYearlyStats } from '../helpers' -const courseCodeToGroupId = { - MAT21003: 'hy-CU-117375829', -} +const MAT21003 = 'hy-CU-117375829' void describe('Course yearly statistics - MAT21003 (no substitutions)', () => { let app: Express @@ -18,7 +16,7 @@ void describe('Course yearly statistics - MAT21003 (no substitutions)', () => { describe('duplicate failed grades across a large timespan are not double-counted', () => { let body: CourseYearlyStats beforeAll(async () => { - body = await getCourseYearlyStats(app, `courses=${courseCodeToGroupId.MAT21003}&substitutions=false`) + body = await getCourseYearlyStats(app, `courses=${MAT21003}&substitutions=false`) }) it('2017-2018 should not include a failed grade', () => { @@ -46,7 +44,7 @@ void describe('Course yearly statistics - MAT21003 (no substitutions)', () => { ])('should include correct years for %s', async (name, from, to) => { const body = await getCourseYearlyStats( app, - `courses=${courseCodeToGroupId.MAT21003}&substitutions=false&fromYearCode=${yearToYearCode(from)}&toYearCode=${yearToYearCode(to)}` + `courses=${MAT21003}&substitutions=false&fromYearCode=${yearToYearCode(from)}&toYearCode=${yearToYearCode(to)}` ) const years: string[] = [] @@ -65,7 +63,7 @@ void describe('Course yearly statistics - MAT21003 (no substitutions)', () => { it('2017-2018 should include a failed grade', async () => { const body = await getCourseYearlyStats( app, - `courses=${courseCodeToGroupId.MAT21003}&substitutions=false&fromYearCode=${yearToYearCode(2017)}&toYearCode=${yearToYearCode(2017)}` + `courses=${MAT21003}&substitutions=false&fromYearCode=${yearToYearCode(2017)}&toYearCode=${yearToYearCode(2017)}` ) const year = body.unifyStats.statistics.find(year => year.name === '2017-2018') assert(year && 'enrollments' in year, 'Missing stats for 2017-2018') @@ -78,7 +76,7 @@ void describe('Course yearly statistics - MAT21003 (no substitutions)', () => { it('2018-2019 should include a failed grade', async () => { const body = await getCourseYearlyStats( app, - `courses=${courseCodeToGroupId.MAT21003}&substitutions=false&fromYearCode=${yearToYearCode(2018)}&toYearCode=${yearToYearCode(2018)}` + `courses=${MAT21003}&substitutions=false&fromYearCode=${yearToYearCode(2018)}&toYearCode=${yearToYearCode(2018)}` ) const year = body.unifyStats.statistics.find(year => year.name === '2018-2019') assert(year && 'enrollments' in year, 'Missing stats for 2018-2019') diff --git a/services/backend/tests/api/courses/courseYearlyStats/studentStatistics/tkt10002.test.ts b/services/backend/tests/api/courses/courseYearlyStats/studentStatistics/tkt10002.test.ts index d62a0a6f3..fc02f0c18 100644 --- a/services/backend/tests/api/courses/courseYearlyStats/studentStatistics/tkt10002.test.ts +++ b/services/backend/tests/api/courses/courseYearlyStats/studentStatistics/tkt10002.test.ts @@ -5,9 +5,7 @@ import { yearToYearCode } from '@oodikone/shared/util' import { initTests } from '../../../../utils' import { calculatePassedAndFailed, getCourseYearlyStats, CourseYearlyStats } from '../helpers' -const courseCodeToGroupId = { - TKT10002: 'hy-CU-118023867', -} +const TKT10002 = 'hy-CU-118023867' void describe('Course yearly statistics - TKT10002 (no substitutions)', () => { let app: Express @@ -20,7 +18,7 @@ void describe('Course yearly statistics - TKT10002 (no substitutions)', () => { beforeAll(async () => { body = await getCourseYearlyStats( app, - `courses=${courseCodeToGroupId.TKT10002}&substitutions=false&fromYearCode=${yearToYearCode(2016)}&toYearCode=${yearToYearCode(2023)}` + `courses=${TKT10002}&substitutions=false&fromYearCode=${yearToYearCode(2016)}&toYearCode=${yearToYearCode(2023)}` ) }) @@ -236,7 +234,7 @@ void describe('Course yearly statistics - TKT10002 (no substitutions)', () => { ])('should include correct stats for one academic year ($0)', async (year, categories, grades) => { const body = await getCourseYearlyStats( app, - `courses=${courseCodeToGroupId.TKT10002}&substitutions=false&fromYearCode=${yearToYearCode(year.split('-').at(0))}&toYearCode=${yearToYearCode(parseInt(year.split('-').at(1)!)) - 1}` + `courses=${TKT10002}&substitutions=false&fromYearCode=${yearToYearCode(year.split('-').at(0))}&toYearCode=${yearToYearCode(parseInt(year.split('-').at(1)!)) - 1}` ) const stats = body.unifyStats.statistics.find(yearStats => yearStats.name === year)! assert('enrollments' in stats, 'Missing field enrollment in statsitics') diff --git a/services/backend/tests/api/population/populationStatisticsByCourse.test.ts b/services/backend/tests/api/population/populationStatisticsByCourse.test.ts index 824861e95..0feb23189 100644 --- a/services/backend/tests/api/population/populationStatisticsByCourse.test.ts +++ b/services/backend/tests/api/population/populationStatisticsByCourse.test.ts @@ -8,10 +8,8 @@ import { PopulationstatisticsbycourseResBody } from '@oodikone/shared/routes/pop import { CreditModel } from '@/models' import { EnrollmentState } from '@oodikone/shared/types' -const courseCodeToGroupId = { - MAT21003: 'hy-CU-117375829', - MAT21005: 'hy-CU-117376344', -} +const MAT21003 = 'hy-CU-117375829' +const MAT21005 = 'hy-CU-117376344' void describe('Population statistics by course MAT21003 + MAT21005 (hy-CU-117375829 + hy-CU-117376344)', () => { let app: Express @@ -45,9 +43,7 @@ void describe('Population statistics by course MAT21003 + MAT21005 (hy-CU-117375 [2023, 21, 1, 0, 36], ])('should return correct amount of students for single year ($0)', async (year, total, passed, failed, enrolled) => { const res = await request(app) - .get( - `/populationstatisticsbycourse?courses=${courseCodeToGroupId.MAT21003}&from=${yearToYearCode(year)}&to=${yearToYearCode(year)}` - ) + .get(`/populationstatisticsbycourse?courses=${MAT21003}&from=${yearToYearCode(year)}&to=${yearToYearCode(year)}`) .set('shib-session-id', 'test') .set('uid', 'basic') .set('hygroupcn', 'grp-oodikone-basic-users') @@ -60,14 +56,14 @@ void describe('Population statistics by course MAT21003 + MAT21005 (hy-CU-117375 assert.strictEqual(body.students.length, total, 'Incorrect amount of students') assert.strictEqual( body.coursestatistics.credits.filter( - credit => body.idToGroupIdMap[credit.course_id] === courseCodeToGroupId.MAT21003 && CreditModel.passed(credit) + credit => body.idToGroupIdMap[credit.course_id] === MAT21003 && CreditModel.passed(credit) ).length, passed, 'Incorrect amount of passed credits' ) assert.strictEqual( body.coursestatistics.credits.filter( - credit => body.idToGroupIdMap[credit.course_id] === courseCodeToGroupId.MAT21003 && CreditModel.failed(credit) + credit => body.idToGroupIdMap[credit.course_id] === MAT21003 && CreditModel.failed(credit) ).length, failed, 'Incorrect amount of failed credits' @@ -75,8 +71,7 @@ void describe('Population statistics by course MAT21003 + MAT21005 (hy-CU-117375 assert.strictEqual( body.coursestatistics.enrollments.filter( enrollment => - body.idToGroupIdMap[enrollment.course_id] === courseCodeToGroupId.MAT21003 && - enrollment.state === EnrollmentState.ENROLLED + body.idToGroupIdMap[enrollment.course_id] === MAT21003 && enrollment.state === EnrollmentState.ENROLLED ).length, enrolled, 'Incorrect amount of enrollments' @@ -85,7 +80,7 @@ void describe('Population statistics by course MAT21003 + MAT21005 (hy-CU-117375 it('should return correct amount of students for a course', async () => { const res = await request(app) - .get(`/populationstatisticsbycourse?courses=${courseCodeToGroupId.MAT21005}&from=70&to=70`) + .get(`/populationstatisticsbycourse?courses=${MAT21005}&from=70&to=70`) .set('shib-session-id', 'test') .set('uid', 'basic') .set('hygroupcn', 'grp-oodikone-basic-users') diff --git a/services/backend/tests/services/courses/index.test.ts b/services/backend/tests/services/courses/index.test.ts index 3425da06e..acb425e13 100644 --- a/services/backend/tests/services/courses/index.test.ts +++ b/services/backend/tests/services/courses/index.test.ts @@ -5,11 +5,8 @@ import { yearToYearCode } from '@oodikone/shared/util' import { Unification } from '@oodikone/shared/types' import { getRelevantCourseIdMap } from '@/services/courses' -const courseCodeToGroupId = { - MAT11001: 'hy-CU-117375151', - CSM14204: 'hy-CU-119366777', - MAT21018: 'hy-CU-117377764', -} +const CSM14204 = 'hy-CU-119366777' +const MAT21018 = 'hy-CU-117377764' void describe.concurrent('Search and complete substitution groups to codes', () => { beforeAll(async () => { @@ -29,7 +26,7 @@ void describe.concurrent('Search and complete substitution groups to codes', () ] as TestList)( 'should return correct student numbers for a short course (CSM14204, 2019-2023) by $0', async (separate, to, from) => { - const courseIds = await getRelevantCourseIdMap([courseCodeToGroupId.CSM14204], false) + const courseIds = await getRelevantCourseIdMap([CSM14204], false) const res = await findByCourseAndSemesters( Object.keys(courseIds), to, @@ -46,7 +43,7 @@ void describe.concurrent('Search and complete substitution groups to codes', () ['semester', semesterToSemesterCode(2020, 'fall'), semesterToSemesterCode(2023, 'spring')], ['year', yearToYearCode(2020), yearToYearCode(2023)], ] as TestList)('should filter out students outside of 2020-2023 by $0', async (separate, to, from) => { - const courseIds = await getRelevantCourseIdMap([courseCodeToGroupId.CSM14204], false) + const courseIds = await getRelevantCourseIdMap([CSM14204], false) const res = await findByCourseAndSemesters( Object.keys(courseIds), to, @@ -63,7 +60,7 @@ void describe.concurrent('Search and complete substitution groups to codes', () ] as TestList)( 'should return correct student numbers for a longer course (MAT21018, 2017-2021) by $0', async (separate, to, from) => { - const courseIds = await getRelevantCourseIdMap([courseCodeToGroupId.MAT21018], false) + const courseIds = await getRelevantCourseIdMap([MAT21018], false) const res = await findByCourseAndSemesters( Object.keys(courseIds), to, @@ -94,7 +91,7 @@ void describe.concurrent('Search and complete substitution groups to codes', () ] as TestList)( 'should return correct student numbers for a longer course (MAT21018, 2021-2023) by $0', async (separate, to, from) => { - const courseIds = await getRelevantCourseIdMap([courseCodeToGroupId.MAT21018], false) + const courseIds = await getRelevantCourseIdMap([MAT21018], false) const res = await findByCourseAndSemesters( Object.keys(courseIds), to, @@ -133,7 +130,7 @@ void describe.concurrent('Search and complete substitution groups to codes', () describe('should work with specific cases', () => { it('Student with enrollment in -21 and passed grade in -23 should be included in both stats when querying one year at a time (522321)', async () => { - const courseIds = await getRelevantCourseIdMap([courseCodeToGroupId.MAT21018], false) + const courseIds = await getRelevantCourseIdMap([MAT21018], false) const res21 = await findByCourseAndSemesters( Object.keys(courseIds), yearToYearCode(2021), diff --git a/services/backend/tests/unit/services/courses/getCreditsForCourses.test.ts b/services/backend/tests/unit/services/courses/getCreditsForCourses.test.ts index a14fa8c56..5d77d339c 100644 --- a/services/backend/tests/unit/services/courses/getCreditsForCourses.test.ts +++ b/services/backend/tests/unit/services/courses/getCreditsForCourses.test.ts @@ -2,125 +2,153 @@ import { describe, it, assert, vi, afterEach } from 'vitest' import { Op } from 'sequelize' import { CreditTypeCode, Unification } from '@oodikone/shared/types' +import { Credit } from '@oodikone/shared/models' import { createCredit as credit } from '@oodikone/shared/test/utils' -import { StudentModel } from '@/models' +import { CreditModel } from '@/models' import { getCreditsForCourses } from '@/services/courses/creditsAndEnrollmentsOfCourse' -const mockStudents = (students: Array<{ studentnumber: string; credits: Array> }>) => - vi.spyOn(StudentModel, 'findAll').mockResolvedValue(students as any) +const MAT11002 = 'hy-CU-117375394' +const MAT21001 = 'hy-CU-117375754' +const MAT21002 = 'hy-CU-117375793' +const OTHER101 = 'hy-CU-000000000' + +const mockCredits = (credits: Array>) => + vi.spyOn(CreditModel, 'findAll').mockResolvedValue(credits as any) const from = new Date(2000, 0, 1) const to = new Date(2030, 0, 1) -// Tests share a spy on the same StudentModel.findAll, so they must not run concurrently +// Tests share a spy on the same CreditModel.findAll, so they must not run concurrently // (the suite config default is sequence.concurrent: true). void describe('Get credits for courses (unit, mocked db)', { concurrent: false }, () => { afterEach(() => { vi.restoreAllMocks() }) - it('should return no groups without any course codes, without querying credits by course', async () => { - const findAll = mockStudents([{ studentnumber: '111', credits: [credit()] }]) + it('should return no groups when there are no groupId groups to match', async () => { + const findAll = mockCredits([credit()]) - const res = await getCreditsForCourses([], Unification.UNIFY, from, to) + const res = await getCreditsForCourses([], [], Unification.UNIFY, from, to) assert.deepStrictEqual(res, []) assert.strictEqual(findAll.mock.calls.length, 1) }) - it('should query StudentModel with course codes, date range and openness filters', async () => { - const findAll = mockStudents([]) + it('should query CreditModel with course ids, date range and openness filters', async () => { + const findAll = mockCredits([]) - await getCreditsForCourses([['MAT11002'], ['MAT21001', 'MAT21002']], Unification.OPEN, from, to) + await getCreditsForCourses([[MAT11002], [MAT21001, MAT21002]], ['course-1', 'course-2'], Unification.OPEN, from, to) const call = findAll.mock.calls[0][0] as any - const creditInclude = call.include[0] - assert.deepStrictEqual(creditInclude.where.course_code, { [Op.in]: ['MAT11002', 'MAT21001', 'MAT21002'] }) - assert.deepStrictEqual(creditInclude.where.attainment_date, { [Op.between]: [from, to] }) - assert.deepStrictEqual(creditInclude.where.is_open, { [Op.eq]: true }) + assert.deepStrictEqual(call.where.course_id, { [Op.in]: ['course-1', 'course-2'] }) + assert.deepStrictEqual(call.where.attainment_date, { [Op.between]: [from, to] }) + assert.deepStrictEqual(call.where.is_open, { [Op.eq]: true }) }) it('should include both passed and failed credits for a single-code group as one group', async () => { - mockStudents([ - { - studentnumber: '111', - credits: [credit({ credittypecode: CreditTypeCode.FAILED }), credit({ credittypecode: CreditTypeCode.PASSED })], - }, - ]) + mockCredits([credit({ credittypecode: CreditTypeCode.FAILED }), credit({ credittypecode: CreditTypeCode.PASSED })]) - const res = await getCreditsForCourses([['MAT11002']], Unification.UNIFY, from, to) + const res = await getCreditsForCourses([[MAT11002]], ['course-1'], Unification.UNIFY, from, to) assert.strictEqual(res.length, 1) assert.strictEqual(res.flat().length, 2) }) it('should create a separate group per student for a single-code group', async () => { - mockStudents([ - { studentnumber: '111', credits: [credit({ student_studentnumber: '111' })] }, - { studentnumber: '222', credits: [credit({ student_studentnumber: '222' })] }, - ]) + mockCredits([credit({ student_studentnumber: '111' }), credit({ student_studentnumber: '222' })]) - const res = await getCreditsForCourses([['MAT11002']], Unification.UNIFY, from, to) + const res = await getCreditsForCourses([[MAT11002]], ['course-1'], Unification.UNIFY, from, to) assert.strictEqual(res.length, 2) assert.deepStrictEqual(res.map(group => group.map(c => c.student_studentnumber)).sort(), [['111'], ['222']]) }) it('should not create a group for a single course code the student has no credit for', async () => { - mockStudents([{ studentnumber: '111', credits: [credit({ course_code: 'OTHER101' })] }]) + mockCredits([credit({ course_code: 'OTHER101', course: { groupId: OTHER101 } as Credit['course'] })]) - const res = await getCreditsForCourses([['MAT11002']], Unification.UNIFY, from, to) + const res = await getCreditsForCourses([[MAT11002]], ['course-1'], Unification.UNIFY, from, to) assert.deepStrictEqual(res, []) }) it('should only include the passed credits of a substitution group when every code was passed', async () => { - mockStudents([ - { - studentnumber: '111', - credits: [ - credit({ course_code: 'MAT11002', credittypecode: CreditTypeCode.PASSED }), - credit({ course_code: 'MAT21001', credittypecode: CreditTypeCode.APPROVED }), - ], - }, + mockCredits([ + credit({ + course_code: 'MAT11002', + course: { groupId: MAT11002 } as Credit['course'], + credittypecode: CreditTypeCode.PASSED, + }), + credit({ + course_code: 'MAT21001', + course: { groupId: MAT21001 } as Credit['course'], + credittypecode: CreditTypeCode.APPROVED, + }), ]) - const res = await getCreditsForCourses([['MAT11002', 'MAT21001']], Unification.UNIFY, from, to) + const res = await getCreditsForCourses( + [[MAT11002, MAT21001]], + ['course-1', 'course-2'], + Unification.UNIFY, + from, + to + ) assert.strictEqual(res.length, 1) assert.deepStrictEqual(res[0].map(c => c.course_code).sort(), ['MAT11002', 'MAT21001']) }) it('should exclude a partially completed substitution group entirely', async () => { - mockStudents([ - { - studentnumber: '111', - credits: [ - credit({ course_code: 'MAT11002', credittypecode: CreditTypeCode.PASSED }), - credit({ course_code: 'MAT21001', credittypecode: CreditTypeCode.FAILED }), - ], - }, + mockCredits([ + credit({ + course_code: 'MAT11002', + course: { groupId: MAT11002 } as Credit['course'], + credittypecode: CreditTypeCode.PASSED, + }), + credit({ + course_code: 'MAT21001', + course: { groupId: MAT21001 } as Credit['course'], + credittypecode: CreditTypeCode.FAILED, + }), ]) - const res = await getCreditsForCourses([['MAT11002', 'MAT21001']], Unification.UNIFY, from, to) + const res = await getCreditsForCourses( + [[MAT11002, MAT21001]], + ['course-1', 'course-2'], + Unification.UNIFY, + from, + to + ) assert.deepStrictEqual(res, []) }) it('should exclude an earlier failed attempt from a substitution group even when it later passed', async () => { - mockStudents([ - { - studentnumber: '111', - credits: [ - credit({ course_code: 'MAT11002', credittypecode: CreditTypeCode.FAILED }), - credit({ course_code: 'MAT11002', credittypecode: CreditTypeCode.PASSED }), - credit({ course_code: 'MAT21001', credittypecode: CreditTypeCode.PASSED }), - ], - }, + mockCredits([ + credit({ + course_code: 'MAT11002', + course: { groupId: MAT11002 } as Credit['course'], + credittypecode: CreditTypeCode.FAILED, + }), + credit({ + course_code: 'MAT11002', + course: { groupId: MAT11002 } as Credit['course'], + credittypecode: CreditTypeCode.PASSED, + }), + credit({ + course_code: 'MAT21001', + course: { groupId: MAT21001 } as Credit['course'], + credittypecode: CreditTypeCode.PASSED, + }), ]) - const res = await getCreditsForCourses([['MAT11002', 'MAT21001']], Unification.UNIFY, from, to) + const res = await getCreditsForCourses( + [[MAT11002, MAT21001]], + ['course-1', 'course-2'], + Unification.UNIFY, + from, + to + ) assert.strictEqual(res.length, 1) assert.strictEqual(res.flat().length, 2) @@ -131,18 +159,33 @@ void describe('Get credits for courses (unit, mocked db)', { concurrent: false } }) it('should handle independent groups and students together', async () => { - mockStudents([ - { studentnumber: '111', credits: [credit({ student_studentnumber: '111', course_code: 'MAT11002' })] }, - { - studentnumber: '222', - credits: [ - credit({ student_studentnumber: '222', course_code: 'MAT21001', credittypecode: CreditTypeCode.PASSED }), - credit({ student_studentnumber: '222', course_code: 'MAT21002', credittypecode: CreditTypeCode.PASSED }), - ], - }, + mockCredits([ + credit({ + student_studentnumber: '111', + course_code: 'MAT11002', + course: { groupId: MAT11002 } as Credit['course'], + }), + credit({ + student_studentnumber: '222', + course_code: 'MAT21001', + course: { groupId: MAT21001 } as Credit['course'], + credittypecode: CreditTypeCode.PASSED, + }), + credit({ + student_studentnumber: '222', + course_code: 'MAT21002', + course: { groupId: MAT21002 } as Credit['course'], + credittypecode: CreditTypeCode.PASSED, + }), ]) - const res = await getCreditsForCourses([['MAT11002'], ['MAT21001', 'MAT21002']], Unification.UNIFY, from, to) + const res = await getCreditsForCourses( + [[MAT11002], [MAT21001, MAT21002]], + ['course-1', 'course-2', 'course-3'], + Unification.UNIFY, + from, + to + ) assert.strictEqual(res.length, 2) }) diff --git a/services/backend/tests/unit/services/courses/parseCredit.test.ts b/services/backend/tests/unit/services/courses/parseCredit.test.ts index c014fb81c..dd0680d6e 100644 --- a/services/backend/tests/unit/services/courses/parseCredit.test.ts +++ b/services/backend/tests/unit/services/courses/parseCredit.test.ts @@ -1,6 +1,7 @@ import { describe, it, assert } from 'vitest' import { CreditTypeCode } from '@oodikone/shared/types' +import { Credit } from '@oodikone/shared/models' import { createCredit as credit, createStudyRightElementModel } from '@oodikone/shared/test/utils' import { parseCredit } from '@/services/courses' import { SISStudyRightElementModel } from '@/models' @@ -30,7 +31,10 @@ void describe('parseCredit', () => { it('should combine a substitution group into one credit with summed credits', () => { const res = parseCredit( - [credit({ course_code: 'MAT11002', credits: 5 }), credit({ course_code: 'MAT21001', credits: 5 })], + [ + credit({ course_code: 'MAT11002', course: { groupId: 'hy-CU-117375394' } as Credit['course'], credits: 5 }), + credit({ course_code: 'MAT21001', course: { groupId: 'hy-CU-117375754' } as Credit['course'], credits: 5 }), + ], null, 'MAT11002', [studyRightElement()] diff --git a/services/shared/test/utils/formatted.ts b/services/shared/test/utils/formatted.ts index d0000108e..3ec4b1029 100644 --- a/services/shared/test/utils/formatted.ts +++ b/services/shared/test/utils/formatted.ts @@ -69,8 +69,8 @@ export const createStudyRight = (overrides: Partial = {}): St }) export const createCourse = (overrides: Partial = {}): StudentCourse => ({ - course_code: 'MAT001', - date: new Date('2024-09-01'), + course_id: 'hy-CU-000000001-2024-08-01', + date: new Date('2024-08-01'), passed: true, grade: '5', credits: 5, @@ -94,9 +94,9 @@ export const createStudyPlan = (overrides: Partial = {}): Stud export const createEnrollment = ( overrides: Partial = {} ): FormattedStudent['enrollments'][number] => ({ - course_code: 'MAT001', + course_id: 'hy-CU-000000001-2024-08-01', state: EnrollmentState.ENROLLED, - enrollment_date_time: new Date('2024-09-01'), + enrollment_date_time: new Date('2024-08-01'), semestercode: 149, studyright_id: 'sr-1', ...overrides, @@ -113,6 +113,7 @@ export const createCredit = (overrides: Partial = {}) => ({ grade: '5', course_code: 'MAT11002', + course: { groupId: 'hy-CU-117375394' } as Credit['course'], credits: 5, attainment_date: new Date(2020, 0, 1), student_studentnumber: '111',