@wdio/browserstack-service 8.0.14 → 8.1.1

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.
@@ -1,5 +1,14 @@
1
- import type { BrowserstackConfig } from './types';
1
+ import type { BrowserstackConfig } from './types.js';
2
2
  export declare const BROWSER_DESCRIPTION: readonly ["device", "os", "osVersion", "os_version", "browserName", "browser", "browserVersion", "browser_version"];
3
3
  export declare const VALID_APP_EXTENSION: string[];
4
4
  export declare const DEFAULT_OPTIONS: Partial<BrowserstackConfig>;
5
+ export declare const DATA_ENDPOINT = "https://collector-observability.browserstack.com";
6
+ export declare const DATA_EVENT_ENDPOINT = "api/v1/event";
7
+ export declare const DATA_BATCH_ENDPOINT = "api/v1/batch";
8
+ export declare const DATA_SCREENSHOT_ENDPOINT = "api/v1/screenshots";
9
+ export declare const DATA_BATCH_SIZE = 1000;
10
+ export declare const DATA_BATCH_INTERVAL = 2000;
11
+ export declare const BATCH_EVENT_TYPES: string[];
12
+ export declare const DEFAULT_WAIT_TIMEOUT_FOR_PENDING_UPLOADS = 5000;
13
+ export declare const DEFAULT_WAIT_INTERVAL_FOR_PENDING_UPLOADS = 100;
5
14
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAEjD,eAAO,MAAM,mBAAmB,qHAStB,CAAA;AAEV,eAAO,MAAM,mBAAmB,UAI/B,CAAA;AAED,eAAO,MAAM,eAAe,EAAE,OAAO,CAAC,kBAAkB,CAGvD,CAAA"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAEpD,eAAO,MAAM,mBAAmB,qHAStB,CAAA;AAEV,eAAO,MAAM,mBAAmB,UAI/B,CAAA;AAED,eAAO,MAAM,eAAe,EAAE,OAAO,CAAC,kBAAkB,CAIvD,CAAA;AAED,eAAO,MAAM,aAAa,qDAAqD,CAAA;AAC/E,eAAO,MAAM,mBAAmB,iBAAiB,CAAA;AACjD,eAAO,MAAM,mBAAmB,iBAAiB,CAAA;AACjD,eAAO,MAAM,wBAAwB,uBAAuB,CAAA;AAC5D,eAAO,MAAM,eAAe,OAAO,CAAA;AACnC,eAAO,MAAM,mBAAmB,OAAO,CAAA;AACvC,eAAO,MAAM,iBAAiB,UAAgH,CAAA;AAC9I,eAAO,MAAM,wCAAwC,OAAO,CAAA;AAC5D,eAAO,MAAM,yCAAyC,MAAM,CAAA"}
@@ -15,5 +15,15 @@ export const VALID_APP_EXTENSION = [
15
15
  ];
16
16
  export const DEFAULT_OPTIONS = {
17
17
  setSessionName: true,
18
- setSessionStatus: true
18
+ setSessionStatus: true,
19
+ testObservability: true
19
20
  };
21
+ export const DATA_ENDPOINT = 'https://collector-observability.browserstack.com';
22
+ export const DATA_EVENT_ENDPOINT = 'api/v1/event';
23
+ export const DATA_BATCH_ENDPOINT = 'api/v1/batch';
24
+ export const DATA_SCREENSHOT_ENDPOINT = 'api/v1/screenshots';
25
+ export const DATA_BATCH_SIZE = 1000;
26
+ export const DATA_BATCH_INTERVAL = 2000;
27
+ export const BATCH_EVENT_TYPES = ['LogCreated', 'TestRunStarted', 'TestRunFinished', 'HookRunFinished', 'HookRunStarted', 'ScreenshotCreated'];
28
+ export const DEFAULT_WAIT_TIMEOUT_FOR_PENDING_UPLOADS = 5000; // 5s
29
+ export const DEFAULT_WAIT_INTERVAL_FOR_PENDING_UPLOADS = 100; // 100ms
@@ -0,0 +1,177 @@
1
+ export interface ITestCaseHookParameter {
2
+ gherkinDocument: GherkinDocument;
3
+ pickle: Pickle;
4
+ result?: TestStepResult;
5
+ willBeRetried?: boolean;
6
+ testCaseStartedId: string;
7
+ }
8
+ export declare class Duration {
9
+ seconds: number;
10
+ nanos: number;
11
+ }
12
+ export declare class GherkinDocument {
13
+ uri?: string;
14
+ feature?: Feature;
15
+ comments: readonly Comment[];
16
+ }
17
+ export declare class Background {
18
+ location: Location;
19
+ keyword: string;
20
+ name: string;
21
+ description: string;
22
+ steps: readonly Step[];
23
+ id: string;
24
+ }
25
+ export declare class DataTable {
26
+ location: Location;
27
+ rows: readonly TableRow[];
28
+ }
29
+ export declare class DocString {
30
+ location: Location;
31
+ mediaType?: string;
32
+ content: string;
33
+ delimiter: string;
34
+ }
35
+ export declare class Examples {
36
+ location: Location;
37
+ tags: readonly Tag[];
38
+ keyword: string;
39
+ name: string;
40
+ description: string;
41
+ tableHeader?: TableRow;
42
+ tableBody: readonly TableRow[];
43
+ id: string;
44
+ }
45
+ export declare class Feature {
46
+ location: Location;
47
+ tags: readonly Tag[];
48
+ language: string;
49
+ keyword: string;
50
+ name: string;
51
+ description: string;
52
+ children: readonly FeatureChild[];
53
+ }
54
+ export declare class FeatureChild {
55
+ rule?: Rule;
56
+ background?: Background;
57
+ scenario?: Scenario;
58
+ }
59
+ export declare class Rule {
60
+ location: Location;
61
+ tags: readonly Tag[];
62
+ keyword: string;
63
+ name: string;
64
+ description: string;
65
+ children: readonly RuleChild[];
66
+ id: string;
67
+ }
68
+ export declare class RuleChild {
69
+ background?: Background;
70
+ scenario?: Scenario;
71
+ }
72
+ export declare class Scenario {
73
+ location: Location;
74
+ tags: readonly Tag[];
75
+ keyword: string;
76
+ name: string;
77
+ description: string;
78
+ steps: readonly Step[];
79
+ examples: readonly Examples[];
80
+ id: string;
81
+ }
82
+ export declare class Step {
83
+ location: Location;
84
+ keyword: string;
85
+ keywordType?: StepKeywordType;
86
+ text: string;
87
+ docString?: DocString;
88
+ dataTable?: DataTable;
89
+ id: string;
90
+ }
91
+ export declare class TableCell {
92
+ location: Location;
93
+ value: string;
94
+ }
95
+ export declare class TableRow {
96
+ location: Location;
97
+ cells: readonly TableCell[];
98
+ id: string;
99
+ }
100
+ export declare class Tag {
101
+ location: Location;
102
+ name: string;
103
+ id: string;
104
+ }
105
+ export declare class Pickle {
106
+ id: string;
107
+ uri: string;
108
+ name: string;
109
+ language: string;
110
+ steps: readonly PickleStep[];
111
+ tags: readonly PickleTag[];
112
+ astNodeIds: readonly string[];
113
+ }
114
+ export declare class PickleDocString {
115
+ mediaType?: string;
116
+ content: string;
117
+ }
118
+ export declare class PickleStep {
119
+ argument?: PickleStepArgument;
120
+ astNodeIds: readonly string[];
121
+ id: string;
122
+ type?: PickleStepType;
123
+ text: string;
124
+ }
125
+ export declare class PickleStepArgument {
126
+ docString?: PickleDocString;
127
+ dataTable?: PickleTable;
128
+ }
129
+ export declare class PickleTable {
130
+ rows: readonly PickleTableRow[];
131
+ }
132
+ export declare class PickleTableCell {
133
+ value: string;
134
+ }
135
+ export declare class PickleTableRow {
136
+ cells: readonly PickleTableCell[];
137
+ }
138
+ export declare class PickleTag {
139
+ name: string;
140
+ astNodeId: string;
141
+ }
142
+ export declare class TestStepResult {
143
+ duration: Duration;
144
+ message?: string;
145
+ status: TestStepResultStatus;
146
+ }
147
+ export declare enum PickleStepType {
148
+ UNKNOWN = "Unknown",
149
+ CONTEXT = "Context",
150
+ ACTION = "Action",
151
+ OUTCOME = "Outcome"
152
+ }
153
+ export declare enum StepKeywordType {
154
+ UNKNOWN = "Unknown",
155
+ CONTEXT = "Context",
156
+ ACTION = "Action",
157
+ OUTCOME = "Outcome",
158
+ CONJUNCTION = "Conjunction"
159
+ }
160
+ export declare enum TestStepResultStatus {
161
+ UNKNOWN = "UNKNOWN",
162
+ PASSED = "PASSED",
163
+ SKIPPED = "SKIPPED",
164
+ PENDING = "PENDING",
165
+ UNDEFINED = "UNDEFINED",
166
+ AMBIGUOUS = "AMBIGUOUS",
167
+ FAILED = "FAILED"
168
+ }
169
+ export declare class Location {
170
+ line: number;
171
+ column?: number;
172
+ }
173
+ export declare class Comment {
174
+ location: Location;
175
+ text: string;
176
+ }
177
+ //# sourceMappingURL=cucumber-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cucumber-types.d.ts","sourceRoot":"","sources":["../src/cucumber-types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ // mimic types from @cucumber/@cucumber such that users don't install that dependency when not needed
2
+ export {};
package/build/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import BrowserstackLauncher from './launcher.js';
2
2
  import BrowserstackService from './service.js';
3
- import type { BrowserstackConfig } from './types';
3
+ import type { BrowserstackConfig } from './types.js';
4
4
  export default BrowserstackService;
5
5
  export declare const launcher: typeof BrowserstackLauncher;
6
6
  export * from './types.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,MAAM,eAAe,CAAA;AAChD,OAAO,mBAAmB,MAAM,cAAc,CAAA;AAC9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAEjD,eAAe,mBAAmB,CAAA;AAClC,eAAO,MAAM,QAAQ,6BAAuB,CAAA;AAC5C,cAAc,YAAY,CAAA;AAE1B,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,WAAW,CAAC;QAClB,UAAU,aAAc,SAAQ,kBAAkB;SAAG;KACxD;CACJ"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,MAAM,eAAe,CAAA;AAChD,OAAO,mBAAmB,MAAM,cAAc,CAAA;AAC9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAEpD,eAAe,mBAAmB,CAAA;AAClC,eAAO,MAAM,QAAQ,6BAAuB,CAAA;AAC5C,cAAc,YAAY,CAAA;AAE1B,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,WAAW,CAAC;QAClB,UAAU,aAAc,SAAQ,kBAAkB;SAAG;KACxD;CACJ"}
@@ -0,0 +1,40 @@
1
+ import type { Capabilities, Frameworks } from '@wdio/types';
2
+ import type { Browser, MultiRemoteBrowser } from 'webdriverio';
3
+ import type { BeforeCommandArgs, AfterCommandArgs } from '@wdio/reporter';
4
+ import type { Pickle, ITestCaseHookParameter } from './cucumber-types.js';
5
+ export default class InsightsHandler {
6
+ private _browser;
7
+ private _framework?;
8
+ private _tests;
9
+ private _hooks;
10
+ private _platformMeta;
11
+ private _commands;
12
+ private _gitConfigPath?;
13
+ private _requestQueueHandler;
14
+ constructor(_browser: Browser<'async'> | MultiRemoteBrowser<'async'>, browserCaps?: Capabilities.Capabilities, isAppAutomate?: boolean, sessionId?: string, _framework?: string | undefined);
15
+ before(): Promise<void>;
16
+ beforeHook(test: Frameworks.Test, context: any): Promise<void>;
17
+ afterHook(test: Frameworks.Test, result: Frameworks.TestResult): Promise<void>;
18
+ beforeTest(test: Frameworks.Test): Promise<void>;
19
+ afterTest(test: Frameworks.Test, result: Frameworks.TestResult): Promise<void>;
20
+ /**
21
+ * Cucumber Only
22
+ */
23
+ beforeScenario(world: ITestCaseHookParameter): Promise<void>;
24
+ afterScenario(world: ITestCaseHookParameter): Promise<void>;
25
+ beforeStep(step: Frameworks.PickleStep, scenario: Pickle): Promise<void>;
26
+ afterStep(step: Frameworks.PickleStep, scenario: Pickle, result: Frameworks.PickleResult): Promise<void>;
27
+ uploadPending(waitTimeout?: number, waitInterval?: number): Promise<unknown>;
28
+ teardown(): Promise<void>;
29
+ /**
30
+ * misc methods
31
+ */
32
+ browserCommand(commandType: string, args: BeforeCommandArgs & AfterCommandArgs, test?: Frameworks.Test | ITestCaseHookParameter): Promise<void>;
33
+ private attachHookData;
34
+ private getHierarchy;
35
+ private sendTestRunEvent;
36
+ private sendTestRunEventForCucumber;
37
+ private getIntegrationsObject;
38
+ private getIdentifier;
39
+ }
40
+ //# sourceMappingURL=insights-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"insights-handler.d.ts","sourceRoot":"","sources":["../src/insights-handler.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAC3D,OAAO,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAC9D,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAGzE,OAAO,KAAK,EAAE,MAAM,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAOzE,MAAM,CAAC,OAAO,OAAO,eAAe;IASnB,OAAO,CAAC,QAAQ;IAAwI,OAAO,CAAC,UAAU,CAAC;IAPxL,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,aAAa,CAAc;IACnC,OAAO,CAAC,SAAS,CAA2D;IAC5E,OAAO,CAAC,cAAc,CAAC,CAAQ;IAC/B,OAAO,CAAC,oBAAoB,CAAoC;gBAE3C,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,kBAAkB,CAAC,OAAO,CAAC,EAAE,WAAW,CAAC,EAAE,YAAY,CAAC,YAAY,EAAE,aAAa,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,MAAM,EAAU,UAAU,CAAC,oBAAQ;IAa1L,MAAM;IAkBN,UAAU,CAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG;IAa/C,SAAS,CAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,UAAU;IAc/D,UAAU,CAAE,IAAI,EAAE,UAAU,CAAC,IAAI;IASjC,SAAS,CAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,UAAU;IASrE;;QAEI;IAEE,cAAc,CAAE,KAAK,EAAE,sBAAsB;IA4B7C,aAAa,CAAE,KAAK,EAAE,sBAAsB;IAI5C,UAAU,CAAE,IAAI,EAAE,UAAU,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM;IAkBzD,SAAS,CAAE,IAAI,EAAE,UAAU,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,YAAY;IA0BzF,aAAa,CACf,WAAW,SAA2C,EACtD,YAAY,SAA4C,GACzD,OAAO,CAAC,OAAO,CAAC;IASb,QAAQ;IAId;;OAEG;IACG,cAAc,CAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,gBAAgB,EAAE,IAAI,CAAC,EAAE,UAAU,CAAC,IAAI,GAAG,sBAAsB;IAoDtI,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,YAAY;YAYN,gBAAgB;YAsEhB,2BAA2B;IAmFzC,OAAO,CAAC,qBAAqB;IAW7B,OAAO,CAAC,aAAa;CAMxB"}
@@ -0,0 +1,389 @@
1
+ import path from 'node:path';
2
+ import { v4 as uuidv4 } from 'uuid';
3
+ import { getCloudProvider, getGitMetaData, getHookType, getScenarioExamples, getUniqueIdentifier, getUniqueIdentifierForCucumber, isBrowserstackSession, isScreenshotCommand, removeAnsiColors, sleep, uploadEventData } from './util.js';
4
+ import RequestQueueHandler from './request-handler.js';
5
+ import { DATA_SCREENSHOT_ENDPOINT, DEFAULT_WAIT_INTERVAL_FOR_PENDING_UPLOADS, DEFAULT_WAIT_TIMEOUT_FOR_PENDING_UPLOADS } from './constants.js';
6
+ export default class InsightsHandler {
7
+ _browser;
8
+ _framework;
9
+ _tests = {};
10
+ _hooks = {};
11
+ _platformMeta;
12
+ _commands = {};
13
+ _gitConfigPath;
14
+ _requestQueueHandler = RequestQueueHandler.getInstance();
15
+ constructor(_browser, browserCaps, isAppAutomate, sessionId, _framework) {
16
+ this._browser = _browser;
17
+ this._framework = _framework;
18
+ this._requestQueueHandler.start();
19
+ this._platformMeta = {
20
+ browserName: browserCaps?.browserName,
21
+ browserVersion: browserCaps?.browserVersion,
22
+ platformName: browserCaps?.platformName,
23
+ caps: browserCaps,
24
+ sessionId: sessionId,
25
+ product: isAppAutomate ? 'app-automate' : 'automate'
26
+ };
27
+ }
28
+ async before() {
29
+ if (isBrowserstackSession(this._browser)) {
30
+ // await this._browser.execute(`browserstack_executor: {"action": "annotate", "arguments": {"data": "ObservabilitySync:${Date.now()}","level": "debug"}}`)
31
+ await this._browser.execute(`browserstack_executor: ${JSON.stringify({
32
+ action: 'annotate',
33
+ arguments: {
34
+ data: `ObservabilitySync:${Date.now()}`,
35
+ level: 'debug'
36
+ }
37
+ })}`);
38
+ }
39
+ const gitMeta = await getGitMetaData();
40
+ if (gitMeta) {
41
+ this._gitConfigPath = gitMeta.root;
42
+ }
43
+ }
44
+ async beforeHook(test, context) {
45
+ const fullTitle = `${test.parent} - ${test.title}`;
46
+ const hookId = uuidv4();
47
+ this._tests[fullTitle] = {
48
+ uuid: hookId,
49
+ startedAt: (new Date()).toISOString()
50
+ };
51
+ this.attachHookData(context, hookId);
52
+ if (this._framework === 'mocha') {
53
+ await this.sendTestRunEvent(test, 'HookRunStarted');
54
+ }
55
+ }
56
+ async afterHook(test, result) {
57
+ const fullTitle = getUniqueIdentifier(test);
58
+ if (this._tests[fullTitle]) {
59
+ this._tests[fullTitle].finishedAt = (new Date()).toISOString();
60
+ }
61
+ else {
62
+ this._tests[fullTitle] = {
63
+ finishedAt: (new Date()).toISOString()
64
+ };
65
+ }
66
+ if (this._framework === 'mocha') {
67
+ await this.sendTestRunEvent(test, 'HookRunFinished', result);
68
+ }
69
+ }
70
+ async beforeTest(test) {
71
+ const fullTitle = getUniqueIdentifier(test);
72
+ this._tests[fullTitle] = {
73
+ uuid: uuidv4(),
74
+ startedAt: (new Date()).toISOString()
75
+ };
76
+ await this.sendTestRunEvent(test, 'TestRunStarted');
77
+ }
78
+ async afterTest(test, result) {
79
+ const fullTitle = getUniqueIdentifier(test);
80
+ this._tests[fullTitle] = {
81
+ ...(this._tests[fullTitle] || {}),
82
+ finishedAt: (new Date()).toISOString()
83
+ };
84
+ await this.sendTestRunEvent(test, 'TestRunFinished', result);
85
+ }
86
+ /**
87
+ * Cucumber Only
88
+ */
89
+ async beforeScenario(world) {
90
+ const pickleData = world.pickle;
91
+ const gherkinDocument = world.gherkinDocument;
92
+ const featureData = gherkinDocument.feature;
93
+ const uniqueId = getUniqueIdentifierForCucumber(world);
94
+ const testMetaData = {
95
+ uuid: uuidv4(),
96
+ startedAt: (new Date()).toISOString()
97
+ };
98
+ if (pickleData) {
99
+ testMetaData.scenario = {
100
+ name: pickleData.name,
101
+ };
102
+ }
103
+ if (gherkinDocument && featureData) {
104
+ testMetaData.feature = {
105
+ path: gherkinDocument.uri,
106
+ name: featureData.name,
107
+ description: featureData.description,
108
+ };
109
+ }
110
+ this._tests[uniqueId] = testMetaData;
111
+ await this.sendTestRunEventForCucumber(world, 'TestRunStarted');
112
+ }
113
+ async afterScenario(world) {
114
+ await this.sendTestRunEventForCucumber(world, 'TestRunFinished');
115
+ }
116
+ async beforeStep(step, scenario) {
117
+ const uniqueId = getUniqueIdentifierForCucumber({ pickle: scenario });
118
+ const testMetaData = this._tests[uniqueId] || { steps: [] };
119
+ if (testMetaData && !testMetaData.steps) {
120
+ testMetaData.steps = [];
121
+ }
122
+ testMetaData.steps?.push({
123
+ id: step.id,
124
+ text: step.text,
125
+ keyword: step.keyword,
126
+ started_at: (new Date()).toISOString()
127
+ });
128
+ this._tests[uniqueId] = testMetaData;
129
+ }
130
+ async afterStep(step, scenario, result) {
131
+ const uniqueId = getUniqueIdentifierForCucumber({ pickle: scenario });
132
+ const testMetaData = this._tests[uniqueId] || { steps: [] };
133
+ if (!testMetaData.steps) {
134
+ testMetaData.steps = [{
135
+ id: step.id,
136
+ text: step.text,
137
+ keyword: step.keyword,
138
+ finished_at: (new Date()).toISOString(),
139
+ result: result.passed ? 'PASSED' : 'FAILED',
140
+ duration: result.duration,
141
+ failure: result.error ? removeAnsiColors(result.error) : result.error
142
+ }];
143
+ }
144
+ const stepDetails = testMetaData.steps?.find(item => item.id === step.id);
145
+ if (stepDetails) {
146
+ stepDetails.finished_at = (new Date()).toISOString();
147
+ stepDetails.result = result.passed ? 'PASSED' : 'FAILED';
148
+ stepDetails.duration = result.duration;
149
+ stepDetails.failure = result.error ? removeAnsiColors(result.error) : result.error;
150
+ }
151
+ this._tests[uniqueId] = testMetaData;
152
+ }
153
+ async uploadPending(waitTimeout = DEFAULT_WAIT_TIMEOUT_FOR_PENDING_UPLOADS, waitInterval = DEFAULT_WAIT_INTERVAL_FOR_PENDING_UPLOADS) {
154
+ if (this._requestQueueHandler.pendingUploads <= 0 || waitTimeout <= 0) {
155
+ return;
156
+ }
157
+ await sleep(waitInterval);
158
+ return this.uploadPending(waitTimeout - waitInterval);
159
+ }
160
+ async teardown() {
161
+ await this._requestQueueHandler.shutdown();
162
+ }
163
+ /**
164
+ * misc methods
165
+ */
166
+ async browserCommand(commandType, args, test) {
167
+ const dataKey = `${args.sessionId}_${args.method}_${args.endpoint}`;
168
+ if (commandType === 'client:beforeCommand') {
169
+ this._commands[dataKey] = args;
170
+ return;
171
+ }
172
+ if (!test) {
173
+ return;
174
+ }
175
+ const identifier = this.getIdentifier(test);
176
+ // log screenshot
177
+ if (Boolean(process.env.BS_TESTOPS_ALLOW_SCREENSHOTS) && isScreenshotCommand(args) && args.result.value) {
178
+ await uploadEventData([{
179
+ event_type: 'LogCreated',
180
+ logs: [{
181
+ test_run_uuid: this._tests[identifier].uuid,
182
+ timestamp: new Date().toISOString(),
183
+ message: args.result.value,
184
+ kind: 'TEST_SCREENSHOT'
185
+ }]
186
+ }], DATA_SCREENSHOT_ENDPOINT);
187
+ }
188
+ const requestData = this._commands[dataKey];
189
+ // log http request
190
+ const req = this._requestQueueHandler.add({
191
+ event_type: 'LogCreated',
192
+ logs: [{
193
+ test_run_uuid: this._tests[identifier].uuid,
194
+ timestamp: new Date().toISOString(),
195
+ kind: 'HTTP',
196
+ http_response: {
197
+ path: requestData.endpoint,
198
+ method: requestData.method,
199
+ body: requestData.body,
200
+ response: args.result
201
+ }
202
+ }]
203
+ });
204
+ if (req.proceed && req.data) {
205
+ await uploadEventData(req.data, req.url);
206
+ }
207
+ }
208
+ /*
209
+ * private methods
210
+ */
211
+ attachHookData(context, hookId) {
212
+ if (!context.currentTest || !context.currentTest.parent) {
213
+ return;
214
+ }
215
+ const parentTest = `${context.currentTest.parent.title} - ${context.currentTest.title}`;
216
+ if (!this._hooks[parentTest]) {
217
+ this._hooks[parentTest] = [];
218
+ }
219
+ this._hooks[parentTest].push(hookId);
220
+ }
221
+ /*
222
+ * Get hierarchy info
223
+ */
224
+ getHierarchy(test) {
225
+ const value = [];
226
+ if (test.ctx && test.ctx.test) {
227
+ let parent = test.ctx.test.parent;
228
+ while (parent && parent.title !== '') {
229
+ value.push(parent.title);
230
+ parent = parent.parent;
231
+ }
232
+ }
233
+ return value.reverse();
234
+ }
235
+ async sendTestRunEvent(test, eventType, results) {
236
+ const fullTitle = getUniqueIdentifier(test);
237
+ const testMetaData = this._tests[fullTitle];
238
+ const testData = {
239
+ uuid: testMetaData.uuid,
240
+ type: test.type,
241
+ name: test.title,
242
+ body: {
243
+ lang: 'webdriverio',
244
+ code: test.body
245
+ },
246
+ scope: fullTitle,
247
+ scopes: this.getHierarchy(test),
248
+ identifier: fullTitle,
249
+ file_name: test.file,
250
+ location: test.file,
251
+ vc_filepath: (this._gitConfigPath && test.file) ? path.relative(this._gitConfigPath, test.file) : undefined,
252
+ started_at: testMetaData.startedAt,
253
+ finished_at: testMetaData.finishedAt,
254
+ result: 'pending',
255
+ framework: this._framework
256
+ };
257
+ if ((eventType === 'TestRunFinished' || eventType === 'HookRunFinished') && results) {
258
+ const { error, passed } = results;
259
+ if (!passed) {
260
+ testData.result = (error && error.message && error.message.includes('sync skip; aborting execution')) ? 'ignore' : 'failed';
261
+ if (error && testData.result !== 'skipped') {
262
+ testData.failure = [{ backtrace: [removeAnsiColors(error.message)] }]; // add all errors here
263
+ testData.failure_reason = removeAnsiColors(error.message);
264
+ testData.failure_type = error.message === null ? null : error.message.toString().match(/AssertionError/) ? 'AssertionError' : 'UnhandledError'; //verify if this is working
265
+ }
266
+ }
267
+ else {
268
+ testData.result = 'passed';
269
+ }
270
+ testData.retries = results.retries;
271
+ testData.duration_in_ms = results.duration;
272
+ if (this._hooks[fullTitle]) {
273
+ testData.hooks = this._hooks[fullTitle];
274
+ }
275
+ }
276
+ if (eventType === 'TestRunStarted') {
277
+ testData.integrations = {};
278
+ if (this._browser && this._platformMeta) {
279
+ const provider = getCloudProvider(this._browser);
280
+ testData.integrations[provider] = this.getIntegrationsObject();
281
+ }
282
+ }
283
+ const uploadData = {
284
+ event_type: eventType,
285
+ };
286
+ /* istanbul ignore if */
287
+ if (eventType.match(/HookRun/)) {
288
+ testData.hook_type = testData.name?.toLowerCase() ? getHookType(testData.name.toLowerCase()) : 'undefined';
289
+ uploadData.hook_run = testData;
290
+ }
291
+ else {
292
+ uploadData.test_run = testData;
293
+ }
294
+ const req = this._requestQueueHandler.add(uploadData);
295
+ if (req.proceed && req.data) {
296
+ await uploadEventData(req.data, req.url);
297
+ }
298
+ }
299
+ async sendTestRunEventForCucumber(world, eventType) {
300
+ const uniqueId = getUniqueIdentifierForCucumber(world);
301
+ const { feature, scenario, steps, uuid, startedAt, finishedAt } = this._tests[uniqueId] || {};
302
+ const examples = getScenarioExamples(world);
303
+ const fullNameWithExamples = examples
304
+ ? world.pickle.name + ' (' + examples.join(', ') + ')'
305
+ : world.pickle.name;
306
+ const testData = {
307
+ uuid: uuid,
308
+ started_at: startedAt,
309
+ finished_at: finishedAt,
310
+ type: 'test',
311
+ body: {
312
+ lang: 'webdriverio',
313
+ code: null
314
+ },
315
+ name: fullNameWithExamples,
316
+ scope: fullNameWithExamples,
317
+ scopes: [feature?.name || ''],
318
+ identifier: scenario?.name,
319
+ file_name: feature?.path,
320
+ vc_filepath: (this._gitConfigPath && feature?.path) ? path.relative(this._gitConfigPath, feature?.path) : undefined,
321
+ location: feature?.path,
322
+ framework: this._framework,
323
+ result: 'pending',
324
+ meta: {
325
+ feature: feature,
326
+ scenario: scenario,
327
+ steps: steps,
328
+ examples: examples
329
+ }
330
+ };
331
+ if (eventType === 'TestRunStarted') {
332
+ testData.integrations = {};
333
+ if (this._browser && this._platformMeta) {
334
+ const provider = getCloudProvider(this._browser);
335
+ testData.integrations[provider] = this.getIntegrationsObject();
336
+ }
337
+ }
338
+ /* istanbul ignore if */
339
+ if (world.result) {
340
+ let result = world.result.status.toLowerCase();
341
+ if (result !== 'passed' && result !== 'failed') {
342
+ result = 'skipped'; // mark UNKNOWN/UNDEFINED/AMBIGUOUS/PENDING as skipped
343
+ }
344
+ testData.finished_at = (new Date()).toISOString();
345
+ testData.result = result;
346
+ testData.duration_in_ms = world.result.duration.nanos / 1000000; // send duration in ms
347
+ if (result === 'failed') {
348
+ testData.failure = [
349
+ {
350
+ 'backtrace': [world.result.message ? removeAnsiColors(world.result.message) : 'unknown']
351
+ }
352
+ ],
353
+ testData.failure_reason = world.result.message ? removeAnsiColors(world.result.message) : world.result.message;
354
+ if (world.result.message) {
355
+ testData.failure_type = world.result.message.match(/AssertionError/)
356
+ ? 'AssertionError'
357
+ : 'UnhandledError';
358
+ }
359
+ }
360
+ }
361
+ if (world.pickle) {
362
+ testData.tags = world.pickle.tags.map(({ name }) => (name));
363
+ }
364
+ const uploadData = {
365
+ event_type: eventType,
366
+ test_run: testData
367
+ };
368
+ const req = this._requestQueueHandler.add(uploadData);
369
+ if (req.proceed && req.data) {
370
+ await uploadEventData(req.data, req.url);
371
+ }
372
+ }
373
+ getIntegrationsObject() {
374
+ return {
375
+ capabilities: this._platformMeta?.caps,
376
+ session_id: this._platformMeta?.sessionId,
377
+ browser: this._platformMeta?.browserName,
378
+ browser_version: this._platformMeta?.browserVersion,
379
+ platform: this._platformMeta?.platformName,
380
+ product: this._platformMeta?.product
381
+ };
382
+ }
383
+ getIdentifier(test) {
384
+ if ('pickle' in test) {
385
+ return getUniqueIdentifierForCucumber(test);
386
+ }
387
+ return getUniqueIdentifier(test);
388
+ }
389
+ }