"""Execute the real V5 billing loader with a minimal DOM, rather than text assertions.""" import shutil import subprocess from pathlib import Path import pytest @pytest.mark.skipif(not shutil.which('node'), reason='Node required for UI behavior check') @pytest.mark.parametrize('active', [True, False]) def test_v5_normal_registration_never_exposes_billing_choice(active): source = Path('static/js/case-v5.js').read_text() function = source.split('function setAutomaticRegistrationControls', 1)[1].split(" if(document.readyState", 1)[0] script = r''' const assert=require('node:assert/strict'); const controls={}; for(const id of ['v5QuickBilling','time_billing_method','v5CompactBilling'])controls[id]={dataset:{},parentElement:{querySelector:()=>({hidden:false})},replaceChildren(...items){this.options=items;},after(){}}; controls.v5BillingHint={textContent:''}; const byId=id=>controls[id],config={caseId:1}; const billingHost={querySelector:()=>({textContent:''})},compactBillingHost={querySelector:()=>({textContent:''})}; const document={createElement:()=>({})}; function Option(label,value){this.label=label;this.value=value;} const active=ACTIVE; const fetch=async()=>({ok:true,json:async()=>({workflow_active:active,has_customer:true,hourly_rate:100,prepaid_cards:[],agreements:[]})}); function setAutomaticRegistrationControls BODY loadBillingOptions().then(()=>{ for(const id of ['v5QuickBilling','time_billing_method','v5CompactBilling']){ const select=controls[id];assert.equal(select.dataset.billingReady,'true');assert.equal(select.value,'draft'); assert.equal(select.disabled,true);assert.equal(!!select.hidden,true); assert.equal(select.options.length,1); } }).catch(err=>{console.error(err);process.exitCode=1}); '''.replace('ACTIVE', 'true' if active else 'false').replace('BODY', function) result = subprocess.run(['node', '-e', script], capture_output=True, text=True) assert result.returncode == 0, result.stderr @pytest.mark.skipif(not shutil.which('node'), reason='Node required for UI behavior check') @pytest.mark.parametrize('active', [True, False]) def test_queue_active_selection_uses_decisions_and_line_mode(active): source = Path('app/economy/frontend/time_queue.html').read_text() functions = source.split('function allWorkflowSelected()', 1)[1].split(' function status(', 1)[0] script = r''' const assert=require('node:assert/strict'); const active=ACTIVE; const controls={settlementMethod:{value:'prepaid'},prepaidCard:{value:'8'},agreementId:{value:''},setMethodBtn:{},workflowLineMode:{value:'combined'},workflowLineModeHost:{classList:{toggle(){}}}}; const $=id=>controls[id],ids=()=>[1],selectedRows=()=>[{id:1,workflow_active:active}]; function allWorkflowSelected() BODY const data=payload(); assert.deepEqual(data,active?{ids:[1],line_mode:'combined'}:{ids:[1],billing_method:'prepaid',prepaid_card_id:8}); syncWorkflowControls();assert.equal(controls.settlementMethod.disabled,active);assert.equal(controls.setMethodBtn.disabled,active); '''.replace('ACTIVE', 'true' if active else 'false').replace('BODY', functions) result = subprocess.run(['node', '-e', script], capture_output=True, text=True) assert result.returncode == 0, result.stderr