@wdio/browserstack-service 9.36.1 → 9.38.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/README.md +34 -0
- package/build/Percy/PercySDK.d.ts +3 -3
- package/build/cleanup.js +31 -10
- package/build/cli/frameworks/wdioCucumberTestFramework.d.ts +132 -0
- package/build/cli/index.d.ts +3 -2
- package/build/cli/modules/automateModule.d.ts +31 -0
- package/build/cli/modules/customTagsModule.d.ts +1 -0
- package/build/index.js +1008 -135
- package/build/insights-handler.d.ts +1 -1
- package/build/service.d.ts +38 -0
- package/build/util.d.ts +7 -0
- package/package.json +7 -6
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import TestFramework from './testFramework.js';
|
|
2
|
+
import TestFrameworkInstance from '../instances/testFrameworkInstance.js';
|
|
3
|
+
import type { Frameworks } from '@wdio/types';
|
|
4
|
+
import type { CucumberHook, Feature } from '../../cucumber-types.js';
|
|
5
|
+
type CucumberHookType = 'BEFORE_ALL' | 'AFTER_ALL' | 'BEFORE_EACH' | 'AFTER_EACH';
|
|
6
|
+
/**
|
|
7
|
+
* CLI test framework for `framework: 'cucumber'` under WebdriverIO.
|
|
8
|
+
*
|
|
9
|
+
* Extends the BASE TestFramework, never WdioMochaTestFramework: WDIO does not call
|
|
10
|
+
* `beforeTest`/`afterTest`/titled hooks for cucumber at all, so mocha's INIT_TEST/TEST/hook
|
|
11
|
+
* boundary semantics have no source here and borrowing them would report cucumber through the
|
|
12
|
+
* wrong runner's event model.
|
|
13
|
+
*
|
|
14
|
+
* Cucumber's unit of work is the scenario, and every `cli/modules/*` observer subscribes to
|
|
15
|
+
* `TestFrameworkState.TEST` — so a scenario raises TEST/PRE at `beforeScenario` and TEST/POST at
|
|
16
|
+
* `afterScenario`, and the module set works unchanged.
|
|
17
|
+
*/
|
|
18
|
+
export default class WdioCucumberTestFramework extends TestFramework {
|
|
19
|
+
static KEY_HOOK_LAST_STARTED: string;
|
|
20
|
+
static KEY_HOOK_LAST_FINISHED: string;
|
|
21
|
+
/**
|
|
22
|
+
* The bookkeeping `classifyHookType()` derives hook types from. A cucumber hook invocation
|
|
23
|
+
* carries no title, and `BeforeAll`/`AfterAll` pass no hook object at all, so classification
|
|
24
|
+
* is state-machine derived — `util.ts → getHookType()` is Mocha-title-shaped and can only
|
|
25
|
+
* return 'unknown' or throw here.
|
|
26
|
+
*/
|
|
27
|
+
private cucumberData;
|
|
28
|
+
/**
|
|
29
|
+
* Steps accumulated for the scenario in flight. Re-allocated (never cleared in place) at each
|
|
30
|
+
* scenario start so a payload already built from the previous scenario can never observe the
|
|
31
|
+
* next one's steps.
|
|
32
|
+
*/
|
|
33
|
+
private scenarioSteps;
|
|
34
|
+
/** The hook currently open on this worker — started and not yet finished. */
|
|
35
|
+
private openHook;
|
|
36
|
+
constructor(testFrameworks: string[], testFrameworkVersions: Record<string, string>, binSessionId: string);
|
|
37
|
+
/**
|
|
38
|
+
* Feature bookkeeping. Raises no framework state — cucumber has no feature-level wire event,
|
|
39
|
+
* and `beforeSuite`/`afterSuite` are not part of its WDIO surface.
|
|
40
|
+
*/
|
|
41
|
+
onFeatureStart(uri: string, feature: Feature): void;
|
|
42
|
+
/**
|
|
43
|
+
* Step bookkeeping. Steps travel inside the scenario payload's BDD meta, never as their own
|
|
44
|
+
* event — `TestFrameworkState.STEP` has zero producers anywhere in this SDK.
|
|
45
|
+
*/
|
|
46
|
+
onStepStart(step: Frameworks.PickleStep): void;
|
|
47
|
+
onStepEnd(step: Frameworks.PickleStep, result: Frameworks.PickleResult): void;
|
|
48
|
+
/**
|
|
49
|
+
* Classify a cucumber hook invocation from the bookkeeping state.
|
|
50
|
+
*
|
|
51
|
+
* Returns null for a step-scoped hook (`BeforeStep`/`AfterStep`), which is never reported —
|
|
52
|
+
* reporting it would change the dashboard hook count, which is a feature and not parity.
|
|
53
|
+
*/
|
|
54
|
+
classifyHookType(test: CucumberHook | undefined): CucumberHookType | null;
|
|
55
|
+
/** The TestFrameworkState a cucumber hook invocation maps to, or null when unreported. */
|
|
56
|
+
classifyHookState(test: CucumberHook | undefined): State | null;
|
|
57
|
+
/**
|
|
58
|
+
* `<HOOK_TYPE> for <scenario|feature name>` — the separator is a literal ' ' + 'for' + ' '.
|
|
59
|
+
*/
|
|
60
|
+
private hookName;
|
|
61
|
+
private featurePath;
|
|
62
|
+
/**
|
|
63
|
+
* The feature path as the bdd meta blob wants it — cwd-relative, matching legacy.
|
|
64
|
+
*
|
|
65
|
+
* `cucumberData.uri` cannot be forwarded raw: WDIO hands `beforeFeature` an ABSOLUTE uri, so
|
|
66
|
+
* the raw value carries the developer's home directory. Legacy never sees that value — it
|
|
67
|
+
* reads the cucumber world's `gherkinDocument.uri`, which is cwd-relative.
|
|
68
|
+
*/
|
|
69
|
+
private featureUriForMeta;
|
|
70
|
+
trackEvent(testFrameworkState: State, hookState: State, args?: Record<string, unknown>): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* One instance per scenario, keyed by the worker (`pid:threadId`) — the single lookup every
|
|
73
|
+
* `cli/modules/*` reads, via `TestFramework.getTrackedInstance()`. WDIO forks one worker
|
|
74
|
+
* process per spec file, so the worker key is the scenario's execution context; a thread id
|
|
75
|
+
* alone would collide once threads are reused.
|
|
76
|
+
*/
|
|
77
|
+
private resolveInstance;
|
|
78
|
+
private trackWdioCucumberInstance;
|
|
79
|
+
/** Scenario identity. Each field matches what the legacy flow sent; the asymmetries are deliberate. */
|
|
80
|
+
private loadScenarioData;
|
|
81
|
+
/**
|
|
82
|
+
* `feature.path` is cwd-relative, matching legacy (`insights-handler` builds
|
|
83
|
+
* `feature = { path: gherkinDocument.uri, … }` off the cucumber world). It is NOT the absolute
|
|
84
|
+
* path used for `test_file_path`: the binary re-bases that one, but never touches this blob, so
|
|
85
|
+
* an absolute value here reaches the dashboard as-is, home directory and all.
|
|
86
|
+
*/
|
|
87
|
+
private buildBddMetaInfo;
|
|
88
|
+
/**
|
|
89
|
+
* Scenario result, loaded at the real "scenario ends" state.
|
|
90
|
+
*
|
|
91
|
+
* KEY_TEST_RESULT_AT is load-bearing, not decoration: `testHubModule → onAllTestEvents()`
|
|
92
|
+
* treats a TEST/POST without it as result-less, marks the test deferred, and then waits for a
|
|
93
|
+
* `LOG_REPORT` POST to recover it — a state cucumber never emits.
|
|
94
|
+
*/
|
|
95
|
+
private loadScenarioResult;
|
|
96
|
+
/**
|
|
97
|
+
* One detached instance per scenario the feature never ran, for the BEFORE_ALL cascade
|
|
98
|
+
* (Rule-nested included). Detached is load-bearing: not registered via `setTrackedInstance`,
|
|
99
|
+
* so the live instance and `process.env[TEST_ANALYTICS_ID]` are untouched, and the caller
|
|
100
|
+
* sends each straight to TestHub — routing them through the observers would rename the
|
|
101
|
+
* session, stop accessibility and run a Percy teardown per row. No tags: legacy's cascade
|
|
102
|
+
* payload has no `world`.
|
|
103
|
+
*/
|
|
104
|
+
buildSkippedScenarioInstances(): TestFrameworkInstance[];
|
|
105
|
+
private buildSkippedScenarioInstance;
|
|
106
|
+
/**
|
|
107
|
+
* Whether the scenario in flight failed in a STEP, as opposed to failing only in a hook.
|
|
108
|
+
* Public because `ignoreHooksStatus` has two surfaces: the o11y result below, and the Automate
|
|
109
|
+
* session status, which `service.afterScenario()` derives from the same answer.
|
|
110
|
+
*/
|
|
111
|
+
hasStepFailures(): boolean;
|
|
112
|
+
/**
|
|
113
|
+
* Route a console log to the row it belongs on: the open hook's uuid while a hook is in
|
|
114
|
+
* flight and unfinished, otherwise the scenario's uuid.
|
|
115
|
+
*
|
|
116
|
+
* The record itself always goes into KEY_TEST_LOGS, because the send path
|
|
117
|
+
* (`testHubModule → onAllTestEvents`, unchanged) collects test logs plus the last FINISHED
|
|
118
|
+
* hook's logs — a record parked on a still-open hook's own array would never be picked up.
|
|
119
|
+
* The routing is carried by KEY_HOOK_ID on the record, which `sendLogCreatedEvent` reads in
|
|
120
|
+
* preference to the test uuid.
|
|
121
|
+
*/
|
|
122
|
+
private loadLogEntry;
|
|
123
|
+
/**
|
|
124
|
+
* Hook lifecycle. Entries are keyed by the short state name, matching how the binary looks
|
|
125
|
+
* them up via `event.test_hooks_started[request.testFrameworkState]`.
|
|
126
|
+
*
|
|
127
|
+
* A finish with no recorded start is dropped rather than emitted — an unmatched
|
|
128
|
+
* HookRunFinished orphans a hook row the backend cannot pair.
|
|
129
|
+
*/
|
|
130
|
+
private trackHookEvents;
|
|
131
|
+
}
|
|
132
|
+
export {};
|
package/build/cli/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { StartBinSessionResponse } from '../grpc/index.js';
|
|
|
4
4
|
import type BaseModule from './modules/baseModule.js';
|
|
5
5
|
import type { Options } from '@wdio/types';
|
|
6
6
|
import WdioMochaTestFramework from './frameworks/wdioMochaTestFramework.js';
|
|
7
|
+
import WdioCucumberTestFramework from './frameworks/wdioCucumberTestFramework.js';
|
|
7
8
|
import WdioAutomationFramework from './frameworks/wdioAutomationFramework.js';
|
|
8
9
|
import type { BrowserstackConfig, BrowserstackOptions } from '../types.js';
|
|
9
10
|
/**
|
|
@@ -26,7 +27,7 @@ export declare class BrowserstackCLI {
|
|
|
26
27
|
modulesLoaded: boolean;
|
|
27
28
|
binSessionId: string | null;
|
|
28
29
|
modules: Record<string, BaseModule>;
|
|
29
|
-
testFramework: WdioMochaTestFramework | null;
|
|
30
|
+
testFramework: WdioMochaTestFramework | WdioCucumberTestFramework | null;
|
|
30
31
|
cliParams: Record<string, string> | null;
|
|
31
32
|
automationFramework: WdioAutomationFramework | null;
|
|
32
33
|
SDK_CLI_BIN_PATH: string | null;
|
|
@@ -152,7 +153,7 @@ export declare class BrowserstackCLI {
|
|
|
152
153
|
* Get the test framework
|
|
153
154
|
* @returns {Object} The test framework
|
|
154
155
|
*/
|
|
155
|
-
getTestFramework(): WdioMochaTestFramework | null;
|
|
156
|
+
getTestFramework(): WdioMochaTestFramework | WdioCucumberTestFramework | null;
|
|
156
157
|
/**
|
|
157
158
|
* Get the automation framework
|
|
158
159
|
* @returns {Object} The automation framework
|
|
@@ -18,8 +18,39 @@ export default class AutomateModule extends BaseModule {
|
|
|
18
18
|
*/
|
|
19
19
|
private flushSessionName;
|
|
20
20
|
onAfterTest(args: Record<string, unknown>): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* A `BeforeAll` / `AfterAll` failure produces no scenario result, so it can never enter the
|
|
23
|
+
* per-test `testResults` map that onAfterExecute aggregates — a run whose BeforeAll blew up
|
|
24
|
+
* reports its session as PASSED. Legacy pushed the hook error into `_failReasons` and
|
|
25
|
+
* `after()` marked the session failed; that whole accumulation is gated
|
|
26
|
+
* `setSessionStatus && !BrowserstackCLI.isRunning()`, so it is dead while the binary is up.
|
|
27
|
+
*
|
|
28
|
+
* Cucumber-gated deliberately. `wdio_mocha` has the identical latent shape on this flow, but
|
|
29
|
+
* legacy mocha behaved the same way, so repairing it here would be an unrequested behaviour
|
|
30
|
+
* change to the one framework already working on the CLI flow.
|
|
31
|
+
*/
|
|
32
|
+
onBuildLevelHookEnd(hookKey: string, args: Record<string, unknown>): Promise<void>;
|
|
33
|
+
private isCucumberInstance;
|
|
34
|
+
/** The hook's reported name (`BEFORE_ALL for <feature>`), so the session reason names the hook. */
|
|
35
|
+
private resolveHookName;
|
|
21
36
|
onAfterExecute(): Promise<void>;
|
|
22
37
|
private isAppAutomate;
|
|
38
|
+
private isTurboScale;
|
|
39
|
+
/**
|
|
40
|
+
* Resolve the REST endpoint a session marker must hit.
|
|
41
|
+
*
|
|
42
|
+
* Turboscale is not a variant of Automate here — it is a different API on a different path
|
|
43
|
+
* with a different VERB (PATCH, not PUT). The legacy path expressed this through
|
|
44
|
+
* `_sessionBaseUrl` + `_update()`, both gated `!BrowserstackCLI.isRunning()`, so neither
|
|
45
|
+
* survives onto the CLI flow and nothing in the binary compensates.
|
|
46
|
+
*
|
|
47
|
+
* Precedence mirrors legacy's assignment order in `beforeSession()`: the turboscale base URL
|
|
48
|
+
* is assigned AFTER the app-automate one, so a turboscale grid wins even with an app cap set.
|
|
49
|
+
*
|
|
50
|
+
* Single resolver for both markers deliberately: naming and status previously duplicated the
|
|
51
|
+
* ternary, which is how the two can drift apart.
|
|
52
|
+
*/
|
|
53
|
+
private resolveSessionApi;
|
|
23
54
|
markSessionName(sessionId: string, sessionName: string, config: {
|
|
24
55
|
user: string;
|
|
25
56
|
key: string;
|
|
@@ -28,6 +28,7 @@ export default class CustomTagsModule extends BaseModule {
|
|
|
28
28
|
private pendingTestLevelTags;
|
|
29
29
|
constructor();
|
|
30
30
|
getModuleName(): string;
|
|
31
|
+
private isMochaFramework;
|
|
31
32
|
onBeforeExecute(): Promise<void>;
|
|
32
33
|
/**
|
|
33
34
|
* At each test start (TEST/PRE — after beforeTest tracks the instance), flush any
|