tests: Add tests and some other changes
All checks were successful
Remote Deploy / deploy (push) Successful in 5s
All checks were successful
Remote Deploy / deploy (push) Successful in 5s
This commit is contained in:
@@ -50,7 +50,7 @@ const makeResult = (teacherCode, spec, teacherMap) => {
|
|||||||
const { name } = resolveTeacher(teacherCode, teacherMap);
|
const { name } = resolveTeacher(teacherCode, teacherMap);
|
||||||
const type = spec ? (spec.kind === "range" ? "range" : "single") : "wholeDay";
|
const type = spec ? (spec.kind === "range" ? "range" : "single") : "wholeDay";
|
||||||
const hours = spec ? spec.value : null;
|
const hours = spec ? spec.value : null;
|
||||||
return { teacher: name, teacherCode, type, hours };
|
return { teacher: name, teacherCode: teacherCode.toLowerCase(), type, hours };
|
||||||
};
|
};
|
||||||
|
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
@@ -58,18 +58,15 @@ const makeResult = (teacherCode, spec, teacherMap) => {
|
|||||||
// -------------------------------
|
// -------------------------------
|
||||||
const processTeacherList = (teacherListStr, spec, teacherMap) => {
|
const processTeacherList = (teacherListStr, spec, teacherMap) => {
|
||||||
let results = [];
|
let results = [];
|
||||||
|
const teachers = teacherListStr.split(/[,;]\s*/).filter(Boolean);
|
||||||
|
|
||||||
if (teacherListStr.includes(",")) {
|
if (teacherListStr.includes(";")) {
|
||||||
const teachers = teacherListStr.split(/\s*,\s*/).filter(Boolean);
|
|
||||||
results = teachers.map((t) => makeResult(t, spec, teacherMap));
|
|
||||||
} else if (teacherListStr.includes(";")) {
|
|
||||||
const teachers = teacherListStr.split(/\s*;\s*/).filter(Boolean);
|
|
||||||
teachers.forEach((t, i) => {
|
teachers.forEach((t, i) => {
|
||||||
const resSpec = i === teachers.length - 1 ? spec : null;
|
const resSpec = i === teachers.length - 1 ? spec : null;
|
||||||
results.push(makeResult(t, resSpec, teacherMap));
|
results.push(makeResult(t, resSpec, teacherMap));
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
results.push(makeResult(teacherListStr, spec, teacherMap));
|
results = teachers.map((t) => makeResult(t, spec, teacherMap));
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
@@ -104,6 +101,23 @@ export default function parseAbsence(input, teacherMap = {}) {
|
|||||||
markConsumed(matchStart, matchEnd);
|
markConsumed(matchStart, matchEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const teacherExkRe = /([A-Za-z]+)-exk/gi;
|
||||||
|
while ((m = teacherExkRe.exec(s)) !== null) {
|
||||||
|
const matchStart = m.index;
|
||||||
|
const matchEnd = teacherExkRe.lastIndex;
|
||||||
|
if (isConsumed(matchStart)) continue;
|
||||||
|
|
||||||
|
const teacherCode = m[1];
|
||||||
|
const { name } = resolveTeacher(teacherCode, teacherMap);
|
||||||
|
results.push({
|
||||||
|
teacher: name,
|
||||||
|
teacherCode: teacherCode.toLowerCase(),
|
||||||
|
type: "exkurze",
|
||||||
|
hours: null,
|
||||||
|
});
|
||||||
|
markConsumed(matchStart, matchEnd);
|
||||||
|
}
|
||||||
|
|
||||||
// Standalone teachers → whole day
|
// Standalone teachers → whole day
|
||||||
const teacherOnlyRe = /([A-Za-z]+(?:[,;]\s?[A-Za-z]+)*)/g;
|
const teacherOnlyRe = /([A-Za-z]+(?:[,;]\s?[A-Za-z]+)*)/g;
|
||||||
while ((m = teacherOnlyRe.exec(s)) !== null) {
|
while ((m = teacherOnlyRe.exec(s)) !== null) {
|
||||||
|
|||||||
@@ -20,6 +20,15 @@ app.get('/', async (_, res) => {
|
|||||||
res.json(data);
|
res.json(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.get('/versioned/v1', async (_, res) => {
|
||||||
|
const dataStr = await fs.readFile(path.join(process.cwd(), "db", "current.json"), "utf8");
|
||||||
|
const data = JSON.parse(dataStr);
|
||||||
|
|
||||||
|
data["status"]["currentUpdateSchedule"] = getCurrentInterval();
|
||||||
|
|
||||||
|
res.json(data);
|
||||||
|
});
|
||||||
|
|
||||||
app.get("/status", async (_, res) => {
|
app.get("/status", async (_, res) => {
|
||||||
const dataStr = await fs.readFile(path.resolve("./volume/customState.json"), {encoding: "utf8"});
|
const dataStr = await fs.readFile(path.resolve("./volume/customState.json"), {encoding: "utf8"});
|
||||||
const data = JSON.parse(dataStr);
|
const data = JSON.parse(dataStr);
|
||||||
|
|||||||
71
tests/teachermap.json
Normal file
71
tests/teachermap.json
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
{
|
||||||
|
"ad": "Bc. Daniel Adámek",
|
||||||
|
"bo": "Ing. Anna Bodnárová",
|
||||||
|
"bc": "Ing. Lucie Brčáková",
|
||||||
|
"bu": "Mgr. Lenka Brůnová",
|
||||||
|
"bp": "Ing. Peter Budai",
|
||||||
|
"cf": "RNDr. Mgr. Petr Couf",
|
||||||
|
"cn": "Ing. Richard Černý, CSc.",
|
||||||
|
"dk": "Pavel Dočkal, DiS.",
|
||||||
|
"ex": "Ing. Jana Exnerová",
|
||||||
|
"ha": "Kateřina Haasová",
|
||||||
|
"he": "Mgr. Jan Hehl",
|
||||||
|
"hm": "Doc. Ing. Aleš Herman, PhD.",
|
||||||
|
"ht": "Ing. Jiří Herout",
|
||||||
|
"ho": "Adam Horyna",
|
||||||
|
"hr": "Mgr. Libuše Hrabalová",
|
||||||
|
"ir": "Mgr. Iulia Iarosciuc",
|
||||||
|
"ja": "Mgr. et Mgr. Martin Janečka, Ph.D.",
|
||||||
|
"jk": "David Janoušek",
|
||||||
|
"jd": "Ing. Jiří Jedlička",
|
||||||
|
"jr": "Doc. Ing. Vítězslav Jeřábek, CSc.",
|
||||||
|
"jz": "Mgr. Zbyněk Ježek",
|
||||||
|
"je": "Mgr. Ondřej Ježil",
|
||||||
|
"ju": "Ing. Tomáš Juchelka",
|
||||||
|
"kl": "Ing. Filip Kallmünzer",
|
||||||
|
"ka": "Ing. Ivana Kantnerová",
|
||||||
|
"ks": "Mgr. Svatava Klemová",
|
||||||
|
"kt": "Tomáš Klíma",
|
||||||
|
"kn": "Mgr. Marie Kmoníčková",
|
||||||
|
"kr": "Ing. Zdeněk Křída",
|
||||||
|
"ku": "Ing. Dušan Kuchařík",
|
||||||
|
"ki": "Mgr. Jan Kuchařík",
|
||||||
|
"kp": "RNDr. Olga Kvapilová",
|
||||||
|
"la": "Bc. Marek Lavička",
|
||||||
|
"lc": "Mgr. Pavel Lopocha",
|
||||||
|
"ma": "Ing. Ondřej Mandík",
|
||||||
|
"ms": "Ing. Lukáš Masopust",
|
||||||
|
"mz": "PhDr. Jakub Mazuch",
|
||||||
|
"me": "Michaela Meitnerová",
|
||||||
|
"mo": "Jan Molič",
|
||||||
|
"mr": "Mgr. Jindřiška Mrázová",
|
||||||
|
"mu": "Mgr. Martina Mušecová",
|
||||||
|
"nm": "Vratislav Němec",
|
||||||
|
"ng": "Mgr. Eva Neugebauerová",
|
||||||
|
"nv": "Ing. Jan Novotný, Ph.D.",
|
||||||
|
"pa": "Ing. Bc. Šárka Páltiková",
|
||||||
|
"pp": "Bc. Adam Papula",
|
||||||
|
"pv": "Mgr. Jan Pavlát",
|
||||||
|
"pt": "Ing. Martin Peter",
|
||||||
|
"pr": "Petr Procházka",
|
||||||
|
"rk": "RNDr. Luboš Rašek",
|
||||||
|
"re": "Mgr. Alena Reichlová",
|
||||||
|
"ry": "Mgr. Jitka Rychlíková",
|
||||||
|
"so": "Ing. Oleg Sivkov, Ph.D",
|
||||||
|
"su": "MUDr. Kristina Studénková",
|
||||||
|
"sy": "Ing. Vladislav Sýkora",
|
||||||
|
"se": "Matěj Šedivý",
|
||||||
|
"sd": "Ing. Jana Šedová",
|
||||||
|
"sv": "Ing. Jan Šváb",
|
||||||
|
"uh": "Bc. Karolína Uhlířová",
|
||||||
|
"vd": "Ing. Mgr. Vladimír Váňa, CSc.",
|
||||||
|
"vm": "Bc. Martin Váňa",
|
||||||
|
"va": "Ing. Jan Vaněk",
|
||||||
|
"vl": "Ing. Zdeněk Velich",
|
||||||
|
"vk": "Ing. Jiří Vlček",
|
||||||
|
"vc": "Ing. Antonín Vobecký",
|
||||||
|
"vn": "Ing. Zdeněk Vondra",
|
||||||
|
"we": "Mgr. David Weber",
|
||||||
|
"ze": "Ing. Jan Zelenka",
|
||||||
|
"zn": "Mgr. Tomáš Žilinčár"
|
||||||
|
}
|
||||||
261
tests/test.js
Normal file
261
tests/test.js
Normal file
@@ -0,0 +1,261 @@
|
|||||||
|
import fs from "fs"
|
||||||
|
import parseAbsence from "../scrape/utils/parseAbsence.js";
|
||||||
|
|
||||||
|
const teachermap = JSON.parse(fs.readFileSync("./teachermap.json"))
|
||||||
|
|
||||||
|
|
||||||
|
test("Me", [
|
||||||
|
{
|
||||||
|
teacher: "Michaela Meitnerová",
|
||||||
|
teacherCode: "me",
|
||||||
|
type: "wholeDay",
|
||||||
|
hours: null
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
test("ad", [
|
||||||
|
{
|
||||||
|
teacher: "Bc. Daniel Adámek",
|
||||||
|
teacherCode: "ad",
|
||||||
|
type: "wholeDay",
|
||||||
|
hours: null
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
test("me ad", [
|
||||||
|
{
|
||||||
|
teacher: "Michaela Meitnerová",
|
||||||
|
teacherCode: "me",
|
||||||
|
type: "wholeDay",
|
||||||
|
hours: null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
teacher: "Bc. Daniel Adámek",
|
||||||
|
teacherCode: "ad",
|
||||||
|
type: "wholeDay",
|
||||||
|
hours: null
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
test("me 3", [
|
||||||
|
{
|
||||||
|
teacher: "Michaela Meitnerová",
|
||||||
|
teacherCode: "me",
|
||||||
|
type: "single",
|
||||||
|
hours: 3
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
test("ad 1", [
|
||||||
|
{
|
||||||
|
teacher: "Bc. Daniel Adámek",
|
||||||
|
teacherCode: "ad",
|
||||||
|
type: "single",
|
||||||
|
hours: 1
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
test("me 2-4", [
|
||||||
|
{
|
||||||
|
teacher: "Michaela Meitnerová",
|
||||||
|
teacherCode: "me",
|
||||||
|
type: "range",
|
||||||
|
hours: { from: 2, to: 4 }
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
test("ad 5,6", [
|
||||||
|
{
|
||||||
|
teacher: "Bc. Daniel Adámek",
|
||||||
|
teacherCode: "ad",
|
||||||
|
type: "range",
|
||||||
|
hours: { from: 5, to: 6 }
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
test("me 7+", [
|
||||||
|
{
|
||||||
|
teacher: "Michaela Meitnerová",
|
||||||
|
teacherCode: "me",
|
||||||
|
type: "range",
|
||||||
|
hours: { from: 7, to: 10 }
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
test("me,ad 3-5", [
|
||||||
|
{
|
||||||
|
teacher: "Michaela Meitnerová",
|
||||||
|
teacherCode: "me",
|
||||||
|
type: "range",
|
||||||
|
hours: { from: 3, to: 5 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
teacher: "Bc. Daniel Adámek",
|
||||||
|
teacherCode: "ad",
|
||||||
|
type: "range",
|
||||||
|
hours: { from: 3, to: 5 }
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
test("me;ad 4", [
|
||||||
|
{
|
||||||
|
teacher: "Michaela Meitnerová",
|
||||||
|
teacherCode: "me",
|
||||||
|
type: "wholeDay",
|
||||||
|
hours: null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
teacher: "Bc. Daniel Adámek",
|
||||||
|
teacherCode: "ad",
|
||||||
|
type: "single",
|
||||||
|
hours: 4
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
test("me;ad;bo 2-3", [
|
||||||
|
{
|
||||||
|
teacher: "Michaela Meitnerová",
|
||||||
|
teacherCode: "me",
|
||||||
|
type: "wholeDay",
|
||||||
|
hours: null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
teacher: "Bc. Daniel Adámek",
|
||||||
|
teacherCode: "ad",
|
||||||
|
type: "wholeDay",
|
||||||
|
hours: null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
teacher: "Ing. Anna Bodnárová",
|
||||||
|
teacherCode: "bo",
|
||||||
|
type: "range",
|
||||||
|
hours: { from: 2, to: 3 }
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
test("me 2 ad 4-5", [
|
||||||
|
{
|
||||||
|
teacher: "Michaela Meitnerová",
|
||||||
|
teacherCode: "me",
|
||||||
|
type: "single",
|
||||||
|
hours: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
teacher: "Bc. Daniel Adámek",
|
||||||
|
teacherCode: "ad",
|
||||||
|
type: "range",
|
||||||
|
hours: { from: 4, to: 5 }
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
test("3", [
|
||||||
|
{
|
||||||
|
type: "invalid",
|
||||||
|
teacher: null,
|
||||||
|
teacherCode: null,
|
||||||
|
hours: null,
|
||||||
|
original: "3"
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
test("2-4", [
|
||||||
|
{
|
||||||
|
type: "invalid",
|
||||||
|
teacher: null,
|
||||||
|
teacherCode: null,
|
||||||
|
hours: null,
|
||||||
|
original: "2-4"
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
test("me Xx 3", [
|
||||||
|
{
|
||||||
|
teacher: "Michaela Meitnerová",
|
||||||
|
teacherCode: "me",
|
||||||
|
type: "wholeDay",
|
||||||
|
hours: null
|
||||||
|
},
|
||||||
|
{ teacher: null, teacherCode: 'xx', type: 'single', hours: 3 },
|
||||||
|
]);
|
||||||
|
|
||||||
|
test("me,ad;bo 1-2 ad 5+", [
|
||||||
|
{
|
||||||
|
teacher: "Michaela Meitnerová",
|
||||||
|
teacherCode: "me",
|
||||||
|
type: "wholeDay",
|
||||||
|
hours: null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
teacher: "Bc. Daniel Adámek",
|
||||||
|
teacherCode: "ad",
|
||||||
|
type: "wholeDay",
|
||||||
|
hours: null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
teacher: "Ing. Anna Bodnárová",
|
||||||
|
teacherCode: "bo",
|
||||||
|
type: "range",
|
||||||
|
hours: { from: 1, to: 2 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
teacher: "Bc. Daniel Adámek",
|
||||||
|
teacherCode: "ad",
|
||||||
|
type: "range",
|
||||||
|
hours: { from: 5, to: 10 }
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
test("Me-exk", [
|
||||||
|
{
|
||||||
|
teacher: "Michaela Meitnerová",
|
||||||
|
teacherCode: "me",
|
||||||
|
type: "exkurze",
|
||||||
|
hours: null
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
function test(input, expectedOutput) {
|
||||||
|
const res = parseAbsence(input, teachermap);
|
||||||
|
|
||||||
|
if (!deepEqual(res, expectedOutput)) {
|
||||||
|
console.error("ERROR for input: " + input);
|
||||||
|
console.log(res);
|
||||||
|
console.log(expectedOutput);
|
||||||
|
console.log();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function deepEqual(a, b) {
|
||||||
|
if (a === b) return true;
|
||||||
|
|
||||||
|
if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle arrays (ignore order)
|
||||||
|
if (Array.isArray(a) && Array.isArray(b)) {
|
||||||
|
if (a.length !== b.length) return false;
|
||||||
|
|
||||||
|
const used = new Array(b.length).fill(false);
|
||||||
|
|
||||||
|
return a.every(itemA =>
|
||||||
|
b.some((itemB, i) => {
|
||||||
|
if (used[i]) return false; // don't reuse elements
|
||||||
|
if (deepEqual(itemA, itemB)) {
|
||||||
|
used[i] = true; // mark element as used
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(a) !== Array.isArray(b)) return false;
|
||||||
|
|
||||||
|
const keysA = Object.keys(a);
|
||||||
|
const keysB = Object.keys(b);
|
||||||
|
|
||||||
|
if (keysA.length !== keysB.length) return false;
|
||||||
|
|
||||||
|
return keysA.every(key => keysB.includes(key) && deepEqual(a[key], b[key]));
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user