"""Drive Wonder Ink's print preview through one scenario, headless. usage: wonderink-print-rig.py WONDERINK_COMMAND SCENARIO Run by tools/lab/wonderink-print-check inside the lab, against the command the package installed. It presses the preview's own buttons the way a teacher would, and prints what happened; the check around it asks CUPS what actually arrived. """ import importlib.machinery, importlib.util, sys, time, faulthandler, gc, os faulthandler.enable() path, scenario = sys.argv[1], sys.argv[2] loader = importlib.machinery.SourceFileLoader("wonderink", path) spec = importlib.util.spec_from_loader("wonderink", loader) wi = importlib.util.module_from_spec(spec); loader.exec_module(wi) from pathlib import Path from PyQt6.QtCore import QTimer, QUrl from PyQt6.QtGui import QPdfWriter, QPainter, QFont, QPageSize from PyQt6.QtWidgets import QApplication from PyQt6.QtWebEngineCore import QWebEngineProfile, QWebEngineSettings notes = [] wi.notify = lambda s, b: (notes.append(s), print("NOTIFY", s, "|", b, flush=True)) app = QApplication(sys.argv) profile = QWebEngineProfile("rig", app) for a in ("PdfViewerEnabled", "PluginsEnabled"): profile.settings().setAttribute(getattr(QWebEngineSettings.WebAttribute, a), True) window = wi.WonderInk(profile) profile.downloadRequested.connect(window.on_download) window.resize(1280, 800); window.show() t0 = time.monotonic() def stamp(m): print(f"[{time.monotonic()-t0:6.2f}s] {m}", flush=True) def lesson(view, title="Noahs Ark lesson"): view.setHtml(f"{title}" + "".join( f"

{title}, part {i}

{'Noah built an ark. ' * 80}

" for i in range(5) ) + "", QUrl("https://app.wonderink.org/lesson")) def worksheet(name="Colour the Ark"): d = wi.DOWNLOADS; d.mkdir(parents=True, exist_ok=True) p = d / f"{name}.pdf" w = QPdfWriter(str(p)); w.setPageSize(QPageSize(QPageSize.PageSizeId.Letter)); w.setResolution(300) pa = QPainter(w); pa.setFont(QFont("DejaVu Sans", 28)) pa.drawText(200, 400, f"WORKSHEET {name} page one"); pa.drawRect(200, 600, 2000, 1500) w.newPage(); pa.drawText(200, 400, f"WORKSHEET {name} page two"); pa.end() return p def when(cond, then, label, limit=30): start = time.monotonic() def poll(): try: ok = cond() except Exception as e: ok = False if ok: return then() if time.monotonic() - start > limit: stamp(f"GAVE UP waiting for {label}"); app.exit(4); return QTimer.singleShot(100, poll) QTimer.singleShot(100, poll) def preview(): return window._preview def ready(): return preview() is not None and preview()._pdf is not None def describe(d): return f"pages={d._pages} printers={[d._printer.itemText(i) for i in range(d._printer.count())]} paper={d.paper()} colour_offered={d._colour.isVisible()} status={d._status.text()!r}" def finish(code=0): stamp(f"RESULT notes={notes} preview_open={preview() is not None} tabs={window._tabs.count()}") QTimer.singleShot(1500, lambda: app.exit(code)) def press_print(then=None): d = preview(); stamp("PREVIEW " + describe(d)) d._print.click() stamp(f"after Print: open={preview() is not None} status={d._status.text() if preview() else ''!r}") (then or finish)() actions = { "web": lambda view: when(ready, press_print, "preview"), "cancel": lambda view: when(ready, lambda: (stamp("PREVIEW " + describe(preview())), preview()._cancel.click(), finish()), "preview"), "options": lambda view: when(ready, lambda: ( preview()._which.setCurrentIndex(1), preview()._range.setText("2-3"), preview()._copies.setValue(2), preview()._colour.setCurrentIndex(1), press_print()), "preview"), "bad-range": lambda view: when(ready, lambda: ( preview()._which.setCurrentIndex(1), preview()._range.setText("7"), preview()._print.click(), stamp(f"bad range: open={preview() is not None} status={preview()._status.text()!r}"), preview()._range.setText("1"), press_print()), "preview"), "broken": lambda view: when(ready, lambda: ( preview()._printer.setCurrentText("Refusing"), stamp(f"switched to Refusing: paper={preview().paper()} status={preview()._status.text()!r}"), when(ready, lambda: ( stamp(f"re-rendered on {preview().paper()}: pages={preview()._pages}"), preview()._print.click(), stamp(f"broken: open={preview() is not None} status={preview()._status.text()!r}"), preview()._cancel.click(), finish()), "re-render")), "preview"), "page-closes-itself": lambda view: when(ready, lambda: ( view.page().runJavaScript("window.close()"), when(lambda: preview() and "closed" in preview()._status.text(), lambda: ( stamp(f"after page closed: status={preview()._status.text()!r} print_enabled={preview()._print.isEnabled()}"), preview()._cancel.click(), finish()), "closed message")), "preview"), "close-window": lambda view: when(ready, lambda: (stamp("closing window with preview open"), window.close()), "preview"), "page-prints-again": lambda view: when(ready, lambda: ( view.page().runJavaScript("window.print()"), QTimer.singleShot(800, lambda: (stamp(f"second request while open: still one preview={preview() is not None}"), press_print()))), "preview"), } if scenario == "repeat": view = window.open_tab(); lesson(view); n = [0] def once(): if n[0] == 5: return finish() n[0] += 1; QTimer.singleShot(0, lambda: window.print_view(view)) when(ready, lambda: press_print(then=lambda: QTimer.singleShot(200, once)), "preview") view.loadFinished.connect(lambda ok: once() if n[0] == 0 else None) elif scenario in ("pdf", "pdf-options"): window.open_pdf(worksheet()); view = window.current() if scenario == "pdf-options": actions["pdf-options"] = lambda view: when(ready, lambda: ( preview()._which.setCurrentIndex(1), preview()._range.setText("2"), preview()._copies.setValue(3), preview()._colour.setCurrentIndex(1), press_print()), "preview") QTimer.singleShot(2500, lambda: (QTimer.singleShot(0, lambda: window.print_view(view)), actions[scenario if scenario == "pdf-options" else "web"](view))) elif scenario == "pdf-viewer-button": # The viewer's own print button reaches the page as a print request. window.open_pdf(worksheet()); view = window.current() QTimer.singleShot(2500, lambda: (actions["web"](view), view.page().printRequested.emit())) elif scenario == "inline": view = window.open_tab(); view.load(QUrl("http://127.0.0.1:8088/ark.pdf")) QTimer.singleShot(4000, lambda: (stamp(f"inline mime={window._mime.get(view)!r} shows_pdf={window._shows_pdf(view)}"), QTimer.singleShot(0, lambda: window.print_view(view)), when(ready, lambda: (stamp(f"worksheet tab opened: tabs={window._tabs.count()} current_is_pdf={window.current() in window._pdf_views}"), press_print()), "inline preview"))) else: if scenario == "page-closes-itself": lesson(window.open_tab(), "The other lesson") view = window.open_tab(); lesson(view) fired = [] def go(ok): if fired: return fired.append(1); QTimer.singleShot(0, lambda: window.print_view(view)); actions[scenario](view) view.loadFinished.connect(go) QTimer.singleShot(90000, lambda: (stamp("TIMEOUT"), app.exit(3))) rc = app.exec() stamp(f"EXIT {rc} scratch_left={sorted(p.name for p in Path(os.environ.get('XDG_RUNTIME_DIR','/tmp')).glob('wonderink-print-*'))}") sys.exit(rc)