feat(FN-1739): merge fusion/fn-1739
This commit is contained in:
@@ -357,7 +357,7 @@ export function TerminalModal({ isOpen, onClose, initialCommand, projectId }: Te
|
||||
cursorBlink: true,
|
||||
cursorStyle: "block",
|
||||
fontSize: 14,
|
||||
fontFamily: "monospace",
|
||||
fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace',
|
||||
theme: {
|
||||
background: "#1e1e1e",
|
||||
foreground: "#d4d4d4",
|
||||
@@ -384,15 +384,19 @@ export function TerminalModal({ isOpen, onClose, initialCommand, projectId }: Te
|
||||
terminal.loadAddon(webLinksAddon);
|
||||
|
||||
// Try to load WebGL addon for better performance
|
||||
try {
|
||||
const { WebglAddon } = await import("@xterm/addon-webgl");
|
||||
const webglAddon = new WebglAddon();
|
||||
webglAddon.onContextLoss(() => {
|
||||
webglAddon.dispose();
|
||||
});
|
||||
terminal.loadAddon(webglAddon);
|
||||
} catch {
|
||||
// WebGL not available, fallback to canvas
|
||||
// Skip WebGL on mobile devices to avoid rendering artifacts (e.g., garbled
|
||||
// Unicode characters in powerline prompt symbols on iOS Safari/WebKit).
|
||||
if (!isMobileDevice()) {
|
||||
try {
|
||||
const { WebglAddon } = await import("@xterm/addon-webgl");
|
||||
const webglAddon = new WebglAddon();
|
||||
webglAddon.onContextLoss(() => {
|
||||
webglAddon.dispose();
|
||||
});
|
||||
terminal.loadAddon(webglAddon);
|
||||
} catch {
|
||||
// WebGL not available, fallback to canvas
|
||||
}
|
||||
}
|
||||
|
||||
// Open terminal in container
|
||||
|
||||
@@ -865,6 +865,84 @@ describe("TerminalModal", () => {
|
||||
});
|
||||
});
|
||||
|
||||
// --- FN-1739 mobile WebGL skip regression tests ---
|
||||
describe("mobile WebGL skip (FN-1739)", () => {
|
||||
let savedInnerWidth: typeof window.innerWidth;
|
||||
let savedOntouchstart: typeof window.ontouchstart;
|
||||
let savedNavigator: typeof navigator;
|
||||
|
||||
beforeEach(() => {
|
||||
savedInnerWidth = window.innerWidth;
|
||||
savedOntouchstart = window.ontouchstart;
|
||||
savedNavigator = navigator;
|
||||
|
||||
// Mock WebGL addon to track if it's loaded
|
||||
vi.mock("@xterm/addon-webgl", () => ({
|
||||
WebglAddon: vi.fn(() => ({
|
||||
onContextLoss: vi.fn(),
|
||||
dispose: vi.fn(),
|
||||
})),
|
||||
}));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
Object.defineProperty(window, "innerWidth", {
|
||||
value: savedInnerWidth,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
});
|
||||
Object.defineProperty(window, "ontouchstart", {
|
||||
value: savedOntouchstart,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
});
|
||||
Object.defineProperty(navigator, "maxTouchPoints", {
|
||||
value: (savedNavigator as any).maxTouchPoints,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
});
|
||||
});
|
||||
|
||||
function simulateMobileDevice() {
|
||||
Object.defineProperty(window, "innerWidth", {
|
||||
value: 375,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
});
|
||||
Object.defineProperty(window, "ontouchstart", {
|
||||
value: undefined,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
});
|
||||
Object.defineProperty(navigator, "maxTouchPoints", {
|
||||
value: 2,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
});
|
||||
}
|
||||
|
||||
it("does not load WebGL addon when device is mobile", async () => {
|
||||
simulateMobileDevice();
|
||||
|
||||
// Import WebGL addon mock to get reference for assertions
|
||||
const webglModule = await import("@xterm/addon-webgl");
|
||||
const loadAddonSpy = vi.spyOn(mockTerminalInstance, "loadAddon");
|
||||
|
||||
render(<TerminalModal isOpen={true} onClose={mockOnClose} />);
|
||||
|
||||
// Wait for xterm initialization to complete
|
||||
await waitFor(() => {
|
||||
expect(mockTerminalInstance.open).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
// WebGL addon constructor should NOT have been called
|
||||
expect(webglModule.WebglAddon).not.toHaveBeenCalled();
|
||||
|
||||
// loadAddon should NOT have been called with WebGL addon
|
||||
expect(loadAddonSpy).not.toHaveBeenCalledWith(expect.any(Object));
|
||||
});
|
||||
});
|
||||
|
||||
describe("xterm import MIME type retry", () => {
|
||||
function isXtermImportBatch(values: Iterable<unknown>): values is Promise<unknown>[] {
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user