"""Behavioural tests that drive the actual `_applyReasoningChip()` from static/ui.js via node, not just a regex over the source. The static checks in test_reasoning_chip_btw_fixes.py confirm the *shape* of the function (no `display='none'`, the right toggle call exists, etc.) but they pass even if a runtime detail is wrong — e.g. if `inactive` were inverted, or `_normalizeReasoningEffort` mishandled whitespace, or the label fell through to a wrong value for an unknown input. This file pins the actual rendered output for every effort state so the chip's None/Default visibility cannot silently regress. """ import os import shutil import subprocess from pathlib import Path import pytest REPO_ROOT = Path(__file__).parent.parent.resolve() UI_JS_PATH = REPO_ROOT / "static" / "ui.js" NODE = shutil.which("node") pytestmark = pytest.mark.skipif(NODE is None, reason="node not on PATH") _DRIVER_SRC = r""" const fs = require('fs'); const src = fs.readFileSync(process.argv[2], 'utf8'); function makeEl() { return { style: {}, classList: { _set: new Set(), add(c){this._set.add(c)}, remove(c){this._set.delete(c)}, toggle(c, on){ const want = on === undefined ? !this._set.has(c) : Boolean(on); if (want) this._set.add(c); else this._set.delete(c); }, contains(c){return this._set.has(c)}, }, dataset: {}, title: '', textContent: '', querySelectorAll(){return []}, }; } const els = { composerReasoningWrap: makeEl(), composerReasoningLabel: makeEl(), composerReasoningChip: makeEl(), composerReasoningDropdown: makeEl(), }; els.composerReasoningWrap.style.display = 'none'; // mirrors the HTML default global.window = {}; global.document = { createElement: () => makeEl(), addEventListener: () => {}, querySelectorAll: () => [], querySelector: () => null, }; global.$ = id => els[id] || null; global.api = () => ({ then: () => ({ catch: () => {} }), catch: () => {} }); function extractFunc(name) { const re = new RegExp('function\\s+' + name + '\\s*\\('); const start = src.search(re); if (start < 0) throw new Error(name + ' not found'); let i = src.indexOf('{', start); let depth = 1; i++; while (depth > 0 && i < src.length) { if (src[i] === '{') depth++; else if (src[i] === '}') depth--; i++; } return src.slice(start, i); } eval(extractFunc('_normalizeReasoningEffort')); eval(extractFunc('_formatReasoningEffortLabel')); eval(extractFunc('_highlightReasoningOption')); eval(extractFunc('_applyReasoningChip')); const input = JSON.parse(process.argv[3]); _applyReasoningChip(input); const result = { display: els.composerReasoningWrap.style.display, label: els.composerReasoningLabel.textContent, inactive: els.composerReasoningChip.classList.contains('inactive'), title: els.composerReasoningChip.title, }; process.stdout.write(JSON.stringify(result)); """ @pytest.fixture(scope="module") def driver_path(tmp_path_factory): p = tmp_path_factory.mktemp("reasoning_driver") / "driver.js" p.write_text(_DRIVER_SRC, encoding="utf-8") return str(p) def _apply(driver_path, value): """Run _applyReasoningChip(value) against the actual ui.js.""" import json as _json result = subprocess.run( [NODE, driver_path, str(UI_JS_PATH), _json.dumps(value)], capture_output=True, text=True, timeout=10, ) if result.returncode != 0: raise RuntimeError(f"node driver failed: {result.stderr}") return _json.loads(result.stdout) # ───────────────────────────────────────────────────────────────────────────── # The chip MUST stay visible for every effort state (issue #1068). This used # to be hidden for !eff and 'none', and the source-regex tests in # test_reasoning_chip_btw_fixes.py verify the literal `display='none'` is gone # — but only a behavioural check confirms the wrap actually receives `''`. # ───────────────────────────────────────────────────────────────────────────── class TestChipAlwaysVisible: def test_empty_string_shows_chip_with_default_label(self, driver_path): out = _apply(driver_path, "") assert out["display"] == "", f"empty effort must show the chip: {out}" assert out["label"] == "Default" assert out["inactive"] is True def test_null_shows_chip_with_default_label(self, driver_path): out = _apply(driver_path, None) assert out["display"] == "" assert out["label"] == "Default" assert out["inactive"] is True def test_none_shows_chip_with_none_label(self, driver_path): """The bug from #1068 — 'none' must NOT hide the chip.""" out = _apply(driver_path, "none") assert out["display"] == "", ( f"'none' must show the chip (the regression that started #1068): {out}" ) assert out["label"] == "None" assert out["inactive"] is True def test_low_shows_chip_active(self, driver_path): out = _apply(driver_path, "low") assert out["display"] == "" assert out["label"] == "low" assert out["inactive"] is False def test_high_shows_chip_active(self, driver_path): out = _apply(driver_path, "high") assert out["display"] == "" assert out["inactive"] is False class TestNormalizationEdgeCases: """Pin the input-normalisation contract so it can't silently shift.""" def test_uppercase_normalises(self, driver_path): # Even though the API and slash command use lowercase, defensive # normalisation matters — copy/paste of an uppercase value or a # mis-cased server response shouldn't break the chip. out = _apply(driver_path, "NONE") assert out["label"] == "None" assert out["inactive"] is True def test_whitespace_trimmed(self, driver_path): out = _apply(driver_path, " none ") assert out["label"] == "None" assert out["inactive"] is True def test_unknown_value_falls_through_visible(self, driver_path): # Defensive: unknown effort still shows the chip rather than hiding. out = _apply(driver_path, "banana") assert out["display"] == "" assert out["label"] == "banana" assert out["inactive"] is False class TestTitleAttributeAccessibility: """The chip's `title` is the hover tooltip and a screen-reader hint — confirm it always carries the current state in human-readable form.""" def test_title_has_default_label_for_unset(self, driver_path): out = _apply(driver_path, "") assert out["title"] == "Reasoning effort: Default" def test_title_has_none_label_for_none(self, driver_path): out = _apply(driver_path, "none") assert out["title"] == "Reasoning effort: None" def test_title_has_active_label_for_high(self, driver_path): out = _apply(driver_path, "high") assert out["title"] == "Reasoning effort: high"