Tests
npm testThe tests cover the rules that decide what counts as learning and the academic arithmetic — the places where a silent bug would make the app lie to the student. They also check that every interface string has a translation.
| File | Tests | What it guarantees |
|---|---|---|
tests/learning.test.mjs | 16 | Mastery only from unaided tests (R7); practice with help kept apart; the relies-on-help warning; overconfidence (R6) and the order on Progress; ECTS × deficit allocation with a 10% floor (R9); priority for the nearest exam and the day before (R3); a weak foundation adds time without touching mastery; correct answers never exceed attempts |
tests/curriculum.test.mjs | 17 | ECTS-weighted average, truncated (checked against a real transcript: 16.57 over 78 ECTS); the grade needed not to lower your average and to reach a target; elective groups; official rounding; continuous assessment with minimum grades; resit and special period; next assessment; prerequisites; the degree record → plan link |
tests/backup.test.mjs | 4 | A backup restores everything except the owner; files from another app, non-JSON files and files from future versions are rejected; invalid rows are discarded |
tests/import.test.mjs | 2 | The AI output from the photo import is cleaned (grades 0–20, ISO dates, empty rows removed); only JPEG/PNG/WebP images |
tests/i18n.test.mjs | 4 | Every interface string and every server message (Worker API and npm start) has an English translation; translations keep the same {placeholders} and HTML tags as the Portuguese original |
43 tests in total. tests/i18n-keys.mjs is not a test: it collects the strings the interface uses, and running node tests/i18n-keys.mjs lists any that are missing from the dictionary.
Grades use the Portuguese 0–20 scale, where 9.5 is a pass; averages are weighted by ECTS credits.
Mutations
A passing test proves nothing if it would also pass with the rule broken. So each rule was deliberately broken and at least one test was confirmed to fail:
| Mutation | Caught |
|---|---|
| Mastery counts tests taken with help / counts practice | ✅ |
| Overconfidence threshold removed | ✅ |
| 10% floor not applied | ✅ |
| Deficit ignores mastery | ✅ |
| Exam window ignored / day before off by one | ✅ |
| Progress ignores overconfidence | ✅ |
| Relies-on-help warning never fires | ✅ |
| Unweighted average / rounded instead of truncated | ✅ |
| Minimum grade ignored / resit does not replace / fixed pass mark | ✅ |
| Elective groups counted twice | ✅ |
| "Not to lower your average" rounded down | ✅ |
| Weak foundation ignores "not taken yet" or the threshold | ✅ |
| After failing, the regular exam period still sets the date | ✅ (test added when this mutation survived) |
| Derived date saved as manual | ✅ |
When you change a rule, repeat the exercise: break it, run npm test, confirm it fails.
Documentation screenshots
The images on this site are generated by a script, with a fictional student:
cd docs
npm install
npm run screenshotsThe script starts the local server, seeds demo data, mocks server responses where needed (for example, the all-green status panel) and saves each screen with the Edge or Chrome already installed — in Portuguese to docs/public/screenshots/ and in English to docs/public/screenshots/en/. When the interface changes, run it again.