Files
hermes-webui/tests/test_typography_contract.py
T
e88aff4388 Batch release exp-v0.52.234 — O_BINARY (#7077), native-control font (#6871), mobile nav order (#6909) (#7099)
* fix(navigation): preserve mobile action mirror order

Reposition stale extension action mirrors during synchronization without moving already-correct elements, preserving native tab order and keyboard focus.

Assisted-by: Hermes Agent:gpt-5.6-sol
Assisted-by: Codex:gpt-5.6-luna
Assisted-by: Claude Code:claude-opus-5

* fix(typography): route native controls through UI font

Assisted-by: Hermes Agent:gpt-5.6-sol
Assisted-by: Codex:gpt-5.6-luna
Assisted-by: Claude Code:claude-opus-5

* fix(windows): open anchored files in binary mode

* docs(changelog): note #7077 O_BINARY, #6871 native-control font, #6909 mobile nav order

---------

Co-authored-by: starship-s <45587122+starship-s@users.noreply.github.com>
Co-authored-by: allenliang2022 <allenliang2022@users.noreply.github.com>
Co-authored-by: n <a@n>
2026-08-17 01:42:02 +00:00

892 lines
34 KiB
Python

from pathlib import Path
import json
import re
import shutil
import subprocess
import pytest
try:
from playwright.sync_api import Error as PlaywrightError, sync_playwright
except Exception: # pragma: no cover - dependency optional
PlaywrightError = None
sync_playwright = None
REPO = Path(__file__).parent.parent
CSS = (REPO / "static" / "style.css").read_text(encoding="utf-8")
TERMINAL_JS = (REPO / "static" / "terminal.js").read_text(encoding="utf-8")
PANEL_JS = (REPO / "static" / "panels.js").read_text(encoding="utf-8")
UI_JS = (REPO / "static" / "ui.js").read_text(encoding="utf-8")
BOOT_JS = (REPO / "static" / "boot.js").read_text(encoding="utf-8")
INDEX_HTML = (REPO / "static" / "index.html").read_text(encoding="utf-8")
NODE = shutil.which("node")
def _iter_root_skin_blocks(css):
selector_re = re.compile(r'(:root(?:\.dark)?\[data-skin="[^"]+"\][^{]*?)\{')
for selector_match in selector_re.finditer(css):
selector = selector_match.group(1).strip()
idx = selector_match.end()
depth = 1
end = idx
while end < len(css) and depth:
ch = css[end]
if ch == "{":
depth += 1
elif ch == "}":
depth -= 1
end += 1
if depth:
continue
yield selector, css[idx : end - 1]
def _get_root_skin_block(css, skin):
target = f':root[data-skin="{skin}"]'
for selector, block in _iter_root_skin_blocks(css):
if selector == target:
return block
return ""
def _font_stack_offenders(css):
cleaned = re.sub(r"/\*.*?\*/", "", css, flags=re.S)
pattern = re.compile(r"(?i)\b(font-family|font)\s*:\s*([^;]+);")
offenders = []
for _, declaration in pattern.findall(cleaned):
value = declaration.strip().lower()
if ("monospace" not in value and "ui-monospace" not in value):
continue
if value == "inherit":
continue
offenders.append(declaration)
return offenders
def test_typography_root_tokens_are_defined():
assert '--font-ui:-apple-system,BlinkMacSystemFont,"Segoe UI",Inter,system-ui,sans-serif;' in CSS
assert '--font-conversation:var(--font-ui);' in CSS
assert '--font-mono:ui-monospace,"SFMono-Regular","SF Mono",Menlo,Consolas,"Liberation Mono",monospace;' in CSS
def test_msg_body_uses_conversation_font():
assert '.msg-body{font-family:var(--font-conversation);font-size:var(--message-body-font-size);line-height:var(--message-body-line-height);' in CSS
def test_builtin_skin_msg_body_rules_use_conversation_font():
for skin in ("graphite", "codex", "terracotta", "github"):
selector = (
f':root[data-skin="{skin}"] .msg-body'
'{font-family:var(--font-conversation);font-size:13px;font-weight:430;letter-spacing:0;line-height:1.6;}'
)
assert selector in CSS
def test_no_skin_msg_body_rules_use_root_font_ui_token():
assert not re.search(
r':root(?:\.dark)?\[data-skin="[^"]+"\]\s*\.msg-body\s*\{[^{}]*\bfont-family\s*:\s*var\(--font-ui\)\s*;[^{}]*\}',
CSS,
re.S,
)
def test_no_skin_redefines_font_conversation():
for selector, block in _iter_root_skin_blocks(CSS):
if '--font-conversation:' in block:
raise AssertionError(f'Unexpected skin-level --font-conversation: {selector}')
def test_nous_skin_keeps_monospace_ui_default():
assert _get_root_skin_block(CSS, "nous")
assert re.search(
r'--font-ui:"SF Mono","Roboto Mono","Courier New",monospace;',
_get_root_skin_block(CSS, "nous"),
re.S,
)
def test_geist_and_neon_skins_set_expected_font_ui_tokens():
geist_block = _get_root_skin_block(CSS, "geist-contrast")
assert geist_block
assert "--font-ui:\"Geist\",\"Geist Sans\",-apple-system,BlinkMacSystemFont,\"Segoe UI\",Helvetica,Arial,sans-serif;" in geist_block
for skin in ("neon", "neon-soft", "neon-paint"):
block = _get_root_skin_block(CSS, skin)
assert block, f"Missing {skin} root skin block"
assert "--font-ui:system-ui,-apple-system,sans-serif;" in block
def test_no_stale_var_mono_usage_or_literal_monospace_font_family_stacks():
assert 'var(--mono' not in CSS
offending_lines = _font_stack_offenders(CSS)
assert not offending_lines, f"Unexpected literal monospace font stacks: {offending_lines[:4]}"
def test_edit_surfaces_use_font_contract_tokens_structurally():
assert re.search(
r"\.msg-edit-area\{[^}]*font-family:var\(--font-conversation\)",
CSS,
re.S,
), ".msg-edit-area must use var(--font-conversation)"
assert re.search(
r'<textarea id="previewEditArea"[^>]*style="[^"]*font-family:var\(--font-mono\)',
INDEX_HTML,
), "#previewEditArea must use var(--font-mono)"
def test_playwright_regression_ensures_font_contract_for_syntax_and_edit_surfaces():
preview_style_match = re.search(
r'<textarea id="previewEditArea"[^>]*style="([^"]*)"',
INDEX_HTML,
)
assert preview_style_match, "Could not locate #previewEditArea inline style in index.html"
fixture_html = f"""
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>{CSS}</style>
<style>
:root{{
--font-ui:"UiFontSentinel";
--font-conversation:"ConvoFontSentinel";
--font-mono:"MonoFontSentinel";
}}
</style>
<style>
code[class*="language-"],pre[class*="language-"]{{font-family: "PrismIntruder", sans-serif;}}
</style>
</head>
<body>
<button id="buttonSentinel">button</button>
<input id="inputSentinel">
<select id="selectSentinel"><option>select</option></select>
<textarea id="textareaSentinel"></textarea>
<div class="msg-body">
<p>inline <code id="inlineCode" class="language-js">token</code> sample.</p>
<pre id="fencedPre" class="language-js"><code id="fencedCode" class="language-js">fenced token</code></pre>
<input class="markdown-table-filter" id="markdownTableFilter">
<table>
<thead><tr><th><button class="markdown-table-sort" id="markdownTableSort">sort</button></th></tr></thead>
<tbody><tr><td id="markdownTableCell">row</td></tr></tbody>
</table>
</div>
<textarea class="msg-edit-area" id="msgEditArea"></textarea>
<textarea id="previewEditArea" style="{preview_style_match.group(1)}"></textarea>
<div class="detail-form-row">
<textarea id="detailFormTextarea"></textarea>
</div>
</body>
</html>
"""
if sync_playwright is None:
pytest.skip("playwright is unavailable; run `playwright install chromium`")
with sync_playwright() as playwright:
browser = None
try:
try:
browser = playwright.chromium.launch(
headless=True,
args=["--no-sandbox", "--disable-dev-shm-usage"],
)
except PlaywrightError as exc:
if "Executable doesn't exist at" in str(exc):
pytest.skip("playwright chromium executable is unavailable; run `playwright install chromium`")
raise
page = browser.new_page(viewport={"width": 1024, "height": 768})
page.set_content(fixture_html)
inline_code_font = page.eval_on_selector(
"#inlineCode",
"el => getComputedStyle(el).fontFamily",
)
fenced_pre_font = page.eval_on_selector(
"#fencedPre",
"el => getComputedStyle(el).fontFamily",
)
fenced_code_font = page.eval_on_selector(
"#fencedCode",
"el => getComputedStyle(el).fontFamily",
)
message_edit_font = page.eval_on_selector(
"#msgEditArea",
"el => getComputedStyle(el).fontFamily",
)
preview_edit_font = page.eval_on_selector(
"#previewEditArea",
"el => getComputedStyle(el).fontFamily",
)
component_fonts = page.evaluate(
"""
() => Object.fromEntries(
["markdownTableFilter", "markdownTableSort", "markdownTableCell", "detailFormTextarea"]
.map(id => [id, getComputedStyle(document.getElementById(id)).fontFamily])
)
"""
)
native_control_fonts = page.evaluate(
"""
() => Object.fromEntries(
["buttonSentinel", "inputSentinel", "selectSentinel", "textareaSentinel"]
.map(id => [id, getComputedStyle(document.getElementById(id)).fontFamily])
)
"""
)
runtime_token_font = page.evaluate("""
() => {
const style = document.createElement('style');
style.id = 'runtime-font-sentinel';
style.textContent = ':root { --font-mono: "RuntimeMono", monospace; }';
document.head.appendChild(style);
return getComputedStyle(document.documentElement).getPropertyValue('--font-mono');
}
""")
edited_runtime_token_font = page.evaluate("""
() => {
const style = document.getElementById('runtime-font-sentinel');
style.textContent = ':root { --font-mono: "EditedRuntimeMono", monospace; }';
return getComputedStyle(document.documentElement).getPropertyValue('--font-mono');
}
""")
linked_stylesheet_font = page.evaluate("""
async () => {
const link = document.createElement('link');
const encodedCss = encodeURIComponent(':root { --font-mono: "LinkedRuntimeMono", monospace; }');
link.rel = 'stylesheet';
link.href = 'data:text/css,' + encodedCss;
return await new Promise((resolve) => {
link.onload = () => {
resolve(getComputedStyle(document.documentElement).getPropertyValue('--font-mono'));
};
link.onerror = () => {
resolve(getComputedStyle(document.documentElement).getPropertyValue('--font-mono'));
};
document.head.appendChild(link);
});
}
""")
finally:
if browser is not None:
browser.close()
assert "MonoFontSentinel" in inline_code_font
assert "MonoFontSentinel" in fenced_pre_font
assert "MonoFontSentinel" in fenced_code_font
assert "ConvoFontSentinel" in message_edit_font
assert "MonoFontSentinel" in preview_edit_font
for control_id, font in native_control_fonts.items():
assert "UiFontSentinel" in font, f"{control_id} computed {font!r}"
assert "UiFontSentinel" in component_fonts["markdownTableFilter"]
assert "MonoFontSentinel" in component_fonts["markdownTableSort"]
assert "MonoFontSentinel" in component_fonts["markdownTableCell"]
assert component_fonts["markdownTableSort"] == component_fonts["markdownTableCell"]
assert "MonoFontSentinel" in component_fonts["detailFormTextarea"]
assert "RuntimeMono" in runtime_token_font
assert "EditedRuntimeMono" in edited_runtime_token_font
assert "LinkedRuntimeMono" in linked_stylesheet_font
def test_terminal_sync_tracks_applied_appearance_and_observes_relevant_root_attributes():
block_match = re.search(
r"function\s+syncComposerTerminalAppearance\([^)]*\)\s*\{.*?\n\}\s*\n\s*function\s+_xtermReady\(\)",
TERMINAL_JS,
re.S,
)
assert block_match
sync_block = block_match.group(0)
assert "function _terminalThemesEqual" in TERMINAL_JS
assert "lastAppliedTheme" in sync_block
assert "lastAppliedFontFamily" in sync_block
assert re.search(
r"new\s+MutationObserver\(\(\)\s*=>\s*syncComposerTerminalAppearance\(\)\)\.observe\(document\.documentElement,\{.*?attributeFilter:\s*\[\s*['\"]class['\"],\s*['\"]data-skin['\"],\s*['\"]style['\"],?\s*\]",
TERMINAL_JS,
re.S,
)
assert "const terminalHead=document.head" in TERMINAL_JS
assert "if(terminalHead){" in TERMINAL_JS
assert "terminalHeadStylesheetLoadListener" in TERMINAL_JS
assert re.search(
r"new\s+MutationObserver\(\(\)\s*=>\s*syncComposerTerminalAppearance\(true\)\)\.observe\(terminalHead,\{\s*attributes:\s*true,\s*attributeFilter:\s*\[\s*['\"]href['\"],\s*['\"]media['\"],\s*['\"]disabled['\"]\s*\],\s*childList:\s*true,\s*subtree:\s*true,\s*characterData:\s*true,\s*\}\)",
TERMINAL_JS,
re.S,
)
head_decl=TERMINAL_JS.index("const terminalHead=document.head")
head_guard=TERMINAL_JS.index("if(terminalHead){")
head_load_listener=TERMINAL_JS.index("terminalHead.addEventListener('load',terminalHeadStylesheetLoadListener,true)")
head_observer=TERMINAL_JS.index("new MutationObserver(()=>syncComposerTerminalAppearance(true)).observe(terminalHead,{")
assert head_decl < head_guard < head_load_listener < head_observer
assert re.search(
r"terminalHead\.addEventListener\(\s*['\"]load['\"],\s*terminalHeadStylesheetLoadListener,\s*true\s*\)",
TERMINAL_JS,
re.S,
)
@pytest.mark.skipif(NODE is None, reason="node not on PATH")
def test_terminal_appearance_sync_is_behaviorally_idempotent_and_lifecycle_safe():
script = (
"""
const styles={
'--font-mono':'"Active Mono",monospace',
'--code-bg':'#111111',
};
const rootInline={};
let dark=false;
let observerCallbacks={};
let observedTargets=[];
let observedOptions={};
let fitCalls=0;
let resizeSchedules=0;
let terminalHeadLoadListener=null;
let terminalHeadLoadListenerOptions=null;
let unhandledFontLoadRejections=0;
let nextAnimationFrameId=1;
const animationFrames=new Map();
const writes=[];
const createdAppearances=[];
const fontLoadCalls=[];
const pendingFontLoads=[];
const surface={textContent:''};
process.on('unhandledRejection',()=>{unhandledFontLoadRejections+=1;});
const terminalFonts={
load(shorthand){
let resolve;
let reject;
const promise=new Promise((resolvePromise,rejectPromise)=>{
resolve=resolvePromise;
reject=rejectPromise;
});
const request={shorthand,resolve,reject};
fontLoadCalls.push(shorthand);
pendingFontLoads.push(request);
return promise;
},
};
function pendingAnimationFrames(){
return animationFrames.size;
}
function flushAnimationFrames(){
const pending=[...animationFrames.values()];
animationFrames.clear();
pending.forEach(callback=>callback());
}
class FakeMutationObserver {
constructor(callback){ this.callback=callback; }
observe(target,options){
const targetName = target===document.documentElement ? 'documentElement' : target===document.head ? 'head' : 'other';
observedTargets.push(targetName);
observedOptions[targetName]=options;
observerCallbacks[targetName]=this.callback;
}
}
class FakeTerminal {
constructor(options){
createdAppearances.push({
fontFamily:options.fontFamily,
fontSize:options.fontSize,
theme:{...options.theme},
});
const current={
fontFamily:options.fontFamily,
fontSize:options.fontSize,
theme:options.theme,
};
this.options=new Proxy(current,{
set(target,key,value){
writes.push(String(key));
target[key]=value;
return true;
},
});
this.cols=80;
this.rows=24;
}
loadAddon(){}
open(){}
onData(){}
dispose(){}
}
class FakeFitAddon {
fit(){ fitCalls+=1; }
}
const root={
classList:{contains(name){ return name==='dark'&&dark; }},
style:{setProperty(name,value){ rootInline[name]=value; }},
};
global.window={
addEventListener(){},
MutationObserver:FakeMutationObserver,
Terminal:FakeTerminal,
FitAddon:{FitAddon:FakeFitAddon},
};
global.MutationObserver=FakeMutationObserver;
global.document={
documentElement:root,
fonts:terminalFonts,
head:{
addEventListener(type,listener,options){
if(type==='load'){
terminalHeadLoadListener=listener;
terminalHeadLoadListenerOptions=options;
}
},
removeEventListener(){
},
},
getElementById(){ return null; },
};
global.getComputedStyle=()=>({
getPropertyValue(name){ return styles[name]||rootInline[name]||''; },
});
global.$=(id)=>id==='terminalSurface'?surface:null;
global.requestAnimationFrame=(callback)=>{
const id=nextAnimationFrameId++;
animationFrames.set(id,callback);
return id;
};
global.cancelAnimationFrame=(id)=>animationFrames.delete(id);
global.setTimeout=(_callback,delay)=>{
if(delay===120)resizeSchedules+=1;
return 1;
};
global.clearTimeout=()=>{};
"""
+ TERMINAL_JS
+ """
async function settleFontLoad(){
await Promise.resolve();
await Promise.resolve();
}
(async()=>{
const first=_ensureXterm();
const initialFontLoad=pendingFontLoads[0];
TERMINAL_UI.open=true;
TERMINAL_UI.sessionId='session-1';
const initialFitCalls=fitCalls;
resizeSchedules=0;
initialFontLoad.resolve([]);
await settleFontLoad();
const initialDelayedPendingFrames=pendingAnimationFrames();
flushAnimationFrames();
const initialDelayedFitDelta=fitCalls-initialFitCalls;
const initialDelayedResizeSchedules=resizeSchedules;
writes.length=0;
resizeSchedules=0;
const fitsBeforeLateSameFamily=fitCalls;
const fontLoadsBeforeLateSameFamily=fontLoadCalls.length;
observerCallbacks.head([{type:'childList'},{type:'characterData'}]);
const lateSameFamilyFontLoad=pendingFontLoads[pendingFontLoads.length-1];
const lateSameFamilyWrites=[...writes];
const lateSameFamilyLoadCount=fontLoadCalls.length-fontLoadsBeforeLateSameFamily;
const lateSameFamilyPendingFramesBeforeCompletion=pendingAnimationFrames();
flushAnimationFrames();
const lateSameFamilyFitDeltaBeforeCompletion=fitCalls-fitsBeforeLateSameFamily;
lateSameFamilyFontLoad.resolve([{}]);
await settleFontLoad();
const lateSameFamilyPendingFramesAfterLoad=pendingAnimationFrames();
const fitsBeforeLateSameFamilyFit=fitCalls;
flushAnimationFrames();
const lateSameFamilyFitDelta=fitCalls-fitsBeforeLateSameFamilyFit;
const lateSameFamilyResizeSchedules=resizeSchedules;
writes.length=0;
const fitsBeforeLateStylesheetLoad=fitCalls;
const fontLoadsBeforeLateStylesheetLoad=fontLoadCalls.length;
terminalHeadLoadListener&&terminalHeadLoadListener({target:{
tagName:'LINK',
getAttribute(name){ return name==='rel'?'stylesheet':null; },
}});
const lateStylesheetFontLoad=pendingFontLoads[pendingFontLoads.length-1];
const lateStylesheetLoadWrites=[...writes];
const lateStylesheetLoadCount=fontLoadCalls.length-fontLoadsBeforeLateStylesheetLoad;
const lateStylesheetPendingFrames=pendingAnimationFrames();
flushAnimationFrames();
lateStylesheetFontLoad.resolve([]);
await settleFontLoad();
const lateStylesheetFitDelta=fitCalls-fitsBeforeLateStylesheetLoad;
const lateStylesheetPendingFramesAfterLoad=pendingAnimationFrames();
writes.length=0;
const fitsBeforeUnchanged=fitCalls;
syncComposerTerminalAppearance();
const unchangedWrites=[...writes];
const unchangedFitDelta=fitCalls-fitsBeforeUnchanged;
const unchangedPendingFrames=pendingAnimationFrames();
writes.length=0;
const fitsBeforeUnrelated=fitCalls;
document.documentElement.style.setProperty('--unrelated-outline-offset','3px');
observerCallbacks.documentElement([{attributeName:'style'}]);
const unrelatedStyleWrites=[...writes];
const unrelatedFitDelta=fitCalls-fitsBeforeUnrelated;
const unrelatedPendingFrames=pendingAnimationFrames();
writes.length=0;
const fitsBeforeTheme=fitCalls;
styles['--code-bg']='#222222';
observerCallbacks.documentElement([{attributeName:'style'}]);
const themeOnlyWrites=[...writes];
const backgroundAfterChange=first.options.theme.background;
const themeOnlyFitDelta=fitCalls-fitsBeforeTheme;
const themeOnlyPendingFrames=pendingAnimationFrames();
writes.length=0;
resizeSchedules=0;
const fitsBeforeFont=fitCalls;
const fontLoadsBeforeExtension=fontLoadCalls.length;
styles['--font-mono']='"Extension Mono",monospace';
observerCallbacks.head([{type:'childList'},{type:'characterData'}]);
const extensionFontLoad=pendingFontLoads[pendingFontLoads.length-1];
const extensionFontLoadCount=fontLoadCalls.length-fontLoadsBeforeExtension;
const fontOnlyWrites=[...writes];
const fontAfterChange=first.options.fontFamily;
const fontFitDeltaBeforeFrame=fitCalls-fitsBeforeFont;
const fontPendingFramesBeforeFlush=pendingAnimationFrames();
flushAnimationFrames();
const fontFitDeltaAfterFrame=fitCalls-fitsBeforeFont;
const fontResizeSchedules=resizeSchedules;
extensionFontLoad.resolve([{}]);
await settleFontLoad();
const fontPendingFramesAfterLoad=pendingAnimationFrames();
const fitsBeforeDelayedFontFit=fitCalls;
flushAnimationFrames();
const fontFitDeltaAfterLoad=fitCalls-fitsBeforeDelayedFontFit;
const fontResizeSchedulesAfterLoad=resizeSchedules;
writes.length=0;
resizeSchedules=0;
const fitsBeforeNonStylesheetLoad=fitCalls;
styles['--font-mono']='\"Non Stylesheet Mono\",monospace';
terminalHeadLoadListener&&terminalHeadLoadListener({target:{
tagName:'SCRIPT',
getAttribute:()=>null,
}});
const nonStylesheetLoadWrites=[...writes];
const nonStylesheetLoadFitDelta=fitCalls-fitsBeforeNonStylesheetLoad;
const nonStylesheetLoadPendingFrames=pendingAnimationFrames();
writes.length=0;
resizeSchedules=0;
const fitsBeforeEmptyFont=fitCalls;
styles['--font-mono']='ui-monospace,monospace';
observerCallbacks.head([{type:'childList'}]);
const emptyFontLoad=pendingFontLoads[pendingFontLoads.length-1];
const emptyFontWrites=[...writes];
const emptyFontPendingFramesBeforeFlush=pendingAnimationFrames();
flushAnimationFrames();
const emptyFontImmediateFitDelta=fitCalls-fitsBeforeEmptyFont;
const emptyFontResizeSchedules=resizeSchedules;
const fitsBeforeEmptyFontCompletion=fitCalls;
emptyFontLoad.resolve([]);
await settleFontLoad();
const emptyFontPendingFramesAfterLoad=pendingAnimationFrames();
const emptyFontDelayedFitDelta=fitCalls-fitsBeforeEmptyFontCompletion;
writes.length=0;
resizeSchedules=0;
const fitsBeforeStylesheetLoad=fitCalls;
styles['--font-mono']='\"Stylesheet Load Mono\",monospace';
terminalHeadLoadListener&&terminalHeadLoadListener({target:{
tagName:'LINK',
getAttribute(name){ return name==='rel'?'stylesheet':null; },
}});
const stylesheetFontLoad=pendingFontLoads[pendingFontLoads.length-1];
const stylesheetLoadWrites=[...writes];
const stylesheetLoadFontAfterChange=first.options.fontFamily;
const stylesheetLoadFitDeltaBeforeFrame=fitCalls-fitsBeforeStylesheetLoad;
const stylesheetLoadPendingFramesBeforeFlush=pendingAnimationFrames();
flushAnimationFrames();
const stylesheetLoadFitDeltaAfterFrame=fitCalls-fitsBeforeStylesheetLoad;
const stylesheetLoadResizeSchedules=resizeSchedules;
stylesheetFontLoad.resolve([]);
await settleFontLoad();
resizeSchedules=0;
styles['--font-mono']='"Stale Prior Mono",monospace';
observerCallbacks.head([{type:'childList'}]);
const staleFontLoad=pendingFontLoads[pendingFontLoads.length-1];
flushAnimationFrames();
styles['--font-mono']='"Replacement Mono",monospace';
observerCallbacks.head([{type:'childList'}]);
const replacementFontLoad=pendingFontLoads[pendingFontLoads.length-1];
flushAnimationFrames();
const fitsBeforeStaleCompletion=fitCalls;
staleFontLoad.resolve([{}]);
await settleFontLoad();
const staleCompletionFitDelta=fitCalls-fitsBeforeStaleCompletion;
const staleCompletionPendingFrames=pendingAnimationFrames();
replacementFontLoad.resolve([]);
await settleFontLoad();
styles['--font-mono']='"Rejecting Mono",monospace';
observerCallbacks.head([{type:'childList'}]);
const rejectedFontLoad=pendingFontLoads[pendingFontLoads.length-1];
flushAnimationFrames();
const fitsBeforeRejectedCompletion=fitCalls;
rejectedFontLoad.reject(new Error('optional font failed'));
await settleFontLoad();
const rejectedCompletionFitDelta=fitCalls-fitsBeforeRejectedCompletion;
const rejectedCompletionPendingFrames=pendingAnimationFrames();
styles['--font-mono']='"Disposed Mono",monospace';
observerCallbacks.head([{type:'childList'}]);
const disposedFontLoad=pendingFontLoads[pendingFontLoads.length-1];
const oldTerm=TERMINAL_UI.term;
const generationBeforeDispose=TERMINAL_UI.fontLoadGeneration;
const pendingFitBeforeDispose=pendingAnimationFrames();
_disposeXterm();
const pendingFitAfterDispose=pendingAnimationFrames();
const cacheReset=TERMINAL_UI.lastAppliedTheme===null
&&TERMINAL_UI.lastAppliedFontFamily===null
&&TERMINAL_UI.fontFitFrame===null
&&TERMINAL_UI.fontLoadRequest===null
&&TERMINAL_UI.fontLoadGeneration===generationBeforeDispose+1;
styles['--font-mono']='"Recreated Mono",monospace';
styles['--code-bg']='#333333';
const fitsBeforeRecreate=fitCalls;
const recreated=_ensureXterm();
const recreatedFontLoad=pendingFontLoads[pendingFontLoads.length-1];
const recreateFitDelta=fitCalls-fitsBeforeRecreate;
const recreatePendingFrames=pendingAnimationFrames();
const fitsBeforeDisposedCompletion=fitCalls;
disposedFontLoad.resolve([{}]);
await settleFontLoad();
const disposedCompletionFitDelta=fitCalls-fitsBeforeDisposedCompletion;
const disposedCompletionPendingFrames=pendingAnimationFrames();
recreatedFontLoad.resolve([]);
await settleFontLoad();
TERMINAL_UI.open=true;
styles['--font-mono']='"Closed Terminal Mono",monospace';
observerCallbacks.head([{type:'childList'}]);
const closedFontLoad=pendingFontLoads[pendingFontLoads.length-1];
flushAnimationFrames();
const fitsBeforeClosedCompletion=fitCalls;
TERMINAL_UI.open=false;
closedFontLoad.resolve([{}]);
await settleFontLoad();
const closedCompletionFitDelta=fitCalls-fitsBeforeClosedCompletion;
const closedCompletionPendingFrames=pendingAnimationFrames();
TERMINAL_UI.open=true;
styles['--font-mono']='"Collapsed Terminal Mono",monospace';
observerCallbacks.head([{type:'childList'}]);
const collapsedFontLoad=pendingFontLoads[pendingFontLoads.length-1];
flushAnimationFrames();
const fitsBeforeCollapsedCompletion=fitCalls;
TERMINAL_UI.collapsed=true;
collapsedFontLoad.resolve([{}]);
await settleFontLoad();
const collapsedCompletionFitDelta=fitCalls-fitsBeforeCollapsedCompletion;
const collapsedCompletionPendingFrames=pendingAnimationFrames();
TERMINAL_UI.collapsed=false;
process.stdout.write(JSON.stringify({
initial:createdAppearances[0],
initialFontLoadShorthand:fontLoadCalls[0],
initialFitCalls,
initialDelayedPendingFrames,
initialDelayedFitDelta,
initialDelayedResizeSchedules,
lateSameFamilyWrites,
lateSameFamilyLoadCount,
lateSameFamilyPendingFramesBeforeCompletion,
lateSameFamilyFitDeltaBeforeCompletion,
lateSameFamilyPendingFramesAfterLoad,
lateSameFamilyFitDelta,
lateSameFamilyResizeSchedules,
lateStylesheetLoadWrites,
lateStylesheetLoadCount,
lateStylesheetPendingFrames,
lateStylesheetFitDelta,
lateStylesheetPendingFramesAfterLoad,
unchangedWrites,
unchangedFitDelta,
unchangedPendingFrames,
unrelatedStyleWrites,
unrelatedFitDelta,
unrelatedPendingFrames,
themeOnlyWrites,
backgroundAfterChange,
themeOnlyFitDelta,
themeOnlyPendingFrames,
fontOnlyWrites,
fontAfterChange,
fontFitDeltaBeforeFrame,
fontPendingFramesBeforeFlush,
fontFitDeltaAfterFrame,
fontResizeSchedules,
extensionFontLoadCount,
fontPendingFramesAfterLoad,
fontFitDeltaAfterLoad,
fontResizeSchedulesAfterLoad,
nonStylesheetLoadWrites,
nonStylesheetLoadFitDelta,
nonStylesheetLoadPendingFrames,
emptyFontWrites,
emptyFontPendingFramesBeforeFlush,
emptyFontImmediateFitDelta,
emptyFontResizeSchedules,
emptyFontPendingFramesAfterLoad,
emptyFontDelayedFitDelta,
stylesheetLoadWrites,
stylesheetLoadFontAfterChange,
stylesheetLoadFitDeltaBeforeFrame,
stylesheetLoadPendingFramesBeforeFlush,
stylesheetLoadFitDeltaAfterFrame,
stylesheetLoadResizeSchedules,
staleCompletionFitDelta,
staleCompletionPendingFrames,
rejectedCompletionFitDelta,
rejectedCompletionPendingFrames,
unhandledFontLoadRejections,
terminalHeadLoadListenerRegistered: typeof terminalHeadLoadListener === 'function',
terminalHeadLoadListenerOptions,
observerTargets:observedTargets,
observerCallbacks:Object.keys(observerCallbacks),
observedOptions,
pendingFitBeforeDispose,
pendingFitAfterDispose,
cacheReset,
oldTermIsReplaced:oldTerm!==recreated,
recreated:createdAppearances[1],
recreateFitDelta,
recreatePendingFrames,
disposedCompletionFitDelta,
disposedCompletionPendingFrames,
closedCompletionFitDelta,
closedCompletionPendingFrames,
collapsedCompletionFitDelta,
collapsedCompletionPendingFrames,
}));
})().catch((error)=>{
process.exitCode=1;
process.stderr.write((error&&error.stack?error.stack:String(error))+"\\n");
});
""")
result = subprocess.run(
[NODE, "-e", script],
cwd=REPO,
capture_output=True,
text=True,
timeout=20,
)
assert result.returncode == 0, result.stderr
observed = json.loads(result.stdout)
assert observed["initial"]["fontFamily"] == '"Active Mono",monospace'
assert observed["initial"]["fontSize"] == 13
assert observed["initial"]["theme"]["background"] == "#111111"
assert observed["initialFontLoadShorthand"] == '13px "Active Mono",monospace'
assert observed["initialFitCalls"] == 1
assert observed["initialDelayedPendingFrames"] == 0
assert observed["initialDelayedFitDelta"] == 0
assert observed["initialDelayedResizeSchedules"] == 0
assert observed["lateSameFamilyWrites"] == []
assert observed["lateSameFamilyLoadCount"] == 1
assert observed["lateSameFamilyPendingFramesBeforeCompletion"] == 0
assert observed["lateSameFamilyFitDeltaBeforeCompletion"] == 0
assert observed["lateSameFamilyPendingFramesAfterLoad"] == 1
assert observed["lateSameFamilyFitDelta"] == 1
assert observed["lateSameFamilyResizeSchedules"] == 1
assert observed["lateStylesheetLoadWrites"] == []
assert observed["lateStylesheetLoadCount"] == 1
assert observed["lateStylesheetPendingFrames"] == 0
assert observed["lateStylesheetFitDelta"] == 0
assert observed["lateStylesheetPendingFramesAfterLoad"] == 0
assert observed["unchangedWrites"] == []
assert observed["unchangedFitDelta"] == 0
assert observed["unchangedPendingFrames"] == 0
assert observed["unrelatedStyleWrites"] == []
assert observed["unrelatedFitDelta"] == 0
assert observed["unrelatedPendingFrames"] == 0
assert observed["themeOnlyWrites"] == ["theme"]
assert observed["backgroundAfterChange"] == "#222222"
assert observed["themeOnlyFitDelta"] == 0
assert observed["themeOnlyPendingFrames"] == 0
assert observed["fontOnlyWrites"] == ["fontFamily"]
assert observed["fontAfterChange"] == '"Extension Mono",monospace'
assert observed["fontFitDeltaBeforeFrame"] == 0
assert observed["fontPendingFramesBeforeFlush"] == 1
assert observed["fontFitDeltaAfterFrame"] == 1
assert observed["fontResizeSchedules"] == 1
assert observed["extensionFontLoadCount"] == 1
assert observed["fontPendingFramesAfterLoad"] == 1
assert observed["fontFitDeltaAfterLoad"] == 1
assert observed["fontResizeSchedulesAfterLoad"] == 2
assert observed["terminalHeadLoadListenerRegistered"] is True
assert observed["terminalHeadLoadListenerOptions"] is True
assert observed["nonStylesheetLoadWrites"] == []
assert observed["nonStylesheetLoadFitDelta"] == 0
assert observed["nonStylesheetLoadPendingFrames"] == 0
assert observed["emptyFontWrites"] == ["fontFamily"]
assert observed["emptyFontPendingFramesBeforeFlush"] == 1
assert observed["emptyFontImmediateFitDelta"] == 1
assert observed["emptyFontResizeSchedules"] == 1
assert observed["emptyFontPendingFramesAfterLoad"] == 0
assert observed["emptyFontDelayedFitDelta"] == 0
assert observed["stylesheetLoadWrites"] == ["fontFamily"]
assert observed["stylesheetLoadFontAfterChange"] == '"Stylesheet Load Mono",monospace'
assert observed["stylesheetLoadFitDeltaBeforeFrame"] == 0
assert observed["stylesheetLoadPendingFramesBeforeFlush"] == 1
assert observed["stylesheetLoadFitDeltaAfterFrame"] == 1
assert observed["stylesheetLoadResizeSchedules"] == 1
assert observed["staleCompletionFitDelta"] == 0
assert observed["staleCompletionPendingFrames"] == 0
assert observed["rejectedCompletionFitDelta"] == 0
assert observed["rejectedCompletionPendingFrames"] == 0
assert observed["unhandledFontLoadRejections"] == 0
assert observed["observerTargets"] == ["documentElement", "head"]
assert observed["observerCallbacks"] == ["documentElement", "head"]
assert observed["observedOptions"]["documentElement"] == {
"attributes": True,
"attributeFilter": ["class", "data-skin", "style"],
}
assert observed["observedOptions"]["head"] == {
"attributes": True,
"attributeFilter": ["href", "media", "disabled"],
"childList": True,
"subtree": True,
"characterData": True,
}
assert observed["pendingFitBeforeDispose"] == 1
assert observed["pendingFitAfterDispose"] == 0
assert observed["cacheReset"] is True
assert observed["oldTermIsReplaced"] is True
assert observed["recreated"]["fontFamily"] == '"Recreated Mono",monospace'
assert observed["recreated"]["theme"]["background"] == "#333333"
assert observed["recreateFitDelta"] == 1
assert observed["recreatePendingFrames"] == 0
assert observed["disposedCompletionFitDelta"] == 0
assert observed["disposedCompletionPendingFrames"] == 0
assert observed["closedCompletionFitDelta"] == 0
assert observed["closedCompletionPendingFrames"] == 0
assert observed["collapsedCompletionFitDelta"] == 0
assert observed["collapsedCompletionPendingFrames"] == 0
def test_first_party_technical_js_uses_font_mono_contract():
assert 'function _terminalMonoFont()' in TERMINAL_JS
assert "'ui-monospace,\"SFMono-Regular\",\"SF Mono\",Menlo,Consolas,\"Liberation Mono\",monospace'" in TERMINAL_JS
assert 'font-family:var(--font-mono)' in PANEL_JS
assert "fontFamily='var(--font-mono)'" in UI_JS
assert "font-family:var(--font-ui)" in BOOT_JS
def test_terminal_contract_updates_on_root_style_changes():
assert "attributeFilter:['class','data-skin','style']" in TERMINAL_JS
assert 'function syncComposerTerminalAppearance' in TERMINAL_JS
assert 'function _terminalMonoFont' in TERMINAL_JS