[Tests][Backend] Fix remaining tests and use better courseCodeToGroupId format

This commit is contained in:
Aaro Koivukangas
2026-09-21 15:24:21 +03:00
committed by Aaro Koivukangas
parent 793bf317e8
commit 7b772e188a
9 changed files with 147 additions and 115 deletions
@@ -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')
@@ -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', () => {
@@ -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')
@@ -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')
@@ -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')
@@ -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),
@@ -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<Record<string, unknown>> }>) =>
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<Record<string, unknown>>) =>
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)
})
@@ -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()]
+5 -4
View File
@@ -69,8 +69,8 @@ export const createStudyRight = (overrides: Partial<StudentStudyRight> = {}): St
})
export const createCourse = (overrides: Partial<StudentCourse> = {}): 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<StudentStudyPlan> = {}): Stud
export const createEnrollment = (
overrides: Partial<FormattedStudent['enrollments'][number]> = {}
): 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<Credit> = {}) =>
({
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',