@wdio/browserstack-service 8.0.11 → 8.1.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.
package/build/types.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { Capabilities, Options } from '@wdio/types';
2
+ import type { Options as BSOptions } from 'browserstack-local';
2
3
  export interface SessionResponse {
3
4
  automation_session: {
4
5
  browser_url: string;
@@ -20,7 +21,26 @@ export interface App {
20
21
  app?: string;
21
22
  customId?: string;
22
23
  }
24
+ export interface TestObservabilityOptions {
25
+ buildName?: string;
26
+ projectName?: string;
27
+ buildTag?: string[];
28
+ user?: string;
29
+ key?: string;
30
+ }
23
31
  export interface BrowserstackConfig {
32
+ /**
33
+ * Set this to true to enable BrowserStack Test Observability which will collect test related data
34
+ * (name, hierarchy, status, error stack trace, file name and hierarchy), test commands, etc.
35
+ * and show all the data in a meaningful manner in BrowserStack Test Observability dashboards for faster test debugging and better insights.
36
+ * @default true
37
+ */
38
+ testObservability?: boolean;
39
+ /**
40
+ * Set the Test Observability related config options under this key.
41
+ * For e.g. buildName, projectName, BrowserStack access credentials, etc.
42
+ */
43
+ testObservabilityOptions?: TestObservabilityOptions;
24
44
  /**
25
45
  * Set this with app file path present locally on your device or
26
46
  * app hashed id returned after uploading app to BrowserStack or
@@ -54,7 +74,7 @@ export interface BrowserstackConfig {
54
74
  * ```
55
75
  * @default {}
56
76
  */
57
- opts?: Partial<import('browserstack-local').Options>;
77
+ opts?: Partial<BSOptions>;
58
78
  /**
59
79
  * Cucumber only. Set the BrowserStack Automate session name to the Scenario name if only a single Scenario ran.
60
80
  * Useful when running in parallel with [wdio-cucumber-parallel-execution](https://github.com/SimitTomar/wdio-cucumber-parallel-execution).
@@ -87,4 +107,104 @@ export interface BrowserstackConfig {
87
107
  */
88
108
  setSessionStatus?: boolean;
89
109
  }
110
+ /**
111
+ * Observability types
112
+ */
113
+ export interface PlatformMeta {
114
+ sessionId?: string;
115
+ browserName?: string;
116
+ browserVersion?: string;
117
+ platformName?: string;
118
+ caps?: Capabilities.Capabilities;
119
+ product?: string;
120
+ }
121
+ export interface TestMeta {
122
+ uuid?: string;
123
+ startedAt?: string;
124
+ finishedAt?: string;
125
+ steps?: StepData[];
126
+ feature?: {
127
+ name: string;
128
+ path?: string;
129
+ description: string | null;
130
+ };
131
+ scenario?: {
132
+ name: string;
133
+ };
134
+ examples?: string[];
135
+ }
136
+ export interface TestData {
137
+ uuid?: string;
138
+ type?: string;
139
+ name?: string;
140
+ scope?: string;
141
+ scopes?: string[];
142
+ identifier?: string;
143
+ file_name?: string;
144
+ vc_filepath?: string;
145
+ location?: string;
146
+ started_at?: string;
147
+ finished_at?: string;
148
+ framework?: string;
149
+ body?: TestCodeBody;
150
+ result?: string;
151
+ failure?: Failure[];
152
+ failure_reason?: string;
153
+ failure_type?: string | null;
154
+ retries?: {
155
+ limit: number;
156
+ attempts: number;
157
+ };
158
+ duration_in_ms?: number;
159
+ integrations?: {
160
+ [index: string]: IntegrationObject;
161
+ };
162
+ hook_type?: string;
163
+ hooks?: string[];
164
+ meta?: TestMeta;
165
+ tags?: string[];
166
+ }
167
+ export interface UserConfig {
168
+ buildName?: string;
169
+ projectName?: string;
170
+ buildTag?: string;
171
+ bstackServiceVersion?: string;
172
+ }
173
+ export interface UploadType {
174
+ event_type: string;
175
+ hook_run?: TestData;
176
+ test_run?: TestData;
177
+ logs?: any[];
178
+ }
179
+ export interface LaunchResponse {
180
+ jwt: string;
181
+ build_hashed_id: string;
182
+ allow_screenshots?: boolean;
183
+ }
184
+ interface IntegrationObject {
185
+ capabilities?: Capabilities.Capabilities;
186
+ session_id?: string;
187
+ browser?: string;
188
+ browser_version?: string;
189
+ platform?: string;
190
+ product?: string;
191
+ }
192
+ interface TestCodeBody {
193
+ lang: string;
194
+ code?: string | null;
195
+ }
196
+ interface StepData {
197
+ id?: string;
198
+ text?: string;
199
+ keyword?: string;
200
+ started_at?: string;
201
+ finished_at?: string;
202
+ result?: string;
203
+ duration?: number;
204
+ failure?: string;
205
+ }
206
+ interface Failure {
207
+ backtrace: string[];
208
+ }
209
+ export {};
90
210
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAExD,MAAM,WAAW,eAAe;IAE5B,kBAAkB,EAAE;QAEhB,WAAW,EAAE,MAAM,CAAA;KACtB,CAAA;CACJ;AAED,MAAM,MAAM,iBAAiB,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;AAE1F,MAAM,MAAM,SAAS,GAAG;IACpB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;CACxB,CAAA;AAED,MAAM,WAAW,iBAAiB;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,GAAG;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,kBAAkB;IAC/B;;;;;OAKG;IACH,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;;;;;OAWG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC,OAAO,oBAAoB,EAAE,OAAO,CAAC,CAAA;IACpD;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,CAChB,MAAM,EAAE,OAAO,CAAC,UAAU,EAC1B,YAAY,EAAE,YAAY,CAAC,gBAAgB,EAC3C,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,KACjB,MAAM,CAAA;IACX;;;OAGG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC;;;OAGG;IACH,oCAAoC,CAAC,EAAE,OAAO,CAAC;IAC/C;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAC7B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/build/util.d.ts CHANGED
@@ -1,5 +1,8 @@
1
1
  import type { Browser, MultiRemoteBrowser } from 'webdriverio';
2
- import type { Capabilities } from '@wdio/types';
2
+ import type { Capabilities, Frameworks, Options } from '@wdio/types';
3
+ import type { BeforeCommandArgs, AfterCommandArgs } from '@wdio/reporter';
4
+ import type { UserConfig, UploadType, BrowserstackConfig } from './types.js';
5
+ import type { ITestCaseHookParameter } from './cucumber-types.js';
3
6
  /**
4
7
  * get browser description for Browserstack service
5
8
  * @param cap browser capablities
@@ -18,4 +21,68 @@ export declare function getBrowserCapabilities(browser: Browser<'async'> | Multi
18
21
  */
19
22
  export declare function isBrowserstackCapability(cap?: Capabilities.Capabilities): boolean;
20
23
  export declare function getParentSuiteName(fullTitle: string, testSuiteTitle: string): string;
24
+ export declare function launchTestSession(options: BrowserstackConfig & Options.Testrunner, config: Options.Testrunner, bsConfig: UserConfig): Promise<void>;
25
+ export declare function stopBuildUpstream(): Promise<{
26
+ status: string;
27
+ message: any;
28
+ } | undefined>;
29
+ export declare function getCiInfo(): {
30
+ name: string;
31
+ build_url: string | undefined;
32
+ job_name: string | undefined;
33
+ build_number: string | undefined;
34
+ } | {
35
+ name: string;
36
+ build_url: null;
37
+ job_name: null;
38
+ build_number: null;
39
+ } | {
40
+ name: string;
41
+ build_url: string | undefined;
42
+ job_name: null;
43
+ build_number: string | undefined;
44
+ } | null;
45
+ export declare function getGitMetaData(): Promise<{
46
+ name: string;
47
+ sha: string;
48
+ short_sha: string;
49
+ branch: string;
50
+ tag: string | null;
51
+ committer: string;
52
+ committer_date: string;
53
+ author: string;
54
+ author_date: string;
55
+ commit_message: string;
56
+ root: string;
57
+ common_git_dir: string;
58
+ worktree_git_dir: string;
59
+ last_tag: string | null;
60
+ commits_since_last_tag: number;
61
+ remotes: {
62
+ name: string;
63
+ url: any;
64
+ }[];
65
+ } | undefined>;
66
+ export declare function getUniqueIdentifier(test: Frameworks.Test): string;
67
+ export declare function getUniqueIdentifierForCucumber(world: ITestCaseHookParameter): string;
68
+ export declare function getCloudProvider(browser: Browser<'async'> | MultiRemoteBrowser<'async'>): string;
69
+ export declare function isBrowserstackSession(browser?: Browser<'async'> | MultiRemoteBrowser<'async'>): boolean | undefined;
70
+ export declare function getScenarioExamples(world: ITestCaseHookParameter): string[] | undefined;
71
+ export declare function removeAnsiColors(message: string): string;
72
+ export declare function getLogTag(eventType: string): string;
73
+ export declare function uploadEventData(eventData: UploadType | Array<UploadType>, eventUrl?: string): Promise<{
74
+ status: string;
75
+ message: string;
76
+ } | undefined>;
77
+ export declare function getHierarchy(fullTitle?: string): string[];
78
+ export declare function getHookType(hookName: string): string;
79
+ export declare function isScreenshotCommand(args: BeforeCommandArgs & AfterCommandArgs): boolean | "" | undefined;
80
+ export declare function shouldAddServiceVersion(config: Options.Testrunner, testObservability?: boolean): boolean;
81
+ export declare function batchAndPostEvents(eventUrl: string, kind: string, data: UploadType[]): Promise<void>;
82
+ export declare function getObservabilityUser(options: BrowserstackConfig & Options.Testrunner, config: Options.Testrunner): string | undefined;
83
+ export declare function getObservabilityKey(options: BrowserstackConfig & Options.Testrunner, config: Options.Testrunner): string | undefined;
84
+ export declare function getObservabilityProject(options: BrowserstackConfig & Options.Testrunner, bstackProjectName?: string): string | undefined;
85
+ export declare function getObservabilityBuild(options: BrowserstackConfig & Options.Testrunner, bstackBuildName?: string): string;
86
+ export declare function getObservabilityBuildTags(options: BrowserstackConfig & Options.Testrunner, bstackBuildTag?: string): string[];
87
+ export declare const sleep: (ms?: number) => Promise<unknown>;
21
88
  //# sourceMappingURL=util.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAI/C;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,YAAY,CAAC,mBAAmB,UAa1E;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,kBAAkB,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,YAAY,CAAC,gBAAgB,EAAE,WAAW,CAAC,EAAE,MAAM,6BASzJ;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,CAAC,EAAE,YAAY,CAAC,YAAY,WAWvE;AAED,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,CAUpF"}
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"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"}
package/build/util.js CHANGED
@@ -1,4 +1,26 @@
1
- import { BROWSER_DESCRIPTION } from './constants.js';
1
+ import { hostname, platform, type, version, arch } from 'node:os';
2
+ import { promisify } from 'node:util';
3
+ import http from 'node:http';
4
+ import https from 'node:https';
5
+ import path from 'node:path';
6
+ import logger from '@wdio/logger';
7
+ import got, { HTTPError } from 'got';
8
+ import gitRepoInfo from 'git-repo-info';
9
+ import gitconfig from 'gitconfiglocal';
10
+ import { BROWSER_DESCRIPTION, DATA_ENDPOINT, DATA_EVENT_ENDPOINT, DATA_SCREENSHOT_ENDPOINT } from './constants.js';
11
+ import RequestQueueHandler from './request-handler.js';
12
+ const pGitconfig = promisify(gitconfig);
13
+ const log = logger('@wdio/browserstack-service');
14
+ const DEFAULT_REQUEST_CONFIG = {
15
+ agent: {
16
+ http: new http.Agent({ keepAlive: true }),
17
+ https: new https.Agent({ keepAlive: true }),
18
+ },
19
+ headers: {
20
+ 'Content-Type': 'application/json',
21
+ 'X-BSTACK-OBS': 'true'
22
+ },
23
+ };
2
24
  /**
3
25
  * get browser description for Browserstack service
4
26
  * @param cap browser capablities
@@ -54,3 +76,421 @@ export function getParentSuiteName(fullTitle, testSuiteTitle) {
54
76
  }
55
77
  return parentSuiteName.trim();
56
78
  }
79
+ export async function launchTestSession(options, config, bsConfig) {
80
+ const data = {
81
+ format: 'json',
82
+ project_name: getObservabilityProject(options, bsConfig.projectName),
83
+ name: getObservabilityBuild(options, bsConfig.buildName),
84
+ start_time: (new Date()).toISOString(),
85
+ tags: getObservabilityBuildTags(options, bsConfig.buildTag),
86
+ host_info: {
87
+ hostname: hostname(),
88
+ platform: platform(),
89
+ type: type(),
90
+ version: version(),
91
+ arch: arch()
92
+ },
93
+ ci_info: getCiInfo(),
94
+ build_run_identifier: process.env.BROWSERSTACK_BUILD_RUN_IDENTIFIER,
95
+ failed_tests_rerun: process.env.BROWSERSTACK_RERUN || false,
96
+ version_control: await getGitMetaData(),
97
+ observability_version: {
98
+ frameworkName: config.framework,
99
+ sdkVersion: bsConfig.bstackServiceVersion
100
+ }
101
+ };
102
+ try {
103
+ const url = `${DATA_ENDPOINT}/api/v1/builds`;
104
+ const response = await got.post(url, {
105
+ ...DEFAULT_REQUEST_CONFIG,
106
+ username: getObservabilityUser(options, config),
107
+ password: getObservabilityKey(options, config),
108
+ json: data
109
+ }).json();
110
+ log.debug(`[Start_Build] Success response: ${JSON.stringify(response)}`);
111
+ process.env.BS_TESTOPS_BUILD_COMPLETED = 'true';
112
+ if (response.jwt) {
113
+ process.env.BS_TESTOPS_JWT = response.jwt;
114
+ }
115
+ if (response.build_hashed_id) {
116
+ process.env.BS_TESTOPS_BUILD_HASHED_ID = response.build_hashed_id;
117
+ }
118
+ if (response.allow_screenshots) {
119
+ process.env.BS_TESTOPS_ALLOW_SCREENSHOTS = response.allow_screenshots.toString();
120
+ }
121
+ }
122
+ catch (error) {
123
+ if (error instanceof HTTPError && error.response && error.response.statusCode === 401) {
124
+ log.debug('Data upload to BrowserStack Test Observability failed either due to incorrect credentials or an unsupported SDK version or because you do not have access to the product.');
125
+ }
126
+ else {
127
+ log.debug(`[Start_Build] Failed. Error: ${error}`);
128
+ }
129
+ }
130
+ }
131
+ export async function stopBuildUpstream() {
132
+ if (!process.env.BS_TESTOPS_BUILD_COMPLETED) {
133
+ return;
134
+ }
135
+ if (!process.env.BS_TESTOPS_JWT) {
136
+ log.debug('[STOP_BUILD] Missing Authentication Token/ Build ID');
137
+ return {
138
+ status: 'error',
139
+ message: 'Token/buildID is undefined, build creation might have failed'
140
+ };
141
+ }
142
+ const data = {
143
+ 'stop_time': (new Date()).toISOString()
144
+ };
145
+ try {
146
+ const url = `${DATA_ENDPOINT}/api/v1/builds/${process.env.BS_TESTOPS_BUILD_HASHED_ID}/stop`;
147
+ const response = await got.put(url, {
148
+ agent: DEFAULT_REQUEST_CONFIG.agent,
149
+ headers: {
150
+ ...DEFAULT_REQUEST_CONFIG.headers,
151
+ 'Authorization': `Bearer ${process.env.BS_TESTOPS_JWT}`
152
+ },
153
+ json: data
154
+ }).json();
155
+ log.debug(`[STOP_BUILD] Success response: ${JSON.stringify(response)}`);
156
+ return {
157
+ status: 'success',
158
+ message: ''
159
+ };
160
+ }
161
+ catch (error) {
162
+ log.debug(`[STOP_BUILD] Failed. Error: ${error}`);
163
+ return {
164
+ status: 'error',
165
+ message: error.message
166
+ };
167
+ }
168
+ }
169
+ export function getCiInfo() {
170
+ const env = process.env;
171
+ // Jenkins
172
+ if ((typeof env.JENKINS_URL === 'string' && env.JENKINS_URL.length > 0) || (typeof env.JENKINS_HOME === 'string' && env.JENKINS_HOME.length > 0)) {
173
+ return {
174
+ name: 'Jenkins',
175
+ build_url: env.BUILD_URL,
176
+ job_name: env.JOB_NAME,
177
+ build_number: env.BUILD_NUMBER
178
+ };
179
+ }
180
+ // CircleCI
181
+ if (env.CI === 'true' && env.CIRCLECI === 'true') {
182
+ return {
183
+ name: 'CircleCI',
184
+ build_url: env.CIRCLE_BUILD_URL,
185
+ job_name: env.CIRCLE_JOB,
186
+ build_number: env.CIRCLE_BUILD_NUM
187
+ };
188
+ }
189
+ // Travis CI
190
+ if (env.CI === 'true' && env.TRAVIS === 'true') {
191
+ return {
192
+ name: 'Travis CI',
193
+ build_url: env.TRAVIS_BUILD_WEB_URL,
194
+ job_name: env.TRAVIS_JOB_NAME,
195
+ build_number: env.TRAVIS_BUILD_NUMBER
196
+ };
197
+ }
198
+ // Codeship
199
+ if (env.CI === 'true' && env.CI_NAME === 'codeship') {
200
+ return {
201
+ name: 'Codeship',
202
+ build_url: null,
203
+ job_name: null,
204
+ build_number: null
205
+ };
206
+ }
207
+ // Bitbucket
208
+ if (env.BITBUCKET_BRANCH && env.BITBUCKET_COMMIT) {
209
+ return {
210
+ name: 'Bitbucket',
211
+ build_url: env.BITBUCKET_GIT_HTTP_ORIGIN,
212
+ job_name: null,
213
+ build_number: env.BITBUCKET_BUILD_NUMBER
214
+ };
215
+ }
216
+ // Drone
217
+ if (env.CI === 'true' && env.DRONE === 'true') {
218
+ return {
219
+ name: 'Drone',
220
+ build_url: env.DRONE_BUILD_LINK,
221
+ job_name: null,
222
+ build_number: env.DRONE_BUILD_NUMBER
223
+ };
224
+ }
225
+ // Semaphore
226
+ if (env.CI === 'true' && env.SEMAPHORE === 'true') {
227
+ return {
228
+ name: 'Semaphore',
229
+ build_url: env.SEMAPHORE_ORGANIZATION_URL,
230
+ job_name: env.SEMAPHORE_JOB_NAME,
231
+ build_number: env.SEMAPHORE_JOB_ID
232
+ };
233
+ }
234
+ // GitLab
235
+ if (env.CI === 'true' && env.GITLAB_CI === 'true') {
236
+ return {
237
+ name: 'GitLab',
238
+ build_url: env.CI_JOB_URL,
239
+ job_name: env.CI_JOB_NAME,
240
+ build_number: env.CI_JOB_ID
241
+ };
242
+ }
243
+ // Buildkite
244
+ if (env.CI === 'true' && env.BUILDKITE === 'true') {
245
+ return {
246
+ name: 'Buildkite',
247
+ build_url: env.BUILDKITE_BUILD_URL,
248
+ job_name: env.BUILDKITE_LABEL || env.BUILDKITE_PIPELINE_NAME,
249
+ build_number: env.BUILDKITE_BUILD_NUMBER
250
+ };
251
+ }
252
+ // Visual Studio Team Services
253
+ if (env.TF_BUILD === 'True') {
254
+ return {
255
+ name: 'Visual Studio Team Services',
256
+ build_url: `${env.SYSTEM_TEAMFOUNDATIONSERVERURI}${env.SYSTEM_TEAMPROJECTID}`,
257
+ job_name: env.SYSTEM_DEFINITIONID,
258
+ build_number: env.BUILD_BUILDID
259
+ };
260
+ }
261
+ // if no matches, return null
262
+ return null;
263
+ }
264
+ export async function getGitMetaData() {
265
+ const info = gitRepoInfo();
266
+ if (!info.commonGitDir) {
267
+ return;
268
+ }
269
+ const { remote } = await pGitconfig(info.commonGitDir);
270
+ const remotes = Object.keys(remote).map(remoteName => ({ name: remoteName, url: remote[remoteName].url }));
271
+ return {
272
+ name: 'git',
273
+ sha: info.sha,
274
+ short_sha: info.abbreviatedSha,
275
+ branch: info.branch,
276
+ tag: info.tag,
277
+ committer: info.committer,
278
+ committer_date: info.committerDate,
279
+ author: info.author,
280
+ author_date: info.authorDate,
281
+ commit_message: info.commitMessage,
282
+ root: info.root,
283
+ common_git_dir: info.commonGitDir,
284
+ worktree_git_dir: info.worktreeGitDir,
285
+ last_tag: info.lastTag,
286
+ commits_since_last_tag: info.commitsSinceLastTag,
287
+ remotes: remotes
288
+ };
289
+ }
290
+ export function getUniqueIdentifier(test) {
291
+ return `${test.parent} - ${test.title}`;
292
+ }
293
+ export function getUniqueIdentifierForCucumber(world) {
294
+ return world.pickle.uri + '_' + world.pickle.astNodeIds.join(',');
295
+ }
296
+ export function getCloudProvider(browser) {
297
+ if (browser.options && browser.options.hostname && browser.options.hostname.includes('browserstack')) {
298
+ return 'browserstack';
299
+ }
300
+ return 'unknown_grid';
301
+ }
302
+ export function isBrowserstackSession(browser) {
303
+ return browser && getCloudProvider(browser).toLowerCase() === 'browserstack';
304
+ }
305
+ export function getScenarioExamples(world) {
306
+ const scenario = world.pickle;
307
+ // no examples present
308
+ if ((scenario.astNodeIds && scenario.astNodeIds.length <= 1) || scenario.astNodeIds === undefined) {
309
+ return;
310
+ }
311
+ const pickleId = scenario.astNodeIds[0];
312
+ const examplesId = scenario.astNodeIds[1];
313
+ const gherkinDocumentChildren = world.gherkinDocument.feature?.children;
314
+ let examples = [];
315
+ gherkinDocumentChildren?.forEach(child => {
316
+ if (child.rule) {
317
+ // handle if rule is present
318
+ child.rule.children.forEach(childLevel2 => {
319
+ if (childLevel2.scenario && childLevel2.scenario.id === pickleId && childLevel2.scenario.examples) {
320
+ const passedExamples = childLevel2.scenario.examples.flatMap((val) => (val.tableBody)).find((item) => item.id === examplesId)?.cells.map((val) => (val.value));
321
+ if (passedExamples) {
322
+ examples = passedExamples;
323
+ }
324
+ }
325
+ });
326
+ }
327
+ else if (child.scenario && child.scenario.id === pickleId && child.scenario.examples) {
328
+ // handle if scenario outside rule
329
+ const passedExamples = child.scenario.examples.flatMap((val) => (val.tableBody)).find((item) => item.id === examplesId)?.cells.map((val) => (val.value));
330
+ if (passedExamples) {
331
+ examples = passedExamples;
332
+ }
333
+ }
334
+ });
335
+ if (examples.length) {
336
+ return examples;
337
+ }
338
+ return;
339
+ }
340
+ export function removeAnsiColors(message) {
341
+ // https://stackoverflow.com/a/29497680
342
+ // eslint-disable-next-line no-control-regex
343
+ return message.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, '');
344
+ }
345
+ export function getLogTag(eventType) {
346
+ if (eventType === 'TestRunStarted' || eventType === 'TestRunFinished') {
347
+ return 'Test_Upload';
348
+ }
349
+ else if (eventType === 'HookRunStarted' || eventType === 'HookRunFinished') {
350
+ return 'Hook_Upload';
351
+ }
352
+ else if (eventType === 'ScreenshotCreated') {
353
+ return 'Screenshot_Upload';
354
+ }
355
+ else if (eventType === 'LogCreated') {
356
+ return 'Log_Upload';
357
+ }
358
+ return 'undefined';
359
+ }
360
+ export async function uploadEventData(eventData, eventUrl = DATA_EVENT_ENDPOINT) {
361
+ let logTag = 'BATCH_UPLOAD';
362
+ if (!Array.isArray(eventData)) {
363
+ logTag = getLogTag(eventData.event_type);
364
+ }
365
+ if (eventUrl === DATA_SCREENSHOT_ENDPOINT) {
366
+ logTag = 'screenshot_upload';
367
+ }
368
+ if (!process.env.BS_TESTOPS_BUILD_COMPLETED) {
369
+ return;
370
+ }
371
+ if (!process.env.BS_TESTOPS_JWT) {
372
+ log.debug(`[${logTag}] Missing Authentication Token/ Build ID`);
373
+ return {
374
+ status: 'error',
375
+ message: 'Token/buildID is undefined, build creation might have failed'
376
+ };
377
+ }
378
+ try {
379
+ const url = `${DATA_ENDPOINT}/${eventUrl}`;
380
+ RequestQueueHandler.getInstance().pendingUploads += 1;
381
+ const data = await got.post(url, {
382
+ agent: DEFAULT_REQUEST_CONFIG.agent,
383
+ headers: {
384
+ ...DEFAULT_REQUEST_CONFIG.headers,
385
+ 'Authorization': `Bearer ${process.env.BS_TESTOPS_JWT}`
386
+ },
387
+ json: eventData
388
+ }).json();
389
+ log.debug(`[${logTag}] Success response: ${JSON.stringify(data)}`);
390
+ RequestQueueHandler.getInstance().pendingUploads -= 1;
391
+ }
392
+ catch (error) {
393
+ log.debug(`[${logTag}] Failed. Error: ${error}`);
394
+ RequestQueueHandler.getInstance().pendingUploads -= 1;
395
+ }
396
+ }
397
+ // get hierarchy for a particular test (called by reporter for skipped tests)
398
+ export function getHierarchy(fullTitle) {
399
+ if (!fullTitle) {
400
+ return [];
401
+ }
402
+ return fullTitle.split('.').slice(0, -1);
403
+ }
404
+ export function getHookType(hookName) {
405
+ if (hookName.includes('before each')) {
406
+ return 'BEFORE_EACH';
407
+ }
408
+ else if (hookName.includes('before all')) {
409
+ return 'BEFORE_ALL';
410
+ }
411
+ else if (hookName.includes('after each')) {
412
+ return 'AFTER_EACH';
413
+ }
414
+ else if (hookName.includes('after all')) {
415
+ return 'AFTER_ALL';
416
+ }
417
+ return 'unknown';
418
+ }
419
+ export function isScreenshotCommand(args) {
420
+ return args.endpoint && args.endpoint.includes('/screenshot');
421
+ }
422
+ export function shouldAddServiceVersion(config, testObservability) {
423
+ if (config.services && config.services.toString().includes('chromedriver') && testObservability !== false) {
424
+ return false;
425
+ }
426
+ return true;
427
+ }
428
+ export async function batchAndPostEvents(eventUrl, kind, data) {
429
+ if (!process.env.BS_TESTOPS_BUILD_COMPLETED || !process.env.BS_TESTOPS_JWT) {
430
+ return;
431
+ }
432
+ try {
433
+ const url = `${DATA_ENDPOINT}/${eventUrl}`;
434
+ const response = await got.post(url, {
435
+ agent: DEFAULT_REQUEST_CONFIG.agent,
436
+ headers: {
437
+ ...DEFAULT_REQUEST_CONFIG.headers,
438
+ 'Authorization': `Bearer ${process.env.BS_TESTOPS_JWT}`
439
+ },
440
+ json: data
441
+ }).json();
442
+ log.debug(`[${kind}] Success response: ${JSON.stringify(response)}`);
443
+ }
444
+ catch (error) {
445
+ log.debug(`[${kind}] EXCEPTION IN ${kind} REQUEST TO TEST OBSERVABILITY : ${error}`);
446
+ }
447
+ }
448
+ export function getObservabilityUser(options, config) {
449
+ if (process.env.BROWSERSTACK_USERNAME) {
450
+ return process.env.BROWSERSTACK_USERNAME;
451
+ }
452
+ if (options.testObservabilityOptions && options.testObservabilityOptions.user) {
453
+ return options.testObservabilityOptions.user;
454
+ }
455
+ return config.user;
456
+ }
457
+ export function getObservabilityKey(options, config) {
458
+ if (process.env.BROWSERSTACK_ACCESS_KEY) {
459
+ return process.env.BROWSERSTACK_ACCESS_KEY;
460
+ }
461
+ if (options.testObservabilityOptions && options.testObservabilityOptions.key) {
462
+ return options.testObservabilityOptions.key;
463
+ }
464
+ return config.key;
465
+ }
466
+ export function getObservabilityProject(options, bstackProjectName) {
467
+ if (process.env.TEST_OBSERVABILITY_PROJECT_NAME) {
468
+ return process.env.TEST_OBSERVABILITY_PROJECT_NAME;
469
+ }
470
+ if (options.testObservabilityOptions && options.testObservabilityOptions.projectName) {
471
+ return options.testObservabilityOptions.projectName;
472
+ }
473
+ return bstackProjectName;
474
+ }
475
+ export function getObservabilityBuild(options, bstackBuildName) {
476
+ if (process.env.TEST_OBSERVABILITY_BUILD_NAME) {
477
+ return process.env.TEST_OBSERVABILITY_BUILD_NAME;
478
+ }
479
+ if (options.testObservabilityOptions && options.testObservabilityOptions.buildName) {
480
+ return options.testObservabilityOptions.buildName;
481
+ }
482
+ return bstackBuildName || path.basename(path.resolve(process.cwd()));
483
+ }
484
+ export function getObservabilityBuildTags(options, bstackBuildTag) {
485
+ if (process.env.TEST_OBSERVABILITY_BUILD_TAG) {
486
+ return process.env.TEST_OBSERVABILITY_BUILD_TAG.split(',');
487
+ }
488
+ if (options.testObservabilityOptions && options.testObservabilityOptions.buildTag) {
489
+ return options.testObservabilityOptions.buildTag;
490
+ }
491
+ if (bstackBuildTag) {
492
+ return [bstackBuildTag];
493
+ }
494
+ return [];
495
+ }
496
+ export const sleep = (ms = 100) => new Promise((resolve) => setTimeout(resolve, ms));