@stanterprise/playwright-reporter 0.0.0-debug-flag-2

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 (47) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +472 -0
  3. package/dist/client/grpcClient.d.ts +10 -0
  4. package/dist/client/grpcClient.js +158 -0
  5. package/dist/handlers/index.d.ts +9 -0
  6. package/dist/handlers/index.js +19 -0
  7. package/dist/handlers/onBeginHandler.d.ts +5 -0
  8. package/dist/handlers/onBeginHandler.js +96 -0
  9. package/dist/handlers/onEndHandler.d.ts +4 -0
  10. package/dist/handlers/onEndHandler.js +51 -0
  11. package/dist/handlers/onErrorHandler.d.ts +4 -0
  12. package/dist/handlers/onErrorHandler.js +15 -0
  13. package/dist/handlers/onStepBeginHandler.d.ts +4 -0
  14. package/dist/handlers/onStepBeginHandler.js +38 -0
  15. package/dist/handlers/onStepEndHandler.d.ts +4 -0
  16. package/dist/handlers/onStepEndHandler.js +59 -0
  17. package/dist/handlers/onTestBeginHandler.d.ts +4 -0
  18. package/dist/handlers/onTestBeginHandler.js +32 -0
  19. package/dist/handlers/onTestEndHandler.d.ts +4 -0
  20. package/dist/handlers/onTestEndHandler.js +57 -0
  21. package/dist/handlers/onTestFailHandler.d.ts +4 -0
  22. package/dist/handlers/onTestFailHandler.js +24 -0
  23. package/dist/index.d.ts +3 -0
  24. package/dist/index.js +10 -0
  25. package/dist/reporter.d.ts +22 -0
  26. package/dist/reporter.js +149 -0
  27. package/dist/types.d.ts +94 -0
  28. package/dist/types.js +5 -0
  29. package/dist/utils/attachmentProcessor.d.ts +21 -0
  30. package/dist/utils/attachmentProcessor.js +73 -0
  31. package/dist/utils/debugLogger.d.ts +13 -0
  32. package/dist/utils/debugLogger.js +75 -0
  33. package/dist/utils/envRetriever.d.ts +9 -0
  34. package/dist/utils/envRetriever.js +23 -0
  35. package/dist/utils/idGenerators.d.ts +20 -0
  36. package/dist/utils/idGenerators.js +40 -0
  37. package/dist/utils/index.d.ts +10 -0
  38. package/dist/utils/index.js +26 -0
  39. package/dist/utils/metadataHelpers.d.ts +42 -0
  40. package/dist/utils/metadataHelpers.js +91 -0
  41. package/dist/utils/optionsMapper.d.ts +7 -0
  42. package/dist/utils/optionsMapper.js +31 -0
  43. package/dist/utils/statusMapper.d.ts +12 -0
  44. package/dist/utils/statusMapper.js +29 -0
  45. package/dist/utils/timeHelpers.d.ts +26 -0
  46. package/dist/utils/timeHelpers.js +61 -0
  47. package/package.json +58 -0
package/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2025 Stanterprise Team
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,472 @@
1
+ # stanterprise-playwright-reporter
2
+
3
+ Custom Playwright test reporter that sends test results to Stanterprise via gRPC.
4
+
5
+ ## Features
6
+
7
+ - 📊 **Comprehensive Test Reporting**: Reports test lifecycle events including begin, end, and failures
8
+ - 🔄 **Step Tracking**: Tracks and reports individual test steps with timing and status
9
+ - 📎 **Attachment Support**: Handles screenshots, videos, and other test attachments
10
+ - 🔌 **gRPC Integration**: Communicates with Stanterprise backend via gRPC protocol
11
+ - ⚙️ **Configurable**: Supports environment variables and configuration options
12
+ - 🛡️ **Error Resilient**: Graceful error handling that doesn't interrupt test execution
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install stanterprise-playwright-reporter --save-dev
18
+ ```
19
+
20
+ ## Configuration
21
+
22
+ ### Basic Setup
23
+
24
+ Add the reporter to your `playwright.config.ts`:
25
+
26
+ ```typescript
27
+ import { defineConfig } from "@playwright/test";
28
+
29
+ export default defineConfig({
30
+ reporter: [["stanterprise-playwright-reporter"]],
31
+ // ... other config
32
+ });
33
+ ```
34
+
35
+ ### Advanced Configuration
36
+
37
+ ```typescript
38
+ import { defineConfig } from "@playwright/test";
39
+
40
+ export default defineConfig({
41
+ reporter: [
42
+ [
43
+ "stanterprise-playwright-reporter",
44
+ {
45
+ grpcAddress: "localhost:50051", // gRPC server address
46
+ grpcEnabled: true, // Enable/disable gRPC reporting
47
+ grpcTimeout: 1000, // Timeout for gRPC calls in milliseconds
48
+ grpcMaxMessageSize: 104857600, // Max message size (100MB default)
49
+ maxAttachmentSize: 10485760, // Max attachment size (10MB default)
50
+ verbose: false, // Enable verbose logging
51
+ },
52
+ ],
53
+ ],
54
+ // ... other config
55
+ });
56
+ ```
57
+
58
+ ### Environment Variables
59
+
60
+ You can also configure the reporter using environment variables:
61
+
62
+ - `STANTERPRISE_GRPC_ADDRESS`: gRPC server address (default: `localhost:50051`)
63
+ - `STANTERPRISE_GRPC_ENABLED`: Enable/disable gRPC reporting (default: `true`)
64
+ - `STANTERPRISE_META_*`: Custom metadata fields for test runs (prefix will be stripped)
65
+
66
+ #### Custom Metadata
67
+
68
+ Any environment variable with the `STANTERPRISE_META_` prefix will be automatically included in the test run metadata. The prefix is stripped from the key name.
69
+
70
+ For example:
71
+
72
+ - `STANTERPRISE_META_BUILD_ID=12345` becomes `BUILD_ID: 12345` in metadata
73
+ - `STANTERPRISE_META_BRANCH=main` becomes `BRANCH: main` in metadata
74
+ - `STANTERPRISE_META_COMMIT_SHA=abc123` becomes `COMMIT_SHA: abc123` in metadata
75
+
76
+ Example:
77
+
78
+ ```bash
79
+ STANTERPRISE_GRPC_ADDRESS=myserver.com:50051 \
80
+ STANTERPRISE_META_BUILD_ID=12345 \
81
+ STANTERPRISE_META_BRANCH=main \
82
+ npx playwright test
83
+ ```
84
+
85
+ ## Configuration Options
86
+
87
+ | Option | Type | Default | Description |
88
+ | -------------------- | ------- | ----------------- | --------------------------------------------------- |
89
+ | `grpcAddress` | string | `localhost:50051` | gRPC server address |
90
+ | `grpcEnabled` | boolean | `true` | Enable/disable gRPC reporting |
91
+ | `grpcTimeout` | number | `1000` | Timeout for gRPC calls in milliseconds |
92
+ | `grpcMaxMessageSize` | number | `104857600` | Max message size in bytes (100MB default) |
93
+ | `maxAttachmentSize` | number | `10485760` | Max attachment content size in bytes (10MB default) |
94
+ | `verbose` | boolean | `false` | Enable verbose logging |
95
+ | `grpcMaxRetries` | number | `3` | Maximum number of retry attempts for failed gRPC calls |
96
+ | `grpcRetryDelay` | number | `100` | Initial delay for retries in ms (uses exponential backoff) |
97
+
98
+ ### Retry Configuration
99
+
100
+ The reporter automatically retries failed gRPC calls for transient errors using exponential backoff:
101
+
102
+ - **Retryable errors**: `UNAVAILABLE`, `DEADLINE_EXCEEDED`, `INTERNAL`, `UNKNOWN`
103
+ - **Non-retryable errors**: `INVALID_ARGUMENT`, `NOT_FOUND`, `PERMISSION_DENIED`, `UNAUTHENTICATED`, `ALREADY_EXISTS`
104
+
105
+ **Exponential backoff formula**: `grpcRetryDelay * (2 ^ attemptNumber)`
106
+
107
+ Example with default settings (`grpcRetryDelay: 100`, `grpcMaxRetries: 3`):
108
+ - Initial attempt: Immediate
109
+ - Retry 1: Wait 100ms (100 * 2^0)
110
+ - Retry 2: Wait 200ms (100 * 2^1)
111
+ - Retry 3: Wait 400ms (100 * 2^2)
112
+
113
+ ```typescript
114
+ export default defineConfig({
115
+ reporter: [
116
+ [
117
+ "stanterprise-playwright-reporter",
118
+ {
119
+ grpcMaxRetries: 5, // Try up to 5 times
120
+ grpcRetryDelay: 200, // Start with 200ms delay
121
+ verbose: true, // Log retry attempts
122
+ },
123
+ ],
124
+ ],
125
+ });
126
+ ```
127
+
128
+ To disable retries:
129
+
130
+ ```typescript
131
+ {
132
+ grpcMaxRetries: 0 // No retries, fail fast
133
+ }
134
+ ```
135
+
136
+ ## Sharding Support
137
+
138
+ The reporter automatically detects and reports when tests are running in sharded mode. When sharding is configured, the reporter includes the following metadata in test run events:
139
+
140
+ - `shard.current`: The current shard number (1-based)
141
+ - `shard.total`: The total number of shards
142
+
143
+ ### Configuring Sharding
144
+
145
+ In your `playwright.config.ts`:
146
+
147
+ ```typescript
148
+ import { defineConfig } from "@playwright/test";
149
+
150
+ export default defineConfig({
151
+ shard: { total: 5, current: 1 },
152
+ reporter: [["stanterprise-playwright-reporter"]],
153
+ });
154
+ ```
155
+
156
+ Or via CLI:
157
+
158
+ ```bash
159
+ npx playwright test --shard=1/5
160
+ npx playwright test --shard=2/5
161
+ # ... etc
162
+ ```
163
+
164
+ ### Aggregating Results Across Shards
165
+
166
+ **Important:** To have a complete set of tests accumulated in the observability server, you must specify the same `STANTERPRISE_RUN_ID` environment variable for all shards. This ensures that results from all shards are associated with the same test run.
167
+
168
+ ```bash
169
+ # Set the same run ID for all shards
170
+ export STANTERPRISE_RUN_ID="my-test-run-123"
171
+
172
+ # Run all shards with the same run ID
173
+ npx playwright test --shard=1/5
174
+ npx playwright test --shard=2/5
175
+ npx playwright test --shard=3/5
176
+ npx playwright test --shard=4/5
177
+ npx playwright test --shard=5/5
178
+ ```
179
+
180
+ In CI/CD environments, you can use a unique identifier from your CI system:
181
+
182
+ ```bash
183
+ # GitHub Actions example
184
+ STANTERPRISE_RUN_ID="${GITHUB_RUN_ID}" npx playwright test --shard=1/5
185
+
186
+ # GitLab CI example
187
+ STANTERPRISE_RUN_ID="${CI_PIPELINE_ID}" npx playwright test --shard=1/5
188
+
189
+ # Jenkins example
190
+ STANTERPRISE_RUN_ID="${BUILD_ID}" npx playwright test --shard=1/5
191
+ ```
192
+
193
+ Without a shared `STANTERPRISE_RUN_ID`, each shard will generate its own unique run ID, and the results will be reported as separate test runs rather than a single aggregated run.
194
+
195
+ The shard information is automatically included in the metadata sent to the server, allowing you to:
196
+
197
+ - Track which tests ran on which shard
198
+ - Aggregate results from multiple shards
199
+ - Debug shard-specific issues
200
+
201
+ When verbose logging is enabled, you'll see shard information in the console output:
202
+
203
+ ```
204
+ Stanterprise Reporter: Test run started with ID: 123e4567-e89b-12d3-a456-426614174000
205
+ Number of tests: 42
206
+ Run started at: 2026-01-25T10:30:00.000Z
207
+ Shard: 1 of 5
208
+ ```
209
+
210
+ ## What Gets Reported
211
+
212
+ ### Test Events
213
+
214
+ - **Test Begin**: When a test starts
215
+ - **Test End**: When a test completes with status (passed/failed/skipped/timedOut)
216
+ - **Test Failure**: Detailed failure information including error messages and stack traces
217
+
218
+ ### Step Events
219
+
220
+ - **Step Begin**: When a test step starts
221
+ - **Step End**: When a test step completes with duration and status
222
+
223
+ ### Attachments
224
+
225
+ The reporter automatically processes and sends:
226
+
227
+ - Screenshots
228
+ - Videos
229
+ - Trace files
230
+ - Any other attachments captured during test execution
231
+
232
+ ## Usage Example
233
+
234
+ ```typescript
235
+ // playwright.config.ts
236
+ import { defineConfig } from "@playwright/test";
237
+
238
+ export default defineConfig({
239
+ use: {
240
+ screenshot: "only-on-failure",
241
+ video: "retain-on-failure",
242
+ },
243
+ reporter: [
244
+ ["list"], // Also show in console
245
+ [
246
+ "stanterprise-playwright-reporter",
247
+ {
248
+ grpcAddress: process.env.STANTERPRISE_GRPC_ADDRESS || "localhost:50051",
249
+ verbose: process.env.CI === "true",
250
+ },
251
+ ],
252
+ ],
253
+ });
254
+ ```
255
+
256
+ ## API
257
+
258
+ ### StanterpriseReporter
259
+
260
+ Main reporter class implementing Playwright's `Reporter` interface.
261
+
262
+ ```typescript
263
+ import { StanterpriseReporter } from "stanterprise-playwright-reporter";
264
+
265
+ const reporter = new StanterpriseReporter({
266
+ grpcAddress: "localhost:50051",
267
+ grpcEnabled: true,
268
+ grpcTimeout: 1000,
269
+ grpcMaxMessageSize: 104857600, // 100MB
270
+ maxAttachmentSize: 10485760, // 10MB
271
+ verbose: false,
272
+ });
273
+ ```
274
+
275
+ ### Types
276
+
277
+ ```typescript
278
+ import type {
279
+ StanterpriseReporterOptions,
280
+ TestExecutionContext,
281
+ StepExecutionContext,
282
+ } from "stanterprise-playwright-reporter";
283
+ ```
284
+
285
+ ## Development
286
+
287
+ ### Building
288
+
289
+ ```bash
290
+ npm run build
291
+ ```
292
+
293
+ ### Testing
294
+
295
+ ```bash
296
+ npm test
297
+ ```
298
+
299
+ ### Cleaning
300
+
301
+ ```bash
302
+ npm run clean
303
+ ```
304
+
305
+ ## How It Works
306
+
307
+ 1. **Test Run Initialization**: When tests start, the reporter generates a unique run ID and establishes a gRPC connection
308
+ 2. **Event Reporting**: As tests execute, the reporter sends events to the Stanterprise backend via gRPC
309
+ 3. **Fire-and-Forget**: Events are sent asynchronously to avoid slowing down test execution
310
+ 4. **Error Handling**: Connection errors are logged once and further attempts are disabled for that run
311
+ 5. **Cleanup**: When tests complete, the gRPC connection is properly closed
312
+
313
+ ## Architecture
314
+
315
+ The reporter is organized into several modules:
316
+
317
+ - **reporter.ts**: Main reporter implementation
318
+ - **types.ts**: TypeScript type definitions and interfaces
319
+ - **utils/statusMapper.ts**: Maps Playwright statuses to protobuf enums
320
+ - **utils/attachmentProcessor.ts**: Processes test attachments
321
+ - **utils/timeHelpers.ts**: Handles timestamp and duration conversions
322
+
323
+ ## Troubleshooting
324
+
325
+ ### gRPC Error 13 INTERNAL: failed to publish event
326
+
327
+ This error typically occurs due to one of two issues:
328
+
329
+ **1. Metadata Serialization (Most Common)**
330
+
331
+ If you see this error with the stack trace mentioning "metadata is not iterable" or serialization issues, it was a bug in v0.0.13 and earlier versions. **Solution: Upgrade to v0.0.14 or later.**
332
+
333
+ **2. Large Attachments**
334
+
335
+ This error can also occur when test event payloads exceed the gRPC message size limit. Common causes:
336
+
337
+ 1. **Large attachments**: Tests with large screenshots, videos, or trace files
338
+ 2. **Default size limits**: gRPC has a default 4MB message size limit
339
+
340
+ **Solutions:**
341
+
342
+ 1. **Increase message size limits** (recommended):
343
+
344
+ ```typescript
345
+ reporter: [
346
+ [
347
+ "stanterprise-playwright-reporter",
348
+ {
349
+ grpcMaxMessageSize: 104857600, // 100MB (default)
350
+ maxAttachmentSize: 10485760, // 10MB (default)
351
+ },
352
+ ],
353
+ ],
354
+ ```
355
+
356
+ 2. **Reduce attachment sizes**:
357
+ - Configure Playwright to save attachments to disk instead of embedding them
358
+ - The reporter automatically uses file paths when available instead of content
359
+
360
+ ```typescript
361
+ use: {
362
+ screenshot: "only-on-failure",
363
+ video: "retain-on-failure",
364
+ trace: "retain-on-failure",
365
+ },
366
+ ```
367
+
368
+ 3. **Monitor payload sizes**: Enable verbose logging to see actual payload sizes:
369
+ ```typescript
370
+ reporter: [
371
+ ["stanterprise-playwright-reporter", { verbose: true }],
372
+ ],
373
+ ```
374
+
375
+ The reporter will log warnings when attachments exceed the size limit and automatically skip their content while preserving metadata.
376
+
377
+ ### Connection Issues
378
+
379
+ If you see gRPC connection errors:
380
+
381
+ 1. Verify the gRPC server is running and accessible
382
+ 2. Check the `grpcAddress` configuration
383
+ 3. Ensure firewall rules allow the connection
384
+ 4. Enable verbose logging to see detailed error messages
385
+
386
+ ### Reporter Not Working
387
+
388
+ 1. Verify the reporter is properly configured in `playwright.config.ts`
389
+ 2. Check that `grpcEnabled` is not set to `false`
390
+ 3. Look for error messages in the test output
391
+ 4. Try with `verbose: true` to see detailed logs
392
+
393
+ ## Contributing
394
+
395
+ Contributions are welcome! Please feel free to submit a Pull Request.
396
+
397
+ ## For Maintainers
398
+
399
+ ### Publishing to NPM
400
+
401
+ #### Automated Publishing (Recommended)
402
+
403
+ The repository uses GitHub Actions to automatically publish to NPM when a version tag is pushed:
404
+
405
+ 1. Update the version following [semantic versioning](https://semver.org/):
406
+
407
+ ```bash
408
+ npm version patch # for bug fixes (1.0.0 → 1.0.1)
409
+ npm version minor # for new features (1.0.0 → 1.1.0)
410
+ npm version major # for breaking changes (1.0.0 → 2.0.0)
411
+ ```
412
+
413
+ 2. Push the version tag to GitHub:
414
+
415
+ ```bash
416
+ git push --follow-tags
417
+ ```
418
+
419
+ 3. The GitHub Actions workflow will automatically:
420
+ - Run tests
421
+ - Build the package
422
+ - Publish to NPM with provenance
423
+
424
+ **Note**: Requires `NPM_TOKEN` secret to be configured in GitHub repository settings with a valid NPM access token.
425
+
426
+ #### Manual Publishing
427
+
428
+ Alternatively, you can publish manually:
429
+
430
+ 1. Ensure all tests pass:
431
+
432
+ ```bash
433
+ npm test
434
+ ```
435
+
436
+ 2. Update the version:
437
+
438
+ ```bash
439
+ npm version patch|minor|major
440
+ ```
441
+
442
+ 3. Publish to NPM (prepublishOnly script will build automatically):
443
+
444
+ ```bash
445
+ npm publish
446
+ ```
447
+
448
+ 4. Push the tag to GitHub:
449
+ ```bash
450
+ git push --follow-tags
451
+ ```
452
+
453
+ ### What Gets Published
454
+
455
+ The package includes:
456
+
457
+ - `dist/` - Compiled JavaScript and TypeScript declarations
458
+ - `README.md` - Documentation
459
+
460
+ The following are excluded via `.npmignore`:
461
+
462
+ - Source files (`src/`, `tests/`, `examples/`)
463
+ - Development configuration files
464
+ - Build artifacts and logs
465
+
466
+ ## License
467
+
468
+ ISC - See [LICENSE](LICENSE) file for details
469
+
470
+ ## Support
471
+
472
+ For issues and questions, please visit the [GitHub repository](https://github.com/stanterprise/stanterprise-playwright-reporter).
@@ -0,0 +1,10 @@
1
+ import { StanterpriseReporterOptions } from "../types";
2
+ import * as grpc from "@grpc/grpc-js";
3
+ export default function getClient(options: StanterpriseReporterOptions): grpc.Client | null;
4
+ /**
5
+ * Helper: generic unary call using raw method path with retry support
6
+ */
7
+ export declare function reportUnary(options: StanterpriseReporterOptions, grpcClient: grpc.Client, path: string, message: {
8
+ serialize?: (w?: any) => Uint8Array;
9
+ serializeBinary?: () => Uint8Array;
10
+ }, deadlineMs?: number): Promise<Buffer>;
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.default = getClient;
37
+ exports.reportUnary = reportUnary;
38
+ const grpc = __importStar(require("@grpc/grpc-js"));
39
+ const debugLogger_1 = require("../utils/debugLogger");
40
+ function getClient(options) {
41
+ try {
42
+ const maxMessageSize = options.grpcMaxMessageSize || 104857600; // 100MB default
43
+ return new grpc.Client(options.grpcAddress, grpc.credentials.createInsecure(), {
44
+ "grpc.max_send_message_length": maxMessageSize,
45
+ "grpc.max_receive_message_length": maxMessageSize,
46
+ });
47
+ }
48
+ catch (e) {
49
+ console.error("Failed to create gRPC client", e);
50
+ }
51
+ return null;
52
+ }
53
+ /**
54
+ * Determines if a gRPC error code represents a transient failure worth retrying
55
+ */
56
+ function shouldAttemptRetryForCode(errorCode) {
57
+ const transientCodes = new Set([
58
+ grpc.status.UNAVAILABLE,
59
+ grpc.status.DEADLINE_EXCEEDED,
60
+ grpc.status.INTERNAL,
61
+ grpc.status.UNKNOWN,
62
+ ]);
63
+ return transientCodes.has(errorCode);
64
+ }
65
+ /**
66
+ * Calculates wait time using power-of-two exponential backoff
67
+ */
68
+ function calculateWaitDuration(baseDelayMs, attemptsSoFar) {
69
+ return baseDelayMs * Math.pow(2, attemptsSoFar);
70
+ }
71
+ /**
72
+ * Performs a single gRPC unary request attempt
73
+ */
74
+ function executeSingleAttempt(grpcClient, path, message, deadlineMs) {
75
+ const reqSerialize = (arg) => {
76
+ const m = arg;
77
+ const bytes = m?.serializeBinary
78
+ ? m.serializeBinary()
79
+ : m?.serialize
80
+ ? m.serialize()
81
+ : new Uint8Array(0);
82
+ return Buffer.from(bytes);
83
+ };
84
+ const resDeserialize = (bytes) => bytes;
85
+ const metadata = new grpc.Metadata();
86
+ const callOptions = {
87
+ deadline: new Date(Date.now() + deadlineMs),
88
+ };
89
+ return new Promise((resolve, reject) => {
90
+ try {
91
+ grpcClient.makeUnaryRequest(path, reqSerialize, resDeserialize, message, metadata, callOptions, (err, response) => {
92
+ if (err)
93
+ return reject(err);
94
+ resolve(response);
95
+ });
96
+ }
97
+ catch (e) {
98
+ reject(e);
99
+ }
100
+ });
101
+ }
102
+ /**
103
+ * Pauses execution for specified milliseconds with unref'd timer to avoid blocking shutdown
104
+ */
105
+ function pauseExecution(durationMs) {
106
+ return new Promise((resolve) => {
107
+ const timer = setTimeout(resolve, durationMs);
108
+ // Unref the timer so it doesn't keep the process alive
109
+ timer.unref();
110
+ });
111
+ }
112
+ /**
113
+ * Attempts gRPC call with exponential backoff retry logic using iterative approach
114
+ */
115
+ async function attemptWithRetries(options, grpcClient, path, message, deadlineMs, maxRetries) {
116
+ let attemptNumber = 0;
117
+ let lastError = null;
118
+ // Try initial attempt + retries
119
+ for (let retriesRemaining = maxRetries; retriesRemaining >= 0; retriesRemaining--) {
120
+ try {
121
+ return await executeSingleAttempt(grpcClient, path, message, deadlineMs);
122
+ }
123
+ catch (err) {
124
+ lastError = err;
125
+ const grpcErr = err;
126
+ const statusCode = grpcErr?.code ?? grpc.status.UNKNOWN;
127
+ // Check if we should retry this error
128
+ const isRetryable = shouldAttemptRetryForCode(statusCode);
129
+ const hasRetriesLeft = retriesRemaining > 0;
130
+ if (!isRetryable || !hasRetriesLeft) {
131
+ throw err;
132
+ }
133
+ // Log retry attempt if verbose
134
+ if (options.verbose) {
135
+ console.log(`gRPC call failed (code: ${statusCode}), retrying... ` +
136
+ `(attempt ${attemptNumber + 1}, ${retriesRemaining} retries left)`);
137
+ }
138
+ // Calculate and wait for backoff duration
139
+ const baseDelay = options.grpcRetryDelay ?? 100;
140
+ const waitTime = calculateWaitDuration(baseDelay, attemptNumber);
141
+ await pauseExecution(waitTime);
142
+ attemptNumber++;
143
+ }
144
+ }
145
+ // This should never be reached due to the throw in the loop, but TypeScript needs it
146
+ throw lastError || new Error("Retry loop exhausted without result");
147
+ }
148
+ /**
149
+ * Helper: generic unary call using raw method path with retry support
150
+ */
151
+ async function reportUnary(options, grpcClient, path, message, deadlineMs = 1000) {
152
+ (0, debugLogger_1.writeDebugEntry)(options, path, message);
153
+ if (!options.grpcEnabled || !grpcClient) {
154
+ return Buffer.alloc(0);
155
+ }
156
+ const maxRetries = options.grpcMaxRetries ?? 3;
157
+ return attemptWithRetries(options, grpcClient, path, message, deadlineMs, maxRetries);
158
+ }
@@ -0,0 +1,9 @@
1
+ import { handleOnBeginEvent } from "./onBeginHandler";
2
+ import { handleOnEndEvent } from "./onEndHandler";
3
+ import { handleOnStepBeginEvent } from "./onStepBeginHandler";
4
+ import { handleOnStepEndEvent } from "./onStepEndHandler";
5
+ import { handleOnTestBeginEvent } from "./onTestBeginHandler";
6
+ import { handleOnTestEndEvent } from "./onTestEndHandler";
7
+ import { handleOnTestFailEvent } from "./onTestFailHandler";
8
+ import { handleOnErrorEvent } from "./onErrorHandler";
9
+ export { handleOnBeginEvent, handleOnEndEvent, handleOnStepBeginEvent, handleOnStepEndEvent, handleOnTestBeginEvent, handleOnTestEndEvent, handleOnTestFailEvent, handleOnErrorEvent, };
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleOnErrorEvent = exports.handleOnTestFailEvent = exports.handleOnTestEndEvent = exports.handleOnTestBeginEvent = exports.handleOnStepEndEvent = exports.handleOnStepBeginEvent = exports.handleOnEndEvent = exports.handleOnBeginEvent = void 0;
4
+ const onBeginHandler_1 = require("./onBeginHandler");
5
+ Object.defineProperty(exports, "handleOnBeginEvent", { enumerable: true, get: function () { return onBeginHandler_1.handleOnBeginEvent; } });
6
+ const onEndHandler_1 = require("./onEndHandler");
7
+ Object.defineProperty(exports, "handleOnEndEvent", { enumerable: true, get: function () { return onEndHandler_1.handleOnEndEvent; } });
8
+ const onStepBeginHandler_1 = require("./onStepBeginHandler");
9
+ Object.defineProperty(exports, "handleOnStepBeginEvent", { enumerable: true, get: function () { return onStepBeginHandler_1.handleOnStepBeginEvent; } });
10
+ const onStepEndHandler_1 = require("./onStepEndHandler");
11
+ Object.defineProperty(exports, "handleOnStepEndEvent", { enumerable: true, get: function () { return onStepEndHandler_1.handleOnStepEndEvent; } });
12
+ const onTestBeginHandler_1 = require("./onTestBeginHandler");
13
+ Object.defineProperty(exports, "handleOnTestBeginEvent", { enumerable: true, get: function () { return onTestBeginHandler_1.handleOnTestBeginEvent; } });
14
+ const onTestEndHandler_1 = require("./onTestEndHandler");
15
+ Object.defineProperty(exports, "handleOnTestEndEvent", { enumerable: true, get: function () { return onTestEndHandler_1.handleOnTestEndEvent; } });
16
+ const onTestFailHandler_1 = require("./onTestFailHandler");
17
+ Object.defineProperty(exports, "handleOnTestFailEvent", { enumerable: true, get: function () { return onTestFailHandler_1.handleOnTestFailEvent; } });
18
+ const onErrorHandler_1 = require("./onErrorHandler");
19
+ Object.defineProperty(exports, "handleOnErrorEvent", { enumerable: true, get: function () { return onErrorHandler_1.handleOnErrorEvent; } });
@@ -0,0 +1,5 @@
1
+ import { FullConfig } from "@playwright/test";
2
+ import { Suite } from "@playwright/test/reporter";
3
+ import { StanterpriseReporterOptions } from "../types";
4
+ import * as grpc from "@grpc/grpc-js";
5
+ export declare function handleOnBeginEvent(config: FullConfig, suite: Suite, name: string, runId: string, client: grpc.Client, options: StanterpriseReporterOptions): void;