Scoped browser acceptance
tests/browser_acceptance.mjs runs this addon's HOOT suite on the desktop and
mobile presets, then opens the real configuration form for all four shapes at
1440 px and 390 px widths. It verifies buffered moves, undo/redo, explicit saving,
mouse/touch dragging, discarding, readable numbered anchors, responsive bounds,
translated labels and unclipped controls, and approval/revision immutability.
It creates synthetic configurations in the
selected disposable database; remove that database after testing.
tests/browser_editing_boundaries.mjs extends the same invocation with draft
lifecycle and pagination cases at both widths. New fabrications are entered in
the real Fabrications table; their drawing identities remain unavailable until
the form is saved. Native browser key events exercise selection, moves and
undo/redo. Numeric table edits invalidate old position history, then permit a new
undoable move. Invalid placements can be saved as drafts; the UI hides approval
and an explicit RPC attempt must be denied without changing workflow evidence.
The corrected draft is saved before approval. Approval/reopen/reapproval proves
that a second revision does not change the first snapshot or attachment link.
The approved table is readonly, direct fabrication writes are denied, and the
prior PDF checksum/file size remain unchanged after editing and reapproval.
Pagination cases use 85 nonoverlapping synthetic holes and the view's actual page size. They verify loaded selection identities, global numbering, cleared selection/history after changing pages, loaded-row keyboard wraparound and a saved move surviving a page round trip. The cases visit the first, middle and final partial pages; native pagination wraps between the first and last pages, and keyboard selection wraps only its loaded rows. Mobile approval/reopen actions use Odoo's native collapsed action menu. These boundary cases run in the selected language; they do not replace the four-shape geometry cases or server security tests.
Boundary fixtures now belong to real quotation lines and run in the ordinary salesperson's browser and RPC session. A buffered move survives a three-page round trip before saving; the backend stays unchanged until the normal form save. The saved move then survives another page round trip.
tests/browser_sale_line_workflow.mjs extends the invocation with ordinary sales
permissions. It adds an unsaved product line to a quotation, uses Configure Glass,
checks the explicit Save-first guidance and hidden unsaved-line actions, saves
the quotation before opening a drawing, returns to the quotation and
reopens the same design. It duplicates the quotation and uses the real Copy Drawing
wizard to create an independent draft. Unit and Surface products run at both widths;
ordered quantities remain unchanged and Surface physical counts are explicit.
Quotation duplication uses the native Actions / Duplicate menu, including its
Slovenian label, before opening Copy Drawing. Each resulting Unit/Surface draft
continues into the approval journey at the same viewport width.
The helper creates a synthetic salesperson with an ephemeral password in the
disposable database and switches only its browser session. The password is neither
persisted in repository artifacts nor emitted in logs. English and Slovenian
acceptance passes at both widths; see TODO.md for exact evidence and coverage.
tests/browser_drawing_authoring.mjs completes the Iteration 2 journey from
quotation-line actions in that same ordinary-sales session. At both widths it
authors all four shapes numerically, creates an eight-hole pattern through the
actual Placement Helpers wizard, adds a boundary notch and interior slot, and
removes an extra hole. Shape and dimension changes invalidate move history while
retaining buffered fabrications; Discard restores the saved design. Incomplete
dimensions, outside cuts and overlapping holes produce identical form/RPC
feedback and cannot be approved. Corrected drawings combine material, treatment,
coating and applicable edge finishes; ten numbered anchors and their wrapped
callouts remain readable before approval. A second customer's quotation reuses
an approved template through Copy Drawing with independent geometry and no
approval or manufacturing links. Model regressions also cover archived templates
with canceled manufacturing history.
Approved revision acceptance
tests/browser_approved_revisions.mjs adds six quotation-driven approval journeys
in the same ordinary-sales session: two independent revision cases and four
copied Unit/Surface handoffs at desktop/mobile widths. It approves R1,
downloads it from the line, reopens/edits while R1 remains available, approves R2,
and selects/downloads R1 from Approved Drawings. SHA-256 checks prove both PDFs
are unchanged by sales-label edits. Actual /web/content requests enforce current
ownership: the previous salesperson loses access and the new owner gains access;
foreign-company sales, portal and anonymous requests remain denied. Each language
records its results in browser-approved-revisions.json. Completed browser files
must match the corresponding approved binary's SHA-256 checksum, including R2
from the sale line. Approved editors expose no movement controls; reopening
restores draft editing. Products and native sale quantities remain unchanged
through the complete copied-drawing handoff.
Native download clicks wait for settled viewport placement and verify that the
pointer hits the PDF button before clicking, including on mobile quotation cards.
The model suite uses the real wkhtmltopdf engine and pdftotext for all four shapes
at 50, 1000 and 10000 mm with 90 fabrication rows. It checks visible vector labels,
identity, finishing instructions, repeated table headers and draft watermarks.
Its concurrent-approval regression uses two isolated transactions on a committed
synthetic drawing, then removes that fixture through the uninstall cleanup path.
Prerequisites
- Node.js 22 or later, with built-in
fetchandWebSocket; no npm dependencies. - Headless Chromium in a dedicated temporary profile, with extensions disabled
and its debugging endpoint bound to
127.0.0.1. - A fresh database prepared by the supported scoped pytest runner with
--keep-db. Its name must start withtest_glass_. - An Odoo HTTP server bound to
127.0.0.1, restricted to that exact database with--db-filter,--no-database-listand--max-cron-threads=0. - A temporary admin password in that disposable database, stored in a private temporary file. Never change an application database's credentials for testing.
The normal pytest wrappers do not start an HTTP server. This standalone browser check is a focused exception using Odoo's native HOOT assets and actual form/ORM traffic, while Python tests and coverage still use the supported scoped runner. Restart/update the disposable server after asset/view changes. Disable browser extensions and caching to avoid stale assets or modified browser globals.
Invocation
With the disposable Odoo server on port 18083 and Chromium debugging on 19223:
GLASS_BROWSER_DATABASE=test_glass_browser_pmis_sheet_configurator \
GLASS_BROWSER_PASSWORD_FILE=/tmp/glass_browser_password \
GLASS_BROWSER_OUTPUT=/tmp/glass_browser_evidence \
node pmis_sheet_configurator/tests/browser_acceptance.mjs
GLASS_BROWSER_URL and GLASS_BROWSER_DEBUGGER optionally override the two
loopback endpoints. GLASS_BROWSER_OUTPUT must identify a directory outside the
repository. The runner opens and closes its own Chromium tab; it does not stop
the Odoo or Chromium processes. Stop those processes and remove the owned test
database and temporary password file after collecting evidence.
English and Slovenian acceptance
The runner defaults to GLASS_BROWSER_LANGUAGE=en_US. Set the disposable admin
user's language to English before that run. For Slovenian, install Slovenian
(sl_SI) through Odoo's standard language installer in the same disposable
database, then change that user's language to Slovenian. Installation loads both
the standard Odoo terms and this addon's i18n/sl.po. Authenticate again by
starting a new runner invocation; the runner verifies the session language before
opening its browser tab. Language setup changes only the disposable database.
GLASS_BROWSER_LANGUAGE=sl_SI \
GLASS_BROWSER_DATABASE=test_glass_browser_pmis_sheet_configurator \
GLASS_BROWSER_PASSWORD_FILE=/tmp/glass_browser_password \
GLASS_BROWSER_OUTPUT=/tmp/glass_browser_evidence_sl \
node pmis_sheet_configurator/tests/browser_acceptance.mjs
Use a separate artifact directory for each language. Only en_US and sl_SI are
supported. The checks require translated accessible selection, move and zoom
labels, coordinate status and diameter callouts. They also verify that each
editor control stays within the editor and does not clip its label. All existing
shape, pointer, save/discard and approval checks run in the selected language.
Odoo's shared frontend catalog can resolve the common "Move right" source string
to either this addon's "Premakni desno" or the installed editor/spreadsheet
catalog's "Premakni se desno". Both shipped Slovenian terms are accepted; English
fallback labels still fail Slovenian acceptance. The actual label is recorded.
Authoring likewise accepts the shipped "Premakni navzgor" and "Premakni se navzgor"
labels for "Move up"; English fallback still fails.
Artifacts and coverage boundaries
browser-acceptance.json: eight real-form shape/viewport cases, with the verified language, accessible labels and control-fit results.browser-editing-boundaries.json: four real-form boundary cases per language, covering draft lifecycle and pagination at desktop/mobile widths.browser-sale-line-workflow.json: four non-superuser quotation/drawing/copy cases per language, covering Unit and Surface products at desktop/mobile widths.browser-drawing-authoring.json: eight complete non-superuser shape/viewport journeys and two template-reuse cases per language.browser-approved-revisions.json: six non-superuser approval/PDF journeys per language, including four copied Unit/Surface handoffs, completed-file checksums, unchanged sales quantities and binary ownership/company/portal denial.browser-failure.json: bounded synthetic form state and the failed condition when browser execution fails; retain it with that attempt's log for diagnosis.<shape>-<width>.pngand<shape>-<width>-controls.png: synthetic UI evidence.frontend-v8-coverage.json: editor source and measured execution ranges.frontend-coverage-summary.json: merged executable-location, function and block counts; the runner requires 100% for all three.
Chrome DevTools supplies executable locations and precise V8 function/block
ranges. Return-only breakpoints are excluded from executable-location counts.
V8 inherits counts for blocks without a separate range; merging respects those
counts across identical editor sources. These metrics are not Istanbul's
statement/branch instrumentation and must not be labeled as such. Coverage is
scoped to glass_drawing_editor.js; XML templates, generated module wrappers,
the browser acceptance harness and Odoo dependencies are excluded. Python
statement/branch coverage is independent.
Model tests remain authoritative for ownership/company permissions and RPC approval guards. Browser evidence does not certify manufacturing tolerances or machine exports. Runtime English and Slovenian acceptance have separate evidence directories; neither language's result substitutes for testing the other.