Skip to content

Commit

Permalink
Bugfix/559/limit window region to main screen dimensions (#561)
Browse files Browse the repository at this point in the history
* (#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
  • Loading branch information
s1hofmann authored Feb 16, 2024
1 parent 2599ab5 commit 49f1464
Show file tree
Hide file tree
Showing 13 changed files with 110 additions and 36 deletions.
14 changes: 12 additions & 2 deletions core/nut.js/lib/window.class.spec.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
import { Window } from "./window.class";
import { ProviderRegistry, WindowProviderInterface } from "@nut-tree/provider-interfaces";
import { ProviderRegistry, ScreenProviderInterface, WindowProviderInterface } from "@nut-tree/provider-interfaces";
import { mockPartial } from "sneer";
import { Region } from "@nut-tree/shared";

describe("Window class", () => {
it("should retrieve the window region via provider", async () => {
// GIVEN
const windowMock = jest.fn();
const windowMock = jest.fn(() => {
return Promise.resolve(new Region(10, 10, 100, 100));
});
const providerRegistryMock = mockPartial<ProviderRegistry>({
getWindow(): WindowProviderInterface {
return mockPartial<WindowProviderInterface>({
getWindowRegion: windowMock
});
},
getScreen(): ScreenProviderInterface {
return mockPartial<ScreenProviderInterface>({
screenSize(): Promise<Region> {
return Promise.resolve(new Region(0, 0, 1920, 1080));
}
});
}
});
const mockWindowHandle = 123;
Expand Down
28 changes: 27 additions & 1 deletion core/nut.js/lib/window.class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,33 @@ export class Window implements WindowInterface {
}

async getRegion(): Promise<Region> {
return this.providerRegistry.getWindow().getWindowRegion(this.windowHandle);
const region = await this.providerRegistry.getWindow().getWindowRegion(this.windowHandle);
const mainWindowRegion = await this.providerRegistry.getScreen().screenSize();
if (region.left < 0) {
region.width = region.width + region.left;
region.left = 0;
}
if (region.top < 0) {
region.height = region.height + region.top;
region.top = 0;
}
const rightWindowBound = region.left + region.width;
if (rightWindowBound > mainWindowRegion.width) {
const excessWidth = rightWindowBound - mainWindowRegion.width;
region.width = region.width - excessWidth;
}
const bottomWindowBound = region.top + region.height;
if (bottomWindowBound > mainWindowRegion.height) {
const excessHeight = bottomWindowBound - mainWindowRegion.height;
region.height = region.height - excessHeight;
}
if (region.width < 0) {
region.width = 0;
}
if (region.height < 0) {
region.height = 0;
}
return region;
}

async move(newOrigin: Point) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
const POS_X = 50;
const POS_Y = 100;
const WIDTH = 400;
const HEIGTH = 300;
const HEIGHT = 300;
const TITLE = "libnut window test";

module.exports = {
POS_X,
POS_Y,
WIDTH,
HEIGTH,
HEIGHT,
TITLE,
};
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions examples/window-test/main.js → e2e/window-test/main.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
const { app, ipcMain, BrowserWindow } = require("electron");
const path = require("path");
const { POS_X, POS_Y, WIDTH, HEIGTH } = require("./constants");
const { POS_X, POS_Y, WIDTH, HEIGHT } = require("./constants");

function createWindow() {
const mainWindow = new BrowserWindow({
width: WIDTH,
height: HEIGTH,
height: HEIGHT,
alwaysOnTop: true,
webPreferences: {
nodeIntegration: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
},
"scripts": {
"pretest": "pnpx playwright install --with-deps",
"test": "jest"
"test": "jest",
"coverage": "jest --coverage --runInBand --logHeapUsage",
"coverage:clean": "rimraf coverage"
},
"devDependencies": {
"@nut-tree/nut-js": "workspace:*",
"@playwright/test": "1.41.2",
"electron": "28.2.3",
"electron": "28.0.0",
"jest": "29.7.0",
"jest-playwright-preset": "4.0.0",
"playwright": "1.41.2"
Expand Down
File renamed without changes.
File renamed without changes.
40 changes: 37 additions & 3 deletions examples/window-test/test.spec.js → e2e/window-test/test.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const { _electron: electron } = require("playwright");
const { sleep, getActiveWindow, getWindows } = require("@nut-tree/nut-js");
const { POS_X, POS_Y, WIDTH, HEIGTH, TITLE } = require("./constants");
const { sleep, getActiveWindow, screen, getWindows } = require("@nut-tree/nut-js");
const { POS_X, POS_Y, WIDTH, HEIGHT, TITLE } = require("./constants");

let app;
let page;
Expand Down Expand Up @@ -57,7 +57,7 @@ describe("getActiveWindow", () => {
expect(activeWindowRegion.left).toBe(POS_X);
expect(activeWindowRegion.top).toBe(POS_Y);
expect(activeWindowRegion.width).toBe(WIDTH);
expect(activeWindowRegion.height).toBe(HEIGTH);
expect(activeWindowRegion.height).toBe(HEIGHT);
});

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

describe("window regions", () => {
it("should crop window coordinates on main screen boundaries to the left", async () => {
// GIVEN
const newLeft = -40;

// WHEN
const foregroundWindow = await getActiveWindow();
await foregroundWindow.move({ x: newLeft, y: POS_Y });
await sleep(1000);
const activeWindowRegion = await foregroundWindow.region;

// THEN
expect(activeWindowRegion.left).toBe(0);
expect(activeWindowRegion.width).toBe(WIDTH + newLeft);
});

it("should crop window coordinates on main screen boundaries to the right", async () => {
// GIVEN
const screenWidth = await screen.width();
const delta = 40;
const newLeft = screenWidth - delta;

// WHEN
const foregroundWindow = await getActiveWindow();
await foregroundWindow.move({ x: newLeft, y: POS_Y });
await sleep(1000);
const activeWindowRegion = await foregroundWindow.region;

// THEN
expect(activeWindowRegion.left).toBe(newLeft);
expect(activeWindowRegion.width).toBe(delta);
});
});

afterEach(async () => {
if (app) {
await app.close();
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"workspaces": [
"core/*",
"providers/*",
"examples/*"
"examples/*",
"e2e/*"
],
"dependencies": {},
"devDependencies": {
Expand Down
46 changes: 23 additions & 23 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ packages:
- 'core/*'
- 'providers/*'
- 'examples/*'
- 'e2e/*'

0 comments on commit 49f1464

Please sign in to comment.