#!/usr/bin/env python3 """Does the export print what the field needs, and nothing it does not? — CR-008, T9.1. The export was never walked through in the meeting. This is the walk: every required field present, CR-006-suppressed sections absent, the two CR-002 fields (ACU Cost Code, Acumatica Task) appearing NOWHERE under the Micron configuration, status carried by words (a black-and-white print keeps its meaning), and the whole document legible on a tablet. Exit 0 all passed, 1 a failure, 2 could not run. """ import json import os import re import sys import tempfile import time sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) import cdp # noqa: E402 from browser_check import seed, start_server, chk, _PASS, _FAIL # noqa: E402 from sections_check import set_sop # noqa: E402 from stepper_check import dismiss_dialogs # noqa: E402 def ascii_(v, n=280): return re.sub(r"\s+", " ", str(v)).encode("ascii", "replace").decode()[:n] def settle(seconds=0.5): time.sleep(seconds) def wait_creator(page, tries=40): for _ in range(tries): if page.eval("!!window.wpCreatorReady"): return True time.sleep(0.3) return False def main(): exe = cdp.find_browser() if not exe: print("no headless-capable browser found; set WP_BROWSER.") return 2 tmpdir = tempfile.mkdtemp(prefix="wpsuite-export-") db_path = os.path.join(tmpdir, "check.db") server = None browser = None try: tok = seed(db_path) set_sop(db_path, {}) port = cdp.free_port() base = "http://127.0.0.1:%d" % port server = start_server(port, db_path) browser = cdp.Browser(exe) page = browser.page() page.clear_cookies() page.set_cookie("wp_session", tok["root"]) page.viewport(1440, 900) page.goto(base + "/wp-creation-index.html?project=projA") dismiss_dialogs(page) chk("the creator boots", wait_creator(page)) settle(1.6) page.eval("window.alert=()=>{}; window.confirm=()=>false; window.prompt=()=>null;") # The Micron configuration and its example package - the real shape. page.eval("loadSampleSOP()") settle(1.0) page.eval("loadExample()") settle(1.0) doc = page.eval("(() => { renderPackage(collectPackage()); " "return document.getElementById('pkg-doc').innerHTML; })()") text = page.eval("(document.getElementById('pkg-doc')||{textContent:''}).textContent") print("\n1. every listed field, present") for label, needle in [ ("P6 Activity id + description", "P6 Activity"), ("Priority", "Priority"), ("scope of work", "Scope & Work"), ("materials", "Material List"), ("constraints", "Constraints — Release Readiness"), ("QA/QC", "Quality & Hold Points"), ]: chk("the export carries %s" % label, needle in text or needle in doc, needle) chk("...and the location row (Building / Floor / Sector is a row of " "General Information)", "Location" in text) chk("constraint status prints as WORDS - a black-and-white print keeps " "its meaning", "Cleared" in text and "Open" in text) print("\n2. what must be absent, absent") chk("ACU Cost Code appears nowhere", "Cost Code" not in text) chk("Acumatica Task appears nowhere", "Acumatica Task" not in text) chk("the toggled-off sections are absent (assets, kitting - the Micron " "sample's CR-006 state)", "Kitting & MIMO" not in text and "Asset" not in text.replace("Assets is off", "")) print("\n3. the attachment index") chk("every attachment is listed", "Drawings & Attachments" in text) chk("...uploads would carry their descriptions (the columns exist)", "Focus area" in text or "Link / Note" in text) print("\n4. the tablet") page.viewport(390, 844, mobile=True) settle(0.8) page.eval("renderPackage(collectPackage())") settle(0.8) # scrollWidth vs clientWidth is the wrong ruler for a padded overflow-y # container: Chrome reports scrollWidth as content+padding even with # nothing protruding, so the naive comparison is off by exactly the # padding+border. What legibility actually needs: the BOX fits the # screen, and no element inside pokes past the box. fits = page.eval("""(() => { const d = document.getElementById('pkg-doc'); const dr = d.getBoundingClientRect(); const cs = getComputedStyle(d); let poke = 0; d.querySelectorAll('*').forEach(el => { const r = el.getBoundingClientRect(); if (r.right > dr.right + 2) poke++; }); return {boxFits: dr.width <= 390, poke, font: parseFloat(cs.fontSize)}; })()""") chk("390px: the document fits the screen and nothing inside pokes past it", fits["boxFits"] and fits["poke"] == 0, ascii_(fits)) chk("390px: the base type is readable (>= 12px)", fits["font"] >= 12, ascii_(fits)) js_errors = [e for e in page.js_errors() if "beforeunload" not in e] chk("no JavaScript errors anywhere in this run", not js_errors, ascii_(js_errors[:2])) finally: if browser is not None: try: browser.close() except Exception: pass if server is not None: try: server.terminate() except Exception: pass print("\n" + "-" * 54) print("%d/%d checks passed." % (len(_PASS), len(_PASS) + len(_FAIL))) for f in _FAIL: print(" - " + f) return 1 if _FAIL else 0 if __name__ == "__main__": sys.exit(main())