82 lines
4.1 KiB
Python
82 lines
4.1 KiB
Python
|
|
"""V8.34 easy Banner/card presentation settings, validation and build parity."""
|
||
|
|
from pathlib import Path
|
||
|
|
from bs4 import BeautifulSoup
|
||
|
|
import pytest
|
||
|
|
from app import blueprints
|
||
|
|
from test_factory_v2 import factory, site
|
||
|
|
|
||
|
|
ROOT=Path(__file__).resolve().parents[1]
|
||
|
|
|
||
|
|
|
||
|
|
def test_banner_three_predefined_layouts_and_image_fit():
|
||
|
|
for variant in ('split','image-first','centered'):
|
||
|
|
block=blueprints.new_block('hero',{'title':'出口车型','image':'/assets/car.png',
|
||
|
|
'layout_variant':variant,'image_fit':'contain'})
|
||
|
|
markup=blueprints.render_blocks([block],{'name':'Demo'},{'route':'/','type':'home'},[])
|
||
|
|
soup=BeautifulSoup(markup,'html.parser')
|
||
|
|
assert soup.select_one(f'.sf-hero-layout-{variant}.sf-fit-contain')
|
||
|
|
assert soup.select_one('.sf-hero-img img').get('loading')=='eager'
|
||
|
|
assert soup.select_one('.sf-hero-img img').get('fetchpriority')=='high'
|
||
|
|
|
||
|
|
|
||
|
|
def test_collection_three_card_modes_and_product_photo_fit():
|
||
|
|
entries=[{'route':'/products/one/','title':'HDPE 管材','summary':'专业产品',
|
||
|
|
'type':'product','cover':'/media/hdpe.webp','meta_json':'{}'}]
|
||
|
|
for kind in ('standard','compact','showcase'):
|
||
|
|
block=blueprints.new_block('collection',{'card_style':kind,'image_fit':'contain'})
|
||
|
|
html=blueprints.render_blocks([block],{}, {'route':'/','type':'home'},entries)
|
||
|
|
assert f'sf-card-style-{kind} sf-fit-contain' in html
|
||
|
|
assert 'data-sf-filterable="false"' in html
|
||
|
|
assert 'hdpe.webp' in html
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.parametrize('typ,key,value',[
|
||
|
|
('hero','layout_variant','<script>alert(1)</script>'),
|
||
|
|
('hero','image_fit','calc(100vw)'),
|
||
|
|
('collection','card_style','custom'),
|
||
|
|
('collection','image_fit','url(javascript:1)'),
|
||
|
|
])
|
||
|
|
def test_invalid_presentation_options_blocked(typ,key,value):
|
||
|
|
with pytest.raises(ValueError,match='不支持的区块展示选项'):
|
||
|
|
blueprints.validate_blocks([blueprints.new_block(typ,{key:value})])
|
||
|
|
|
||
|
|
|
||
|
|
def test_legacy_blocks_preserve_default_appearance():
|
||
|
|
old_hero={'id':'hero-legacy-123','type':'hero','title':'旧首页','image':''}
|
||
|
|
old_list={'id':'cards-legacy-123','type':'collection','title':'旧列表','source':'product','limit':6,'columns':3}
|
||
|
|
markup=blueprints.render_blocks([old_hero,old_list],{}, {'route':'/','type':'home'},[])
|
||
|
|
assert 'sf-hero-layout-split' not in markup
|
||
|
|
assert 'sf-card-style-standard' not in markup
|
||
|
|
assert 'sf-fit-cover' not in markup
|
||
|
|
assert 'sf-section sf-collection' in markup
|
||
|
|
|
||
|
|
|
||
|
|
def test_studio_uses_plain_language_and_shared_presentation():
|
||
|
|
script=(ROOT/'app/static/editor.js').read_text()
|
||
|
|
stylesheet=(ROOT/'app/static/blocks.css').read_text()
|
||
|
|
for phrase in ('Banner 排版','文字左侧 · 图片右侧','图片左侧 · 文字右侧','图片优先 · 大图展示','完整显示(不裁切)'):
|
||
|
|
assert phrase in script
|
||
|
|
assert 'sf-hero-layout-image-first' in stylesheet
|
||
|
|
assert 'sf-card-style-showcase' in stylesheet
|
||
|
|
assert 'sf-fit-contain .sf-item-img img' in stylesheet
|
||
|
|
|
||
|
|
|
||
|
|
def test_real_preview_and_build_use_same_variants(factory):
|
||
|
|
sid=site(factory)
|
||
|
|
pages=factory.get(f'/api/sites/{sid}/entries').json()
|
||
|
|
home=next(x for x in pages if x['route']=='/')
|
||
|
|
blocks=[blueprints.new_block('hero',{'title':'产品供应','layout_variant':'image-first','image_fit':'contain'}),
|
||
|
|
blueprints.new_block('collection',{'title':'最新产品','card_style':'showcase','image_fit':'contain'})]
|
||
|
|
saved=factory.put(f'/api/sites/{sid}/pages/{home["id"]}/blueprint',json={'blocks':blocks,'page_template':'home'})
|
||
|
|
assert saved.status_code==200,saved.text
|
||
|
|
built=factory.post(f'/api/sites/{sid}/builds',json={})
|
||
|
|
assert built.status_code==200,built.text
|
||
|
|
version=built.json()['version']
|
||
|
|
built_html=factory.get(f'/preview/{sid}/{version}/').text
|
||
|
|
assert 'sf-hero-layout-image-first sf-fit-contain' in built_html
|
||
|
|
assert 'sf-card-style-showcase sf-fit-contain' in built_html
|
||
|
|
css=factory.get(f'/preview/{sid}/{version}/assets/blocks.css')
|
||
|
|
assert css.status_code==200
|
||
|
|
assert 'sf-card-style-showcase' in css.text
|
||
|
|
assert not factory.get(f'/api/sites/{sid}/builds/{version}/report').json()['errors']
|