Skip to content

Commit 7d9d682

Browse files
Merge pull request #240 from RtlZeroMemory/fix/222-modal-actions-order
test(core): lock modal action order and click mapping
2 parents bc3182e + 90223f1 commit 7d9d682

File tree

1 file changed

+62
-0
lines changed

1 file changed

+62
-0
lines changed

packages/core/src/app/__tests__/widgetRenderer.integration.test.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import type { DrawlistBuilder } from "../../drawlist/index.js";
1010
import type { ZrevEvent } from "../../events.js";
1111
import { type VNode, defineWidget, ui } from "../../index.js";
1212
import { DEFAULT_TERMINAL_CAPS } from "../../terminalCaps.js";
13+
import { createTestRenderer } from "../../testing/index.js";
1314
import { defaultTheme } from "../../theme/defaultTheme.js";
1415
import { TOAST_HEIGHT, getToastActionFocusId } from "../../widgets/toast.js";
1516
import { createApp } from "../createApp.js";
@@ -1089,6 +1090,67 @@ describe("WidgetRenderer integration battery", () => {
10891090
assert.deepEqual(events, []);
10901091
});
10911092

1093+
test("modal actions preserve declared order and click behavior", () => {
1094+
const backend = createNoopBackend();
1095+
const renderer = new WidgetRenderer<void>({
1096+
backend,
1097+
requestRender: () => {},
1098+
});
1099+
1100+
const calls: string[] = [];
1101+
const vnode = ui.modal({
1102+
id: "confirm-quit",
1103+
title: "Confirm quit",
1104+
content: ui.text("Are you sure?"),
1105+
actions: [
1106+
ui.button({
1107+
id: "cancel",
1108+
label: "Cancel",
1109+
onPress: () => calls.push("cancel"),
1110+
}),
1111+
ui.button({
1112+
id: "confirm",
1113+
label: "Quit",
1114+
onPress: () => calls.push("confirm"),
1115+
}),
1116+
],
1117+
});
1118+
1119+
const res = renderer.submitFrame(
1120+
() => vnode,
1121+
undefined,
1122+
{ cols: 80, rows: 24 },
1123+
defaultTheme,
1124+
noRenderHooks(),
1125+
);
1126+
assert.ok(res.ok);
1127+
const textSnapshot = createTestRenderer({ viewport: { cols: 80, rows: 24 } })
1128+
.render(vnode)
1129+
.toText();
1130+
assert.equal(textSnapshot.includes("Cancel"), true);
1131+
1132+
const rects = renderer.getRectByIdIndex();
1133+
const cancelRect = rects.get("cancel");
1134+
const confirmRect = rects.get("confirm");
1135+
assert.ok(cancelRect !== undefined, "cancel rect should exist");
1136+
assert.ok(confirmRect !== undefined, "confirm rect should exist");
1137+
if (!cancelRect || !confirmRect) return;
1138+
1139+
assert.equal(cancelRect.x < confirmRect.x, true, "cancel should render left of confirm");
1140+
1141+
const cancelX = cancelRect.x + Math.max(0, Math.floor((cancelRect.w - 1) / 2));
1142+
const cancelY = cancelRect.y;
1143+
renderer.routeEngineEvent(mouseDownEvent(cancelX, cancelY));
1144+
renderer.routeEngineEvent(mouseEvent(cancelX, cancelY, 4));
1145+
1146+
const confirmX = confirmRect.x + Math.max(0, Math.floor((confirmRect.w - 1) / 2));
1147+
const confirmY = confirmRect.y;
1148+
renderer.routeEngineEvent(mouseDownEvent(confirmX, confirmY));
1149+
renderer.routeEngineEvent(mouseEvent(confirmX, confirmY, 4));
1150+
1151+
assert.deepEqual(calls, ["cancel", "confirm"]);
1152+
});
1153+
10921154
test("splitPane double-click toggles collapse via onCollapse", () => {
10931155
const backend = createNoopBackend();
10941156
const renderer = new WidgetRenderer<void>({

0 commit comments

Comments
 (0)