"""V8.23 nested authoring contract. These checks execute against the real renderer.""" from pathlib import Path from bs4 import BeautifulSoup from app import blueprints from tests.test_factory import client,create ROOT=Path(__file__).resolve().parents[1] def test_nested_ids_are_rendered_and_duplicate_ids_rejected(): layout=blueprints.new_block('layout') child=blueprints.new_block('image_text',{'title':'Subcomponent editing'}) layout['columns'][0]['blocks']=[child] clean=blueprints.validate_blocks([layout]);assert clean[0]['columns'][0]['blocks'][0]['id']==child['id'] html=blueprints.render_blocks(clean,{}, {},[]) soup=BeautifulSoup(html,'html.parser') assert soup.select_one(f'.sf-layout-grid[data-layout="{layout["id"]}"]') assert soup.select_one(f'.sf-layout-column .sf-section[data-block="{child["id"]}"]') assert 'onload=' not in html layout['columns'][1]['blocks']=[child] import pytest with pytest.raises(ValueError,match='重复'):blueprints.validate_blocks([layout]) def test_nested_view_is_only_in_draft_editor(): editor=(ROOT/'app/static/editor.js').read_text(encoding='utf-8') bridge=(ROOT/'app/static/studio-canvas-bridge.js').read_text(encoding='utf-8') helpers=(ROOT/'app/static/editor-helpers.js').read_text(encoding='utf-8') for marker in ('child-select','child-inline-text','child-duplicate','child-delete'): assert marker in bridge and marker in editor assert 'safeNestedCanvasCommand' in helpers assert 'childQuickEditor' in editor and 'setLayoutPreset' in editor assert 'event.source!==frame.contentWindow' in editor assert 'eval(' not in bridge and 'new Function(' not in bridge assert 'studio-canvas-bridge.js' not in (ROOT/'app/builder.py').read_text(encoding='utf-8') def test_editor_sandbox_keeps_scripts_isolated(): soup=BeautifulSoup((ROOT/'app/templates/editor.html').read_text(encoding='utf-8'),'html.parser') assert soup.select_one('#sitePreview')['sandbox']==['allow-scripts'] assert soup.select_one('#saveDraftButton') def test_nested_layout_draft_round_trip(client): sid=create(client) entries=client.get(f'/api/sites/{sid}/entries').json() eid=next(row['id'] for row in entries if row['route']=='/') parent=blueprints.new_block('layout') child=blueprints.new_block('image_text',{'title':'Nested draft stable'}) parent['columns'][0]['blocks']=[child] uri=f'/api/sites/{sid}/pages/{eid}/studio-draft' payload={'blocks':[parent],'page_template':'home','layout_mode':'replace','expected_revision':0} put=client.put(uri,json=payload) assert put.status_code==200,put.text result=client.get(uri).json() assert result['blocks'][0]['columns'][0]['blocks'][0]['title']=='Nested draft stable' assert result['revision']==1 assert client.put(uri,json=payload).status_code==409