@wdio/browserstack-service 8.48.0 → 8.48.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 (68) hide show
  1. package/build/accessibility-handler.d.ts.map +1 -1
  2. package/build/accessibility-handler.js +13 -11
  3. package/build/ai-handler.d.ts.map +1 -1
  4. package/build/ai-handler.js +11 -0
  5. package/build/cli/cliLogger.d.ts +1 -0
  6. package/build/cli/cliLogger.d.ts.map +1 -1
  7. package/build/cli/cliLogger.js +23 -12
  8. package/build/cli/cliUtils.d.ts +18 -0
  9. package/build/cli/cliUtils.d.ts.map +1 -1
  10. package/build/cli/cliUtils.js +29 -0
  11. package/build/cli/frameworks/wdioMochaTestFramework.d.ts.map +1 -1
  12. package/build/cli/frameworks/wdioMochaTestFramework.js +4 -2
  13. package/build/cli/grpcClient.d.ts +19 -3
  14. package/build/cli/grpcClient.d.ts.map +1 -1
  15. package/build/cli/grpcClient.js +133 -21
  16. package/build/cli/index.d.ts +2 -0
  17. package/build/cli/index.d.ts.map +1 -1
  18. package/build/cli/index.js +52 -4
  19. package/build/cli/modules/accessibilityModule.d.ts +3 -0
  20. package/build/cli/modules/accessibilityModule.d.ts.map +1 -1
  21. package/build/cli/modules/accessibilityModule.js +75 -10
  22. package/build/constants.d.ts +28 -0
  23. package/build/constants.d.ts.map +1 -1
  24. package/build/constants.js +37 -1
  25. package/build/exitHandler.d.ts +1 -1
  26. package/build/exitHandler.d.ts.map +1 -1
  27. package/build/exitHandler.js +6 -5
  28. package/build/insights-handler.d.ts.map +1 -1
  29. package/build/insights-handler.js +33 -7
  30. package/build/instrumentation/funnelInstrumentation.d.ts +2 -2
  31. package/build/instrumentation/funnelInstrumentation.d.ts.map +1 -1
  32. package/build/instrumentation/funnelInstrumentation.js +30 -8
  33. package/build/instrumentation/performance/constants.d.ts +64 -0
  34. package/build/instrumentation/performance/constants.d.ts.map +1 -1
  35. package/build/instrumentation/performance/constants.js +73 -2
  36. package/build/instrumentation/performance/performance-tester.d.ts +11 -0
  37. package/build/instrumentation/performance/performance-tester.d.ts.map +1 -1
  38. package/build/instrumentation/performance/performance-tester.js +115 -12
  39. package/build/launcher.d.ts +1 -0
  40. package/build/launcher.d.ts.map +1 -1
  41. package/build/launcher.js +151 -6
  42. package/build/service.d.ts.map +1 -1
  43. package/build/service.js +77 -5
  44. package/build/testorchestration/apply-orchestration.d.ts +7 -0
  45. package/build/testorchestration/apply-orchestration.d.ts.map +1 -0
  46. package/build/testorchestration/apply-orchestration.js +42 -0
  47. package/build/testorchestration/helpers.d.ts +20 -0
  48. package/build/testorchestration/helpers.d.ts.map +1 -0
  49. package/build/testorchestration/helpers.js +412 -0
  50. package/build/testorchestration/request-utils.d.ts +23 -0
  51. package/build/testorchestration/request-utils.d.ts.map +1 -0
  52. package/build/testorchestration/request-utils.js +81 -0
  53. package/build/testorchestration/test-ordering-server.d.ts +33 -0
  54. package/build/testorchestration/test-ordering-server.d.ts.map +1 -0
  55. package/build/testorchestration/test-ordering-server.js +168 -0
  56. package/build/testorchestration/testorcherstrationhandler.d.ts +50 -0
  57. package/build/testorchestration/testorcherstrationhandler.d.ts.map +1 -0
  58. package/build/testorchestration/testorcherstrationhandler.js +133 -0
  59. package/build/testorchestration/testorcherstrationutils.d.ts +86 -0
  60. package/build/testorchestration/testorcherstrationutils.d.ts.map +1 -0
  61. package/build/testorchestration/testorcherstrationutils.js +379 -0
  62. package/build/types.d.ts +21 -0
  63. package/build/types.d.ts.map +1 -1
  64. package/build/util.d.ts +33 -4
  65. package/build/util.d.ts.map +1 -1
  66. package/build/util.js +112 -18
  67. package/package.json +3 -2
  68. package/tsconfig.prod.tsbuildinfo +1 -1
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Utility class for making API requests to the BrowserStack orchestration API
3
+ */
4
+ export declare class RequestUtils {
5
+ /**
6
+ * Makes a request to the test orchestration split tests endpoint
7
+ */
8
+ static testOrchestrationSplitTests(reqEndpoint: string, data: any): Promise<any>;
9
+ /**
10
+ * Gets ordered tests from the test orchestration
11
+ */
12
+ static getTestOrchestrationOrderedTests(reqEndpoint: string): Promise<any>;
13
+ /**
14
+ * Makes an orchestration request with the given method and data
15
+ */
16
+ static makeOrchestrationRequest(method: 'GET' | 'POST' | 'PUT', reqEndpoint: string, options: {
17
+ data?: any;
18
+ params?: Record<string, any>;
19
+ extraHeaders?: Record<string, string>;
20
+ }): Promise<any>;
21
+ }
22
+ export default RequestUtils;
23
+ //# sourceMappingURL=request-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-utils.d.ts","sourceRoot":"","sources":["../../src/testorchestration/request-utils.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,qBAAa,YAAY;IACrB;;OAEG;WACU,2BAA2B,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG;IAKvE;;OAEG;WACU,gCAAgC,CAAC,WAAW,EAAE,MAAM;IAKjE;;OAEG;WACU,wBAAwB,CAAC,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE;QAChG,IAAI,CAAC,EAAE,GAAG,CAAC;QACX,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC7B,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KACxC;CA4DJ;AAED,eAAe,YAAY,CAAA"}
@@ -0,0 +1,81 @@
1
+ import got from 'got';
2
+ import { BStackLogger } from '../bstackLogger.js';
3
+ import APIUtils from '../cli/apiUtils.js';
4
+ /**
5
+ * Utility class for making API requests to the BrowserStack orchestration API
6
+ */
7
+ export class RequestUtils {
8
+ /**
9
+ * Makes a request to the test orchestration split tests endpoint
10
+ */
11
+ static async testOrchestrationSplitTests(reqEndpoint, data) {
12
+ BStackLogger.debug('Processing Request for testOrchestrationSplitTests');
13
+ return RequestUtils.makeOrchestrationRequest('POST', reqEndpoint, { data });
14
+ }
15
+ /**
16
+ * Gets ordered tests from the test orchestration
17
+ */
18
+ static async getTestOrchestrationOrderedTests(reqEndpoint) {
19
+ BStackLogger.debug('Processing Request for getTestOrchestrationOrderedTests');
20
+ return RequestUtils.makeOrchestrationRequest('GET', reqEndpoint, {});
21
+ }
22
+ /**
23
+ * Makes an orchestration request with the given method and data
24
+ */
25
+ static async makeOrchestrationRequest(method, reqEndpoint, options) {
26
+ const jwtToken = process.env.BROWSERSTACK_TESTHUB_JWT || '';
27
+ const headers = {
28
+ 'authorization': `Bearer ${jwtToken}`,
29
+ 'Content-Type': 'application/json',
30
+ 'Accept': 'application/json'
31
+ };
32
+ if (options.extraHeaders) {
33
+ Object.assign(headers, options.extraHeaders);
34
+ }
35
+ const url = `${APIUtils.DATA_ENDPOINT}/${reqEndpoint.replace(/^\//, '')}`;
36
+ try {
37
+ let response;
38
+ const requestOptions = {
39
+ headers,
40
+ responseType: 'json'
41
+ };
42
+ if (options.data) {
43
+ requestOptions.json = options.data;
44
+ }
45
+ if (options.params) {
46
+ requestOptions.searchParams = options.params;
47
+ }
48
+ if (method === 'GET') {
49
+ response = await got.get(url, requestOptions);
50
+ }
51
+ else if (method === 'POST') {
52
+ response = await got.post(url, requestOptions);
53
+ }
54
+ else if (method === 'PUT') {
55
+ response = await got.put(url, requestOptions);
56
+ }
57
+ else {
58
+ throw new Error(`Unsupported HTTP method: ${method}`);
59
+ }
60
+ BStackLogger.debug(`Orchestration request made to URL: ${url} with method: ${method}`);
61
+ let responseObj = {};
62
+ try {
63
+ responseObj = response.body;
64
+ }
65
+ catch (e) {
66
+ BStackLogger.debug(`Failed to parse JSON response: ${e} - ${response.body}`);
67
+ }
68
+ if (responseObj) {
69
+ responseObj.next_poll_time = response.headers.next_poll_time ||
70
+ String(Date.now());
71
+ responseObj.status = response.statusCode;
72
+ }
73
+ return responseObj;
74
+ }
75
+ catch (e) {
76
+ BStackLogger.error(`Orchestration request failed: ${e} - ${url}`);
77
+ return null;
78
+ }
79
+ }
80
+ }
81
+ export default RequestUtils;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Handles test ordering orchestration with the BrowserStack server.
3
+ */
4
+ export declare class TestOrderingServer {
5
+ private config;
6
+ private ORDERING_ENDPOINT;
7
+ private requestData;
8
+ private defaultTimeout;
9
+ private defaultTimeoutInterval;
10
+ private splitTestsApiCallCount;
11
+ /**
12
+ * @param config Test orchestration config
13
+ */
14
+ constructor(config: Record<string, any>);
15
+ /**
16
+ * Initiates the split tests request and stores the response data for polling.
17
+ */
18
+ splitTests(testFiles: string[], orchestrationStrategy: string, orchestrationMetadata?: string): Promise<void>;
19
+ /**
20
+ * Processes the split tests API response and extracts relevant fields.
21
+ */
22
+ private _processSplitTestsResponse;
23
+ /**
24
+ * Retrieves the ordered test files from the orchestration server
25
+ */
26
+ getOrderedTestFiles(): Promise<any[] | null>;
27
+ /**
28
+ * Returns the count of split tests API calls made.
29
+ */
30
+ getSplitTestsApiCallCount(): number;
31
+ }
32
+ export default TestOrderingServer;
33
+ //# sourceMappingURL=test-ordering-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-ordering-server.d.ts","sourceRoot":"","sources":["../../src/testorchestration/test-ordering-server.ts"],"names":[],"mappings":"AAOA;;GAEG;AACH,qBAAa,kBAAkB;IAC3B,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,iBAAiB,CAAQ;IACjC,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,cAAc,CAAQ;IAC9B,OAAO,CAAC,sBAAsB,CAAQ;IACtC,OAAO,CAAC,sBAAsB,CAAQ;IAEtC;;OAEG;gBACS,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IASvC;;OAEG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,qBAAqB,EAAE,MAAM,EAAE,qBAAqB,GAAE,MAAa;IAsCzG;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAoClC;;OAEG;IACG,mBAAmB;IAgEzB;;OAEG;IACH,yBAAyB;CAG5B;AAED,eAAe,kBAAkB,CAAA"}
@@ -0,0 +1,168 @@
1
+ import path from 'node:path';
2
+ import { getHostInfo, getGitMetadataForAISelection } from './helpers.js';
3
+ import { RequestUtils } from './request-utils.js';
4
+ import APIUtils from '../cli/apiUtils.js';
5
+ import { BStackLogger } from '../bstackLogger.js';
6
+ /**
7
+ * Handles test ordering orchestration with the BrowserStack server.
8
+ */
9
+ export class TestOrderingServer {
10
+ config;
11
+ ORDERING_ENDPOINT;
12
+ requestData;
13
+ defaultTimeout;
14
+ defaultTimeoutInterval;
15
+ splitTestsApiCallCount;
16
+ /**
17
+ * @param config Test orchestration config
18
+ */
19
+ constructor(config) {
20
+ this.config = config;
21
+ this.ORDERING_ENDPOINT = 'testorchestration/api/v1/split-tests';
22
+ this.requestData = null;
23
+ this.defaultTimeout = 60;
24
+ this.defaultTimeoutInterval = 5;
25
+ this.splitTestsApiCallCount = 0;
26
+ }
27
+ /**
28
+ * Initiates the split tests request and stores the response data for polling.
29
+ */
30
+ async splitTests(testFiles, orchestrationStrategy, orchestrationMetadata = '{}') {
31
+ BStackLogger.debug(`[splitTests] Initiating split tests with strategy: ${orchestrationStrategy}`);
32
+ try {
33
+ let prDetails = [];
34
+ const parsedMetadata = JSON.parse(orchestrationMetadata);
35
+ const source = parsedMetadata.run_smart_selection?.source;
36
+ const isGithubAppApproach = Array.isArray(source) && source.length > 0 && source.every(src => src && typeof src === 'object' && !Array.isArray(src));
37
+ if (parsedMetadata.run_smart_selection?.enabled && !isGithubAppApproach) {
38
+ const multiRepoSource = parsedMetadata.run_smart_selection?.source;
39
+ prDetails = getGitMetadataForAISelection(multiRepoSource);
40
+ }
41
+ BStackLogger.info(`PR Details for AI Selection: ${JSON.stringify(prDetails)}`);
42
+ const payload = {
43
+ tests: testFiles.map(f => ({ filePath: f })),
44
+ orchestrationStrategy,
45
+ orchestrationMetadata: parsedMetadata,
46
+ nodeIndex: parseInt(process.env.BROWSERSTACK_NODE_INDEX || '0'),
47
+ totalNodes: parseInt(process.env.BROWSERSTACK_TOTAL_NODE_COUNT || '1'),
48
+ projectName: this.config.testObservabilityOptions.projectName || '',
49
+ buildName: this.config.testObservabilityOptions.buildName || path.basename(process.cwd()),
50
+ buildRunIdentifier: process.env.BROWSERSTACK_BUILD_RUN_IDENTIFIER || '',
51
+ hostInfo: getHostInfo(),
52
+ prDetails
53
+ };
54
+ const response = await RequestUtils.testOrchestrationSplitTests(this.ORDERING_ENDPOINT, payload);
55
+ if (response) {
56
+ this.requestData = this._processSplitTestsResponse(response);
57
+ BStackLogger.debug(`[splitTests] Split tests response: ${JSON.stringify(this.requestData)}`);
58
+ }
59
+ else {
60
+ BStackLogger.error('[splitTests] Failed to get split tests response.');
61
+ }
62
+ }
63
+ catch (e) {
64
+ BStackLogger.error(`[splitTests] Exception in sending test files:: ${e}`);
65
+ }
66
+ }
67
+ /**
68
+ * Processes the split tests API response and extracts relevant fields.
69
+ */
70
+ _processSplitTestsResponse(response) {
71
+ const responseData = {};
72
+ responseData.timeout = response.timeout !== undefined ? response.timeout : this.defaultTimeout;
73
+ responseData.timeoutInterval = response.timeoutInterval !== undefined ? response.timeoutInterval : this.defaultTimeoutInterval;
74
+ const resultUrl = response.resultUrl;
75
+ const timeoutUrl = response.timeoutUrl;
76
+ // Remove the API prefix if present
77
+ if (resultUrl) {
78
+ responseData.resultUrl = resultUrl.includes(`${APIUtils.DATA_ENDPOINT}/`)
79
+ ? resultUrl.split(`${APIUtils.DATA_ENDPOINT}/`)[1]
80
+ : resultUrl;
81
+ }
82
+ else {
83
+ responseData.resultUrl = null;
84
+ }
85
+ if (timeoutUrl) {
86
+ responseData.timeoutUrl = timeoutUrl.includes(`${APIUtils.DATA_ENDPOINT}/`)
87
+ ? timeoutUrl.split(`${APIUtils.DATA_ENDPOINT}/`)[1]
88
+ : timeoutUrl;
89
+ }
90
+ else {
91
+ responseData.timeoutUrl = null;
92
+ }
93
+ if (response.timeout === undefined ||
94
+ response.timeoutInterval === undefined ||
95
+ response.timeoutUrl === undefined ||
96
+ response.resultUrl === undefined) {
97
+ BStackLogger.debug('[process_split_tests_response] Received null value(s) for some attributes in split tests API response');
98
+ }
99
+ return responseData;
100
+ }
101
+ /**
102
+ * Retrieves the ordered test files from the orchestration server
103
+ */
104
+ async getOrderedTestFiles() {
105
+ if (!this.requestData) {
106
+ BStackLogger.error('[getOrderedTestFiles] No request data available to fetch ordered test files.');
107
+ return null;
108
+ }
109
+ let testFilesJsonList = null;
110
+ const testFiles = [];
111
+ const startTimeMillis = Date.now();
112
+ const timeoutInterval = parseInt(String(this.requestData.timeoutInterval || this.defaultTimeoutInterval), 10);
113
+ const timeoutMillis = parseInt(String(this.requestData.timeout || this.defaultTimeout), 10) * 1000;
114
+ const timeoutUrl = this.requestData.timeoutUrl;
115
+ const resultUrl = this.requestData.resultUrl;
116
+ if (resultUrl === null && timeoutUrl === null) {
117
+ return null;
118
+ }
119
+ try {
120
+ // Poll resultUrl until timeout or until tests are available
121
+ while (resultUrl && (Date.now() - startTimeMillis) < timeoutMillis) {
122
+ const response = await RequestUtils.getTestOrchestrationOrderedTests(resultUrl);
123
+ if (response && response.tests) {
124
+ testFilesJsonList = response.tests;
125
+ }
126
+ this.splitTestsApiCallCount++;
127
+ if (testFilesJsonList) {
128
+ break;
129
+ }
130
+ await new Promise(resolve => setTimeout(resolve, timeoutInterval * 1000));
131
+ BStackLogger.debug(`[getOrderedTestFiles] Fetching ordered tests from result URL after waiting for ${timeoutInterval} seconds.`);
132
+ }
133
+ // If still not available, try timeoutUrl
134
+ if (timeoutUrl && !testFilesJsonList) {
135
+ BStackLogger.debug('[getOrderedTestFiles] Fetching ordered tests from timeout URL');
136
+ const response = await RequestUtils.getTestOrchestrationOrderedTests(timeoutUrl);
137
+ if (response && response.tests) {
138
+ testFilesJsonList = response.tests;
139
+ }
140
+ }
141
+ // Extract file paths
142
+ if (testFilesJsonList && testFilesJsonList.length > 0) {
143
+ for (const testData of testFilesJsonList) {
144
+ const filePath = testData.filePath;
145
+ if (filePath) {
146
+ testFiles.push(filePath);
147
+ }
148
+ }
149
+ }
150
+ if (!testFilesJsonList) {
151
+ return null;
152
+ }
153
+ BStackLogger.debug(`[getOrderedTestFiles] Ordered test files received: ${JSON.stringify(testFiles)}`);
154
+ return testFiles;
155
+ }
156
+ catch (e) {
157
+ BStackLogger.error(`[getOrderedTestFiles] Exception in fetching ordered test files: ${e}`);
158
+ return null;
159
+ }
160
+ }
161
+ /**
162
+ * Returns the count of split tests API calls made.
163
+ */
164
+ getSplitTestsApiCallCount() {
165
+ return this.splitTestsApiCallCount;
166
+ }
167
+ }
168
+ export default TestOrderingServer;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Handles test orchestration operations
3
+ */
4
+ export declare class TestOrchestrationHandler {
5
+ private static _instance;
6
+ private config;
7
+ private testOrderingServerHandler;
8
+ private orchestrationUtils;
9
+ private orderingInstrumentationData;
10
+ private testOrderingApplied;
11
+ private isTestOrderingEnabled;
12
+ /**
13
+ * @param config Service configuration
14
+ */
15
+ constructor(config: Record<string, any>);
16
+ /**
17
+ * Get or create an instance of TestOrchestrationHandler
18
+ */
19
+ static getInstance(config: Record<string, any>): TestOrchestrationHandler;
20
+ /**
21
+ * Checks if observability is enabled
22
+ */
23
+ private _isObservabilityEnabled;
24
+ /**
25
+ * Logs test ordering checks
26
+ */
27
+ logTestOrderingChecks(): void;
28
+ /**
29
+ * Checks if test ordering is applied
30
+ */
31
+ isTestOrderingApplied(): boolean;
32
+ /**
33
+ * Sets whether test ordering is applied
34
+ */
35
+ setTestOrderingApplied(orderingApplied: boolean): void;
36
+ /**
37
+ * Reorders test files based on the orchestration strategy
38
+ */
39
+ reorderTestFiles(testFiles: string[]): Promise<string[] | null>;
40
+ /**
41
+ * Adds data to the ordering instrumentation data
42
+ */
43
+ addToOrderingInstrumentationData(key: string, value: any): void;
44
+ /**
45
+ * Gets the ordering instrumentation data
46
+ */
47
+ getOrderingInstrumentationData(): Record<string, any>;
48
+ }
49
+ export default TestOrchestrationHandler;
50
+ //# sourceMappingURL=testorcherstrationhandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testorcherstrationhandler.d.ts","sourceRoot":"","sources":["../../src/testorchestration/testorcherstrationhandler.ts"],"names":[],"mappings":"AAmBA;;GAEG;AACH,qBAAa,wBAAwB;IACjC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAwC;IAChE,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,yBAAyB,CAAoB;IACrD,OAAO,CAAC,kBAAkB,CAA2B;IACrD,OAAO,CAAC,2BAA2B,CAAqB;IACxD,OAAO,CAAC,mBAAmB,CAAS;IACpC,OAAO,CAAC,qBAAqB,CAAS;IAEtC;;OAEG;gBACS,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IASvC;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,wBAAwB;IAOzE;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAI/B;;OAEG;IACH,qBAAqB,IAAI,IAAI;IAU7B;;OAEG;IACH,qBAAqB,IAAI,OAAO;IAIhC;;OAEG;IACH,sBAAsB,CAAC,eAAe,EAAE,OAAO,GAAG,IAAI;IAKtD;;OAEG;IACG,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC;IA2CrE;;OAEG;IACH,gCAAgC,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI;IAI/D;;OAEG;IACH,8BAA8B,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;CAGxD;AAED,eAAe,wBAAwB,CAAA"}
@@ -0,0 +1,133 @@
1
+ import { TestOrderingServer } from './test-ordering-server.js';
2
+ import { OrchestrationUtils } from './testorcherstrationutils.js';
3
+ import { GrpcClient } from '../cli/grpcClient.js';
4
+ import { BrowserstackCLI } from '../cli/index.js';
5
+ import { BStackLogger } from '../bstackLogger.js';
6
+ /**
7
+ * Checks if a value is true
8
+ */
9
+ function isTrue(value) {
10
+ if (typeof value === 'boolean') {
11
+ return value;
12
+ }
13
+ if (typeof value === 'string') {
14
+ return value.toLowerCase() === 'true';
15
+ }
16
+ return !!value;
17
+ }
18
+ /**
19
+ * Handles test orchestration operations
20
+ */
21
+ export class TestOrchestrationHandler {
22
+ static _instance = null;
23
+ config;
24
+ testOrderingServerHandler;
25
+ orchestrationUtils;
26
+ orderingInstrumentationData;
27
+ testOrderingApplied;
28
+ isTestOrderingEnabled;
29
+ /**
30
+ * @param config Service configuration
31
+ */
32
+ constructor(config) {
33
+ this.config = config;
34
+ this.testOrderingServerHandler = new TestOrderingServer(this.config);
35
+ this.orchestrationUtils = OrchestrationUtils.getInstance(config);
36
+ this.orderingInstrumentationData = {};
37
+ this.testOrderingApplied = false;
38
+ this.isTestOrderingEnabled = config.testOrchestration?.enabled || false;
39
+ }
40
+ /**
41
+ * Get or create an instance of TestOrchestrationHandler
42
+ */
43
+ static getInstance(config) {
44
+ if (TestOrchestrationHandler._instance === null && config !== null) {
45
+ TestOrchestrationHandler._instance = new TestOrchestrationHandler(config);
46
+ }
47
+ return TestOrchestrationHandler._instance;
48
+ }
49
+ /**
50
+ * Checks if observability is enabled
51
+ */
52
+ _isObservabilityEnabled() {
53
+ return isTrue(this.config.testObservability);
54
+ }
55
+ /**
56
+ * Logs test ordering checks
57
+ */
58
+ logTestOrderingChecks() {
59
+ if (this.config.projectName === undefined || this.config.buildName === undefined) {
60
+ BStackLogger.info("Test Reordering can't work as buildName or projectName is null. Please set a non-null value.");
61
+ }
62
+ if (!this._isObservabilityEnabled()) {
63
+ BStackLogger.info("Test Reordering can't work as testReporting is disabled. Please enable it from browserstack.yml file.");
64
+ }
65
+ }
66
+ /**
67
+ * Checks if test ordering is applied
68
+ */
69
+ isTestOrderingApplied() {
70
+ return this.testOrderingApplied;
71
+ }
72
+ /**
73
+ * Sets whether test ordering is applied
74
+ */
75
+ setTestOrderingApplied(orderingApplied) {
76
+ this.testOrderingApplied = orderingApplied;
77
+ this.addToOrderingInstrumentationData('applied', orderingApplied);
78
+ }
79
+ /**
80
+ * Reorders test files based on the orchestration strategy
81
+ */
82
+ async reorderTestFiles(testFiles) {
83
+ try {
84
+ if (!testFiles || testFiles.length === 0) {
85
+ BStackLogger.debug('[reorderTestFiles] No test files provided for ordering.');
86
+ return null;
87
+ }
88
+ let orchestrationStrategy = null;
89
+ const orchestrationMetadata = this.orchestrationUtils?.getTestOrchestrationMetadata() || {};
90
+ if (this.orchestrationUtils !== null) {
91
+ orchestrationStrategy = this.orchestrationUtils.getTestOrderingName();
92
+ }
93
+ if (orchestrationStrategy === null) {
94
+ BStackLogger.error('Orchestration strategy is None. Cannot proceed with test orchestration session.');
95
+ return null;
96
+ }
97
+ BStackLogger.info(`Reordering test files with orchestration strategy: ${orchestrationStrategy}`);
98
+ let orderedTestFiles = [];
99
+ if (BrowserstackCLI.getInstance().isRunning()) {
100
+ BStackLogger.info('Using CLI flow for test files orchestration.');
101
+ orderedTestFiles = await GrpcClient.getInstance().testOrchestrationSession(testFiles, orchestrationStrategy, JSON.stringify(orchestrationMetadata)) || [];
102
+ }
103
+ else {
104
+ BStackLogger.info('Using SDK flow for test files orchestration.');
105
+ await this.testOrderingServerHandler.splitTests(testFiles, orchestrationStrategy, JSON.stringify(orchestrationMetadata));
106
+ orderedTestFiles = await this.testOrderingServerHandler.getOrderedTestFiles() || [];
107
+ }
108
+ this.addToOrderingInstrumentationData('uploadedTestFilesCount', testFiles.length);
109
+ this.addToOrderingInstrumentationData('nodeIndex', parseInt(process.env.BROWSERSTACK_NODE_INDEX || '0'));
110
+ this.addToOrderingInstrumentationData('totalNodes', parseInt(process.env.BROWSERSTACK_NODE_COUNT || '1'));
111
+ this.addToOrderingInstrumentationData('downloadedTestFilesCount', orderedTestFiles.length);
112
+ this.addToOrderingInstrumentationData('splitTestsAPICallCount', this.testOrderingServerHandler.getSplitTestsApiCallCount());
113
+ return orderedTestFiles;
114
+ }
115
+ catch (e) {
116
+ BStackLogger.debug(`[reorderTestFiles] Error in ordering test classes: ${e}`);
117
+ }
118
+ return null;
119
+ }
120
+ /**
121
+ * Adds data to the ordering instrumentation data
122
+ */
123
+ addToOrderingInstrumentationData(key, value) {
124
+ this.orderingInstrumentationData[key] = value;
125
+ }
126
+ /**
127
+ * Gets the ordering instrumentation data
128
+ */
129
+ getOrderingInstrumentationData() {
130
+ return this.orderingInstrumentationData;
131
+ }
132
+ }
133
+ export default TestOrchestrationHandler;
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Utility class for test orchestration
3
+ */
4
+ export declare class OrchestrationUtils {
5
+ private static _instance;
6
+ private runSmartSelection;
7
+ private smartSelectionMode;
8
+ private testOrdering;
9
+ private smartSelectionSource;
10
+ private projectName?;
11
+ private buildName?;
12
+ private buildIdentifier?;
13
+ /**
14
+ * @param config Configuration object
15
+ */
16
+ constructor(config: Record<string, any>);
17
+ /**
18
+ * Extract build details from capabilities
19
+ */
20
+ private _extractBuildDetails;
21
+ /**
22
+ * Get or create an instance of OrchestrationUtils
23
+ */
24
+ static getInstance(config?: Record<string, any>): OrchestrationUtils | null;
25
+ /**
26
+ * Get orchestration data from config
27
+ */
28
+ static getOrchestrationData(config: Record<string, any>): Record<string, any>;
29
+ /**
30
+ * Get run smart selection setting
31
+ */
32
+ getRunSmartSelection(): boolean;
33
+ /**
34
+ * Get smart selection mode
35
+ */
36
+ getSmartSelectionMode(): string;
37
+ /**
38
+ * Get smart selection source
39
+ */
40
+ getSmartSelectionSource(): string[] | Array<Record<string, any>> | null;
41
+ /**
42
+ * Get project name
43
+ */
44
+ getProjectName(): string | undefined;
45
+ /**
46
+ * Get build name
47
+ */
48
+ getBuildName(): string | undefined;
49
+ /**
50
+ * Get build identifier
51
+ */
52
+ getBuildIdentifier(): string | undefined;
53
+ /**
54
+ * Set build details
55
+ */
56
+ setBuildDetails(projectName?: string, buildName?: string, buildIdentifier?: string): void;
57
+ /**
58
+ * Set run smart selection
59
+ */
60
+ private _setRunSmartSelection;
61
+ /**
62
+ * Parse JSON source configuration file and format it for smart selection.
63
+ *
64
+ * @param filePath - Path to the JSON configuration file
65
+ * @returns Formatted list of repository configurations
66
+ */
67
+ private _loadSourceFromFile;
68
+ /**
69
+ * Set test ordering based on priorities
70
+ */
71
+ private _setTestOrdering;
72
+ /**
73
+ * Get test ordering name
74
+ */
75
+ getTestOrderingName(): string | null;
76
+ /**
77
+ * Get test orchestration metadata
78
+ */
79
+ getTestOrchestrationMetadata(): Record<string, any>;
80
+ /**
81
+ * Get build start data
82
+ */
83
+ getBuildStartData(): Record<string, any>;
84
+ }
85
+ export default OrchestrationUtils;
86
+ //# sourceMappingURL=testorcherstrationutils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testorcherstrationutils.d.ts","sourceRoot":"","sources":["../../src/testorchestration/testorcherstrationutils.ts"],"names":[],"mappings":"AA0CA;;GAEG;AACH,qBAAa,kBAAkB;IAC3B,OAAO,CAAC,MAAM,CAAC,SAAS,CAAkC;IAC1D,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,kBAAkB,CAAQ;IAClC,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,oBAAoB,CAA8C;IAC1E,OAAO,CAAC,WAAW,CAAC,CAAQ;IAC5B,OAAO,CAAC,SAAS,CAAC,CAAQ;IAC1B,OAAO,CAAC,eAAe,CAAC,CAAQ;IAEhC;;OAEG;gBACS,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAiCvC;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAuC5B;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,kBAAkB,GAAG,IAAI;IAO3E;;OAEG;IACH,MAAM,CAAC,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAa7E;;OAEG;IACH,oBAAoB,IAAI,OAAO;IAI/B;;OAEG;IACH,qBAAqB,IAAI,MAAM;IAI/B;;OAEG;IACH,uBAAuB,IAAI,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI;IAIvE;;OAEG;IACH,cAAc,IAAI,MAAM,GAAG,SAAS;IAIpC;;OAEG;IACH,YAAY,IAAI,MAAM,GAAG,SAAS;IAIlC;;OAEG;IACH,kBAAkB,IAAI,MAAM,GAAG,SAAS;IAIxC;;OAEG;IACH,eAAe,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI;IAOzF;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAiC7B;;;;;OAKG;IACH,OAAO,CAAC,mBAAmB;IAmI3B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAQxB;;OAEG;IACH,mBAAmB,IAAI,MAAM,GAAG,IAAI;IAOpC;;OAEG;IACH,4BAA4B,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAWnD;;OAEG;IACH,iBAAiB,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;CAW3C;AAED,eAAe,kBAAkB,CAAA"}