80 lines
3.0 KiB
TypeScript
80 lines
3.0 KiB
TypeScript
import { expect, test } from "bun:test";
|
|
import { SCORING_MODEL } from "./scoring-model";
|
|
import { calculateScoringResult, deriveTrafficLight, type LlmScoringAssessment } from "./scoring";
|
|
|
|
function assessmentWithColor(farbe: "gruen" | "gelb" | "rot" | "unbewertbar"): LlmScoringAssessment {
|
|
return {
|
|
ausschlussgruende: [],
|
|
dimensionen: SCORING_MODEL.map((dimension) => ({
|
|
id: dimension.id,
|
|
subcriteria: dimension.subcriteria.map((subcriterion) => ({
|
|
id: subcriterion.id,
|
|
farbe,
|
|
evidence: farbe === "unbewertbar" ? "" : "Test evidence",
|
|
begruendung: "Test begruendung",
|
|
confidence: 0.9,
|
|
missingReason: farbe === "unbewertbar" ? "Keine belastbaren Angaben" : "",
|
|
})),
|
|
})),
|
|
};
|
|
}
|
|
|
|
test("calculates a green weighted score when all criteria are green", () => {
|
|
const scoring = calculateScoringResult(SCORING_MODEL, assessmentWithColor("gruen"));
|
|
|
|
expect(scoring.gesamtScore).toBe(100);
|
|
expect(scoring.farbe).toBe("gruen");
|
|
expect(scoring.unbewertbareKriterien).toBe(0);
|
|
});
|
|
|
|
test("scores against the maximum achievable by assessable dimensions", () => {
|
|
const assessment = assessmentWithColor("gruen");
|
|
for (const subcriterion of assessment.dimensionen[4]!.subcriteria) {
|
|
subcriterion.farbe = "unbewertbar";
|
|
subcriterion.evidence = "";
|
|
subcriterion.missingReason = "Keine belastbaren Angaben";
|
|
}
|
|
|
|
const scoring = calculateScoringResult(SCORING_MODEL, assessment);
|
|
|
|
expect(scoring.gesamtScore).toBe(100);
|
|
expect(scoring.farbe).toBe("gruen");
|
|
expect(scoring.dimensionen[4]!.score).toBe(0);
|
|
expect(scoring.dimensionen[4]!.scorableWeight).toBe(0);
|
|
expect(scoring.unbewertbareKriterien).toBeGreaterThan(0);
|
|
});
|
|
|
|
test("normalizes a partially assessable dimension by answered criterion weight", () => {
|
|
const assessment = assessmentWithColor("gruen");
|
|
const innovation = assessment.dimensionen.find((dimension) => dimension.id === "innovation")!;
|
|
for (const subcriterion of innovation.subcriteria) {
|
|
if (subcriterion.id === "innovation_output") {
|
|
subcriterion.farbe = "unbewertbar";
|
|
subcriterion.evidence = "";
|
|
subcriterion.missingReason = "Keine belastbaren Angaben";
|
|
}
|
|
}
|
|
|
|
const scoring = calculateScoringResult(SCORING_MODEL, assessment);
|
|
const innovationScore = scoring.dimensionen.find((dimension) => dimension.id === "innovation")!;
|
|
|
|
expect(innovationScore.scorableWeight).toBe(75);
|
|
expect(innovationScore.score).toBe(100);
|
|
expect(scoring.gesamtScore).toBe(100);
|
|
expect(scoring.farbe).toBe("gruen");
|
|
});
|
|
|
|
test("derives red when automatic exclusion reasons are present", () => {
|
|
const scoring = calculateScoringResult(SCORING_MODEL, assessmentWithColor("gruen"));
|
|
|
|
expect(deriveTrafficLight(scoring, ["Stiftung als Bewerber"])).toBe("rot");
|
|
});
|
|
|
|
test("keeps low-scoring non-excluded applications yellow rather than discarded", () => {
|
|
const scoring = calculateScoringResult(SCORING_MODEL, assessmentWithColor("rot"));
|
|
|
|
expect(scoring.gesamtScore).toBe(0);
|
|
expect(scoring.farbe).toBe("gelb");
|
|
expect(deriveTrafficLight(scoring, [])).toBe("gelb");
|
|
});
|