Sync CloudShell backend PTY size on terminal resize (#2553)

* Sync CloudShell backend PTY size on terminal resize

Resizing the browser window only re-fit the local xterm; the remote shell kept its original column count, so typed input wrapped/broke at the wrong column. Add resizeTerminal() client call to the CloudShell terminals/{id}/size endpoint and register a debounced terminal.onResize handler that pushes new dimensions to the backend.

* Add unit tests for registerTerminalResizeHandler (debounce, no-op skip, error handling)

* Fix resizeTerminal success test: stub a successful fetch response
This commit is contained in:
Mike Krüger
2026-08-17 10:15:33 +02:00
committed by GitHub
parent 2834bf0fd4
commit 12ad23a061
4 changed files with 252 additions and 2 deletions
@@ -6,6 +6,7 @@ import {
provisionConsole,
putEphemeralUserSettings,
registerCloudShellProvider,
resizeTerminal,
verifyCloudShellProviderRegistration,
} from "./CloudShellClient";
@@ -340,4 +341,66 @@ describe("CloudShellClient", () => {
);
});
});
describe("resizeTerminal", () => {
it("should call fetch with correct parameters", async () => {
const consoleUri = "https://shell.azure.com/console123";
const terminalId = "terminal-id";
const size = { rows: 40, cols: 120 };
global.fetch = jest.fn().mockImplementationOnce(() => {
return {
ok: true,
status: 200,
json: jest.fn().mockResolvedValue({}),
text: jest.fn().mockResolvedValue(""),
headers: new Headers(),
} as unknown as Promise<Response>;
});
await resizeTerminal(consoleUri, terminalId, size);
expect(global.fetch).toHaveBeenCalledWith(
"https://shell.azure.com/console123/terminals/terminal-id/size?cols=120&rows=40&version=2019-01-01",
{
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"Content-Length": "2",
Authorization: "Bearer mock-token",
"x-ms-client-request-id": "mocked-uuid",
"Accept-Language": "en-US",
},
body: "{}",
},
);
});
it("should handle errors when terminal resize fails", async () => {
const consoleUri = "https://shell.azure.com/console123";
const terminalId = "terminal-id";
const size = { rows: 40, cols: 120 };
global.fetch = jest.fn().mockImplementationOnce(() => {
return {
ok: false,
status: 500,
statusText: "Internal Server Error",
json: jest.fn().mockRejectedValue(new Error("Failed to parse JSON")),
text: jest.fn().mockResolvedValue("Server Error"),
headers: new Headers(),
} as unknown as Promise<Response>;
});
await expect(resizeTerminal(consoleUri, terminalId, size)).rejects.toThrow(
"Failed to resize terminal: 500 Internal Server Error",
);
expect(global.fetch).toHaveBeenCalledWith(
"https://shell.azure.com/console123/terminals/terminal-id/size?cols=120&rows=40&version=2019-01-01",
expect.any(Object),
);
});
});
});