Spaces:
Paused
Paused
Download tests/iserv-parse.test.mjs from Luca448/APP-Backend: direct link, hf CLI and curl.
- Browser
- Download file 8.11 kB
-
https://huggingface.co/spaces/Luca448/APP-Backend/resolve/main/tests/iserv-parse.test.mjs
- Command line
-
hf download hf://spaces/Luca448/APP-Backend/tests/iserv-parse.test.mjs
-
curl -L -o iserv-parse.test.mjs https://huggingface.co/spaces/Luca448/APP-Backend/resolve/main/tests/iserv-parse.test.mjs
8.11 kB
| import assert from 'node:assert/strict'; | |
| import test, { after, before } from 'node:test'; | |
| import puppeteer from 'puppeteer'; | |
| import { isoFromText, parseAttachmentLinks, parseListHtml, parseTaskHtml } from '../src/api/iserv-parse.js'; | |
| // Fictional pages in the layouts of IServ (older and current), the same the IServ filter project tests its Python | |
| // parsers with. These parsers run inside a browser page, so the tests run them in one. | |
| const LIST_OLDER = `<html><body><table id="crud-table"><thead><tr><th></th><th>Titel</th><th>Beginn</th><th>Abgabe</th><th>Tags</th></tr></thead><tbody> | |
| <tr><td></td><td><a href="/iserv/exercise/show/101">Bruchrechnung üben</a></td><td data-sort="20261001">01.10.2026</td><td data-sort="20261010235900">10.10.2026 23:59</td><td>Mathe</td></tr> | |
| <tr><td></td><td><a href="https://beispiel.iserv.eu/iserv/exercise/show/102">Referat</a></td><td data-sort="20261002">02.10.2026</td><td data-sort="20261015120000">15.10.2026 12:00</td><td>(keine)</td></tr> | |
| <tr class="success"><td></td><td><a href="/iserv/exercise/show/103">Vokabeln Unit 4</a></td><td data-sort="20260928">28.09.2026</td><td data-sort="20261005080000">05.10.2026 08:00</td><td>Englisch</td><td><span title="Abgegeben">✓</span></td></tr> | |
| </tbody></table></body></html>`; | |
| // Current layout: status icon first, no start column, teacher feedback (Rückmeldungen) right after the due date, | |
| // an empty tag as an italic placeholder. | |
| const ROW = ({ status, id, title, due, tags }) => `<tr><td class="iserv-admin-list-field" data-sort="x"> | |
| <span class="text-center text-large" title="${status}"><span class="fal fa-circle-check"></span></span></td> | |
| <td><a href="/iserv/exercise/show/${id}">${title}</a></td> | |
| <td data-sort="${due}"><ul class="list-unstyled"><li>x</li><li><span class="timeAgo" data-date="2026-10-10T23:59:00+02:00">in 7 Tagen</span></li></ul></td> | |
| <td data-sort="1"><i>Rückmeldung von Frau Zimmermann</i></td><td><div class="tags-width">${tags}</div></td><td></td></tr>`; | |
| const LIST_CURRENT = `<html><body><table><thead><tr><th class="list-header"></th><th>Aufgabe</th><th>Abgabetermin</th><th>Rückmeldungen</th><th>Tags</th><th></th></tr></thead><tbody> | |
| ${ROW({ status: 'Erledigt', id: 201, title: 'Gedicht lernen', due: '20261010235900', tags: '<i>keine</i>' })} | |
| ${ROW({ status: 'Neu', id: 202, title: 'Versuchsprotokoll', due: '20261012080000', tags: 'Physik' })} | |
| </tbody></table></body></html>`; | |
| const DATES = `<table class="table"><thead><tr><th>Erstellt von</th><th>Starttermin</th><th>Abgabetermin</th></tr></thead><tbody><tr> | |
| <td><a class="mailto" href="mailto:zimmermann@beispiel.iserv.eu">Frau Zimmermann</a></td><td>01.10.2026 08:00</td> | |
| <td><ul><li>10.10.2026 23:59</li></ul></td></tr></tbody></table>`; | |
| const TASK_PAGE = (left, right) => `<html><body><div role="navigation"><span class="profile-username">Erika Musterfrau</span></div> | |
| <div id="content"><div class="panel panel-default"><div class="row"><div class="col-md-6"><div class="panel-body">${left}</div></div> | |
| <div class="col-md-6"><div class="panel-body">${right}</div></div></div></div> | |
| <div class="panel panel-default"><div class="panel-body"><form name="submission"><div class="text-break-word p-3">Eigene Abgabe Wolf</div></form></div></div> | |
| <div class="panel panel-default"><div class="panel-body"><div class="text-break-word p-3">Rückmeldung von Kaiser: gut gemacht</div></div></div></div></body></html>`; | |
| const DESCRIPTION = `<div><div class="text-break-word pb-0"><p>Lerne das Gedicht <strong>auswendig</strong> bis Freitag.</p><p>Frau Hofmann fragt ab.<br>Viel Erfolg!</p></div></div>`; | |
| const FILES = `<form name="iserv_exercise_attachment"><table><tbody><tr><td><a class="text-break-word" href="/iserv/fs/file/exercise/1">Blatt.pdf</a></td></tr></tbody></table></form>`; | |
| const PAGE_WITH_FILES = TASK_PAGE(DESCRIPTION + '<hr>' + DATES, FILES); | |
| const PAGE_WITHOUT_FILES = TASK_PAGE(DESCRIPTION, '<hr>' + DATES); // no files: the date table sits in the other column | |
| const PAGE_WITHOUT_DESCRIPTION = TASK_PAGE('', '<hr>' + DATES); | |
| const PAGE_OLDER = `<html><body><table><tbody><tr><th>Erstellt von:</th><td>Frau Zimmermann</td></tr><tr><th>Teilnehmer:</th><td>Klasse 7b Ahrens</td></tr></tbody></table> | |
| <div>Beschreibung:</div><div class="text-break-word">Vokabeln lernen.</div> | |
| <div>Rückmeldungen</div><div class="text-break-word">Rückmeldung von Kaiser: gut gemacht</div> | |
| <form name="submission"><div class="text-break-word">Eigene Abgabe Wolf</div></form></body></html>`; | |
| let browser; | |
| let page; | |
| before(async () => { | |
| browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'] }); | |
| page = await browser.newPage(); | |
| }); | |
| after(async () => { | |
| await browser?.close(); | |
| }); | |
| const list = (html) => page.evaluate(parseListHtml, html); | |
| const task = (html) => page.evaluate(parseTaskHtml, html); | |
| test('older list: tags, start and due by header and data-sort, done by the status title', async () => { | |
| assert.deepEqual(await list(LIST_OLDER), { | |
| 101: { tags: 'Mathe', start: '2026-10-01', due: '2026-10-10T23:59', done: false, expired: false }, | |
| 102: { tags: '', start: '2026-10-02', due: '2026-10-15T12:00', done: false, expired: false }, | |
| 103: { tags: 'Englisch', start: '2026-09-28', due: '2026-10-05T08:00', done: true, expired: false }, | |
| }); | |
| }); | |
| test('current list: the column after the due date (teacher feedback) is never taken for tags', async () => { | |
| assert.deepEqual(await list(LIST_CURRENT), { | |
| 201: { tags: '', start: null, due: '2026-10-10T23:59', done: true, expired: false }, | |
| 202: { tags: 'Physik', start: null, due: '2026-10-12T08:00', done: false, expired: false }, | |
| }); | |
| }); | |
| test('task page: only the description, with its paragraphs and line breaks, and the start date', async () => { | |
| const expected = { description: 'Lerne das Gedicht auswendig bis Freitag.\nFrau Hofmann fragt ab.\nViel Erfolg!', start: '2026-10-01T08:00' }; | |
| for (const html of [PAGE_WITH_FILES, PAGE_WITHOUT_FILES]) { | |
| assert.deepEqual(await task(html), expected); | |
| } | |
| }); | |
| test('task page without a description gives "" and never submission or feedback', async () => { | |
| assert.deepEqual(await task(PAGE_WITHOUT_DESCRIPTION), { description: '', start: '2026-10-01T08:00' }); | |
| }); | |
| test('older task page: the block after the "Beschreibung:" label, no start date', async () => { | |
| assert.deepEqual(await task(PAGE_OLDER), { description: 'Vokabeln lernen.', start: null }); | |
| }); | |
| test('status icon "Abgelaufen" marks the task expired, not done', async () => { | |
| const html = `<table><thead><tr><th></th><th>Aufgabe</th><th>Abgabetermin</th></tr></thead><tbody> | |
| ${ROW({ status: 'Abgelaufen', id: 301, title: 'Alt', due: '20260920120000', tags: 'Mathe' })}</tbody></table>`; | |
| const result = await list(html); | |
| assert.equal(result[301].expired, true); | |
| assert.equal(result[301].done, false); | |
| }); | |
| test('attachment links: the download link of each row, the name from the name link, menu toggles skipped', async () => { | |
| const html = `<form name="iserv_exercise_attachment"><table><tbody> | |
| <tr><td><a class="text-break-word" href="/iserv/fs/file/exercise/1">Blatt.pdf</a></td></tr> | |
| <tr><td><a class="text-break-word" href="/iserv/fs/view/9">Bild.png</a></td><td><a data-toggle="dropdown" href="/">⋮</a> | |
| <ul><li><a href="/iserv/fs/download/9">Herunterladen</a></li></ul></td></tr></tbody></table></form> | |
| <form name="submission"><a href="/iserv/fs/file/own/2">Eigene.docx</a></form>`; | |
| assert.deepEqual(await page.evaluate(parseAttachmentLinks, html), [ | |
| { href: '/iserv/fs/file/exercise/1', filename: 'Blatt.pdf' }, | |
| { href: '/iserv/fs/download/9', filename: 'Bild.png' }, | |
| ]); | |
| }); | |
| test('a page without the provided-files form has no attachment links', async () => { | |
| assert.deepEqual(await page.evaluate(parseAttachmentLinks, PAGE_WITHOUT_FILES), []); | |
| }); | |
| test('isoFromText reads dd.mm.yyyy with an optional time', () => { | |
| assert.equal(isoFromText('Do, 24.09.2026 14:30 Uhr'), '2026-09-24T14:30'); | |
| assert.equal(isoFromText('5.10.2026'), '2026-10-05'); | |
| assert.equal(isoFromText('Morgen'), null); | |
| assert.equal(isoFromText(undefined), null); | |
| }); | |