8884e100f9
Overlay 190 upstream items (V8.22→8.31) preserving trade-pro theme, registry tests, and design docs. Re-applied full patch set on identical anchors (discovery/env_for/blocks.css/type-mapping/locale-override/ theme_color/frontend entries/test_theme_pro_v3 mods) plus compose pins. Verified: theme suites 35/35; dual-baseline full run 415 passed vs pristine 386+29 ours, FAILED-set diff EMPTY (same 10 Windows env fails). Live: container 8.31.1-dev.1 healthy, hesupipe 192 entries intact, trade-pro build 203 pages 0 errors. Co-Authored-By: Claude Code <noreply@anthropic.com>
105 lines
5.8 KiB
Python
105 lines
5.8 KiB
Python
"""V8.26 global chrome review, version snapshots, and safe restoration."""
|
||
import copy
|
||
import json
|
||
from tests.test_factory import client, create
|
||
from app import db, site_design_v87
|
||
|
||
|
||
def config(marker='Global HESU Header'):
|
||
data=copy.deepcopy(site_design_v87.DEFAULTS)
|
||
data['header'].update({'announcement': marker, 'show_announcement': True})
|
||
data['footer']['title']='HESU Footer'
|
||
data['nav']=[{'title':'Products','route':'/products/','children':[
|
||
{'title':'Vehicles','route':'/vehicles/','children':[]}]}]
|
||
return data
|
||
|
||
|
||
def test_human_review_and_reviewed_publication_are_build_isolated(client):
|
||
site=create(client);url=f'/api/sites/{site}/site-design'
|
||
old=db.one('SELECT settings_json FROM sites WHERE id=?',(site,))['settings_json']
|
||
assert client.put(url,json={'config':config(), 'expected_revision':0}).status_code==200
|
||
proof=client.get(url+'/review');assert proof.status_code==200,proof.text
|
||
body=proof.json()
|
||
assert {'header','nav','footer'}.issubset(set(body['changed_sections']))
|
||
assert body['published_site_unchanged'] is True
|
||
assert body['change_count']>=3
|
||
assert db.one('SELECT settings_json FROM sites WHERE id=?',(site,))['settings_json']==old
|
||
wrong=client.post(url+'/publish-reviewed',json={'expected_revision':1,'plan_token':'1'*64})
|
||
assert wrong.status_code==409
|
||
good=client.post(url+'/publish-reviewed',json={'expected_revision':1,'plan_token':body['plan_token']})
|
||
assert good.status_code==200,good.text
|
||
assert 'Global HESU Header' in db.one('SELECT settings_json FROM sites WHERE id=?',(site,))['settings_json']
|
||
assert client.get(url+'/review').status_code==409
|
||
|
||
|
||
def test_old_review_token_invalid_after_draft_edit(client):
|
||
site=create(client);url=f'/api/sites/{site}/site-design'
|
||
assert client.put(url,json={'config':config('First'), 'expected_revision':0}).status_code==200
|
||
stale=client.get(url+'/review').json()
|
||
assert client.put(url,json={'config':config('Second'), 'expected_revision':1}).status_code==200
|
||
assert client.post(url+'/publish-reviewed',json={
|
||
'expected_revision':2,'plan_token':stale['plan_token']}).status_code==409
|
||
fresh=client.get(url+'/review').json()
|
||
assert fresh['plan_token']!=stale['plan_token']
|
||
assert client.post(url+'/publish-reviewed',json={
|
||
'expected_revision':2,'plan_token':fresh['plan_token']}).status_code==200
|
||
|
||
|
||
def test_restore_history_as_new_draft_does_not_mutate_live(client):
|
||
site=create(client);url=f'/api/sites/{site}/site-design'
|
||
assert client.put(url,json={'config':config('Release A'),'expected_revision':0}).status_code==200
|
||
reviewed=client.get(url+'/review').json()
|
||
pub=client.post(url+'/publish-reviewed',json={'expected_revision':1,'plan_token':reviewed['plan_token']}).json()
|
||
pid=pub['publication_id']
|
||
old_live=db.one('SELECT settings_json FROM sites WHERE id=?',(site,))['settings_json']
|
||
history=client.get(url+f'/publications/{pid}');assert history.status_code==200
|
||
assert history.json()['after']['header']['announcement']=='Release A'
|
||
assert any(x['field']=='header.announcement' for x in history.json()['changes'])
|
||
live_hash=client.get(url+'/live-hash').json()['live_hash']
|
||
recovered=client.post(url+f'/publications/{pid}/restore',json={
|
||
'snapshot':'before','expected_revision':0,'expected_live_hash':live_hash})
|
||
assert recovered.status_code==200,recovered.text
|
||
assert recovered.json()['published_unchanged']
|
||
assert client.get(url).json()['revision']==1
|
||
assert db.one('SELECT settings_json FROM sites WHERE id=?',(site,))['settings_json']==old_live
|
||
assert client.post(url+f'/publications/{pid}/restore',json={
|
||
'snapshot':'before','expected_revision':0,'expected_live_hash':live_hash}).status_code==409
|
||
|
||
|
||
def test_restore_rejects_stale_live_site_and_foreign_history(client):
|
||
a=create(client);b=create(client)
|
||
ua=f'/api/sites/{a}/site-design';ub=f'/api/sites/{b}/site-design'
|
||
assert client.put(ua,json={'config':config(), 'expected_revision':0}).status_code==200
|
||
preview=client.get(ua+'/review').json()
|
||
pid=client.post(ua+'/publish-reviewed',json={
|
||
'expected_revision':1,'plan_token':preview['plan_token']}).json()['publication_id']
|
||
old_hash=client.get(ua+'/live-hash').json()['live_hash']
|
||
assert client.get(ub+f'/publications/{pid}').status_code==404
|
||
assert client.post(ub+f'/publications/{pid}/restore',json={
|
||
'snapshot':'after','expected_revision':0,'expected_live_hash':old_hash}).status_code==404
|
||
current=db.one('SELECT settings_json FROM sites WHERE id=?',(a,))
|
||
changed=json.loads(current['settings_json']);changed['external_setting']='changed'
|
||
db.execute('UPDATE sites SET settings_json=? WHERE id=?',(json.dumps(changed),a))
|
||
assert client.post(ua+f'/publications/{pid}/restore',json={
|
||
'snapshot':'after','expected_revision':0,'expected_live_hash':old_hash}).status_code==409
|
||
assert client.post(ua+f'/publications/{pid}/restore',json={
|
||
'snapshot':'bad','expected_revision':0,'expected_live_hash':'a'*64}).status_code==400
|
||
|
||
|
||
def test_nav_editor_is_visual_and_review_ui_is_wired(client):
|
||
sid=create(client)
|
||
entry=next(x for x in client.get(f'/api/sites/{sid}/entries').json() if x['route']=='/')
|
||
page=client.get(f'/editor/{sid}/{entry["id"]}').text
|
||
assert 'siteNavRows' in page and '+ 添加一级菜单' in page
|
||
assert 'siteDesignReviewModal' in page and 'siteDesignHistoryModal' in page
|
||
code=client.get('/ui/editor.js').text
|
||
assert 'drawSiteNav()' in code and 'publish-reviewed' in code
|
||
assert 'showSiteDesignHistory' in code
|
||
|
||
|
||
def test_invalid_navigation_remains_rejected(client):
|
||
sid=create(client);url=f'/api/sites/{sid}/site-design'
|
||
bad=config();bad['nav'][0]['children'][0]['route']='javascript:alert(1)'
|
||
assert client.put(url,json={'config':bad,'expected_revision':0}).status_code==400
|
||
assert client.get(url).json()['revision']==0
|