@wdio/browserstack-service 8.45.0 → 8.47.0

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 (118) hide show
  1. package/README.md +44 -11
  2. package/build/Percy/Percy-Handler.d.ts.map +1 -1
  3. package/build/Percy/Percy-Handler.js +4 -1
  4. package/build/Percy/Percy.d.ts.map +1 -1
  5. package/build/Percy/Percy.js +2 -1
  6. package/build/accessibility-handler.d.ts +9 -3
  7. package/build/accessibility-handler.d.ts.map +1 -1
  8. package/build/accessibility-handler.js +52 -11
  9. package/build/cleanup.js +3 -3
  10. package/build/cli/apiUtils.d.ts +14 -0
  11. package/build/cli/apiUtils.d.ts.map +1 -0
  12. package/build/cli/apiUtils.js +24 -0
  13. package/build/cli/cliLogger.d.ts +16 -0
  14. package/build/cli/cliLogger.d.ts.map +1 -0
  15. package/build/cli/cliLogger.js +70 -0
  16. package/build/cli/cliUtils.d.ts +46 -0
  17. package/build/cli/cliUtils.d.ts.map +1 -0
  18. package/build/cli/cliUtils.js +430 -0
  19. package/build/cli/eventDispatcher.d.ts +28 -0
  20. package/build/cli/eventDispatcher.d.ts.map +1 -0
  21. package/build/cli/eventDispatcher.js +48 -0
  22. package/build/cli/frameworks/automationFramework.d.ts +89 -0
  23. package/build/cli/frameworks/automationFramework.d.ts.map +1 -0
  24. package/build/cli/frameworks/automationFramework.js +131 -0
  25. package/build/cli/frameworks/constants/automationFrameworkConstants.d.ts +18 -0
  26. package/build/cli/frameworks/constants/automationFrameworkConstants.d.ts.map +1 -0
  27. package/build/cli/frameworks/constants/automationFrameworkConstants.js +17 -0
  28. package/build/cli/frameworks/constants/testFrameworkConstants.d.ts +43 -0
  29. package/build/cli/frameworks/constants/testFrameworkConstants.d.ts.map +1 -0
  30. package/build/cli/frameworks/constants/testFrameworkConstants.js +42 -0
  31. package/build/cli/frameworks/testFramework.d.ts +89 -0
  32. package/build/cli/frameworks/testFramework.d.ts.map +1 -0
  33. package/build/cli/frameworks/testFramework.js +125 -0
  34. package/build/cli/frameworks/wdioAutomationFramework.d.ts +28 -0
  35. package/build/cli/frameworks/wdioAutomationFramework.d.ts.map +1 -0
  36. package/build/cli/frameworks/wdioAutomationFramework.js +66 -0
  37. package/build/cli/frameworks/wdioMochaTestFramework.d.ts +82 -0
  38. package/build/cli/frameworks/wdioMochaTestFramework.d.ts.map +1 -0
  39. package/build/cli/frameworks/wdioMochaTestFramework.js +319 -0
  40. package/build/cli/grpcClient.d.ts +70 -0
  41. package/build/cli/grpcClient.d.ts.map +1 -0
  42. package/build/cli/grpcClient.js +419 -0
  43. package/build/cli/index.d.ts +148 -0
  44. package/build/cli/index.d.ts.map +1 -0
  45. package/build/cli/index.js +415 -0
  46. package/build/cli/instances/automationFrameworkInstance.d.ts +33 -0
  47. package/build/cli/instances/automationFrameworkInstance.d.ts.map +1 -0
  48. package/build/cli/instances/automationFrameworkInstance.js +44 -0
  49. package/build/cli/instances/testFrameworkInstance.d.ts +62 -0
  50. package/build/cli/instances/testFrameworkInstance.d.ts.map +1 -0
  51. package/build/cli/instances/testFrameworkInstance.js +96 -0
  52. package/build/cli/instances/trackedContext.d.ts +32 -0
  53. package/build/cli/instances/trackedContext.d.ts.map +1 -0
  54. package/build/cli/instances/trackedContext.js +47 -0
  55. package/build/cli/instances/trackedInstance.d.ts +40 -0
  56. package/build/cli/instances/trackedInstance.d.ts.map +1 -0
  57. package/build/cli/instances/trackedInstance.js +63 -0
  58. package/build/cli/modules/accessibilityModule.d.ts +33 -0
  59. package/build/cli/modules/accessibilityModule.d.ts.map +1 -0
  60. package/build/cli/modules/accessibilityModule.js +347 -0
  61. package/build/cli/modules/automateModule.d.ts +26 -0
  62. package/build/cli/modules/automateModule.d.ts.map +1 -0
  63. package/build/cli/modules/automateModule.js +222 -0
  64. package/build/cli/modules/baseModule.d.ts +33 -0
  65. package/build/cli/modules/baseModule.d.ts.map +1 -0
  66. package/build/cli/modules/baseModule.js +51 -0
  67. package/build/cli/modules/observabilityModule.d.ts +22 -0
  68. package/build/cli/modules/observabilityModule.d.ts.map +1 -0
  69. package/build/cli/modules/observabilityModule.js +45 -0
  70. package/build/cli/modules/percyModule.d.ts +19 -0
  71. package/build/cli/modules/percyModule.d.ts.map +1 -0
  72. package/build/cli/modules/percyModule.js +77 -0
  73. package/build/cli/modules/testHubModule.d.ts +30 -0
  74. package/build/cli/modules/testHubModule.d.ts.map +1 -0
  75. package/build/cli/modules/testHubModule.js +232 -0
  76. package/build/cli/modules/webdriverIOModule.d.ts +29 -0
  77. package/build/cli/modules/webdriverIOModule.d.ts.map +1 -0
  78. package/build/cli/modules/webdriverIOModule.js +128 -0
  79. package/build/cli/states/automationFrameworkState.d.ts +65 -0
  80. package/build/cli/states/automationFrameworkState.d.ts.map +1 -0
  81. package/build/cli/states/automationFrameworkState.js +61 -0
  82. package/build/cli/states/hookState.d.ts +45 -0
  83. package/build/cli/states/hookState.d.ts.map +1 -0
  84. package/build/cli/states/hookState.js +43 -0
  85. package/build/cli/states/testFrameworkState.d.ts +125 -0
  86. package/build/cli/states/testFrameworkState.d.ts.map +1 -0
  87. package/build/cli/states/testFrameworkState.js +115 -0
  88. package/build/constants.d.ts +13 -0
  89. package/build/constants.d.ts.map +1 -1
  90. package/build/constants.js +21 -1
  91. package/build/crash-reporter.d.ts.map +1 -1
  92. package/build/crash-reporter.js +4 -3
  93. package/build/exitHandler.d.ts.map +1 -1
  94. package/build/exitHandler.js +47 -5
  95. package/build/insights-handler.d.ts +8 -0
  96. package/build/insights-handler.d.ts.map +1 -1
  97. package/build/insights-handler.js +57 -1
  98. package/build/instrumentation/funnelInstrumentation.d.ts.map +1 -1
  99. package/build/instrumentation/funnelInstrumentation.js +5 -4
  100. package/build/instrumentation/performance/constants.d.ts +8 -0
  101. package/build/instrumentation/performance/constants.d.ts.map +1 -1
  102. package/build/instrumentation/performance/constants.js +9 -1
  103. package/build/instrumentation/performance/performance-tester.d.ts.map +1 -1
  104. package/build/instrumentation/performance/performance-tester.js +5 -3
  105. package/build/launcher.d.ts.map +1 -1
  106. package/build/launcher.js +94 -51
  107. package/build/request-handler.js +1 -1
  108. package/build/service.d.ts +3 -1
  109. package/build/service.d.ts.map +1 -1
  110. package/build/service.js +244 -69
  111. package/build/testOps/requestUtils.js +3 -2
  112. package/build/types.d.ts +36 -3
  113. package/build/types.d.ts.map +1 -1
  114. package/build/util.d.ts +13 -1
  115. package/build/util.d.ts.map +1 -1
  116. package/build/util.js +173 -27
  117. package/package.json +7 -4
  118. package/tsconfig.prod.tsbuildinfo +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trackedContext.d.ts","sourceRoot":"","sources":["../../../src/cli/instances/trackedContext.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,OAAO,cAAc;;IAM/B;;;;;;KAMC;gBACW,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAOzE;;;KAGC;IACD,WAAW;IAIX;;;KAGC;IACD,YAAY;IAIZ;;;KAGC;IACD,KAAK;IAIL;;;KAGC;IACD,OAAO;CAIV"}
@@ -0,0 +1,47 @@
1
+ export default class TrackedContext {
2
+ #id;
3
+ #threadId;
4
+ #processId;
5
+ #type;
6
+ /**
7
+ * Create TrackedContext
8
+ * @param {number} string - string Id for context - VERIFY
9
+ * @param {number} threadId- Integer Thread Id for context
10
+ * @param {number} processId - Integer Process Id for context
11
+ * @param {string} type
12
+ */
13
+ constructor(id, threadId, processId, type) {
14
+ this.#id = id;
15
+ this.#threadId = threadId;
16
+ this.#processId = processId;
17
+ this.#type = type;
18
+ }
19
+ /**
20
+ * get TrackedContext thread id
21
+ * @returns {number} - return thread id of context
22
+ */
23
+ getThreadId() {
24
+ return this.#threadId;
25
+ }
26
+ /**
27
+ * get TrackedContext process id
28
+ * @returns {number} - return process id of context
29
+ */
30
+ getProcessId() {
31
+ return this.#processId;
32
+ }
33
+ /**
34
+ * get TrackedContext id
35
+ * @returns {string} - returns context id
36
+ */
37
+ getId() {
38
+ return this.#id;
39
+ }
40
+ /**
41
+ * get TrackedContext type
42
+ * @returns {string}
43
+ */
44
+ getType() {
45
+ return this.#type;
46
+ }
47
+ }
@@ -0,0 +1,40 @@
1
+ import TrackedContext from './trackedContext.js';
2
+ export default class TrackedInstance {
3
+ #private;
4
+ /**
5
+ * create TrackedInstance
6
+ * @param {TrackedContext} context
7
+ */
8
+ constructor(context: TrackedContext);
9
+ /**
10
+ * get TrackedInstance ref
11
+ * @returns {number} - returns ref id
12
+ */
13
+ getRef(): string;
14
+ /**
15
+ * get TrackedInstance context
16
+ * @return {TrackedContext} - returns tracked context
17
+ */
18
+ getContext(): TrackedContext;
19
+ /**
20
+ * get All data of Instance
21
+ * @returns {Map} - returns all data
22
+ */
23
+ getAllData(): Map<string, any>;
24
+ /**
25
+ * set multiple data in the instance
26
+ * @param {*} key
27
+ * @param {*} value
28
+ */
29
+ updateMultipleEntries(entries: Record<string, any>): void;
30
+ updateData(key: string, value: any): void;
31
+ /**
32
+ * get Specific data of instance.
33
+ * @param {*} key
34
+ * @returns {*}
35
+ */
36
+ getData(key: string): any;
37
+ hasData(key: string): boolean;
38
+ static createContext(target: string): TrackedContext;
39
+ }
40
+ //# sourceMappingURL=trackedInstance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trackedInstance.d.ts","sourceRoot":"","sources":["../../../src/cli/instances/trackedInstance.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,MAAM,qBAAqB,CAAA;AAIhD,MAAM,CAAC,OAAO,OAAO,eAAe;;IAIhC;;;KAGC;gBACW,OAAO,EAAE,cAAc;IAKnC;;;KAGC;IACD,MAAM;IAIN;;;KAGC;IACD,UAAU;IAIV;;;KAGC;IACD,UAAU;IAIV;;;;KAIC;IACD,qBAAqB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAMlD,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG;IAIlC;;;;KAIC;IACD,OAAO,CAAC,GAAG,EAAE,MAAM;IAInB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAI7B,MAAM,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM;CAQtC"}
@@ -0,0 +1,63 @@
1
+ import TrackedContext from './trackedContext.js';
2
+ import crypto from 'node:crypto';
3
+ import { threadId } from 'node:worker_threads';
4
+ export default class TrackedInstance {
5
+ #context;
6
+ #data;
7
+ /**
8
+ * create TrackedInstance
9
+ * @param {TrackedContext} context
10
+ */
11
+ constructor(context) {
12
+ this.#context = context;
13
+ this.#data = new Map();
14
+ }
15
+ /**
16
+ * get TrackedInstance ref
17
+ * @returns {number} - returns ref id
18
+ */
19
+ getRef() {
20
+ return this.#context.getId();
21
+ }
22
+ /**
23
+ * get TrackedInstance context
24
+ * @return {TrackedContext} - returns tracked context
25
+ */
26
+ getContext() {
27
+ return this.#context;
28
+ }
29
+ /**
30
+ * get All data of Instance
31
+ * @returns {Map} - returns all data
32
+ */
33
+ getAllData() {
34
+ return this.#data;
35
+ }
36
+ /**
37
+ * set multiple data in the instance
38
+ * @param {*} key
39
+ * @param {*} value
40
+ */
41
+ updateMultipleEntries(entries) {
42
+ Object.keys(entries).forEach(key => {
43
+ this.#data.set(key, entries[key]);
44
+ });
45
+ }
46
+ updateData(key, value) {
47
+ this.#data.set(key, value);
48
+ }
49
+ /**
50
+ * get Specific data of instance.
51
+ * @param {*} key
52
+ * @returns {*}
53
+ */
54
+ getData(key) {
55
+ return this.#data.get(key);
56
+ }
57
+ hasData(key) {
58
+ return this.#data.has(key);
59
+ }
60
+ static createContext(target) {
61
+ return new TrackedContext(crypto.createHash('sha256').update(target).digest('hex'), threadId || 0, process.pid, typeof (target));
62
+ }
63
+ }
@@ -0,0 +1,33 @@
1
+ import BaseModule from './baseModule.js';
2
+ import { BStackLogger } from '../cliLogger.js';
3
+ import accessibilityScripts from '../../scripts/accessibility-scripts.js';
4
+ import type { Accessibility } from '@browserstack/wdio-browserstack-service';
5
+ export default class AccessibilityModule extends BaseModule {
6
+ logger: typeof BStackLogger;
7
+ name: string;
8
+ scriptInstance: typeof accessibilityScripts;
9
+ accessibility: boolean;
10
+ isAppAccessibility: boolean;
11
+ isNonBstackA11y: boolean;
12
+ accessibilityConfig: Accessibility;
13
+ static MODULE_NAME: string;
14
+ accessibilityMap: Map<number, boolean>;
15
+ LOG_DISABLED_SHOWN: Map<number, boolean>;
16
+ constructor(accessibilityConfig: Accessibility, isNonBstackA11y: boolean);
17
+ onBeforeExecute(): Promise<void>;
18
+ private commandWrapper;
19
+ onBeforeTest(args: any): Promise<void>;
20
+ onAfterTest(): Promise<void>;
21
+ private shouldPatchExecuteScript;
22
+ private getCapability;
23
+ private performScanCli;
24
+ private sendTestStopEvent;
25
+ getA11yResults(browser: WebdriverIO.Browser): Promise<Array<{
26
+ [key: string]: any;
27
+ }>>;
28
+ getA11yResultsSummary(browser: WebdriverIO.Browser): Promise<{
29
+ [key: string]: any;
30
+ }>;
31
+ getDriverExecuteParams(): Promise<any>;
32
+ }
33
+ //# sourceMappingURL=accessibilityModule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accessibilityModule.d.ts","sourceRoot":"","sources":["../../../src/cli/modules/accessibilityModule.ts"],"names":[],"mappings":"AACA,OAAO,UAAU,MAAM,iBAAiB,CAAA;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAQ9C,OAAO,oBAAoB,MAAM,wCAAwC,CAAA;AAIzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAA;AAO5E,MAAM,CAAC,OAAO,OAAO,mBAAoB,SAAQ,UAAU;IAEvD,MAAM,sBAAe;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,cAAc,EAAE,OAAO,oBAAoB,CAAA;IAC3C,aAAa,EAAE,OAAO,CAAQ;IAC9B,kBAAkB,EAAE,OAAO,CAAA;IAC3B,eAAe,EAAE,OAAO,CAAA;IACxB,mBAAmB,EAAE,aAAa,CAAA;IAClC,MAAM,CAAC,WAAW,SAAwB;IAC1C,gBAAgB,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACtC,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;gBAE5B,mBAAmB,EAAE,aAAa,EAAE,eAAe,EAAE,OAAO;IAelE,eAAe;YAsFP,cAAc;IAkCtB,YAAY,CAAC,IAAI,EAAE,GAAG;IAqCtB,WAAW;IA6DjB,OAAO,CAAC,wBAAwB;IAWhC,OAAO,CAAC,aAAa;YAuBP,cAAc;YAkCd,iBAAiB;IAuBzB,cAAc,CAAC,OAAO,EAAE,WAAW,CAAC,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KAAE,CAAC,CAAC;IAsBrF,qBAAqB,CAAC,OAAO,EAAE,WAAW,CAAC,OAAO,GAAG,OAAO,CAAC;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KAAE,CAAC;IAqBrF,sBAAsB;CAa/B"}
@@ -0,0 +1,347 @@
1
+ /// <reference path="../../@types/bstack-service-types.d.ts" />
2
+ import BaseModule from './baseModule.js';
3
+ import { BStackLogger } from '../cliLogger.js';
4
+ import TestFramework from '../frameworks/testFramework.js';
5
+ import AutomationFramework from '../frameworks/automationFramework.js';
6
+ import { TestFrameworkState } from '../states/testFrameworkState.js';
7
+ import { AutomationFrameworkState } from '../states/automationFrameworkState.js';
8
+ import { HookState } from '../states/hookState.js';
9
+ import accessibilityScripts from '../../scripts/accessibility-scripts.js';
10
+ import { _getParamsForAppAccessibility, formatString, getAppA11yResults, getAppA11yResultsSummary, shouldScanTestForAccessibility, validateCapsWithA11y, validateCapsWithAppA11y, validateCapsWithNonBstackA11y } from '../../util.js';
11
+ import { AutomationFrameworkConstants } from '../frameworks/constants/automationFrameworkConstants.js';
12
+ import util from 'node:util';
13
+ import PerformanceTester from '../../instrumentation/performance/performance-tester.js';
14
+ import * as PERFORMANCE_SDK_EVENTS from '../../instrumentation/performance/constants.js';
15
+ import { GrpcClient } from '../grpcClient.js';
16
+ export default class AccessibilityModule extends BaseModule {
17
+ logger = BStackLogger;
18
+ name;
19
+ scriptInstance;
20
+ accessibility = false;
21
+ isAppAccessibility;
22
+ isNonBstackA11y;
23
+ accessibilityConfig;
24
+ static MODULE_NAME = 'AccessibilityModule';
25
+ accessibilityMap;
26
+ LOG_DISABLED_SHOWN;
27
+ constructor(accessibilityConfig, isNonBstackA11y) {
28
+ super();
29
+ this.name = 'AccessibilityModule';
30
+ this.accessibilityConfig = accessibilityConfig;
31
+ AutomationFramework.registerObserver(AutomationFrameworkState.CREATE, HookState.POST, this.onBeforeExecute.bind(this));
32
+ TestFramework.registerObserver(TestFrameworkState.TEST, HookState.PRE, this.onBeforeTest.bind(this));
33
+ TestFramework.registerObserver(TestFrameworkState.TEST, HookState.POST, this.onAfterTest.bind(this));
34
+ this.accessibility = true;
35
+ this.scriptInstance = accessibilityScripts;
36
+ this.accessibilityMap = new Map();
37
+ this.LOG_DISABLED_SHOWN = new Map();
38
+ this.isAppAccessibility = accessibilityConfig.isAppAccessibility || false;
39
+ this.isNonBstackA11y = isNonBstackA11y;
40
+ }
41
+ async onBeforeExecute() {
42
+ try {
43
+ const autoInstance = AutomationFramework.getTrackedInstance();
44
+ if (!autoInstance) {
45
+ this.logger.debug('No tracked instances found!');
46
+ return;
47
+ }
48
+ const browser = AutomationFramework.getDriver(autoInstance);
49
+ if (!browser) {
50
+ this.logger.debug('No browser instance found for command wrapping');
51
+ return;
52
+ }
53
+ const isBrowserstackSession = AutomationFramework.getState(autoInstance, AutomationFrameworkConstants.KEY_IS_BROWSERSTACK_HUB);
54
+ const browserCaps = AutomationFramework.getState(autoInstance, AutomationFrameworkConstants.KEY_CAPABILITIES);
55
+ const inputCaps = AutomationFramework.getState(autoInstance, AutomationFrameworkConstants.KEY_INPUT_CAPABILITIES);
56
+ const sessionId = AutomationFramework.getState(autoInstance, AutomationFrameworkConstants.KEY_FRAMEWORK_SESSION_ID);
57
+ const platformA11yMeta = {
58
+ browser_name: browserCaps.browserName,
59
+ browser_version: browserCaps?.browserVersion || 'latest',
60
+ platform_name: browserCaps?.platformName,
61
+ platform_version: this.getCapability(browserCaps, 'appium:platformVersion', 'platformVersion'),
62
+ };
63
+ if (this.isAppAccessibility) {
64
+ this.accessibility = validateCapsWithAppA11y(platformA11yMeta);
65
+ }
66
+ else if (this.isNonBstackA11y) {
67
+ if (validateCapsWithNonBstackA11y(platformA11yMeta.browser_name, platformA11yMeta.browser_version)) {
68
+ this.accessibility = true;
69
+ }
70
+ }
71
+ else {
72
+ const device = this.getCapability(inputCaps, 'deviceName');
73
+ const chromeOptions = this.getCapability(inputCaps, 'goog:chromeOptions');
74
+ this.accessibility = validateCapsWithA11y(device, platformA11yMeta, chromeOptions);
75
+ }
76
+ //patching getA11yResultsSummary
77
+ browser.getAccessibilityResultsSummary = async () => {
78
+ if (this.isAppAccessibility) {
79
+ return await getAppA11yResultsSummary(true, browser, isBrowserstackSession, this.accessibility, sessionId);
80
+ }
81
+ return await this.getA11yResultsSummary(browser);
82
+ };
83
+ //patching getA11yResults
84
+ browser.getAccessibilityResults = async () => {
85
+ if (this.isAppAccessibility) {
86
+ return await getAppA11yResults(true, browser, isBrowserstackSession, this.accessibility, sessionId);
87
+ }
88
+ return await this.getA11yResults(browser);
89
+ };
90
+ //patching performScan
91
+ browser.performScan = async () => {
92
+ return await this.performScanCli(browser);
93
+ };
94
+ if (!this.accessibility) {
95
+ this.logger.info('Accessibility automation is disabled for this session.');
96
+ return;
97
+ }
98
+ if (!('overwriteCommand' in browser && Array.isArray(this.scriptInstance.commandsToWrap))) {
99
+ return;
100
+ }
101
+ // Wrap commands if accessibility scripts are available
102
+ if (this.scriptInstance.commandsToWrap && this.scriptInstance.commandsToWrap.length > 0) {
103
+ this.scriptInstance.commandsToWrap
104
+ .filter((command) => command.name && command.class)
105
+ .forEach((command) => {
106
+ browser.overwriteCommand(command.name, this.commandWrapper.bind(this, command), command.class === 'Element');
107
+ });
108
+ }
109
+ }
110
+ catch (error) {
111
+ this.logger.error(`Error in onBeforeExecute: ${error}`);
112
+ }
113
+ }
114
+ async commandWrapper(command, originFunction, ...args) {
115
+ try {
116
+ const autoInstance = AutomationFramework.getTrackedInstance();
117
+ const sessionId = AutomationFramework.getState(autoInstance, AutomationFrameworkConstants.KEY_FRAMEWORK_SESSION_ID);
118
+ // Check if accessibility is still enabled for this session
119
+ if (sessionId && this.accessibilityMap.get(sessionId)) {
120
+ const browser = AutomationFramework.getDriver(autoInstance);
121
+ // Perform accessibility scan before command if script is available
122
+ if (!command.name.includes('execute') ||
123
+ !this.shouldPatchExecuteScript(args.length ? args[0] : null)) {
124
+ try {
125
+ await this.performScanCli(browser, command.name);
126
+ this.logger.debug(`Accessibility scan performed after ${command.name} command`);
127
+ }
128
+ catch (scanError) {
129
+ this.logger.debug(`Error performing accessibility scan after ${command.name}: ${scanError}`);
130
+ }
131
+ }
132
+ }
133
+ // Execute the original command
134
+ const result = await originFunction(...args);
135
+ return result;
136
+ }
137
+ catch (error) {
138
+ this.logger.error(`Error in commandWrapper for ${command.name}: ${error}`);
139
+ // Still execute the original command even if accessibility scan fails
140
+ return await originFunction(...args);
141
+ }
142
+ }
143
+ async onBeforeTest(args) {
144
+ try {
145
+ this.logger.debug('Accessibility before test hook. Starting accessibility scan for this test case.');
146
+ const suiteTitle = args.suiteTitle || '';
147
+ const test = args.test || {};
148
+ const autoInstance = AutomationFramework.getTrackedInstance();
149
+ const testInstance = TestFramework.getTrackedInstance();
150
+ const sessionId = AutomationFramework.getState(autoInstance, AutomationFrameworkConstants.KEY_FRAMEWORK_SESSION_ID);
151
+ const accessibilityOptions = this.config.accessibilityOptions;
152
+ const shouldScanTest = shouldScanTestForAccessibility(suiteTitle, test.title, accessibilityOptions) && this.accessibility;
153
+ // Create test metadata similar to accessibility-handler
154
+ const testIdentifier = testInstance.getContext().getId();
155
+ const testMetadata = {
156
+ scanTestForAccessibility: shouldScanTest,
157
+ accessibilityScanStarted: shouldScanTest
158
+ };
159
+ // Store test metadata in test instance
160
+ TestFramework.setState(testInstance, `accessibility_metadata_${testIdentifier}`, testMetadata);
161
+ this.accessibilityMap.set(sessionId, shouldScanTest);
162
+ // Log if accessibility scan is enabled for this test
163
+ if (shouldScanTest) {
164
+ this.logger.info('Accessibility test case execution has started.');
165
+ }
166
+ else if (!this.LOG_DISABLED_SHOWN.get(sessionId)) {
167
+ this.logger.info('Accessibility scanning disabled for this test case.');
168
+ this.LOG_DISABLED_SHOWN.set(sessionId, true);
169
+ }
170
+ }
171
+ catch (error) {
172
+ this.logger.error(`Exception in starting accessibility automation scan for this test case: ${error}`);
173
+ }
174
+ }
175
+ async onAfterTest() {
176
+ this.logger.debug('Accessibility after test hook. Before sending test stop event');
177
+ try {
178
+ const autoInstance = AutomationFramework.getTrackedInstance();
179
+ const testInstance = TestFramework.getTrackedInstance();
180
+ const sessionId = AutomationFramework.getState(autoInstance, AutomationFrameworkConstants.KEY_FRAMEWORK_SESSION_ID);
181
+ if (!autoInstance || !testInstance) {
182
+ this.logger.error('No tracked instances found for accessibility after test');
183
+ return;
184
+ }
185
+ // Get test metadata that was stored in onBeforeTest
186
+ const testIdentifier = testInstance.getContext().getId();
187
+ const testMetadata = testInstance.getData(`accessibility_metadata_${testIdentifier}`);
188
+ if (!testMetadata) {
189
+ this.logger.debug('No accessibility metadata found for this test');
190
+ return;
191
+ }
192
+ const { accessibilityScanStarted, scanTestForAccessibility } = testMetadata;
193
+ if (!accessibilityScanStarted) {
194
+ this.logger.debug('Accessibility scan was not started for this test');
195
+ return;
196
+ }
197
+ if (scanTestForAccessibility) {
198
+ this.logger.info('Automate test case execution has ended. Processing for accessibility testing is underway.');
199
+ // Get the driver for sending test stop event
200
+ const browser = AutomationFramework.getDriver(autoInstance);
201
+ if (browser) {
202
+ let dataForExtension = {
203
+ 'thTestRunUuid': process.env.TEST_ANALYTICS_ID,
204
+ 'thBuildUuid': process.env.BROWSERSTACK_TESTHUB_UUID,
205
+ 'thJwtToken': process.env.BROWSERSTACK_TESTHUB_JWT
206
+ };
207
+ const driverExecuteParams = await this.getDriverExecuteParams();
208
+ dataForExtension = { ...dataForExtension, ...driverExecuteParams };
209
+ // final scan and saving the results
210
+ await this.sendTestStopEvent(browser, dataForExtension);
211
+ this.logger.info('Accessibility testing for this test case has ended.');
212
+ }
213
+ else {
214
+ this.logger.warn('No driver found to send accessibility test stop event');
215
+ }
216
+ this.accessibilityMap.delete(sessionId);
217
+ // Clean up test metadata
218
+ TestFramework.setState(testInstance, `accessibility_metadata_${testIdentifier}`, null);
219
+ }
220
+ }
221
+ catch (error) {
222
+ this.logger.error(`Accessibility results could not be processed for the test case. Error: ${error}`);
223
+ }
224
+ }
225
+ shouldPatchExecuteScript(script) {
226
+ if (!script || typeof script !== 'string') {
227
+ return true;
228
+ }
229
+ return (script.toLowerCase().indexOf('browserstack_executor') !== -1 ||
230
+ script.toLowerCase().indexOf('browserstack_accessibility_automation_script') !== -1);
231
+ }
232
+ getCapability(capabilities, key, legacyKey = '') {
233
+ if (key === 'deviceName') {
234
+ if (capabilities['bstack:options'] && capabilities['bstack:options']?.deviceName) {
235
+ return capabilities['bstack:options']?.deviceName;
236
+ }
237
+ else if (capabilities['bstack:options'] && capabilities['bstack:options']?.device) {
238
+ return capabilities['bstack:options']?.device;
239
+ }
240
+ else if (capabilities['appium:deviceName']) {
241
+ return capabilities['appium:deviceName'];
242
+ }
243
+ }
244
+ else if (key === 'goog:chromeOptions' && capabilities['goog:chromeOptions']) {
245
+ return capabilities['goog:chromeOptions'];
246
+ }
247
+ else {
248
+ const bstackOptions = capabilities['bstack:options'];
249
+ if (bstackOptions && bstackOptions?.[key]) {
250
+ return bstackOptions?.[key];
251
+ }
252
+ else if (capabilities[legacyKey]) {
253
+ return capabilities[legacyKey];
254
+ }
255
+ }
256
+ }
257
+ async performScanCli(browser, commandName) {
258
+ return await PerformanceTester.measureWrapper(PERFORMANCE_SDK_EVENTS.A11Y_EVENTS.PERFORM_SCAN, async () => {
259
+ try {
260
+ if (!this.accessibility) {
261
+ this.logger.debug('Not an Accessibility Automation session.');
262
+ return;
263
+ }
264
+ if (this.isAppAccessibility) {
265
+ const results = await browser.execute(formatString(this.scriptInstance.performScan, JSON.stringify(_getParamsForAppAccessibility(commandName))), {});
266
+ BStackLogger.debug(util.format(results));
267
+ return results;
268
+ }
269
+ const results = await browser.executeAsync(this.scriptInstance.performScan, { 'method': commandName || '' });
270
+ return results;
271
+ }
272
+ catch (err) {
273
+ this.logger.error('Accessibility Scan could not be performed : ' + err);
274
+ return;
275
+ }
276
+ }, { command: commandName })();
277
+ }
278
+ async sendTestStopEvent(browser, dataForExtension) {
279
+ try {
280
+ if (!this.accessibility) {
281
+ this.logger.debug('Not an Accessibility Automation session.');
282
+ return;
283
+ }
284
+ this.logger.debug('Performing scan before saving results');
285
+ await this.performScanCli(browser);
286
+ if (this.isAppAccessibility) {
287
+ return;
288
+ }
289
+ await PerformanceTester.measureWrapper(PERFORMANCE_SDK_EVENTS.A11Y_EVENTS.SAVE_RESULTS, async () => {
290
+ const results = await browser.executeAsync(accessibilityScripts.saveTestResults, dataForExtension);
291
+ this.logger.debug(`save results : ${util.format(results)}`);
292
+ })();
293
+ }
294
+ catch (error) {
295
+ this.logger.error(`Error while sending test stop event: ${error}`);
296
+ }
297
+ }
298
+ async getA11yResults(browser) {
299
+ return await PerformanceTester.measureWrapper(PERFORMANCE_SDK_EVENTS.A11Y_EVENTS.GET_RESULTS, async () => {
300
+ try {
301
+ if (!this.accessibility) {
302
+ this.logger.debug('Not an Accessibility Automation session.');
303
+ return;
304
+ }
305
+ this.logger.debug('Performing scan before getting results');
306
+ await this.performScanCli(browser);
307
+ const results = await browser.executeAsync(this.scriptInstance.getResults);
308
+ return results;
309
+ }
310
+ catch (error) {
311
+ this.logger.error('No accessibility results were found.');
312
+ this.logger.debug(`getA11yResults Failed. Error: ${error}`);
313
+ return [];
314
+ }
315
+ })();
316
+ }
317
+ async getA11yResultsSummary(browser) {
318
+ return await PerformanceTester.measureWrapper(PERFORMANCE_SDK_EVENTS.A11Y_EVENTS.GET_RESULTS_SUMMARY, async () => {
319
+ try {
320
+ if (!this.accessibility) {
321
+ this.logger.debug('Not an Accessibility Automation session.');
322
+ return;
323
+ }
324
+ this.logger.debug('Performing scan before getting results summary');
325
+ await this.performScanCli(browser);
326
+ const summaryResults = await browser.executeAsync(this.scriptInstance.getResultsSummary);
327
+ return summaryResults;
328
+ }
329
+ catch {
330
+ this.logger.error('No accessibility summary was found.');
331
+ return {};
332
+ }
333
+ })();
334
+ }
335
+ async getDriverExecuteParams() {
336
+ const payload = {
337
+ product: 'accessibility',
338
+ scriptName: 'saveResults'
339
+ };
340
+ const response = await GrpcClient.getInstance().fetchDriverExecuteParamsEvent(payload);
341
+ if (response.success) {
342
+ return response.accessibilityExecuteParams ? JSON.parse(Buffer.from(response.accessibilityExecuteParams).toString('utf8')) : {};
343
+ }
344
+ this.logger.error(`Failed to fetch driver execute params: ${response.error || 'Unknown error'}`);
345
+ return {};
346
+ }
347
+ }
@@ -0,0 +1,26 @@
1
+ import BaseModule from './baseModule.js';
2
+ import { BStackLogger } from '../cliLogger.js';
3
+ import type { Options } from '@wdio/types';
4
+ export default class AutomateModule extends BaseModule {
5
+ logger: typeof BStackLogger;
6
+ browserStackConfig: Options.Testrunner;
7
+ private sessionMap;
8
+ static readonly MODULE_NAME = "AutomateModule";
9
+ /**
10
+ * Create a new AutomateModule
11
+ */
12
+ constructor(browserStackConfig: Options.Testrunner);
13
+ getModuleName(): string;
14
+ onBeforeTest(args: Record<string, unknown>): Promise<void>;
15
+ onAfterTest(args: Record<string, unknown>): Promise<void>;
16
+ onAfterExecute(): Promise<void>;
17
+ markSessionName(sessionId: string, sessionName: string, config: {
18
+ user: string;
19
+ key: string;
20
+ }): Promise<void>;
21
+ markSessionStatus(sessionId: string, sessionStatus: 'passed' | 'failed', sessionErrorMessage: string | undefined, config: {
22
+ user: string;
23
+ key: string;
24
+ }): Promise<void>;
25
+ }
26
+ //# sourceMappingURL=automateModule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"automateModule.d.ts","sourceRoot":"","sources":["../../../src/cli/modules/automateModule.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,iBAAiB,CAAA;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAK9C,OAAO,KAAK,EAAc,OAAO,EAAE,MAAM,aAAa,CAAA;AAsBtD,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,UAAU;IAElD,MAAM,sBAAe;IACrB,kBAAkB,EAAE,OAAO,CAAC,UAAU,CAAA;IACtC,OAAO,CAAC,UAAU,CAAsC;IAExD,MAAM,CAAC,QAAQ,CAAC,WAAW,oBAAmB;IAC9C;;OAEG;gBACS,kBAAkB,EAAE,OAAO,CAAC,UAAU;IASlD,aAAa,IAAI,MAAM;IAIjB,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IA8C1C,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IA0DzC,cAAc;IAwCd,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;KAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IA0C7G,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,GAAG,QAAQ,EAAE,mBAAmB,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CA0CjL"}