107 lines
3.9 KiB
Python
107 lines
3.9 KiB
Python
import json
|
|
import subprocess
|
|
from html.parser import HTMLParser
|
|
from pathlib import Path
|
|
from urllib.parse import urljoin
|
|
|
|
|
|
FRONTEND = Path(__file__).parents[1] / "frontend"
|
|
COMMANDS = FRONTEND / "commands.js"
|
|
|
|
|
|
class ScriptSourceParser(HTMLParser):
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.sources = []
|
|
|
|
def handle_starttag(self, tag, attrs):
|
|
if tag == "script":
|
|
source = dict(attrs).get("src")
|
|
if source:
|
|
self.sources.append(source)
|
|
|
|
|
|
def test_filtered_command_runs_the_matching_action():
|
|
script = f"""
|
|
const filterCommands = require({json.dumps(str(COMMANDS))});
|
|
let action = '';
|
|
const commands = [
|
|
{{ name: 'Open whiteboard', run: () => {{ action = 'whiteboard'; }} }},
|
|
{{ name: 'Refresh now', run: () => {{ action = 'refresh'; }} }},
|
|
];
|
|
const matches = filterCommands(commands, 'refresh');
|
|
if (matches.length !== 1) throw new Error(`expected one match, got ${{matches.length}}`);
|
|
matches[0].run();
|
|
if (action !== 'refresh') throw new Error(`expected refresh, got ${{action}}`);
|
|
"""
|
|
|
|
subprocess.run(["node", "-e", script], check=True, capture_output=True, text=True)
|
|
|
|
|
|
def test_command_script_resolves_inside_dashboard_subpath():
|
|
parser = ScriptSourceParser()
|
|
parser.feed((FRONTEND / "index.html").read_text())
|
|
command_source = next(source for source in parser.sources if source.endswith("commands.js"))
|
|
|
|
assert urljoin(
|
|
"https://forge.alexanderwhitestone.com/dashboard/", command_source
|
|
) == "https://forge.alexanderwhitestone.com/dashboard/static/commands.js"
|
|
|
|
|
|
def test_remote_command_search_ignores_stale_responses():
|
|
script = f"""
|
|
const filterCommands = require({json.dumps(str(COMMANDS))});
|
|
(async () => {{
|
|
const pending = new Map();
|
|
const states = [];
|
|
const controller = filterCommands.createGlobalSearchController({{
|
|
delay: 0,
|
|
search: query => new Promise(resolve => pending.set(query, resolve)),
|
|
onState: state => states.push(state),
|
|
}});
|
|
controller.setQuery('mobile');
|
|
await new Promise(resolve => setTimeout(resolve, 0));
|
|
controller.setQuery('release');
|
|
await new Promise(resolve => setTimeout(resolve, 0));
|
|
pending.get('release')([{{ title: 'Current result' }}]);
|
|
await new Promise(resolve => setTimeout(resolve, 0));
|
|
pending.get('mobile')([{{ title: 'Stale result' }}]);
|
|
await new Promise(resolve => setTimeout(resolve, 0));
|
|
const ready = states.filter(state => state.status === 'ready');
|
|
if (ready.length !== 1) throw new Error(`expected one ready state, got ${{ready.length}}`);
|
|
if (ready[0].query !== 'release' || ready[0].items[0].title !== 'Current result') {{
|
|
throw new Error(`stale response replaced current state: ${{JSON.stringify(ready)}}`);
|
|
}}
|
|
}})().catch(error => {{ console.error(error); process.exit(1); }});
|
|
"""
|
|
|
|
subprocess.run(
|
|
["node", "-e", script],
|
|
check=True, capture_output=True, text=True,
|
|
)
|
|
|
|
|
|
def test_command_selection_wraps_for_arrow_keys():
|
|
script = f"""
|
|
const commands = require({json.dumps(str(COMMANDS))});
|
|
if (commands.nextSelection(-1, 'ArrowDown', 3) !== 0) throw new Error('should select first');
|
|
if (commands.nextSelection(2, 'ArrowDown', 3) !== 0) throw new Error('should wrap down');
|
|
if (commands.nextSelection(0, 'ArrowUp', 3) !== 2) throw new Error('should wrap up');
|
|
if (commands.nextSelection(1, 'Enter', 3) !== 1) throw new Error('other keys should not move');
|
|
"""
|
|
|
|
subprocess.run(["node", "-e", script], check=True, capture_output=True, text=True)
|
|
|
|
|
|
def test_palette_exposes_accessible_global_work_search_under_dashboard_subpath():
|
|
html = (FRONTEND / "index.html").read_text()
|
|
|
|
assert 'role="combobox"' in html
|
|
assert 'aria-controls="cmd-results"' in html
|
|
assert 'role="listbox"' in html
|
|
assert "fetch('api/v1/search?q='" in html
|
|
assert urljoin(
|
|
"https://forge.alexanderwhitestone.com/dashboard/",
|
|
"api/v1/search?q=mobile",
|
|
) == "https://forge.alexanderwhitestone.com/dashboard/api/v1/search?q=mobile"
|