appium-novawindows2-driver 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/build/lib/commands/actions.d.ts +9 -9
  2. package/build/lib/commands/actions.d.ts.map +1 -1
  3. package/build/lib/commands/actions.js.map +1 -1
  4. package/build/lib/commands/app.d.ts +10 -10
  5. package/build/lib/commands/app.d.ts.map +1 -1
  6. package/build/lib/commands/app.js.map +1 -1
  7. package/build/lib/commands/device.d.ts +2 -2
  8. package/build/lib/commands/device.d.ts.map +1 -1
  9. package/build/lib/commands/device.js.map +1 -1
  10. package/build/lib/commands/element.d.ts +13 -13
  11. package/build/lib/commands/element.d.ts.map +1 -1
  12. package/build/lib/commands/element.js.map +1 -1
  13. package/build/lib/commands/extension.d.ts +28 -28
  14. package/build/lib/commands/extension.d.ts.map +1 -1
  15. package/build/lib/commands/extension.js +4 -1
  16. package/build/lib/commands/extension.js.map +1 -1
  17. package/build/lib/commands/index.d.ts +63 -63
  18. package/build/lib/commands/index.d.ts.map +1 -1
  19. package/build/lib/commands/powershell.d.ts +5 -5
  20. package/build/lib/commands/powershell.d.ts.map +1 -1
  21. package/build/lib/commands/powershell.js +59 -46
  22. package/build/lib/commands/powershell.js.map +1 -1
  23. package/build/lib/commands/system.d.ts +2 -2
  24. package/build/lib/commands/system.d.ts.map +1 -1
  25. package/build/lib/driver.d.ts +5 -1
  26. package/build/lib/driver.d.ts.map +1 -1
  27. package/build/lib/driver.js +21 -4
  28. package/build/lib/driver.js.map +1 -1
  29. package/examples/api_test.js +69 -0
  30. package/examples/concurrency_test.js +82 -0
  31. package/examples/debug_test.js +36 -0
  32. package/examples/stress_test.js +94 -0
  33. package/{verify_driver.js → examples/verify_driver.js} +47 -1
  34. package/lib/commands/actions.ts +9 -9
  35. package/lib/commands/app.ts +11 -11
  36. package/lib/commands/device.ts +2 -2
  37. package/lib/commands/element.ts +13 -13
  38. package/lib/commands/extension.ts +35 -31
  39. package/lib/commands/index.ts +1 -1
  40. package/lib/commands/powershell.ts +69 -56
  41. package/lib/commands/system.ts +2 -2
  42. package/lib/driver.ts +21 -2
  43. package/package.json +7 -6
  44. package/examples/C#/CalculatorTest/CalculatorTest/CalculatorSession.cs +0 -44
  45. package/examples/C#/CalculatorTest/CalculatorTest/CalculatorTest.csproj +0 -24
  46. package/examples/C#/CalculatorTest/CalculatorTest/ScenarioStandard.cs +0 -121
  47. package/examples/C#/CalculatorTest/CalculatorTest/ScenarioStandardInvoke.cs +0 -121
  48. package/examples/C#/CalculatorTest/CalculatorTest.sln +0 -16
@@ -1,9 +1,10 @@
1
1
  import { W3C_ELEMENT_KEY, errors } from '@appium/base-driver';
2
2
  import { Element, Rect } from '@appium/types';
3
- import { NovaWindowsDriver } from '../driver';
3
+ import { NovaWindows2Driver } from '../driver';
4
4
  import { $, sleep } from '../util';
5
5
  import { POWER_SHELL_FEATURE } from '../constants';
6
- import { keyDown,
6
+ import {
7
+ keyDown,
7
8
  keyUp,
8
9
  mouseDown,
9
10
  mouseMoveAbsolute,
@@ -94,7 +95,7 @@ type KeyAction = {
94
95
  down?: boolean,
95
96
  }
96
97
 
97
- export async function execute(this: NovaWindowsDriver, script: string, args: any[]) {
98
+ export async function execute(this: NovaWindows2Driver, script: string, args: any[]) {
98
99
  if (script.startsWith(PLATFORM_COMMAND_PREFIX)) {
99
100
  script = script.replace(PLATFORM_COMMAND_PREFIX, '').trim();
100
101
  this.log.info(`Executing command '${PLATFORM_COMMAND_PREFIX} ${script}'...`);
@@ -108,11 +109,14 @@ export async function execute(this: NovaWindowsDriver, script: string, args: any
108
109
 
109
110
  if (script === 'powerShell') {
110
111
  this.assertFeatureEnabled(POWER_SHELL_FEATURE);
112
+ // this.log.info(`Executing command: \n${args[0]}`);
111
113
  return await this.executePowerShellScript(args[0]);
112
114
  }
113
115
 
114
116
  if (script === 'return window.name') {
115
- return await this.sendPowerShellCommand(AutomationElement.automationRoot.buildGetPropertyCommand(Property.NAME));
117
+ const command = AutomationElement.automationRoot.buildGetPropertyCommand(Property.NAME);
118
+ // this.log.info(`Executing command: \n${command}`);
119
+ return await this.sendPowerShellCommand(command);
116
120
  }
117
121
 
118
122
  throw new errors.NotImplementedError();
@@ -127,7 +131,7 @@ type CacheRequest = {
127
131
  const TREE_SCOPE_REGEX = new PropertyRegexMatcher('System.Windows.Automation.TreeScope', ...Object.values(TreeScope)).toRegex('i');
128
132
  const AUTOMATION_ELEMENT_MODE_REGEX = new PropertyRegexMatcher('System.Windows.Automation.AutomationElementMode', ...Object.values(AutomationElementMode)).toRegex('i');
129
133
 
130
- export async function pushCacheRequest(this: NovaWindowsDriver, cacheRequest: CacheRequest): Promise<void> {
134
+ export async function pushCacheRequest(this: NovaWindows2Driver, cacheRequest: CacheRequest): Promise<void> {
131
135
  if (Object.keys(cacheRequest).every((key) => cacheRequest[key] === undefined)) {
132
136
  throw new errors.InvalidArgumentError('At least one property of the cache request must be set.');
133
137
  }
@@ -163,28 +167,28 @@ export async function pushCacheRequest(this: NovaWindowsDriver, cacheRequest: Ca
163
167
  }
164
168
  }
165
169
 
166
- export async function patternInvoke(this: NovaWindowsDriver, element: Element): Promise<void> {
170
+ export async function patternInvoke(this: NovaWindows2Driver, element: Element): Promise<void> {
167
171
  await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildInvokeCommand());
168
172
  }
169
173
 
170
- export async function patternExpand(this: NovaWindowsDriver, element: Element): Promise<void> {
174
+ export async function patternExpand(this: NovaWindows2Driver, element: Element): Promise<void> {
171
175
  await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildExpandCommand());
172
176
  }
173
177
 
174
- export async function patternCollapse(this: NovaWindowsDriver, element: Element): Promise<void> {
178
+ export async function patternCollapse(this: NovaWindows2Driver, element: Element): Promise<void> {
175
179
  await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildCollapseCommand());
176
180
  }
177
181
 
178
- export async function patternScrollIntoView(this: NovaWindowsDriver, element: Element): Promise<void> {
182
+ export async function patternScrollIntoView(this: NovaWindows2Driver, element: Element): Promise<void> {
179
183
  await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildScrollIntoViewCommand());
180
184
  }
181
185
 
182
- export async function patternIsMultiple(this: NovaWindowsDriver, element: Element): Promise<boolean> {
186
+ export async function patternIsMultiple(this: NovaWindows2Driver, element: Element): Promise<boolean> {
183
187
  const result = await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildIsMultipleSelectCommand());
184
188
  return result.toLowerCase() === 'true' ? true : false;
185
189
  }
186
190
 
187
- export async function patternGetSelectedItem(this: NovaWindowsDriver, element: Element): Promise<Element> {
191
+ export async function patternGetSelectedItem(this: NovaWindows2Driver, element: Element): Promise<Element> {
188
192
  const result = await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildGetSelectionCommand());
189
193
  const elId = result.split('\n').filter(Boolean)[0];
190
194
 
@@ -195,28 +199,28 @@ export async function patternGetSelectedItem(this: NovaWindowsDriver, element: E
195
199
  return { [W3C_ELEMENT_KEY]: elId };
196
200
  }
197
201
 
198
- export async function patternGetAllSelectedItems(this: NovaWindowsDriver, element: Element): Promise<Element[]> {
202
+ export async function patternGetAllSelectedItems(this: NovaWindows2Driver, element: Element): Promise<Element[]> {
199
203
  const result = await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildGetSelectionCommand());
200
204
  return result.split('\n').filter(Boolean).map((elId) => ({ [W3C_ELEMENT_KEY]: elId }));
201
205
  }
202
206
 
203
- export async function patternAddToSelection(this: NovaWindowsDriver, element: Element): Promise<void> {
207
+ export async function patternAddToSelection(this: NovaWindows2Driver, element: Element): Promise<void> {
204
208
  await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildAddToSelectionCommand());
205
209
  }
206
210
 
207
- export async function patternRemoveFromSelection(this: NovaWindowsDriver, element: Element): Promise<void> {
211
+ export async function patternRemoveFromSelection(this: NovaWindows2Driver, element: Element): Promise<void> {
208
212
  await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildRemoveFromSelectionCommand());
209
213
  }
210
214
 
211
- export async function patternSelect(this: NovaWindowsDriver, element: Element): Promise<void> {
215
+ export async function patternSelect(this: NovaWindows2Driver, element: Element): Promise<void> {
212
216
  await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildSelectCommand());
213
217
  }
214
218
 
215
- export async function patternToggle(this: NovaWindowsDriver, element: Element): Promise<void> {
219
+ export async function patternToggle(this: NovaWindows2Driver, element: Element): Promise<void> {
216
220
  await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildToggleCommand());
217
221
  }
218
222
 
219
- export async function patternSetValue(this: NovaWindowsDriver, element: Element, value: string): Promise<void> {
223
+ export async function patternSetValue(this: NovaWindows2Driver, element: Element, value: string): Promise<void> {
220
224
  try {
221
225
  await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildSetValueCommand(value));
222
226
  } catch {
@@ -224,31 +228,31 @@ export async function patternSetValue(this: NovaWindowsDriver, element: Element,
224
228
  }
225
229
  }
226
230
 
227
- export async function patternGetValue(this: NovaWindowsDriver, element: Element): Promise<void> {
231
+ export async function patternGetValue(this: NovaWindows2Driver, element: Element): Promise<void> {
228
232
  await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildGetValueCommand());
229
233
  }
230
234
 
231
- export async function patternMaximize(this: NovaWindowsDriver, element: Element): Promise<void> {
235
+ export async function patternMaximize(this: NovaWindows2Driver, element: Element): Promise<void> {
232
236
  await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildMaximizeCommand());
233
237
  }
234
238
 
235
- export async function patternMinimize(this: NovaWindowsDriver, element: Element): Promise<void> {
239
+ export async function patternMinimize(this: NovaWindows2Driver, element: Element): Promise<void> {
236
240
  await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildMinimizeCommand());
237
241
  }
238
242
 
239
- export async function patternRestore(this: NovaWindowsDriver, element: Element): Promise<void> {
243
+ export async function patternRestore(this: NovaWindows2Driver, element: Element): Promise<void> {
240
244
  await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildRestoreCommand());
241
245
  }
242
246
 
243
- export async function patternClose(this: NovaWindowsDriver, element: Element): Promise<void> {
247
+ export async function patternClose(this: NovaWindows2Driver, element: Element): Promise<void> {
244
248
  await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildCloseCommand());
245
249
  }
246
250
 
247
- export async function focusElement(this: NovaWindowsDriver, element: Element): Promise<void> {
251
+ export async function focusElement(this: NovaWindows2Driver, element: Element): Promise<void> {
248
252
  await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildSetFocusCommand());
249
253
  }
250
254
 
251
- export async function getClipboardBase64(this: NovaWindowsDriver, contentType?: ContentType | { contentType?: ContentType }): Promise<string> {
255
+ export async function getClipboardBase64(this: NovaWindows2Driver, contentType?: ContentType | { contentType?: ContentType }): Promise<string> {
252
256
  if (!contentType || (contentType && typeof contentType === 'object')) {
253
257
  contentType = contentType?.contentType ?? ContentType.PLAINTEXT;
254
258
  }
@@ -263,7 +267,7 @@ export async function getClipboardBase64(this: NovaWindowsDriver, contentType?:
263
267
  }
264
268
  }
265
269
 
266
- export async function setClipboardFromBase64(this: NovaWindowsDriver, args: { contentType?: ContentType, b64Content: string }): Promise<string> {
270
+ export async function setClipboardFromBase64(this: NovaWindows2Driver, args: { contentType?: ContentType, b64Content: string }): Promise<string> {
267
271
  if (!args || typeof args !== 'object' || !args.b64Content) {
268
272
  throw new errors.InvalidArgumentError(`'b64Content' must be provided.`);
269
273
  }
@@ -280,7 +284,7 @@ export async function setClipboardFromBase64(this: NovaWindowsDriver, args: { co
280
284
  }
281
285
  }
282
286
 
283
- export async function executePowerShellScript(this: NovaWindowsDriver, script: string | { script: string, command: undefined } | { script: undefined, command: string }): Promise<string> {
287
+ export async function executePowerShellScript(this: NovaWindows2Driver, script: string | { script: string, command: undefined } | { script: undefined, command: string }): Promise<string> {
284
288
  if (script && typeof script === 'object') {
285
289
  if (script.script) {
286
290
  script = script.script;
@@ -299,7 +303,7 @@ export async function executePowerShellScript(this: NovaWindowsDriver, script: s
299
303
  }
300
304
  }
301
305
 
302
- export async function executeKeys(this: NovaWindowsDriver, keyActions: { actions: KeyAction | KeyAction[], forceUnicode: boolean }) {
306
+ export async function executeKeys(this: NovaWindows2Driver, keyActions: { actions: KeyAction | KeyAction[], forceUnicode: boolean }) {
303
307
  if (!Array.isArray(keyActions.actions)) {
304
308
  keyActions.actions = [keyActions.actions];
305
309
  }
@@ -358,7 +362,7 @@ export async function executeKeys(this: NovaWindowsDriver, keyActions: { actions
358
362
  }
359
363
  }
360
364
 
361
- export async function executeClick(this: NovaWindowsDriver, clickArgs: {
365
+ export async function executeClick(this: NovaWindows2Driver, clickArgs: {
362
366
  elementId?: string,
363
367
  x?: number,
364
368
  y?: number,
@@ -404,7 +408,7 @@ export async function executeClick(this: NovaWindowsDriver, clickArgs: {
404
408
  pos = [x!, y!];
405
409
  }
406
410
 
407
- const clickTypeToButtonMapping: { [key in ClickType]: number} = {
411
+ const clickTypeToButtonMapping: { [key in ClickType]: number } = {
408
412
  [ClickType.LEFT]: 0,
409
413
  [ClickType.MIDDLE]: 1,
410
414
  [ClickType.RIGHT]: 2,
@@ -458,7 +462,7 @@ export async function executeClick(this: NovaWindowsDriver, clickArgs: {
458
462
  }
459
463
  }
460
464
 
461
- export async function executeHover(this: NovaWindowsDriver, hoverArgs: {
465
+ export async function executeHover(this: NovaWindows2Driver, hoverArgs: {
462
466
  startElementId?: string,
463
467
  startX?: number,
464
468
  startY?: number,
@@ -561,7 +565,7 @@ export async function executeHover(this: NovaWindowsDriver, hoverArgs: {
561
565
  }
562
566
  }
563
567
 
564
- export async function executeScroll(this: NovaWindowsDriver, scrollArgs: {
568
+ export async function executeScroll(this: NovaWindows2Driver, scrollArgs: {
565
569
  elementId?: string,
566
570
  x?: number,
567
571
  y?: number,
@@ -22,7 +22,7 @@ type Commands = {
22
22
  };
23
23
 
24
24
  declare module '../driver' {
25
- interface NovaWindowsDriver extends Commands {}
25
+ interface NovaWindows2Driver extends Commands { }
26
26
  }
27
27
 
28
28
  export default commands;
@@ -1,5 +1,5 @@
1
1
  import { spawn } from 'node:child_process';
2
- import { NovaWindowsDriver } from '../driver';
2
+ import { NovaWindows2Driver } from '../driver';
3
3
  import { errors } from '@appium/base-driver';
4
4
  import { FIND_CHILDREN_RECURSIVELY, PAGE_SOURCE } from './functions';
5
5
 
@@ -11,10 +11,46 @@ const INIT_ROOT_ELEMENT = /* ps1 */ `$rootElement = [AutomationElement]::RootEle
11
11
  const NULL_ROOT_ELEMENT = /* ps1 */ `$rootElement = $null`;
12
12
  const INIT_ELEMENT_TABLE = /* ps1 */ `$elementTable = New-Object System.Collections.Generic.Dictionary[[string]\`,[AutomationElement]]`;
13
13
 
14
- export async function startPowerShellSession(this: NovaWindowsDriver): Promise<void> {
14
+ async function executeRawCommand(driver: NovaWindows2Driver, command: string): Promise<string> {
15
+ const magicNumber = 0xF2EE;
16
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
17
+ const powerShell = driver.powerShell!;
18
+
19
+ driver.powerShellStdOut = '';
20
+ driver.powerShellStdErr = '';
21
+
22
+ powerShell.stdin.write(`${command}\n`);
23
+ powerShell.stdin.write(/* ps1 */ `Write-Output $([char]0x${magicNumber.toString(16)})\n`);
24
+
25
+ return await new Promise<string>((resolve, reject) => {
26
+ const onClose = (code: number) => {
27
+ reject(new errors.UnknownError(`PowerShell process exited unexpectedly with code ${code}`));
28
+ driver.powerShell = undefined; // Clear the reference as the process is dead
29
+ };
30
+ powerShell.on('close', onClose);
31
+
32
+ const onData: Parameters<typeof powerShell.stdout.on>[1] = ((chunk: any) => {
33
+ const magicChar = String.fromCharCode(magicNumber);
34
+ if (chunk.toString().includes(magicChar)) {
35
+ powerShell.stdout.off('data', onData);
36
+ powerShell.off('close', onClose);
37
+ if (driver.powerShellStdErr) {
38
+ reject(new errors.UnknownError(driver.powerShellStdErr));
39
+ } else {
40
+ resolve(driver.powerShellStdOut.replace(`${magicChar}`, '').trim());
41
+ }
42
+ }
43
+ }).bind(driver);
44
+
45
+ powerShell.stdout.on('data', onData);
46
+ });
47
+ }
48
+
49
+ export async function startPowerShellSession(this: NovaWindows2Driver): Promise<void> {
50
+ this.log.debug('Starting new PowerShell session...');
15
51
  const powerShell = spawn('powershell.exe', ['-NoExit', '-Command', '-']);
16
52
  powerShell.stdout.setEncoding('utf8');
17
- powerShell.stdout.setEncoding('utf8');
53
+ powerShell.stderr.setEncoding('utf8');
18
54
 
19
55
  powerShell.stdout.on('data', (chunk: any) => {
20
56
  this.powerShellStdOut += chunk.toString();
@@ -37,27 +73,29 @@ export async function startPowerShellSession(this: NovaWindowsDriver): Promise<v
37
73
  for (const envVar of envVars) {
38
74
  this.caps.appWorkingDir = this.caps.appWorkingDir.replaceAll(`%${envVar}%`, process.env[envVar.toUpperCase()] ?? '');
39
75
  }
40
- this.sendPowerShellCommand(`Set-Location -Path '${this.caps.appWorkingDir}'`);
76
+ // Use raw execution to bypass queue
77
+ await executeRawCommand(this, `Set-Location -Path '${this.caps.appWorkingDir}'`);
41
78
  }
42
79
 
43
- await this.sendPowerShellCommand(SET_UTF8_ENCODING);
44
- await this.sendPowerShellCommand(ADD_NECESSARY_ASSEMBLIES);
45
- await this.sendPowerShellCommand(USE_UI_AUTOMATION_CLIENT);
46
- await this.sendPowerShellCommand(INIT_CACHE_REQUEST);
47
- await this.sendPowerShellCommand(INIT_ELEMENT_TABLE);
80
+ // Use raw execution to bypass queue
81
+ await executeRawCommand(this, SET_UTF8_ENCODING);
82
+ await executeRawCommand(this, ADD_NECESSARY_ASSEMBLIES);
83
+ await executeRawCommand(this, USE_UI_AUTOMATION_CLIENT);
84
+ await executeRawCommand(this, INIT_CACHE_REQUEST);
85
+ await executeRawCommand(this, INIT_ELEMENT_TABLE);
48
86
 
49
87
  // initialize functions
50
- await this.sendPowerShellCommand(PAGE_SOURCE);
51
- await this.sendPowerShellCommand(FIND_CHILDREN_RECURSIVELY);
88
+ await executeRawCommand(this, PAGE_SOURCE);
89
+ await executeRawCommand(this, FIND_CHILDREN_RECURSIVELY);
52
90
 
53
91
  if ((!this.caps.app && !this.caps.appTopLevelWindow) || (!this.caps.app || this.caps.app.toLowerCase() === 'none')) {
54
92
  this.log.info(`No app or top-level window specified in capabilities. Setting root element to null.`);
55
- await this.sendPowerShellCommand(NULL_ROOT_ELEMENT);
93
+ await executeRawCommand(this, NULL_ROOT_ELEMENT);
56
94
  }
57
95
 
58
96
  if (this.caps.app && this.caps.app.toLowerCase() === 'root') {
59
97
  this.log.info(`'root' specified as app in capabilities. Setting root element to desktop root.`);
60
- await this.sendPowerShellCommand(INIT_ROOT_ELEMENT);
98
+ await executeRawCommand(this, INIT_ROOT_ELEMENT);
61
99
  }
62
100
 
63
101
  if (this.caps.app && this.caps.app.toLowerCase() !== 'none' && this.caps.app.toLowerCase() !== 'root') {
@@ -90,7 +128,7 @@ export async function startPowerShellSession(this: NovaWindowsDriver): Promise<v
90
128
  }
91
129
  }
92
130
 
93
- export async function sendIsolatedPowerShellCommand(this: NovaWindowsDriver, command: string): Promise<string> {
131
+ export async function sendIsolatedPowerShellCommand(this: NovaWindows2Driver, command: string): Promise<string> {
94
132
  const magicNumber = 0xF2EE;
95
133
 
96
134
  const powerShell = spawn('powershell.exe', ['-NoExit', '-Command', '-']);
@@ -165,53 +203,28 @@ export async function sendIsolatedPowerShellCommand(this: NovaWindowsDriver, com
165
203
  }
166
204
  }
167
205
 
168
- export async function sendPowerShellCommand(this: NovaWindowsDriver, command: string): Promise<string> {
169
- const magicNumber = 0xF2EE;
170
-
171
- if (!this.powerShell) {
172
- this.log.warn('PowerShell session not running. It was either closed or has crashed. Attempting to start a new session...');
173
- await this.startPowerShellSession();
174
- }
175
-
176
- const result = await new Promise<string>((resolve, reject) => {
177
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
178
- const powerShell = this.powerShell!;
179
-
180
- this.powerShellStdOut = '';
181
- this.powerShellStdErr = '';
182
-
183
- powerShell.stdin.write(`${command}\n`);
184
- powerShell.stdin.write(/* ps1 */ `Write-Output $([char]0x${magicNumber.toString(16)})\n`);
185
-
186
- const onClose = (code: number) => {
187
- reject(new errors.UnknownError(`PowerShell process exited unexpectedly with code ${code}`));
188
- this.powerShell = undefined; // Clear the reference as the process is dead
189
- };
190
- powerShell.on('close', onClose);
191
-
192
- const onData: Parameters<typeof powerShell.stdout.on>[1] = ((chunk: any) => {
193
- const magicChar = String.fromCharCode(magicNumber);
194
- if (chunk.toString().includes(magicChar)) {
195
- powerShell.stdout.off('data', onData);
196
- powerShell.off('close', onClose);
197
- if (this.powerShellStdErr) {
198
- reject(new errors.UnknownError(this.powerShellStdErr));
199
- } else {
200
- resolve(this.powerShellStdOut.replace(`${magicChar}`, '').trim());
201
- }
202
- }
203
- }).bind(this);
206
+ export async function sendPowerShellCommand(this: NovaWindows2Driver, command: string): Promise<string> {
207
+ const nextCommand = async () => {
208
+ if (!this.powerShell) {
209
+ this.log.warn('PowerShell session not running. It was either closed or has crashed. Attempting to start a new session...');
210
+ await this.startPowerShellSession();
211
+ }
204
212
 
205
- powerShell.stdout.on('data', onData);
206
- });
213
+ // Use the extracted raw command function
214
+ return await executeRawCommand(this, command);
215
+ };
207
216
 
208
- // commented out for now to avoid cluttering the logs with long command outputs
209
- // this.log.debug(`PowerShell command executed:\n${command}\n\nCommand output below:\n${result}\n --------`);
217
+ // Chain the command to the queue
218
+ // Use .catch to ignore previous failures, then .then to queue this command.
219
+ // This prevents re-running this command if it fails (no infinite loop).
220
+ this.commandQueue = this.commandQueue
221
+ .catch(() => { /* ignore previous error */ })
222
+ .then(nextCommand);
210
223
 
211
- return result;
224
+ return this.commandQueue;
212
225
  }
213
226
 
214
- export async function terminatePowerShellSession(this: NovaWindowsDriver): Promise<void> {
227
+ export async function terminatePowerShellSession(this: NovaWindows2Driver): Promise<void> {
215
228
  if (!this.powerShell) {
216
229
  return;
217
230
  }
@@ -1,7 +1,7 @@
1
1
  import { Orientation } from '@appium/types';
2
- import { NovaWindowsDriver } from '../driver';
2
+ import { NovaWindows2Driver } from '../driver';
3
3
  import { getDisplayOrientation } from '../winapi/user32';
4
4
 
5
- export function getOrientation(this: NovaWindowsDriver): Orientation {
5
+ export function getOrientation(this: NovaWindows2Driver): Orientation {
6
6
  return getDisplayOrientation();
7
7
  }
package/lib/driver.ts CHANGED
@@ -54,11 +54,12 @@ const LOCATION_STRATEGIES = Object.freeze([
54
54
  '-windows uiautomation',
55
55
  ] as const);
56
56
 
57
- export class NovaWindowsDriver extends BaseDriver<NovaWindowsDriverConstraints, StringRecord> {
57
+ export class NovaWindows2Driver extends BaseDriver<NovaWindowsDriverConstraints, StringRecord> {
58
58
  isPowerShellSessionStarted: boolean = false;
59
59
  powerShell?: ChildProcessWithoutNullStreams;
60
60
  powerShellStdOut: string = '';
61
61
  powerShellStdErr: string = '';
62
+ commandQueue: Promise<any> = Promise.resolve();
62
63
  keyboardState: KeyboardState = {
63
64
  pressed: new Set(),
64
65
  alt: false,
@@ -67,6 +68,8 @@ export class NovaWindowsDriver extends BaseDriver<NovaWindowsDriverConstraints,
67
68
  shift: false,
68
69
  };
69
70
 
71
+ activeCommands: number = 0;
72
+
70
73
  constructor(opts: InitialOpts = {} as InitialOpts, shouldValidateCaps = true) {
71
74
  super(opts, shouldValidateCaps);
72
75
 
@@ -74,8 +77,24 @@ export class NovaWindowsDriver extends BaseDriver<NovaWindowsDriverConstraints,
74
77
  this.desiredCapConstraints = UI_AUTOMATION_DRIVER_CONSTRAINTS;
75
78
 
76
79
  for (const key in commands) { // TODO: create a decorator that will do that for the class
77
- NovaWindowsDriver.prototype[key] = commands[key].bind(this);
80
+ NovaWindows2Driver.prototype[key] = commands[key].bind(this);
81
+ }
82
+ }
83
+
84
+ override async executeCommand(cmd: string, ...args: any[]): Promise<any> {
85
+ this.activeCommands++;
86
+ try {
87
+ return await super.executeCommand(cmd, ...args);
88
+ } finally {
89
+ this.activeCommands--;
90
+ }
91
+ }
92
+
93
+ override async startNewCommandTimeout() {
94
+ if (this.activeCommands > 0) {
95
+ return;
78
96
  }
97
+ await super.startNewCommandTimeout();
79
98
  }
80
99
 
81
100
  override async findElement(strategy: string, selector: string): Promise<Element> {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appium-novawindows2-driver",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Appium driver for Windows",
5
5
  "keywords": [
6
6
  "appium",
@@ -21,10 +21,10 @@
21
21
  "license": "Apache-2.0",
22
22
  "repository": {
23
23
  "type": "git",
24
- "url": "https://github.com/nguyenvanhuy0612/appium-novawindows-driver.git"
24
+ "url": "https://github.com/nguyenvanhuy0612/appium-novawindows2-driver.git"
25
25
  },
26
26
  "bugs": {
27
- "url": "https://github.com/nguyenvanhuy0612/appium-novawindows-driver/issues"
27
+ "url": "https://github.com/nguyenvanhuy0612/appium-novawindows2-driver/issues"
28
28
  },
29
29
  "peerDependencies": {
30
30
  "appium": "^3.1.0"
@@ -37,11 +37,11 @@
37
37
  },
38
38
  "appium": {
39
39
  "driverName": "novawindows2",
40
- "automationName": "NovaWindows",
40
+ "automationName": "NovaWindows2",
41
41
  "platformNames": [
42
42
  "Windows"
43
43
  ],
44
- "mainClass": "NovaWindowsDriver"
44
+ "mainClass": "NovaWindows2Driver"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@appium/eslint-config-appium-ts": "^2.0.3",
@@ -56,6 +56,7 @@
56
56
  "semantic-release": "^25.0.1",
57
57
  "typescript": "^5.9.3",
58
58
  "typescript-eslint": "^8.46.1",
59
- "webdriverio": "^9.21.0"
59
+ "webdriverio": "^9.21.0",
60
+ "axios": "^1.4.0"
60
61
  }
61
62
  }
@@ -1,44 +0,0 @@
1
- // Based on the original WinAppDriver Calculator test by Microsoft, licensed under the MIT License.
2
-
3
- using OpenQA.Selenium.Appium;
4
- using OpenQA.Selenium.Appium.Windows;
5
-
6
- namespace CalculatorTest;
7
-
8
- public class CalculatorSession
9
- {
10
- private const string AppiumServerUrl = "http://127.0.0.1:4723/";
11
- private const string CalculatorAppId = "Microsoft.WindowsCalculator_8wekyb3d8bbwe!App";
12
-
13
- protected static WindowsDriver Session { get; private set; }
14
-
15
- protected static void Setup()
16
- {
17
- if (Session != null) return;
18
-
19
- // Launch Calculator application if it is not yet launched
20
- // Create a new session to bring up an instance of the Calculator application
21
- // Note: Multiple calculator windows (instances) share the same process Id
22
- var appiumOptions = new AppiumOptions
23
- {
24
- App = CalculatorAppId,
25
- AutomationName = "NovaWindows",
26
- PlatformName = "Windows",
27
- };
28
-
29
- Session = new WindowsDriver(new Uri(AppiumServerUrl), appiumOptions);
30
- Assert.That(Session, Is.Not.Null);
31
-
32
- // Set implicit timeout to 1.5 seconds to make element search to retry every 500 ms for at most three times
33
- Session.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(1.5);
34
- }
35
-
36
- protected static void TearDown()
37
- {
38
- if (Session == null) return;
39
-
40
- // Close the application and delete the session
41
- Session.Quit();
42
- Session = null;
43
- }
44
- }
@@ -1,24 +0,0 @@
1
- <Project Sdk="Microsoft.NET.Sdk">
2
-
3
- <PropertyGroup>
4
- <TargetFramework>net8.0</TargetFramework>
5
- <ImplicitUsings>enable</ImplicitUsings>
6
- <Nullable>disable</Nullable>
7
-
8
- <IsPackable>false</IsPackable>
9
- <IsTestProject>true</IsTestProject>
10
- </PropertyGroup>
11
-
12
- <ItemGroup>
13
- <PackageReference Include="Appium.WebDriver" Version="7.2.0" />
14
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/>
15
- <PackageReference Include="NUnit" Version="3.14.0"/>
16
- <PackageReference Include="NUnit.Analyzers" Version="3.9.0"/>
17
- <PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
18
- </ItemGroup>
19
-
20
- <ItemGroup>
21
- <Using Include="NUnit.Framework"/>
22
- </ItemGroup>
23
-
24
- </Project>