Skip to content

Commit 9786e04

Browse files
authoredNov 6, 2021
Maintenance/310/remove adapters (#311)
* (#310) Delete both adapters * (#310) Migrate window.function to not use adapters * (#310) Migrated window.class to not use adapters * (#310) Migrated screen.class to not use adapters * (#310) Migrated movement.function to not use adapters * (#310) Migrated mouse.class to not use adapters * (#310) Remove leftover notions of adapters in test description * (#310) Fixed expected format when saving a screenshot to disk * (#310) Migrated keyboard.class to not use adapters * (#310) Migrated clipboard.class to not use adapters * (#310) Migrated assert.class test to not use adapters * (#310) Migrated all exported instances to not use adapters * (#310) Removed mention of adapter from test description
1 parent 1ec9d62 commit 9786e04

20 files changed

+729
-1362
lines changed
 

Diff for: ‎index.ts

+6-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import {NativeAdapter} from "./lib/adapter/native.adapter.class";
2-
import {VisionAdapter} from "./lib/adapter/vision.adapter.class";
31
import {AssertClass} from "./lib/assert.class";
42
import {ClipboardClass} from "./lib/clipboard.class";
53
import {KeyboardClass} from "./lib/keyboard.class";
@@ -37,18 +35,16 @@ export {Region} from "./lib/region.class";
3735
export {Window} from "./lib/window.class";
3836
export {FileType} from "./lib/file-type.enum";
3937

40-
const screenActions = new VisionAdapter(providerRegistry);
41-
const nativeActions = new NativeAdapter(providerRegistry);
4238
const lineHelper = new LineHelper();
4339

44-
const clipboard = new ClipboardClass(nativeActions);
45-
const keyboard = new KeyboardClass(nativeActions);
46-
const mouse = new MouseClass(nativeActions);
47-
const screen = new ScreenClass(screenActions);
40+
const clipboard = new ClipboardClass(providerRegistry);
41+
const keyboard = new KeyboardClass(providerRegistry);
42+
const mouse = new MouseClass(providerRegistry);
43+
const screen = new ScreenClass(providerRegistry);
4844
const assert = new AssertClass(screen);
4945

50-
const {straightTo, up, down, left, right} = createMovementApi(nativeActions, lineHelper);
51-
const {getWindows, getActiveWindow} = createWindowApi(nativeActions);
46+
const {straightTo, up, down, left, right} = createMovementApi(providerRegistry, lineHelper);
47+
const {getWindows, getActiveWindow} = createWindowApi(providerRegistry);
5248

5349
const loadImage = providerRegistry.getImageReader().load;
5450
const saveImage = providerRegistry.getImageWriter().store;

Diff for: ‎lib/adapter/native.adapter.class.spec.ts

-263
This file was deleted.

Diff for: ‎lib/adapter/native.adapter.class.ts

-219
This file was deleted.

Diff for: ‎lib/adapter/vision.adapter.class.spec.ts

-129
This file was deleted.

Diff for: ‎lib/adapter/vision.adapter.class.ts

-117
This file was deleted.

Diff for: ‎lib/assert.class.spec.ts

+7-9
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
1-
import {VisionAdapter} from "./adapter/vision.adapter.class";
21
import {AssertClass} from "./assert.class";
32
import {Region} from "./region.class";
43
import {ScreenClass} from "./screen.class";
54
import providerRegistry from "./provider/provider-registry.class";
65

7-
jest.mock('jimp', () => {});
8-
jest.mock("./adapter/native.adapter.class");
9-
jest.mock("./adapter/vision.adapter.class");
6+
jest.mock('jimp', () => {
7+
});
108
jest.mock("./screen.class");
119

1210
describe("Assert", () => {
1311
it("isVisible should not throw if a match is found.", async () => {
1412
// GIVEN
1513
ScreenClass.prototype.find = jest.fn(() => Promise.resolve(new Region(0, 0, 100, 100)));
16-
const screenMock = new ScreenClass(new VisionAdapter(providerRegistry));
14+
const screenMock = new ScreenClass(providerRegistry);
1715
const SUT = new AssertClass(screenMock);
1816
const needle = "foo";
1917

@@ -26,7 +24,7 @@ describe("Assert", () => {
2624
it("isVisible should throw if a match is found.", async () => {
2725
// GIVEN
2826
ScreenClass.prototype.find = jest.fn(() => Promise.reject("foo"));
29-
const screenMock = new ScreenClass(new VisionAdapter(providerRegistry));
27+
const screenMock = new ScreenClass(providerRegistry);
3028
const SUT = new AssertClass(screenMock);
3129
const needle = "foo";
3230

@@ -39,7 +37,7 @@ describe("Assert", () => {
3937
it("isVisible should throw if a match is found.", async () => {
4038
// GIVEN
4139
ScreenClass.prototype.find = jest.fn(() => Promise.reject("foo"));
42-
const screenMock = new ScreenClass(new VisionAdapter(providerRegistry));
40+
const screenMock = new ScreenClass(providerRegistry);
4341
const SUT = new AssertClass(screenMock);
4442
const searchRegion = new Region(10, 10, 10, 10);
4543
const needle = "foo";
@@ -56,7 +54,7 @@ describe("Assert", () => {
5654
it("isNotVisible should throw if a match is found.", async () => {
5755
// GIVEN
5856
ScreenClass.prototype.find = jest.fn(() => Promise.resolve(new Region(0, 0, 100, 100)));
59-
const screenMock = new ScreenClass(new VisionAdapter(providerRegistry));
57+
const screenMock = new ScreenClass(providerRegistry);
6058
const SUT = new AssertClass(screenMock);
6159
const needle = "foo";
6260

@@ -69,7 +67,7 @@ describe("Assert", () => {
6967
it("isVisible should throw if a match is found.", async () => {
7068
// GIVEN
7169
ScreenClass.prototype.find = jest.fn(() => Promise.reject("foo"));
72-
const screenMock = new ScreenClass(new VisionAdapter(providerRegistry));
70+
const screenMock = new ScreenClass(providerRegistry);
7371
const SUT = new AssertClass(screenMock);
7472
const needle = "foo";
7573

Diff for: ‎lib/clipboard.class.e2e.spec.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
import {NativeAdapter} from "./adapter/native.adapter.class";
21
import {ClipboardClass} from "./clipboard.class";
32
import providerRegistry from "./provider/provider-registry.class";
43

54
describe("Clipboard class", () => {
65
it("should paste copied input from system clipboard.", async () => {
7-
const adapterMock = new NativeAdapter(providerRegistry);
8-
const SUT = new ClipboardClass(adapterMock);
6+
const SUT = new ClipboardClass(providerRegistry);
97

108
const textToCopy = "bar";
119

Diff for: ‎lib/clipboard.class.spec.ts

+31-15
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,47 @@
1-
import {NativeAdapter} from "./adapter/native.adapter.class";
21
import {ClipboardClass} from "./clipboard.class";
3-
import providerRegistry from "./provider/provider-registry.class";
2+
import {ProviderRegistry} from "./provider/provider-registry.class";
3+
import {mockPartial} from "sneer";
4+
import {ClipboardProviderInterface} from "./provider";
45

5-
jest.mock('jimp', () => {});
6-
jest.mock("./adapter/native.adapter.class");
6+
jest.mock('jimp', () => {
7+
});
78

89
beforeEach(() => {
9-
jest.resetAllMocks();
10+
jest.clearAllMocks();
1011
});
1112

12-
describe("Clipboard class", () => {
13-
it("should call the native adapters copy method.", () => {
14-
const adapterMock = new NativeAdapter(providerRegistry);
15-
const SUT = new ClipboardClass(adapterMock);
13+
const providerRegistryMock = mockPartial<ProviderRegistry>({})
1614

15+
describe("Clipboard class", () => {
16+
it("should call providers copy method.", () => {
17+
// GIVEN
18+
const SUT = new ClipboardClass(providerRegistryMock);
19+
const copyMock = jest.fn();
20+
providerRegistryMock.getClipboard = jest.fn(() => mockPartial<ClipboardProviderInterface>({
21+
copy: copyMock
22+
}));
1723
const textToCopy = "bar";
1824

25+
// WHEN
1926
SUT.copy(textToCopy);
20-
expect(adapterMock.copy).toHaveBeenCalledTimes(1);
21-
expect(adapterMock.copy).toHaveBeenCalledWith(textToCopy);
27+
28+
// THEN
29+
expect(copyMock).toHaveBeenCalledTimes(1);
30+
expect(copyMock).toHaveBeenCalledWith(textToCopy);
2231
});
2332

24-
it("should call the native adapters paste method.", () => {
25-
const adapterMock = new NativeAdapter(providerRegistry);
26-
const SUT = new ClipboardClass(adapterMock);
33+
it("should call providers paste method.", () => {
34+
// GIVEN
35+
const SUT = new ClipboardClass(providerRegistryMock);
36+
const pasteMock = jest.fn();
37+
providerRegistryMock.getClipboard = jest.fn(() => mockPartial<ClipboardProviderInterface>({
38+
paste: pasteMock
39+
}));
2740

41+
// WHEN
2842
SUT.paste();
29-
expect(adapterMock.paste).toHaveBeenCalledTimes(1);
43+
44+
// THEN
45+
expect(pasteMock).toHaveBeenCalledTimes(1);
3046
});
3147
});

Diff for: ‎lib/clipboard.class.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
1-
import { NativeAdapter } from "./adapter/native.adapter.class";
2-
31
/**
42
* {@link ClipboardClass} class gives access to a systems clipboard
53
*/
4+
import {ProviderRegistry} from "./provider/provider-registry.class";
5+
66
export class ClipboardClass {
77
/**
88
* {@link ClipboardClass} class constructor
9-
* @param nativeAdapter {@link NativeAdapter} instance used to access OS API
9+
* @param providerRegistry
1010
*/
11-
constructor(private nativeAdapter: NativeAdapter) {
11+
constructor(private providerRegistry: ProviderRegistry) {
1212
}
1313

1414
/**
1515
* {@link copy} copies a given text to the system clipboard
1616
* @param text The text to copy
1717
*/
1818
public copy(text: string): Promise<void> {
19-
return this.nativeAdapter.copy(text);
19+
return this.providerRegistry.getClipboard().copy(text);
2020
}
2121

2222
/**
2323
* {@link paste} returns the current content of the system clipboard (limited to text)
2424
*/
2525
public paste(): Promise<string> {
26-
return this.nativeAdapter.paste();
26+
return this.providerRegistry.getClipboard().paste();
2727
}
2828
}

Diff for: ‎lib/keyboard.class.spec.ts

+143-106
Original file line numberDiff line numberDiff line change
@@ -1,115 +1,152 @@
1-
import { NativeAdapter } from "./adapter/native.adapter.class";
2-
import { Key } from "./key.enum";
3-
import { KeyboardClass } from "./keyboard.class";
4-
import providerRegistry from "./provider/provider-registry.class";
1+
import {Key} from "./key.enum";
2+
import {KeyboardClass} from "./keyboard.class";
3+
import {ProviderRegistry} from "./provider/provider-registry.class";
4+
import {mockPartial} from "sneer";
5+
import {KeyboardProviderInterface} from "./provider";
56

6-
jest.mock("./adapter/native.adapter.class");
77
jest.setTimeout(10000);
88

99
beforeEach(() => {
10-
jest.resetAllMocks();
10+
jest.clearAllMocks();
1111
});
1212

13-
describe("Keyboard", () => {
14-
it("should have a default delay of 300 ms", () => {
15-
// GIVEN
16-
const adapterMock = new NativeAdapter(providerRegistry);
17-
const SUT = new KeyboardClass(adapterMock);
18-
19-
// WHEN
20-
21-
// THEN
22-
expect(SUT.config.autoDelayMs).toEqual(300);
23-
});
24-
25-
it("should pass input strings down to the type call.", async () => {
26-
// GIVEN
27-
const adapterMock = new NativeAdapter(providerRegistry);
28-
const SUT = new KeyboardClass(adapterMock);
29-
const payload = "Test input!";
30-
31-
// WHEN
32-
await SUT.type(payload);
33-
34-
// THEN
35-
expect(adapterMock.type).toHaveBeenCalledTimes(payload.length);
36-
for (const char of payload.split("")) {
37-
expect(adapterMock.type).toHaveBeenCalledWith(char);
38-
}
39-
});
40-
41-
it("should pass multiple input strings down to the type call.", async () => {
42-
// GIVEN
43-
const adapterMock = new NativeAdapter(providerRegistry);
44-
const SUT = new KeyboardClass(adapterMock);
45-
const payload = ["Test input!", "Array test2"];
46-
47-
// WHEN
48-
await SUT.type(...payload);
49-
50-
// THEN
51-
expect(adapterMock.type).toHaveBeenCalledTimes(payload.join(" ").length);
52-
for (const char of payload.join(" ").split("")) {
53-
expect(adapterMock.type).toHaveBeenCalledWith(char);
54-
}
55-
});
56-
57-
it("should pass input keys down to the click call.", async () => {
58-
// GIVEN
59-
const adapterMock = new NativeAdapter(providerRegistry);
60-
const SUT = new KeyboardClass(adapterMock);
61-
const payload = [Key.A, Key.S, Key.D, Key.F];
62-
63-
// WHEN
64-
await SUT.type(...payload);
65-
66-
// THEN
67-
expect(adapterMock.click).toHaveBeenCalledTimes(1);
68-
expect(adapterMock.click).toHaveBeenCalledWith(...payload);
69-
});
70-
71-
it("should pass a list of input keys down to the click call.", async () => {
72-
// GIVEN
73-
const adapterMock = new NativeAdapter(providerRegistry);
74-
const SUT = new KeyboardClass(adapterMock);
75-
const payload = [Key.A, Key.S, Key.D, Key.F];
76-
77-
// WHEN
78-
for (const key of payload) {
79-
await SUT.type(key);
13+
const providerRegistryMock = mockPartial<ProviderRegistry>({
14+
getKeyboard(): KeyboardProviderInterface {
15+
return mockPartial<KeyboardProviderInterface>({
16+
setKeyboardDelay: jest.fn(),
17+
})
8018
}
19+
})
8120

82-
// THEN
83-
expect(adapterMock.click).toHaveBeenCalledTimes(payload.length);
84-
});
85-
86-
it("should pass a list of input keys down to the pressKey call.", async () => {
87-
// GIVEN
88-
const adapterMock = new NativeAdapter(providerRegistry);
89-
const SUT = new KeyboardClass(adapterMock);
90-
const payload = [Key.A, Key.S, Key.D, Key.F];
91-
92-
// WHEN
93-
for (const key of payload) {
94-
await SUT.pressKey(key);
95-
}
96-
97-
// THEN
98-
expect(adapterMock.pressKey).toHaveBeenCalledTimes(payload.length);
99-
});
100-
101-
it("should pass a list of input keys down to the releaseKey call.", async () => {
102-
// GIVEN
103-
const adapterMock = new NativeAdapter(providerRegistry);
104-
const SUT = new KeyboardClass(adapterMock);
105-
const payload = [Key.A, Key.S, Key.D, Key.F];
106-
107-
// WHEN
108-
for (const key of payload) {
109-
await SUT.releaseKey(key);
110-
}
111-
112-
// THEN
113-
expect(adapterMock.releaseKey).toHaveBeenCalledTimes(payload.length);
114-
});
21+
describe("Keyboard", () => {
22+
it("should have a default delay of 300 ms", () => {
23+
// GIVEN
24+
const SUT = new KeyboardClass(providerRegistryMock);
25+
26+
// WHEN
27+
28+
// THEN
29+
expect(SUT.config.autoDelayMs).toEqual(300);
30+
});
31+
32+
it("should pass input strings down to the type call.", async () => {
33+
// GIVEN
34+
const SUT = new KeyboardClass(providerRegistryMock);
35+
const payload = "Test input!";
36+
37+
const typeMock = jest.fn();
38+
providerRegistryMock.getKeyboard = jest.fn(() => mockPartial<KeyboardProviderInterface>({
39+
setKeyboardDelay: jest.fn(),
40+
type: typeMock
41+
}));
42+
43+
// WHEN
44+
await SUT.type(payload);
45+
46+
// THEN
47+
expect(typeMock).toHaveBeenCalledTimes(payload.length);
48+
for (const char of payload.split("")) {
49+
expect(typeMock).toHaveBeenCalledWith(char);
50+
}
51+
});
52+
53+
it("should pass multiple input strings down to the type call.", async () => {
54+
// GIVEN
55+
const SUT = new KeyboardClass(providerRegistryMock);
56+
const payload = ["Test input!", "Array test2"];
57+
58+
const typeMock = jest.fn();
59+
providerRegistryMock.getKeyboard = jest.fn(() => mockPartial<KeyboardProviderInterface>({
60+
setKeyboardDelay: jest.fn(),
61+
type: typeMock
62+
}));
63+
64+
// WHEN
65+
await SUT.type(...payload);
66+
67+
// THEN
68+
expect(typeMock).toHaveBeenCalledTimes(payload.join(" ").length);
69+
for (const char of payload.join(" ").split("")) {
70+
expect(typeMock).toHaveBeenCalledWith(char);
71+
}
72+
});
73+
74+
it("should pass input keys down to the click call.", async () => {
75+
// GIVEN
76+
const SUT = new KeyboardClass(providerRegistryMock);
77+
const payload = [Key.A, Key.S, Key.D, Key.F];
78+
79+
const clickMock = jest.fn();
80+
providerRegistryMock.getKeyboard = jest.fn(() => mockPartial<KeyboardProviderInterface>({
81+
setKeyboardDelay: jest.fn(),
82+
click: clickMock
83+
}));
84+
85+
// WHEN
86+
await SUT.type(...payload);
87+
88+
// THEN
89+
expect(clickMock).toHaveBeenCalledTimes(1);
90+
expect(clickMock).toHaveBeenCalledWith(...payload);
91+
});
92+
93+
it("should pass a list of input keys down to the click call.", async () => {
94+
// GIVEN
95+
const SUT = new KeyboardClass(providerRegistryMock);
96+
const payload = [Key.A, Key.S, Key.D, Key.F];
97+
98+
const clickMock = jest.fn();
99+
providerRegistryMock.getKeyboard = jest.fn(() => mockPartial<KeyboardProviderInterface>({
100+
setKeyboardDelay: jest.fn(),
101+
click: clickMock
102+
}));
103+
104+
// WHEN
105+
for (const key of payload) {
106+
await SUT.type(key);
107+
}
108+
109+
// THEN
110+
expect(clickMock).toHaveBeenCalledTimes(payload.length);
111+
});
112+
113+
it("should pass a list of input keys down to the pressKey call.", async () => {
114+
// GIVEN
115+
const SUT = new KeyboardClass(providerRegistryMock);
116+
const payload = [Key.A, Key.S, Key.D, Key.F];
117+
118+
const keyMock = jest.fn();
119+
providerRegistryMock.getKeyboard = jest.fn(() => mockPartial<KeyboardProviderInterface>({
120+
setKeyboardDelay: jest.fn(),
121+
pressKey: keyMock
122+
}));
123+
124+
// WHEN
125+
for (const key of payload) {
126+
await SUT.pressKey(key);
127+
}
128+
129+
// THEN
130+
expect(keyMock).toHaveBeenCalledTimes(payload.length);
131+
});
132+
133+
it("should pass a list of input keys down to the releaseKey call.", async () => {
134+
// GIVEN
135+
const SUT = new KeyboardClass(providerRegistryMock);
136+
const payload = [Key.A, Key.S, Key.D, Key.F];
137+
138+
const keyMock = jest.fn();
139+
providerRegistryMock.getKeyboard = jest.fn(() => mockPartial<KeyboardProviderInterface>({
140+
setKeyboardDelay: jest.fn(),
141+
releaseKey: keyMock
142+
}));
143+
144+
// WHEN
145+
for (const key of payload) {
146+
await SUT.releaseKey(key);
147+
}
148+
149+
// THEN
150+
expect(keyMock).toHaveBeenCalledTimes(payload.length);
151+
});
115152
});

Diff for: ‎lib/keyboard.class.ts

+87-87
Original file line numberDiff line numberDiff line change
@@ -1,105 +1,105 @@
1-
import { NativeAdapter } from "./adapter/native.adapter.class";
2-
import { Key } from "./key.enum";
3-
import { sleep } from "./sleep.function";
1+
import {Key} from "./key.enum";
2+
import {sleep} from "./sleep.function";
3+
import {ProviderRegistry} from "./provider/provider-registry.class";
44

55
type StringOrKey = string[] | Key[];
66

77
const inputIsString = (input: (string | Key)[]): input is string[] => {
8-
return input.every((elem: string | Key) => typeof elem === "string");
8+
return input.every((elem: string | Key) => typeof elem === "string");
99
};
1010

1111
/**
1212
* {@link KeyboardClass} class provides methods to emulate keyboard input
1313
*/
1414
export class KeyboardClass {
1515

16-
/**
17-
* Config object for {@link KeyboardClass} class
18-
*/
19-
public config = {
2016
/**
21-
* Configures the delay between single key events
17+
* Config object for {@link KeyboardClass} class
2218
*/
23-
autoDelayMs: 300,
24-
};
19+
public config = {
20+
/**
21+
* Configures the delay between single key events
22+
*/
23+
autoDelayMs: 300,
24+
};
2525

26-
/**
27-
* {@link KeyboardClass} class constructor
28-
* @param nativeAdapter {@link NativeAdapter} instance which bundles access to mouse, keyboard and clipboard
29-
*/
30-
constructor(private nativeAdapter: NativeAdapter) {
31-
this.nativeAdapter.setKeyboardDelay(this.config.autoDelayMs);
32-
}
26+
/**
27+
* {@link KeyboardClass} class constructor
28+
* @param providerRegistry
29+
*/
30+
constructor(private providerRegistry: ProviderRegistry) {
31+
this.providerRegistry.getKeyboard().setKeyboardDelay(this.config.autoDelayMs);
32+
}
3333

34-
/**
35-
* {@link type} types a sequence of {@link String} or single {@link Key}s via system keyboard
36-
* @example
37-
* ```typescript
38-
* await keyboard.type(Key.A, Key.S, Key.D, Key.F);
39-
* await keyboard.type("Hello, world!");
40-
* ```
41-
*
42-
* @param input Sequence of {@link String} or {@link Key} to type
43-
*/
44-
public type(...input: StringOrKey): Promise<KeyboardClass> {
45-
return new Promise<KeyboardClass>(async (resolve, reject) => {
46-
try {
47-
if (inputIsString(input)) {
48-
for (const char of input.join(" ").split("")) {
49-
await sleep(this.config.autoDelayMs);
50-
await this.nativeAdapter.type(char);
51-
}
52-
} else {
53-
await this.nativeAdapter.click(...input as Key[]);
54-
}
55-
resolve(this);
56-
} catch (e) {
57-
reject(e);
58-
}
59-
});
60-
}
34+
/**
35+
* {@link type} types a sequence of {@link String} or single {@link Key}s via system keyboard
36+
* @example
37+
* ```typescript
38+
* await keyboard.type(Key.A, Key.S, Key.D, Key.F);
39+
* await keyboard.type("Hello, world!");
40+
* ```
41+
*
42+
* @param input Sequence of {@link String} or {@link Key} to type
43+
*/
44+
public type(...input: StringOrKey): Promise<KeyboardClass> {
45+
return new Promise<KeyboardClass>(async (resolve, reject) => {
46+
try {
47+
if (inputIsString(input)) {
48+
for (const char of input.join(" ").split("")) {
49+
await sleep(this.config.autoDelayMs);
50+
await this.providerRegistry.getKeyboard().type(char);
51+
}
52+
} else {
53+
await this.providerRegistry.getKeyboard().click(...input as Key[]);
54+
}
55+
resolve(this);
56+
} catch (e) {
57+
reject(e);
58+
}
59+
});
60+
}
6161

62-
/**
63-
* {@link pressKey} presses and holds a single {@link Key} for {@link Key} combinations
64-
* Modifier {@link Key}s are to be given in "natural" ordering, so first modifier {@link Key}s, followed by the {@link Key} to press
65-
* @example
66-
* ```typescript
67-
* // Will press and hold key combination STRG + V
68-
* await keyboard.pressKey(Key.STRG, Key.A);
69-
* ```
70-
*
71-
* @param keys Array of {@link Key}s to press and hold
72-
*/
73-
public pressKey(...keys: Key[]): Promise<KeyboardClass> {
74-
return new Promise<KeyboardClass>(async (resolve, reject) => {
75-
try {
76-
await this.nativeAdapter.pressKey(...keys);
77-
resolve(this);
78-
} catch (e) {
79-
reject(e);
80-
}
81-
});
82-
}
62+
/**
63+
* {@link pressKey} presses and holds a single {@link Key} for {@link Key} combinations
64+
* Modifier {@link Key}s are to be given in "natural" ordering, so first modifier {@link Key}s, followed by the {@link Key} to press
65+
* @example
66+
* ```typescript
67+
* // Will press and hold key combination STRG + V
68+
* await keyboard.pressKey(Key.STRG, Key.A);
69+
* ```
70+
*
71+
* @param keys Array of {@link Key}s to press and hold
72+
*/
73+
public pressKey(...keys: Key[]): Promise<KeyboardClass> {
74+
return new Promise<KeyboardClass>(async (resolve, reject) => {
75+
try {
76+
await this.providerRegistry.getKeyboard().pressKey(...keys);
77+
resolve(this);
78+
} catch (e) {
79+
reject(e);
80+
}
81+
});
82+
}
8383

84-
/**
85-
* {@link pressKey} releases a single {@link Key} for {@link Key} combinations
86-
* Modifier {@link Key}s are to be given in "natural" ordering, so first modifier {@link Key}s, followed by the {@link Key} to press
87-
* @example
88-
* ```typescript
89-
* // Will release key combination STRG + V
90-
* await keyboard.releaseKey(Key.STRG, Key.A);
91-
* ```
92-
*
93-
* @param keys Array of {@link Key}s to release
94-
*/
95-
public releaseKey(...keys: Key[]): Promise<KeyboardClass> {
96-
return new Promise<KeyboardClass>(async (resolve, reject) => {
97-
try {
98-
await this.nativeAdapter.releaseKey(...keys);
99-
resolve(this);
100-
} catch (e) {
101-
reject(e);
102-
}
103-
});
104-
}
84+
/**
85+
* {@link pressKey} releases a single {@link Key} for {@link Key} combinations
86+
* Modifier {@link Key}s are to be given in "natural" ordering, so first modifier {@link Key}s, followed by the {@link Key} to press
87+
* @example
88+
* ```typescript
89+
* // Will release key combination STRG + V
90+
* await keyboard.releaseKey(Key.STRG, Key.A);
91+
* ```
92+
*
93+
* @param keys Array of {@link Key}s to release
94+
*/
95+
public releaseKey(...keys: Key[]): Promise<KeyboardClass> {
96+
return new Promise<KeyboardClass>(async (resolve, reject) => {
97+
try {
98+
await this.providerRegistry.getKeyboard().releaseKey(...keys);
99+
resolve(this);
100+
} catch (e) {
101+
reject(e);
102+
}
103+
});
104+
}
105105
}

Diff for: ‎lib/mouse.class.spec.ts

+206-145
Original file line numberDiff line numberDiff line change
@@ -1,156 +1,217 @@
1-
import { NativeAdapter } from "./adapter/native.adapter.class";
2-
import { Button } from "./button.enum";
3-
import { MouseClass } from "./mouse.class";
4-
import { Point } from "./point.class";
5-
import { LineHelper } from "./util/linehelper.class";
6-
import providerRegistry from "./provider/provider-registry.class";
7-
8-
jest.mock("./adapter/native.adapter.class");
1+
import {Button} from "./button.enum";
2+
import {MouseClass} from "./mouse.class";
3+
import {Point} from "./point.class";
4+
import {LineHelper} from "./util/linehelper.class";
5+
import {ProviderRegistry} from "./provider/provider-registry.class";
6+
import {mockPartial} from "sneer";
7+
import {MouseProviderInterface} from "./provider";
98

109
beforeEach(() => {
11-
jest.resetAllMocks();
10+
jest.clearAllMocks();
1211
});
1312

1413
const linehelper = new LineHelper();
1514

15+
const providerRegistryMock = mockPartial<ProviderRegistry>({
16+
getMouse(): MouseProviderInterface {
17+
return mockPartial<MouseProviderInterface>({
18+
setMouseDelay: jest.fn()
19+
})
20+
}
21+
});
22+
1623
describe("Mouse class", () => {
17-
it("should have a default delay of 500 ms", () => {
18-
// GIVEN
19-
const adapterMock = new NativeAdapter(providerRegistry);
20-
const SUT = new MouseClass(adapterMock);
21-
22-
// WHEN
23-
24-
// THEN
25-
expect(SUT.config.autoDelayMs).toEqual(100);
26-
});
27-
28-
it("should forward scrollLeft to the native adapter class", async () => {
29-
// GIVEN
30-
const nativeAdapterMock = new NativeAdapter(providerRegistry);
31-
const SUT = new MouseClass(nativeAdapterMock);
32-
const scrollAmount = 5;
33-
34-
// WHEN
35-
const result = await SUT.scrollLeft(scrollAmount);
36-
37-
// THEN
38-
expect(nativeAdapterMock.scrollLeft).toBeCalledWith(scrollAmount);
39-
expect(result).toBe(SUT);
40-
});
41-
42-
it("should forward scrollRight to the native adapter class", async () => {
43-
// GIVEN
44-
const nativeAdapterMock = new NativeAdapter(providerRegistry);
45-
const SUT = new MouseClass(nativeAdapterMock);
46-
const scrollAmount = 5;
47-
48-
// WHEN
49-
const result = await SUT.scrollRight(scrollAmount);
50-
51-
// THEN
52-
expect(nativeAdapterMock.scrollRight).toBeCalledWith(scrollAmount);
53-
expect(result).toBe(SUT);
54-
});
55-
56-
it("should forward scrollDown to the native adapter class", async () => {
57-
// GIVEN
58-
const nativeAdapterMock = new NativeAdapter(providerRegistry);
59-
const SUT = new MouseClass(nativeAdapterMock);
60-
const scrollAmount = 5;
61-
62-
// WHEN
63-
const result = await SUT.scrollDown(scrollAmount);
64-
65-
// THEN
66-
expect(nativeAdapterMock.scrollDown).toBeCalledWith(scrollAmount);
67-
expect(result).toBe(SUT);
68-
});
69-
70-
it("should forward scrollUp to the native adapter class", async () => {
71-
// GIVEN
72-
const nativeAdapterMock = new NativeAdapter(providerRegistry);
73-
const SUT = new MouseClass(nativeAdapterMock);
74-
const scrollAmount = 5;
75-
76-
// WHEN
77-
const result = await SUT.scrollUp(scrollAmount);
78-
79-
// THEN
80-
expect(nativeAdapterMock.scrollUp).toBeCalledWith(scrollAmount);
81-
expect(result).toBe(SUT);
82-
});
83-
84-
it("should forward leftClick to the native adapter class", async () => {
85-
// GIVEN
86-
const nativeAdapterMock = new NativeAdapter(providerRegistry);
87-
const SUT = new MouseClass(nativeAdapterMock);
88-
89-
// WHEN
90-
const result = await SUT.leftClick();
91-
92-
// THEN
93-
expect(nativeAdapterMock.leftClick).toBeCalled();
94-
expect(result).toBe(SUT);
95-
});
96-
97-
it("should forward rightClick to the native adapter class", async () => {
98-
// GIVEN
99-
const nativeAdapterMock = new NativeAdapter(providerRegistry);
100-
const SUT = new MouseClass(nativeAdapterMock);
101-
102-
// WHEN
103-
const result = await SUT.rightClick();
104-
105-
// THEN
106-
expect(nativeAdapterMock.rightClick).toBeCalled();
107-
expect(result).toBe(SUT);
108-
});
109-
110-
it("update mouse position along path on move", async () => {
111-
// GIVEN
112-
const nativeAdapterMock = new NativeAdapter(providerRegistry);
113-
const SUT = new MouseClass(nativeAdapterMock);
114-
const path = linehelper.straightLine(new Point(0, 0), new Point(10, 10));
115-
116-
// WHEN
117-
const result = await SUT.move(path);
118-
119-
// THEN
120-
expect(nativeAdapterMock.setMousePosition).toBeCalledTimes(path.length);
121-
expect(result).toBe(SUT);
122-
});
123-
124-
it("should press and hold left mouse button, move and release left mouse button on drag", async () => {
125-
// GIVEN
126-
const nativeAdapterMock = new NativeAdapter(providerRegistry);
127-
const SUT = new MouseClass(nativeAdapterMock);
128-
const path = linehelper.straightLine(new Point(0, 0), new Point(10, 10));
129-
130-
// WHEN
131-
const result = await SUT.drag(path);
132-
133-
// THEN
134-
expect(nativeAdapterMock.pressButton).toBeCalledWith(Button.LEFT);
135-
expect(nativeAdapterMock.setMousePosition).toBeCalledTimes(path.length);
136-
expect(nativeAdapterMock.releaseButton).toBeCalledWith(Button.LEFT);
137-
expect(result).toBe(SUT);
138-
});
24+
it("should have a default delay of 500 ms", () => {
25+
// GIVEN
26+
const SUT = new MouseClass(providerRegistryMock);
27+
28+
// WHEN
29+
30+
// THEN
31+
expect(SUT.config.autoDelayMs).toEqual(100);
32+
});
33+
34+
it("should forward scrollLeft to the provider", async () => {
35+
// GIVEN
36+
const SUT = new MouseClass(providerRegistryMock);
37+
const scrollAmount = 5;
38+
39+
const scrollMock = jest.fn();
40+
providerRegistryMock.getMouse = jest.fn(() => mockPartial<MouseProviderInterface>({
41+
setMouseDelay: jest.fn(),
42+
scrollLeft: scrollMock
43+
}));
44+
45+
// WHEN
46+
const result = await SUT.scrollLeft(scrollAmount);
47+
48+
// THEN
49+
expect(scrollMock).toBeCalledWith(scrollAmount);
50+
expect(result).toBe(SUT);
51+
});
52+
53+
it("should forward scrollRight to the provider", async () => {
54+
// GIVEN
55+
const SUT = new MouseClass(providerRegistryMock);
56+
const scrollAmount = 5;
57+
58+
const scrollMock = jest.fn();
59+
providerRegistryMock.getMouse = jest.fn(() => mockPartial<MouseProviderInterface>({
60+
setMouseDelay: jest.fn(),
61+
scrollRight: scrollMock
62+
}));
63+
64+
// WHEN
65+
const result = await SUT.scrollRight(scrollAmount);
66+
67+
// THEN
68+
expect(scrollMock).toBeCalledWith(scrollAmount);
69+
expect(result).toBe(SUT);
70+
});
71+
72+
it("should forward scrollDown to the provider", async () => {
73+
// GIVEN
74+
const SUT = new MouseClass(providerRegistryMock);
75+
const scrollAmount = 5;
76+
77+
const scrollMock = jest.fn();
78+
providerRegistryMock.getMouse = jest.fn(() => mockPartial<MouseProviderInterface>({
79+
setMouseDelay: jest.fn(),
80+
scrollDown: scrollMock
81+
}));
82+
83+
// WHEN
84+
const result = await SUT.scrollDown(scrollAmount);
85+
86+
// THEN
87+
expect(scrollMock).toBeCalledWith(scrollAmount);
88+
expect(result).toBe(SUT);
89+
});
90+
91+
it("should forward scrollUp to the provider", async () => {
92+
// GIVEN
93+
const SUT = new MouseClass(providerRegistryMock);
94+
const scrollAmount = 5;
95+
96+
const scrollMock = jest.fn();
97+
providerRegistryMock.getMouse = jest.fn(() => mockPartial<MouseProviderInterface>({
98+
setMouseDelay: jest.fn(),
99+
scrollUp: scrollMock
100+
}));
101+
102+
// WHEN
103+
const result = await SUT.scrollUp(scrollAmount);
104+
105+
// THEN
106+
expect(scrollMock).toBeCalledWith(scrollAmount);
107+
expect(result).toBe(SUT);
108+
});
109+
110+
it("should forward leftClick to the provider", async () => {
111+
// GIVEN
112+
const SUT = new MouseClass(providerRegistryMock);
113+
114+
const clickMock = jest.fn();
115+
providerRegistryMock.getMouse = jest.fn(() => mockPartial<MouseProviderInterface>({
116+
setMouseDelay: jest.fn(),
117+
leftClick: clickMock
118+
}));
119+
120+
// WHEN
121+
const result = await SUT.leftClick();
122+
123+
// THEN
124+
expect(clickMock).toBeCalled();
125+
expect(result).toBe(SUT);
126+
});
127+
128+
it("should forward rightClick to the provider", async () => {
129+
// GIVEN
130+
const SUT = new MouseClass(providerRegistryMock);
131+
132+
const clickMock = jest.fn();
133+
providerRegistryMock.getMouse = jest.fn(() => mockPartial<MouseProviderInterface>({
134+
setMouseDelay: jest.fn(),
135+
rightClick: clickMock
136+
}));
137+
138+
// WHEN
139+
const result = await SUT.rightClick();
140+
141+
// THEN
142+
expect(clickMock).toBeCalled();
143+
expect(result).toBe(SUT);
144+
});
145+
146+
it("update mouse position along path on move", async () => {
147+
// GIVEN
148+
const SUT = new MouseClass(providerRegistryMock);
149+
const path = linehelper.straightLine(new Point(0, 0), new Point(10, 10));
150+
151+
const setPositionMock = jest.fn();
152+
providerRegistryMock.getMouse = jest.fn(() => mockPartial<MouseProviderInterface>({
153+
setMouseDelay: jest.fn(),
154+
setMousePosition: setPositionMock
155+
}));
156+
157+
// WHEN
158+
const result = await SUT.move(path);
159+
160+
// THEN
161+
expect(setPositionMock).toBeCalledTimes(path.length);
162+
expect(result).toBe(SUT);
163+
});
164+
165+
it("should press and hold left mouse button, move and release left mouse button on drag", async () => {
166+
// GIVEN
167+
const SUT = new MouseClass(providerRegistryMock);
168+
const path = linehelper.straightLine(new Point(0, 0), new Point(10, 10));
169+
170+
const setPositionMock = jest.fn();
171+
const pressButtonMock = jest.fn();
172+
const releaseButtonMock = jest.fn();
173+
providerRegistryMock.getMouse = jest.fn(() => mockPartial<MouseProviderInterface>({
174+
setMouseDelay: jest.fn(),
175+
setMousePosition: setPositionMock,
176+
pressButton: pressButtonMock,
177+
releaseButton: releaseButtonMock
178+
}));
179+
180+
// WHEN
181+
const result = await SUT.drag(path);
182+
183+
// THEN
184+
expect(pressButtonMock).toBeCalledWith(Button.LEFT);
185+
expect(setPositionMock).toBeCalledTimes(path.length);
186+
expect(releaseButtonMock).toBeCalledWith(Button.LEFT);
187+
expect(result).toBe(SUT);
188+
});
139189
});
140190

141191
describe("Mousebuttons", () => {
142-
it.each([
143-
[Button.LEFT, Button.LEFT],
144-
[Button.MIDDLE, Button.MIDDLE],
145-
[Button.RIGHT, Button.RIGHT],
146-
] as Array<[Button, Button]>)("should be pressed and released", async (input: Button, expected: Button) => {
147-
const nativeAdapterMock = new NativeAdapter(providerRegistry);
148-
const SUT = new MouseClass(nativeAdapterMock);
149-
const pressed = await SUT.pressButton(input);
150-
const released = await SUT.releaseButton(input);
151-
expect(nativeAdapterMock.pressButton).toBeCalledWith(expected);
152-
expect(nativeAdapterMock.releaseButton).toBeCalledWith(expected);
153-
expect(pressed).toBe(SUT);
154-
expect(released).toBe(SUT);
155-
});
192+
it.each([
193+
[Button.LEFT, Button.LEFT],
194+
[Button.MIDDLE, Button.MIDDLE],
195+
[Button.RIGHT, Button.RIGHT],
196+
] as Array<[Button, Button]>)("should be pressed and released", async (input: Button, expected: Button) => {
197+
// GIVEN
198+
const SUT = new MouseClass(providerRegistryMock);
199+
const pressButtonMock = jest.fn();
200+
const releaseButtonMock = jest.fn();
201+
providerRegistryMock.getMouse = jest.fn(() => mockPartial<MouseProviderInterface>({
202+
setMouseDelay: jest.fn(),
203+
pressButton: pressButtonMock,
204+
releaseButton: releaseButtonMock
205+
}));
206+
207+
// WHEN
208+
const pressed = await SUT.pressButton(input);
209+
const released = await SUT.releaseButton(input);
210+
211+
// THEN
212+
expect(pressButtonMock).toBeCalledWith(expected);
213+
expect(releaseButtonMock).toBeCalledWith(expected);
214+
expect(pressed).toBe(SUT);
215+
expect(released).toBe(SUT);
216+
});
156217
});

Diff for: ‎lib/mouse.class.ts

+17-17
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import {NativeAdapter} from "./adapter/native.adapter.class";
21
import {Button} from "./button.enum";
32
import {Point} from "./point.class";
43
import {busyWaitForNanoSeconds, sleep} from "./sleep.function";
54
import {calculateMovementTimesteps, EasingFunction, linear} from "./mouse-movement.function";
5+
import {ProviderRegistry} from "./provider/provider-registry.class";
66

77
/**
88
* {@link MouseClass} class provides methods to emulate mouse input
@@ -25,10 +25,10 @@ export class MouseClass {
2525

2626
/**
2727
* {@link MouseClass} class constructor
28-
* @param nativeAdapter {@link NativeAdapter} instance which bundles access to mouse, keyboard and clipboard
28+
* @param providerRegistry
2929
*/
30-
constructor(private nativeAdapter: NativeAdapter) {
31-
this.nativeAdapter.setMouseDelay(0);
30+
constructor(private providerRegistry: ProviderRegistry) {
31+
this.providerRegistry.getMouse().setMouseDelay(0);
3232
}
3333

3434
/**
@@ -38,7 +38,7 @@ export class MouseClass {
3838
public async setPosition(target: Point): Promise<MouseClass> {
3939
return new Promise<MouseClass>(async (resolve, reject) => {
4040
try {
41-
await this.nativeAdapter.setMousePosition(target);
41+
await this.providerRegistry.getMouse().setMousePosition(target);
4242
resolve(this);
4343
} catch (e) {
4444
reject(e);
@@ -50,7 +50,7 @@ export class MouseClass {
5050
* {@link getPosition} returns a {@link Point} representing the current mouse position
5151
*/
5252
public getPosition(): Promise<Point> {
53-
return this.nativeAdapter.currentMousePosition();
53+
return this.providerRegistry.getMouse().currentMousePosition();
5454
}
5555

5656
/**
@@ -67,7 +67,7 @@ export class MouseClass {
6767
const node = pathSteps[idx];
6868
const minTime = timeSteps[idx];
6969
await busyWaitForNanoSeconds(minTime);
70-
await this.nativeAdapter.setMousePosition(node);
70+
await this.providerRegistry.getMouse().setMousePosition(node);
7171
}
7272
resolve(this);
7373
} catch (e) {
@@ -82,7 +82,7 @@ export class MouseClass {
8282
public async leftClick(): Promise<MouseClass> {
8383
return new Promise<MouseClass>(async resolve => {
8484
await sleep(this.config.autoDelayMs);
85-
await this.nativeAdapter.leftClick();
85+
await this.providerRegistry.getMouse().leftClick();
8686
resolve(this);
8787
});
8888
}
@@ -94,7 +94,7 @@ export class MouseClass {
9494
return new Promise<MouseClass>(async (resolve, reject) => {
9595
try {
9696
await sleep(this.config.autoDelayMs);
97-
await this.nativeAdapter.rightClick();
97+
await this.providerRegistry.getMouse().rightClick();
9898
resolve(this);
9999
} catch (e) {
100100
reject(e);
@@ -111,7 +111,7 @@ export class MouseClass {
111111
return new Promise<MouseClass>(async (resolve, reject) => {
112112
try {
113113
await sleep(this.config.autoDelayMs);
114-
await this.nativeAdapter.scrollDown(amount);
114+
await this.providerRegistry.getMouse().scrollDown(amount);
115115
resolve(this);
116116
} catch (e) {
117117
reject(e);
@@ -128,7 +128,7 @@ export class MouseClass {
128128
return new Promise<MouseClass>(async (resolve, reject) => {
129129
try {
130130
await sleep(this.config.autoDelayMs);
131-
await this.nativeAdapter.scrollUp(amount);
131+
await this.providerRegistry.getMouse().scrollUp(amount);
132132
resolve(this);
133133
} catch (e) {
134134
reject(e);
@@ -145,7 +145,7 @@ export class MouseClass {
145145
return new Promise<MouseClass>(async (resolve, reject) => {
146146
try {
147147
await sleep(this.config.autoDelayMs);
148-
await this.nativeAdapter.scrollLeft(amount);
148+
await this.providerRegistry.getMouse().scrollLeft(amount);
149149
resolve(this);
150150
} catch (e) {
151151
reject(e);
@@ -162,7 +162,7 @@ export class MouseClass {
162162
return new Promise<MouseClass>(async (resolve, reject) => {
163163
try {
164164
await sleep(this.config.autoDelayMs);
165-
await this.nativeAdapter.scrollRight(amount);
165+
await this.providerRegistry.getMouse().scrollRight(amount);
166166
resolve(this);
167167
} catch (e) {
168168
reject(e);
@@ -179,9 +179,9 @@ export class MouseClass {
179179
return new Promise<MouseClass>(async (resolve, reject) => {
180180
try {
181181
await sleep(this.config.autoDelayMs);
182-
await this.nativeAdapter.pressButton(Button.LEFT);
182+
await this.providerRegistry.getMouse().pressButton(Button.LEFT);
183183
await this.move(path);
184-
await this.nativeAdapter.releaseButton(Button.LEFT);
184+
await this.providerRegistry.getMouse().releaseButton(Button.LEFT);
185185
resolve(this);
186186
} catch (e) {
187187
reject(e);
@@ -196,7 +196,7 @@ export class MouseClass {
196196
public async pressButton(btn: Button): Promise<MouseClass> {
197197
return new Promise<MouseClass>(async (resolve, reject) => {
198198
try {
199-
await this.nativeAdapter.pressButton(btn);
199+
await this.providerRegistry.getMouse().pressButton(btn);
200200
resolve(this);
201201
} catch (e) {
202202
reject(e);
@@ -211,7 +211,7 @@ export class MouseClass {
211211
public async releaseButton(btn: Button): Promise<MouseClass> {
212212
return new Promise<MouseClass>(async (resolve, reject) => {
213213
try {
214-
await this.nativeAdapter.releaseButton(btn);
214+
await this.providerRegistry.getMouse().releaseButton(btn);
215215
resolve(this);
216216
} catch (e) {
217217
reject(e);

Diff for: ‎lib/movement.function.ts

+28-28
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
1-
import { NativeAdapter } from "./adapter/native.adapter.class";
2-
import { MovementApi } from "./movement-api.interface";
3-
import { Point } from "./point.class";
4-
import { LineHelper } from "./util/linehelper.class";
1+
import {MovementApi} from "./movement-api.interface";
2+
import {Point} from "./point.class";
3+
import {LineHelper} from "./util/linehelper.class";
4+
import {ProviderRegistry} from "./provider/provider-registry.class";
55

6-
export const createMovementApi = (native: NativeAdapter, lineHelper: LineHelper): MovementApi => {
7-
return ({
8-
down: async (px: number): Promise<Point[]> => {
9-
const pos = await native.currentMousePosition();
10-
return lineHelper.straightLine(pos, new Point(pos.x, pos.y + px));
11-
},
12-
left: async (px: number): Promise<Point[]> => {
13-
const pos = await native.currentMousePosition();
14-
return lineHelper.straightLine(pos, new Point(pos.x - px, pos.y));
15-
},
16-
right: async (px: number): Promise<Point[]> => {
17-
const pos = await native.currentMousePosition();
18-
return lineHelper.straightLine(pos, new Point(pos.x + px, pos.y));
19-
},
20-
straightTo: async (target: Point | Promise<Point>): Promise<Point[]> => {
21-
const targetPoint = await target;
22-
const origin = await native.currentMousePosition();
23-
return lineHelper.straightLine(origin, targetPoint);
24-
},
25-
up: async (px: number): Promise<Point[]> => {
26-
const pos = await native.currentMousePosition();
27-
return lineHelper.straightLine(pos, new Point(pos.x, pos.y - px));
28-
},
29-
});
6+
export const createMovementApi = (providerRegistry: ProviderRegistry, lineHelper: LineHelper): MovementApi => {
7+
return ({
8+
down: async (px: number): Promise<Point[]> => {
9+
const pos = await providerRegistry.getMouse().currentMousePosition();
10+
return lineHelper.straightLine(pos, new Point(pos.x, pos.y + px));
11+
},
12+
left: async (px: number): Promise<Point[]> => {
13+
const pos = await providerRegistry.getMouse().currentMousePosition();
14+
return lineHelper.straightLine(pos, new Point(pos.x - px, pos.y));
15+
},
16+
right: async (px: number): Promise<Point[]> => {
17+
const pos = await providerRegistry.getMouse().currentMousePosition();
18+
return lineHelper.straightLine(pos, new Point(pos.x + px, pos.y));
19+
},
20+
straightTo: async (target: Point | Promise<Point>): Promise<Point[]> => {
21+
const targetPoint = await target;
22+
const origin = await providerRegistry.getMouse().currentMousePosition();
23+
return lineHelper.straightLine(origin, targetPoint);
24+
},
25+
up: async (px: number): Promise<Point[]> => {
26+
const pos = await providerRegistry.getMouse().currentMousePosition();
27+
return lineHelper.straightLine(pos, new Point(pos.x, pos.y - px));
28+
},
29+
});
3030
};

Diff for: ‎lib/screen.class.spec.ts

+136-161
Large diffs are not rendered by default.

Diff for: ‎lib/screen.class.ts

+14-14
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import {join, normalize} from "path";
22
import {cwd} from "process";
3-
import {VisionAdapter} from "./adapter/vision.adapter.class";
43
import {FileType} from "./file-type.enum";
54
import {generateOutputPath} from "./generate-output-path.function";
65
import {LocationParameters} from "./locationparameters.class";
@@ -9,6 +8,7 @@ import {MatchResult} from "./match-result.class";
98
import {Region} from "./region.class";
109
import {timeout} from "./util/timeout.function";
1110
import {Image} from "./image.class";
11+
import {ProviderRegistry} from "./provider/provider-registry.class";
1212

1313
export type FindHookCallback = (target: MatchResult) => Promise<void>;
1414

@@ -48,11 +48,11 @@ export class ScreenClass {
4848

4949
/**
5050
* {@link ScreenClass} class constructor
51-
* @param vision {@link VisionAdapter} instance which bundles access to screen and / or computer vision related APIs
51+
* @param providerRegistry A {@link ProviderRegistry} used to access underlying implementations
5252
* @param findHooks A {@link Map} of {@link FindHookCallback} methods assigned to a template image filename
5353
*/
5454
constructor(
55-
private vision: VisionAdapter,
55+
private providerRegistry: ProviderRegistry,
5656
private findHooks: Map<string, FindHookCallback[]> = new Map<string, FindHookCallback[]>()) {
5757
}
5858

@@ -62,7 +62,7 @@ export class ScreenClass {
6262
* Screens with higher pixel density (e.g. retina displays in MacBooks) might have a higher width in in actual pixels
6363
*/
6464
public width() {
65-
return this.vision.screenWidth();
65+
return this.providerRegistry.getScreen().screenWidth();
6666
}
6767

6868
/**
@@ -71,7 +71,7 @@ export class ScreenClass {
7171
* Screens with higher pixel density (e.g. retina displays in MacBooks) might have a higher height in in actual pixels
7272
*/
7373
public height() {
74-
return this.vision.screenHeight();
74+
return this.providerRegistry.getScreen().screenHeight();
7575
}
7676

7777
/**
@@ -84,13 +84,13 @@ export class ScreenClass {
8484
params?: LocationParameters,
8585
): Promise<Region> {
8686
const minMatch = (params && params.confidence) || this.config.confidence;
87-
const screenSize = await this.vision.screenSize();
87+
const screenSize = await this.providerRegistry.getScreen().screenSize();
8888
const searchRegion = (params && params.searchRegion) || screenSize;
8989
const searchMultipleScales = (params && params.searchMultipleScales)
9090

9191
const fullPathToNeedle = normalize(join(this.config.resourceDirectory, templateImageFilename));
9292

93-
const screenImage = await this.vision.grabScreen();
93+
const screenImage = await this.providerRegistry.getScreen().grabScreen();
9494

9595
const matchRequest = new MatchRequest(
9696
screenImage,
@@ -118,7 +118,7 @@ export class ScreenClass {
118118
return new Promise<Region>(async (resolve, reject) => {
119119
try {
120120
validateSearchRegion(searchRegion, screenSize);
121-
const matchResult = await this.vision.findOnScreenRegion(matchRequest);
121+
const matchResult = await this.providerRegistry.getImageFinder().findMatch(matchRequest);
122122
if (matchResult.confidence >= minMatch) {
123123
const possibleHooks = this.findHooks.get(templateImageFilename) || [];
124124
for (const hook of possibleHooks) {
@@ -156,7 +156,7 @@ export class ScreenClass {
156156
*/
157157
public async highlight(regionToHighlight: Region | Promise<Region>): Promise<Region> {
158158
const highlightRegion = await regionToHighlight;
159-
await this.vision.highlightScreenRegion(highlightRegion, this.config.highlightDurationMs, this.config.highlightOpacity);
159+
await this.providerRegistry.getScreen().highlightScreenRegion(highlightRegion, this.config.highlightDurationMs, this.config.highlightOpacity);
160160
return highlightRegion;
161161
}
162162

@@ -198,7 +198,7 @@ export class ScreenClass {
198198
filePath: string = cwd(),
199199
fileNamePrefix: string = "",
200200
fileNamePostfix: string = ""): Promise<string> {
201-
const currentScreen = await this.vision.grabScreen();
201+
const currentScreen = await this.providerRegistry.getScreen().grabScreen();
202202
return this.saveImage(
203203
currentScreen,
204204
fileName,
@@ -212,7 +212,7 @@ export class ScreenClass {
212212
* {@link grab} grabs screen content of a systems main display
213213
*/
214214
public async grab(): Promise<Image> {
215-
return this.vision.grabScreen();
215+
return this.providerRegistry.getScreen().grabScreen();
216216
}
217217

218218
/**
@@ -231,7 +231,7 @@ export class ScreenClass {
231231
filePath: string = cwd(),
232232
fileNamePrefix: string = "",
233233
fileNamePostfix: string = ""): Promise<string> {
234-
const regionImage = await this.vision.grabScreenRegion(await regionToCapture);
234+
const regionImage = await this.providerRegistry.getScreen().grabScreenRegion(await regionToCapture);
235235
return this.saveImage(
236236
regionImage,
237237
fileName,
@@ -246,7 +246,7 @@ export class ScreenClass {
246246
* @param regionToGrab The screen region to grab
247247
*/
248248
public async grabRegion(regionToGrab: Region | Promise<Region>): Promise<Image> {
249-
return this.vision.grabScreenRegion(await regionToGrab);
249+
return this.providerRegistry.getScreen().grabScreenRegion(await regionToGrab);
250250
}
251251

252252
private async saveImage(
@@ -262,7 +262,7 @@ export class ScreenClass {
262262
prefix: fileNamePrefix,
263263
type: fileFormat,
264264
});
265-
await this.vision.saveImage(image, outputPath);
265+
await this.providerRegistry.getImageWriter().store({data: image, path: outputPath})
266266
return outputPath;
267267
}
268268
}

Diff for: ‎lib/window.class.spec.ts

+29-14
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,51 @@
11
import {Window} from "./window.class";
2-
import {NativeAdapter} from "./adapter/native.adapter.class";
3-
import providerRegistry from "./provider/provider-registry.class";
2+
import {ProviderRegistry} from "./provider/provider-registry.class";
3+
import {mockPartial} from "sneer";
4+
import {WindowProviderInterface} from "./provider";
45

5-
jest.mock('jimp', () => {});
6-
jest.mock("./adapter/native.adapter.class");
6+
jest.mock('jimp', () => {
7+
});
78

89
describe("Window class", () => {
9-
it("should retrieve the window region via its native adapter", async () => {
10+
it("should retrieve the window region via provider", async () => {
1011
// GIVEN
11-
const nativeAdapterMock = new NativeAdapter(providerRegistry);
12+
const windowMock = jest.fn();
13+
const providerRegistryMock = mockPartial<ProviderRegistry>({
14+
getWindow(): WindowProviderInterface {
15+
return mockPartial<WindowProviderInterface>({
16+
getWindowRegion: windowMock
17+
})
18+
}
19+
})
1220
const mockWindowHandle = 123;
13-
const SUT = new Window(nativeAdapterMock, mockWindowHandle);
21+
const SUT = new Window(providerRegistryMock, mockWindowHandle);
1422

1523
// WHEN
1624
await SUT.region
1725

1826
// THEN
19-
expect(nativeAdapterMock.getWindowRegion).toBeCalledTimes(1);
20-
expect(nativeAdapterMock.getWindowRegion).toBeCalledWith(mockWindowHandle);
27+
expect(windowMock).toBeCalledTimes(1);
28+
expect(windowMock).toBeCalledWith(mockWindowHandle);
2129
});
2230

23-
it("should retrieve the window title via its native adapter", async () => {
31+
it("should retrieve the window title via provider", async () => {
2432
// GIVEN
25-
const nativeAdapterMock = new NativeAdapter(providerRegistry);
33+
const windowMock = jest.fn();
34+
const providerRegistryMock = mockPartial<ProviderRegistry>({
35+
getWindow(): WindowProviderInterface {
36+
return mockPartial<WindowProviderInterface>({
37+
getWindowTitle: windowMock
38+
})
39+
}
40+
})
2641
const mockWindowHandle = 123;
27-
const SUT = new Window(nativeAdapterMock, mockWindowHandle);
42+
const SUT = new Window(providerRegistryMock, mockWindowHandle);
2843

2944
// WHEN
3045
await SUT.title
3146

3247
// THEN
33-
expect(nativeAdapterMock.getWindowTitle).toBeCalledTimes(1);
34-
expect(nativeAdapterMock.getWindowTitle).toBeCalledWith(mockWindowHandle);
48+
expect(windowMock).toBeCalledTimes(1);
49+
expect(windowMock).toBeCalledWith(mockWindowHandle);
3550
});
3651
});

Diff for: ‎lib/window.class.ts

+10-10
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
import { NativeAdapter } from "./adapter/native.adapter.class";
2-
import { Region } from "./region.class";
1+
import {Region} from "./region.class";
2+
import {ProviderRegistry} from "./provider/provider-registry.class";
33

44
export class Window {
5-
constructor(private nativeActions: NativeAdapter, private windowHandle: number) {
6-
}
5+
constructor(private providerRegistry: ProviderRegistry, private windowHandle: number) {
6+
}
77

8-
get title(): Promise<string> {
9-
return this.nativeActions.getWindowTitle(this.windowHandle);
10-
}
8+
get title(): Promise<string> {
9+
return this.providerRegistry.getWindow().getWindowTitle(this.windowHandle);
10+
}
1111

12-
get region(): Promise<Region> {
13-
return this.nativeActions.getWindowRegion(this.windowHandle);
14-
}
12+
get region(): Promise<Region> {
13+
return this.providerRegistry.getWindow().getWindowRegion(this.windowHandle);
14+
}
1515
}

Diff for: ‎lib/window.function.spec.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import {createWindowApi} from "./window.function";
2-
import {NativeAdapter} from "./adapter/native.adapter.class";
32
import {Window} from "./window.class";
43
import providerRegistry from "./provider/provider-registry.class";
54

@@ -9,7 +8,7 @@ describe("WindowApi", () => {
98
describe("getWindows", () => {
109
it("should return a list of open Windows", async () => {
1110
// GIVEN
12-
const SUT = createWindowApi(new NativeAdapter(providerRegistry));
11+
const SUT = createWindowApi(providerRegistry);
1312

1413
// WHEN
1514
const windows = await SUT.getWindows()
@@ -24,7 +23,7 @@ describe("WindowApi", () => {
2423
describe("getActiveWindow", () => {
2524
it("should return the a single Window which is currently active", async () => {
2625
// GIVEN
27-
const SUT = createWindowApi(new NativeAdapter(providerRegistry));
26+
const SUT = createWindowApi(providerRegistry);
2827

2928
// WHEN
3029
const window = await SUT.getActiveWindow();

Diff for: ‎lib/window.function.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
import { WindowApi } from "./window-api.interface";
2-
import { NativeAdapter } from "./adapter/native.adapter.class";
32
import { Window } from "./window.class";
3+
import {ProviderRegistry} from "./provider/provider-registry.class";
44

5-
export const createWindowApi = (nativeAdapter: NativeAdapter): WindowApi => {
5+
export const createWindowApi = (providerRegistry: ProviderRegistry): WindowApi => {
66
return ({
77
async getActiveWindow(): Promise<Window> {
8-
const windowHandle = await nativeAdapter.getActiveWindow();
9-
return new Window(nativeAdapter, windowHandle);
8+
const windowHandle = await providerRegistry.getWindow().getActiveWindow();
9+
return new Window(providerRegistry, windowHandle);
1010
},
1111
async getWindows(): Promise<Window[]> {
12-
const windowHandles = await nativeAdapter.getWindows();
12+
const windowHandles = await providerRegistry.getWindow().getWindows();
1313
return windowHandles.map((handle: number) => {
14-
return new Window(nativeAdapter, handle);
14+
return new Window(providerRegistry, handle);
1515
});
1616
},
1717
});

0 commit comments

Comments
 (0)
Please sign in to comment.