[
{
"name": "plan 1, monthly, 2026-27: 9% over \u00a326,900 / 12, pence dropped",
"args": [
{
"minor": 300000,
"currency": "GBP"
},
"plan-1",
"monthly",
"2026-05-28"
],
"expect": {
"minor": 6800,
"currency": "GBP"
}
},
{
"name": "HMRC's worked example: \u00a3700 a week on plan 1 repays \u00a316",
"args": [
{
"minor": 70000,
"currency": "GBP"
},
"plan-1",
"weekly",
"2026-05-29"
],
"expect": {
"minor": 1600,
"currency": "GBP"
}
},
{
"name": "HMRC's worked example: \u00a32,800 a month on plan 1 repays \u00a350",
"args": [
{
"minor": 280000,
"currency": "GBP"
},
"plan-1",
"monthly",
"2026-05-28"
],
"expect": {
"minor": 5000,
"currency": "GBP"
}
},
{
"name": "plan 2, monthly, 2026-27",
"args": [
{
"minor": 300000,
"currency": "GBP"
},
"plan-2",
"monthly",
"2026-05-28"
],
"expect": {
"minor": 4900,
"currency": "GBP"
}
},
{
"name": "plan 4, monthly, 2026-27",
"args": [
{
"minor": 300000,
"currency": "GBP"
},
"plan-4",
"monthly",
"2026-05-28"
],
"expect": {
"minor": 1600,
"currency": "GBP"
}
},
{
"name": "plan 5 repays from 2026-27: exactly \u00a382.50 drops to \u00a382",
"args": [
{
"minor": 300000,
"currency": "GBP"
},
"plan-5",
"monthly",
"2026-05-28"
],
"expect": {
"minor": 8200,
"currency": "GBP"
}
},
{
"name": "postgraduate loan: 6% over \u00a31,750 a month",
"args": [
{
"minor": 300000,
"currency": "GBP"
},
"postgraduate",
"monthly",
"2026-05-28"
],
"expect": {
"minor": 7500,
"currency": "GBP"
}
},
{
"name": "pay below the threshold repays nothing",
"args": [
{
"minor": 200000,
"currency": "GBP"
},
"plan-1",
"monthly",
"2026-05-28"
],
"expect": {
"minor": 0,
"currency": "GBP"
}
},
{
"name": "the exact monthly threshold, not HMRC's printed \u00a32,241.66: \u00a32,341.66 repays \u00a38, not \u00a39",
"args": [
{
"minor": 234166,
"currency": "GBP"
},
"plan-1",
"monthly",
"2026-05-28"
],
"expect": {
"minor": 800,
"currency": "GBP"
}
},
{
"name": "plan 1 in 2023-24, weekly",
"args": [
{
"minor": 50000,
"currency": "GBP"
},
"plan-1",
"weekly",
"2023-10-06"
],
"expect": {
"minor": 600,
"currency": "GBP"
}
},
{
"name": "plan 1 in 2024-25, monthly",
"args": [
{
"minor": 250000,
"currency": "GBP"
},
"plan-1",
"monthly",
"2024-07-26"
],
"expect": {
"minor": 3700,
"currency": "GBP"
}
},
{
"name": "fortnightly in 2025-26 uses 2/52 of the annual threshold",
"args": [
{
"minor": 150000,
"currency": "GBP"
},
"plan-2",
"fortnightly",
"2025-10-10"
],
"expect": {
"minor": 3600,
"currency": "GBP"
}
},
{
"name": "exactly the fortnightly threshold repays nothing",
"args": [
{
"minor": 109500,
"currency": "GBP"
},
"plan-2",
"fortnightly",
"2025-10-10"
],
"expect": {
"minor": 0,
"currency": "GBP"
}
},
{
"name": "four-weekly in 2025-26 uses 4/52 of the annual threshold",
"args": [
{
"minor": 300000,
"currency": "GBP"
},
"plan-1",
"four-weekly",
"2025-11-14"
],
"expect": {
"minor": 8900,
"currency": "GBP"
}
},
{
"name": "the new tax year's threshold applies from 6 April",
"args": [
{
"minor": 300000,
"currency": "GBP"
},
"plan-1",
"monthly",
"2026-04-06"
],
"expect": {
"minor": 6800,
"currency": "GBP"
}
},
{
"name": "the day before, the old one does",
"args": [
{
"minor": 300000,
"currency": "GBP"
},
"plan-1",
"monthly",
"2026-04-05"
],
"expect": {
"minor": 7400,
"currency": "GBP"
}
},
{
"name": "plan 5 has no threshold before 6 April 2026",
"args": [
{
"minor": 300000,
"currency": "GBP"
},
"plan-5",
"monthly",
"2025-12-28"
],
"expectError": "no student loan threshold for plan-5"
},
{
"name": "a date before the rules this package carries",
"args": [
{
"minor": 300000,
"currency": "GBP"
},
"plan-1",
"monthly",
"2023-04-05"
],
"expectError": "no student loan threshold for plan-1"
},
{
"name": "an unknown plan is an error",
"args": [
{
"minor": 300000,
"currency": "GBP"
},
"plan-3",
"monthly",
"2026-05-28"
],
"expectError": "unknown student loan plan"
},
{
"name": "negative earnings are refused",
"args": [
{
"minor": -1,
"currency": "GBP"
},
"plan-1",
"monthly",
"2026-05-28"
],
"expectError": "earnings must not be negative"
},
{
"name": "another currency is refused",
"args": [
{
"minor": 300000,
"currency": "EUR"
},
"plan-1",
"monthly",
"2026-05-28"
],
"expectError": "must be in GBP"
},
{
"name": "an unknown frequency is refused",
"args": [
{
"minor": 300000,
"currency": "GBP"
},
"plan-1",
"daily",
"2026-05-28"
],
"expectError": "unknown pay frequency"
},
{
"name": "a trailing newline is not part of an ISO date",
"args": [
{
"minor": 300000,
"currency": "GBP"
},
"plan-1",
"monthly",
"2026-05-28\n"
],
"expectError": "payDate must be an ISO date"
},
{
"name": "Arabic-Indic digits are not an ISO date",
"args": [
{
"minor": 300000,
"currency": "GBP"
},
"plan-1",
"monthly",
"٢٠٢٦-٠٥-٢٨"
],
"expectError": "payDate must be an ISO date"
}
]