feat: align legacy operator and playout behavior
This commit is contained in:
103
tests/Web/cut-keyboard-app-integration.test.cjs
Normal file
103
tests/Web/cut-keyboard-app-integration.test.cjs
Normal file
@@ -0,0 +1,103 @@
|
||||
"use strict";
|
||||
|
||||
const assert = require("node:assert/strict");
|
||||
const fs = require("node:fs");
|
||||
const path = require("node:path");
|
||||
const test = require("node:test");
|
||||
const vm = require("node:vm");
|
||||
|
||||
const root = path.resolve(__dirname, "..", "..");
|
||||
const app = fs.readFileSync(path.join(
|
||||
root,
|
||||
"src",
|
||||
"MBN_STOCK_WEBVIEW.LegacyParityApp",
|
||||
"Web",
|
||||
"app.js"), "utf8");
|
||||
const nativeWindow = fs.readFileSync(path.join(
|
||||
root,
|
||||
"src",
|
||||
"MBN_STOCK_WEBVIEW.LegacyParityApp",
|
||||
"MainWindow.xaml.cs"), "utf8");
|
||||
const nativePlayout = fs.readFileSync(path.join(
|
||||
root,
|
||||
"src",
|
||||
"MBN_STOCK_WEBVIEW.LegacyParityApp",
|
||||
"MainWindow.Playout.cs"), "utf8");
|
||||
|
||||
function loadCutHelpers(rows) {
|
||||
const start = app.indexOf("function legacyCutKey");
|
||||
const end = app.indexOf("function createCutElement", start);
|
||||
assert.ok(start >= 0 && end > start);
|
||||
const context = {
|
||||
cutList: { children: rows },
|
||||
result: null
|
||||
};
|
||||
vm.runInNewContext(`
|
||||
${app.slice(start, end)}
|
||||
result = { legacyCutKey, focusCutElement, cutKeyboardTarget };
|
||||
`, context);
|
||||
return context.result;
|
||||
}
|
||||
|
||||
function row(id) {
|
||||
return {
|
||||
id,
|
||||
tabIndex: -1,
|
||||
focusCount: 0,
|
||||
scrollCount: 0,
|
||||
focus() { this.focusCount += 1; },
|
||||
scrollIntoView() { this.scrollCount += 1; }
|
||||
};
|
||||
}
|
||||
|
||||
test("cut keyboard maps only native ListView keys and uses physical boundaries", () => {
|
||||
const rows = [row(0), row(1), row(2)];
|
||||
const helpers = loadCutHelpers(rows);
|
||||
|
||||
assert.equal(helpers.legacyCutKey("ArrowUp"), "arrow-up");
|
||||
assert.equal(helpers.legacyCutKey("ArrowDown"), "arrow-down");
|
||||
assert.equal(helpers.legacyCutKey("Home"), "home");
|
||||
assert.equal(helpers.legacyCutKey("End"), "end");
|
||||
assert.equal(helpers.legacyCutKey(" "), "space");
|
||||
assert.equal(helpers.legacyCutKey("PageDown"), null);
|
||||
assert.equal(helpers.cutKeyboardTarget(rows[0], "ArrowUp").id, 0);
|
||||
assert.equal(helpers.cutKeyboardTarget(rows[1], "ArrowDown").id, 2);
|
||||
assert.equal(helpers.cutKeyboardTarget(rows[1], "Home").id, 0);
|
||||
assert.equal(helpers.cutKeyboardTarget(rows[1], "End").id, 2);
|
||||
});
|
||||
|
||||
test("cut focus is roving and scrolls only for keyboard navigation", () => {
|
||||
const rows = [row(0), row(1), row(2)];
|
||||
const helpers = loadCutHelpers(rows);
|
||||
|
||||
helpers.focusCutElement(rows[1], true);
|
||||
|
||||
assert.deepEqual(rows.map(item => item.tabIndex), [-1, 0, -1]);
|
||||
assert.equal(rows[1].focusCount, 1);
|
||||
assert.equal(rows[1].scrollCount, 1);
|
||||
});
|
||||
|
||||
test("cut key intent preserves Home End bubbling and honors the mutation gate", () => {
|
||||
const start = app.indexOf("function createCutElement");
|
||||
const end = app.indexOf("function renderCuts", start);
|
||||
const factory = app.slice(start, end);
|
||||
assert.match(factory, /element\.addEventListener\("keydown"/);
|
||||
assert.match(factory, /event\.preventDefault\(\)/);
|
||||
assert.match(factory, /if \(playlistMutationLocked\) return/);
|
||||
assert.match(factory, /send\("cut-key-down", \{/);
|
||||
assert.match(factory, /control: event\.ctrlKey/);
|
||||
assert.match(factory, /shift: event\.shiftKey/);
|
||||
assert.doesNotMatch(factory, /stopPropagation/);
|
||||
|
||||
assert.match(nativeWindow, /LegacyCutKeyDownIntent key => _controller\.CutKeyDown/);
|
||||
assert.match(nativePlayout, /LegacyCutKeyDownIntent or/);
|
||||
});
|
||||
|
||||
test("rendered cut rows expose authoritative focus without replacing DOM rows", () => {
|
||||
const start = app.indexOf("function renderCuts");
|
||||
const end = app.indexOf("cutList.addEventListener", start);
|
||||
const render = app.slice(start, end);
|
||||
assert.match(render, /row\.isFocused === true/);
|
||||
assert.match(render, /element\.tabIndex/);
|
||||
assert.doesNotMatch(render, /replaceChildren/);
|
||||
});
|
||||
Reference in New Issue
Block a user