up
This commit is contained in:
@@ -210,3 +210,10 @@ TR3000 V1 2.5.27-20260804-183625 без изменения настроек ро
|
||||
Flow также проверяет переход заполненной БД с числовых ID команд на UUID v7,
|
||||
сохранность данных и ограничений, независимое создание команд в трёх схемах
|
||||
и полную Go-проверку на временном PostgreSQL. `team_uuid.py` вызывается из flow.
|
||||
|
||||
## Дизайн-система (без сервера и БД)
|
||||
|
||||
Запустить фронтенд командой `npm run dev -- --port 5198`, затем из корня
|
||||
`python3 tests/venue/design_system.py`. Требуется установленный Firefox.
|
||||
Smoke проверяет три ширины, клавиатурные вкладки, повторные карточки и ID,
|
||||
локальную форму и окно, состояния, темы и reduced motion.
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
"""Run with Vite on port 5198 and Firefox installed; no API required."""
|
||||
import json, pathlib, socket, subprocess, tempfile, time
|
||||
profile=pathlib.Path(tempfile.mkdtemp(prefix='home-dossier-'))
|
||||
with socket.socket() as s:
|
||||
s.bind(('127.0.0.1',0));port=s.getsockname()[1]
|
||||
(profile/'user.js').write_text(f'user_pref("marionette.port", {port});\nuser_pref("browser.shell.checkDefaultBrowser", false);')
|
||||
log=(profile/'firefox.log').open('w')
|
||||
firefox=subprocess.Popen(['firefox','--headless','--no-remote','--profile',str(profile),'--marionette','--remote-allow-system-access','about:blank'],stdout=log,stderr=log)
|
||||
sock=None
|
||||
try:
|
||||
for _ in range(100):
|
||||
try: sock=socket.create_connection(('127.0.0.1',port),timeout=1);break
|
||||
except OSError: time.sleep(.1)
|
||||
assert sock is not None, 'Firefox did not start'
|
||||
sock.settimeout(20)
|
||||
def read():
|
||||
size=b''
|
||||
while not size.endswith(b':'): size+=sock.recv(1)
|
||||
data=b'';length=int(size[:-1])
|
||||
while len(data)<length: data+=sock.recv(length-len(data))
|
||||
return json.loads(data)
|
||||
read();counter=0
|
||||
def command(name,args=None):
|
||||
global counter
|
||||
counter+=1;payload=json.dumps([0,counter,name,args or {}]).encode()
|
||||
sock.sendall(str(len(payload)).encode()+b':'+payload)
|
||||
result=read();assert not result[2], result[2];return result[3]
|
||||
def js(script):
|
||||
result=command('WebDriver:ExecuteScript',{'script':script,'args':[],'newSandbox':False,'sandbox':None})
|
||||
return result.get('value') if isinstance(result,dict) and 'value' in result else result
|
||||
def wait(script):
|
||||
for _ in range(100):
|
||||
if js('return '+script):return
|
||||
time.sleep(.1)
|
||||
raise AssertionError(script)
|
||||
command('WebDriver:NewSession',{'capabilities':{'alwaysMatch':{}}})
|
||||
command('Marionette:SetContext', {'value':'chrome'})
|
||||
js('document.documentElement.style.minWidth="0";document.documentElement.setAttribute("minwidth","0");return true')
|
||||
command('Marionette:SetContext', {'value':'content'})
|
||||
for width in [375,768,1280]:
|
||||
command('WebDriver:SetWindowRect',{'width':width,'height':900})
|
||||
command('WebDriver:Navigate',{'url':'http://127.0.0.1:5198/design-system'})
|
||||
wait('!!document.querySelector(".site-preview")')
|
||||
assert js('return document.querySelectorAll("[role=tab]").length')==3
|
||||
assert js('return document.documentElement.scrollWidth <= innerWidth')
|
||||
# Third tab, circular arrows and Home/End use real keyboard actions.
|
||||
def key(value):
|
||||
command('WebDriver:PerformActions', {'actions':[{'type':'key','id':'keyboard','actions':[{'type':'keyDown','value':value},{'type':'keyUp','value':value}]}]})
|
||||
js('document.querySelector("#tab-site").focus();return true')
|
||||
key('\ue010')
|
||||
wait('!!document.querySelector(".catalog")')
|
||||
assert js('return document.activeElement.id')=='tab-components'
|
||||
assert js('return document.documentElement.scrollWidth <= innerWidth && document.querySelector(".design-scroll").scrollWidth <= innerWidth'), 'Catalog overflow'
|
||||
assert js('const entries=[...document.querySelectorAll(".catalog-entry")]; return entries.length===20 && entries.every(e=>e.children[0].tagName==="H2" && e.children[1].matches(".component-sample, .n-config-provider") && e.children[3].matches("pre") && e.children[3].querySelector("code"))'), 'Each component needs a heading, sample and usage code'
|
||||
assert js('return [...document.querySelectorAll("[id]")].map(e=>e.id).length===new Set([...document.querySelectorAll("[id]")].map(e=>e.id)).size'), 'Duplicate DOM IDs'
|
||||
assert js('return document.querySelectorAll(".catalog .status-stamp").length===2'), 'Optional folder status'
|
||||
assert js('return !document.querySelectorAll(".catalog .folder-action")[0].disabled && document.querySelectorAll(".catalog .folder-action")[1].disabled'), 'Status controls availability'
|
||||
ids=js('return [...document.querySelectorAll(".catalog .clue-toggle")].map(e=>e.getAttribute("aria-controls"))')
|
||||
assert len(set(ids))==2
|
||||
js('document.querySelectorAll(".catalog .clue-toggle")[0].click();return true')
|
||||
wait('document.querySelectorAll(".catalog .clue-toggle")[0].getAttribute("aria-expanded")==="true"')
|
||||
assert js('return document.querySelectorAll(".catalog .clue-toggle")[1].getAttribute("aria-expanded")')=='false'
|
||||
js('document.querySelectorAll(".catalog .clue-toggle")[1].click();return true')
|
||||
wait('document.querySelectorAll(".catalog .clue-toggle")[1].getAttribute("aria-expanded")==="true"')
|
||||
js('document.querySelectorAll(".catalog .clue-toggle")[0].click();return true')
|
||||
wait('document.querySelectorAll(".catalog .clue-toggle")[0].getAttribute("aria-expanded")==="false"')
|
||||
assert js('return document.querySelectorAll(".catalog .clue-toggle")[1].getAttribute("aria-expanded")')=='true'
|
||||
assert js('return document.querySelector(".catalog .case-board").textContent.includes("Найден у двери")')
|
||||
assert js('return document.querySelector(".catalog [data-component=ObjectCover] .object-cover").textContent.includes("Чердак")')
|
||||
js('document.querySelector(".catalog form").dispatchEvent(new Event("submit",{bubbles:true,cancelable:true}));return true')
|
||||
wait('document.querySelector(".catalog").textContent.includes("Укажите название команды")')
|
||||
js('const e=document.querySelector("#catalog-team");e.value="Сыщики";e.dispatchEvent(new Event("input",{bubbles:true}));return true')
|
||||
js('document.querySelector(".catalog form").dispatchEvent(new Event("submit",{bubbles:true,cancelable:true}));return true')
|
||||
wait('document.querySelector(".catalog").textContent.includes("Сыщики» готова")')
|
||||
js('document.querySelector(".catalog .folder-action").focus();document.querySelector(".catalog .folder-action").click();return true')
|
||||
wait('!!document.querySelector("[role=dialog]")')
|
||||
assert js('return document.querySelector("[role=dialog]").getAttribute("aria-label")')=='Повторное дело'
|
||||
key('\ue00c')
|
||||
wait('!document.querySelector("[role=dialog]")')
|
||||
wait('document.activeElement===document.querySelector(".catalog .folder-action")')
|
||||
assert js('return document.querySelector(".catalog .buttons button[disabled]")!==null && document.querySelector(".catalog .buttons .n-button--loading")!==null')
|
||||
assert js('return getComputedStyle(document.querySelector(".catalog .buttons button")).backgroundColor')=='rgb(255, 212, 59)'
|
||||
js('const e=document.querySelector(".game-input-run");e.value="Сад";e.dispatchEvent(new Event("input",{bubbles:true}));return true')
|
||||
wait('!document.querySelector(".game-button-run").disabled')
|
||||
js('document.querySelector(".game-button-run").click();return true')
|
||||
wait('!!document.querySelector(".action-result")')
|
||||
assert js('return getComputedStyle(document.querySelector(".action-result")).getPropertyValue("--n-icon-color").trim()')!='#ffd43b'
|
||||
js('document.querySelector("#tab-components").focus();return true')
|
||||
key('\ue014'); wait('!!document.querySelector(".site-preview")')
|
||||
key('\ue012'); wait('!!document.querySelector(".catalog")')
|
||||
key('\ue011'); wait('!!document.querySelector(".site-preview")')
|
||||
key('\ue014'); wait('!!document.querySelector(".game-preview")')
|
||||
key('\ue014'); wait('!!document.querySelector(".catalog")')
|
||||
key('\ue011'); wait('!!document.querySelector(".site-preview")')
|
||||
print(f'PASS {width}px: three tabs, quotes, IDs, data, states, form, open, modal, themes', flush=True)
|
||||
command('Marionette:SetContext', {'value':'chrome'})
|
||||
js('Services.prefs.setIntPref("ui.prefersReducedMotion",1);return true')
|
||||
command('Marionette:SetContext', {'value':'content'})
|
||||
wait('matchMedia("(prefers-reduced-motion: reduce)").matches')
|
||||
js('document.querySelector(".clue-toggle").focus();return true')
|
||||
assert js('return getComputedStyle(document.querySelector(".case-folder")).transform')=='none'
|
||||
assert js('return getComputedStyle(document.querySelector(".case-folder")).transitionDuration')=='0s'
|
||||
assert js('return getComputedStyle(document.querySelector(".clues"),"::before").transitionDuration')=='0s'
|
||||
print('PASS reduced motion', flush=True)
|
||||
finally:
|
||||
if sock:sock.close()
|
||||
firefox.terminate();firefox.wait(timeout=10);log.close()
|
||||
Reference in New Issue
Block a user