Skip to content

Commit 49f1464

Browse files
authored
Bugfix/559/limit window region to main screen dimensions (#561)
* (#559) Adjust getRegion implementation It’ll now cut off window regions at the borders of the main screen, avoiding errors due to out of bounds regions * (#559) Moved window e2e test into dedicated e2e subpackage
1 parent 2599ab5 commit 49f1464

File tree

13 files changed

+110
-36
lines changed

13 files changed

+110
-36
lines changed

core/nut.js/lib/window.class.spec.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
11
import { Window } from "./window.class";
2-
import { ProviderRegistry, WindowProviderInterface } from "@nut-tree/provider-interfaces";
2+
import { ProviderRegistry, ScreenProviderInterface, WindowProviderInterface } from "@nut-tree/provider-interfaces";
33
import { mockPartial } from "sneer";
4+
import { Region } from "@nut-tree/shared";
45

56
describe("Window class", () => {
67
it("should retrieve the window region via provider", async () => {
78
// GIVEN
8-
const windowMock = jest.fn();
9+
const windowMock = jest.fn(() => {
10+
return Promise.resolve(new Region(10, 10, 100, 100));
11+
});
912
const providerRegistryMock = mockPartial<ProviderRegistry>({
1013
getWindow(): WindowProviderInterface {
1114
return mockPartial<WindowProviderInterface>({
1215
getWindowRegion: windowMock
1316
});
17+
},
18+
getScreen(): ScreenProviderInterface {
19+
return mockPartial<ScreenProviderInterface>({
20+
screenSize(): Promise<Region> {
21+
return Promise.resolve(new Region(0, 0, 1920, 1080));
22+
}
23+
});
1424
}
1525
});
1626
const mockWindowHandle = 123;

core/nut.js/lib/window.class.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,33 @@ export class Window implements WindowInterface {
2121
}
2222

2323
async getRegion(): Promise<Region> {
24-
return this.providerRegistry.getWindow().getWindowRegion(this.windowHandle);
24+
const region = await this.providerRegistry.getWindow().getWindowRegion(this.windowHandle);
25+
const mainWindowRegion = await this.providerRegistry.getScreen().screenSize();
26+
if (region.left < 0) {
27+
region.width = region.width + region.left;
28+
region.left = 0;
29+
}
30+
if (region.top < 0) {
31+
region.height = region.height + region.top;
32+
region.top = 0;
33+
}
34+
const rightWindowBound = region.left + region.width;
35+
if (rightWindowBound > mainWindowRegion.width) {
36+
const excessWidth = rightWindowBound - mainWindowRegion.width;
37+
region.width = region.width - excessWidth;
38+
}
39+
const bottomWindowBound = region.top + region.height;
40+
if (bottomWindowBound > mainWindowRegion.height) {
41+
const excessHeight = bottomWindowBound - mainWindowRegion.height;
42+
region.height = region.height - excessHeight;
43+
}
44+
if (region.width < 0) {
45+
region.width = 0;
46+
}
47+
if (region.height < 0) {
48+
region.height = 0;
49+
}
50+
return region;
2551
}
2652

2753
async move(newOrigin: Point) {
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
const POS_X = 50;
22
const POS_Y = 100;
33
const WIDTH = 400;
4-
const HEIGTH = 300;
4+
const HEIGHT = 300;
55
const TITLE = "libnut window test";
66

77
module.exports = {
88
POS_X,
99
POS_Y,
1010
WIDTH,
11-
HEIGTH,
11+
HEIGHT,
1212
TITLE,
1313
};
File renamed without changes.
File renamed without changes.

examples/window-test/main.js renamed to e2e/window-test/main.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
const { app, ipcMain, BrowserWindow } = require("electron");
22
const path = require("path");
3-
const { POS_X, POS_Y, WIDTH, HEIGTH } = require("./constants");
3+
const { POS_X, POS_Y, WIDTH, HEIGHT } = require("./constants");
44

55
function createWindow() {
66
const mainWindow = new BrowserWindow({
77
width: WIDTH,
8-
height: HEIGTH,
8+
height: HEIGHT,
99
alwaysOnTop: true,
1010
webPreferences: {
1111
nodeIntegration: true,

examples/window-test/package.json renamed to e2e/window-test/package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@
1111
},
1212
"scripts": {
1313
"pretest": "pnpx playwright install --with-deps",
14-
"test": "jest"
14+
"test": "jest",
15+
"coverage": "jest --coverage --runInBand --logHeapUsage",
16+
"coverage:clean": "rimraf coverage"
1517
},
1618
"devDependencies": {
1719
"@nut-tree/nut-js": "workspace:*",
1820
"@playwright/test": "1.41.2",
19-
"electron": "28.2.3",
21+
"electron": "28.0.0",
2022
"jest": "29.7.0",
2123
"jest-playwright-preset": "4.0.0",
2224
"playwright": "1.41.2"
File renamed without changes.
File renamed without changes.

examples/window-test/test.spec.js renamed to e2e/window-test/test.spec.js

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const { _electron: electron } = require("playwright");
2-
const { sleep, getActiveWindow, getWindows } = require("@nut-tree/nut-js");
3-
const { POS_X, POS_Y, WIDTH, HEIGTH, TITLE } = require("./constants");
2+
const { sleep, getActiveWindow, screen, getWindows } = require("@nut-tree/nut-js");
3+
const { POS_X, POS_Y, WIDTH, HEIGHT, TITLE } = require("./constants");
44

55
let app;
66
let page;
@@ -57,7 +57,7 @@ describe("getActiveWindow", () => {
5757
expect(activeWindowRegion.left).toBe(POS_X);
5858
expect(activeWindowRegion.top).toBe(POS_Y);
5959
expect(activeWindowRegion.width).toBe(WIDTH);
60-
expect(activeWindowRegion.height).toBe(HEIGTH);
60+
expect(activeWindowRegion.height).toBe(HEIGHT);
6161
});
6262

6363
it("should determine correct coordinates for our application after moving the window", async () => {
@@ -93,6 +93,40 @@ describe("getActiveWindow", () => {
9393
});
9494
});
9595

96+
describe("window regions", () => {
97+
it("should crop window coordinates on main screen boundaries to the left", async () => {
98+
// GIVEN
99+
const newLeft = -40;
100+
101+
// WHEN
102+
const foregroundWindow = await getActiveWindow();
103+
await foregroundWindow.move({ x: newLeft, y: POS_Y });
104+
await sleep(1000);
105+
const activeWindowRegion = await foregroundWindow.region;
106+
107+
// THEN
108+
expect(activeWindowRegion.left).toBe(0);
109+
expect(activeWindowRegion.width).toBe(WIDTH + newLeft);
110+
});
111+
112+
it("should crop window coordinates on main screen boundaries to the right", async () => {
113+
// GIVEN
114+
const screenWidth = await screen.width();
115+
const delta = 40;
116+
const newLeft = screenWidth - delta;
117+
118+
// WHEN
119+
const foregroundWindow = await getActiveWindow();
120+
await foregroundWindow.move({ x: newLeft, y: POS_Y });
121+
await sleep(1000);
122+
const activeWindowRegion = await foregroundWindow.region;
123+
124+
// THEN
125+
expect(activeWindowRegion.left).toBe(newLeft);
126+
expect(activeWindowRegion.width).toBe(delta);
127+
});
128+
});
129+
96130
afterEach(async () => {
97131
if (app) {
98132
await app.close();

0 commit comments

Comments
 (0)