Zeeschuimer
diff --git a/popup/interface.js b/popup/interface.js index 3b8aaa9..c56375a 100644 --- a/popup/interface.js +++ b/popup/interface.js @@ -351,16 +351,29 @@ async function button_handler(event) { } else if (event.target.matches('.reset-all')) { await background.db.items.clear(); + } else if (event.target.matches('.dismiss-csv-warning')) { + const warning = document.getElementById('csv-warning'); + if(warning) warning.hidden = true; + } else if (event.target.matches('.download-format')) { const format = event.target.getAttribute('data-format'); - const blobber = format === 'csv' ? get_csv_blob : get_ndjson_blob; const extension = format; let platform = event.target.getAttribute('data-platform'); let date = new Date(); event.target.classList.add('loading'); - let blob = await blobber(platform); + let blob; + if(format === 'csv') { + const result = await get_csv_blob(platform); + blob = result.blob; + if(result.skipped > 0) { + console.warn(`Zeeschuimer: skipped ${result.skipped} ${platform} item(s) during CSV export. First reason: ${result.firstReason}`); + show_csv_warning(platform, result.skipped); + } + } else { + blob = await get_ndjson_blob(platform); + } let filename = 'zeeschuimer-export-' + platform + '-' + date.toISOString().split(".")[0].replace(/:/g, "") + '.' + extension; const downloadUrl = window.URL.createObjectURL(blob); const downloadId = await browser.downloads.download({ @@ -637,27 +650,62 @@ function csv_escape(value) { return value; } +/** + * Surface a CSV-export skip warning in the popup. + * + * Shown when the platform's `map_item` raised MapItemException for one or + * more items — typically the platform's response shape has shifted and the + * mapper no longer recognises every field. The user is steered to the + * .ndjson export, which is unaffected because it skips the mapper entirely. + */ +function show_csv_warning(platform, skipped) { + const warning = document.getElementById('csv-warning'); + if(!warning) return; + const message = warning.querySelector('p'); + message.innerText = `Skipped ${skipped} ${platform} item${skipped === 1 ? '' : 's'} in the CSV export — the platform's data format may have changed. Use the .ndjson export to get the full dataset until Zeeschuimer is updated.`; + warning.hidden = false; +} + /** * Get a CSV dump of items * * Returns a Blob with all items in it as CSV rows, mapped via the module's * registered mapper function. A header row is included. * + * Items whose mapper raises MapItemException are skipped and counted; any + * other error propagates. Skip count and the first skip reason are returned + * alongside the blob so the caller can warn the user. Just like 4CAT! + * * @param platform - * @returns {Promise` and +block elements is the usual suspect. If the comparator emits false- +positive diffs on text fields for the four `strip_tags` modules, the +right fix is to normalise whitespace in the comparator's `deep_equal` +rather than chase parser parity. The Selenium tier sits above and +provides the real-Gecko fidelity check. diff --git a/tests/map_item_compare.test.js b/tests/map_item_compare.test.js index 37e3e4c..86ab707 100644 --- a/tests/map_item_compare.test.js +++ b/tests/map_item_compare.test.js @@ -1,40 +1,60 @@ /** - * @jest-environment node + * Compare JS map_item output against 4CAT's Python map_item via dataset keys. * - * This file runs in Node test environment (not jsdom) because undici's - * fetch implementation uses Node-internal APIs (`clearImmediate`, - * `markResourceTiming`, fast-now timers, etc.) that jsdom shadows or - * doesn't expose. Polyfilling them into jsdom is whack-a-mole; node env - * has them all natively. + * For each 4CAT dataset key in FOURCAT_DATASETS, this test: + * 1. fetches /api/dataset/