@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
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleOnBeginEvent = handleOnBeginEvent;
4
+ const events_1 = require("@stanterprise/protobuf/testsystem/v1/events");
5
+ const grpcClient_1 = require("../client/grpcClient");
6
+ const entities_1 = require("@stanterprise/protobuf/testsystem/v1/entities");
7
+ const utils_1 = require("../utils");
8
+ const common_1 = require("@stanterprise/protobuf/testsystem/v1/common");
9
+ function handleOnBeginEvent(config, suite, name, runId, client, options) {
10
+ // Report root suite and all child suites recursively
11
+ // Convert all metadata values to strings for protobuf compatibility
12
+ // Use plain object instead of Map - protobuf expects object literals
13
+ const metadata = {};
14
+ Object.entries(config.metadata || {}).forEach(([key, value]) => {
15
+ metadata[key] = String(value);
16
+ });
17
+ const variables = (0, utils_1.getEnvVariables)();
18
+ // Merge environment variables into metadata
19
+ variables.forEach((value, key) => {
20
+ metadata[key] = value;
21
+ });
22
+ // Add shard information if present
23
+ if (config.shard) {
24
+ metadata["shard.current"] = String(config.shard.current);
25
+ metadata["shard.total"] = String(config.shard.total);
26
+ }
27
+ const request = new events_1.ReportRunStartEventRequest({
28
+ run_id: runId,
29
+ name: name,
30
+ test_suites: mapSuites(suite, runId),
31
+ total_tests: suite.allTests().length,
32
+ metadata: (0, utils_1.toMetadataMap)(metadata),
33
+ });
34
+ (0, grpcClient_1.reportUnary)(options, client, "/testsystem.v1.observer.TestEventCollector/ReportRunStart", request, options.grpcTimeout).catch((e) => {
35
+ const details = e instanceof Error ? `${e.message}` : String(e);
36
+ console.warn(`onBegin. gRPC disabled for the remainder of the run. Address=${options.grpcAddress}. Details: ${details}`);
37
+ });
38
+ }
39
+ function mapSuites(suite, runId) {
40
+ let allSuites = getAllSuites(suite);
41
+ return allSuites.map((currentSuite) => mapSingleSuite(currentSuite, runId));
42
+ }
43
+ function getAllSuites(suite) {
44
+ let suites = [];
45
+ suites.push(suite);
46
+ suite.suites.forEach((childSuite) => {
47
+ suites = suites.concat(getAllSuites(childSuite));
48
+ });
49
+ return suites;
50
+ }
51
+ function mapSingleSuite(suite, runId) {
52
+ const suiteId = (0, utils_1.generateSuiteId)(suite);
53
+ const parentSuiteId = suite.parent
54
+ ? (0, utils_1.generateSuiteId)(suite.parent)
55
+ : undefined;
56
+ let type;
57
+ switch (suite.type) {
58
+ case "root":
59
+ type = entities_1.SuiteType.ROOT;
60
+ break;
61
+ case "describe":
62
+ type = entities_1.SuiteType.SUBSUITE;
63
+ break;
64
+ case "file":
65
+ type = entities_1.SuiteType.FILE;
66
+ break;
67
+ case "project":
68
+ type = entities_1.SuiteType.PROJECT;
69
+ break;
70
+ }
71
+ return new entities_1.TestSuiteRun({
72
+ id: suiteId,
73
+ name: suite.title,
74
+ run_id: runId,
75
+ parent_suite_id: parentSuiteId,
76
+ status: common_1.TestStatus.NOT_RUN,
77
+ test_cases: suite.tests.map((test) => new entities_1.TestCaseRun({
78
+ id: test.id,
79
+ name: test.title,
80
+ run_id: runId,
81
+ test_suite_id: suiteId,
82
+ tags: test.tags,
83
+ location: test.location
84
+ ? `${test.location.file}:${test.location.line}:${test.location.column}`
85
+ : undefined,
86
+ status: common_1.TestStatus.NOT_RUN,
87
+ retry_count: test.retries,
88
+ retry_index: 0,
89
+ })),
90
+ test_case_ids: suite.tests.map((test) => test.id),
91
+ type: type,
92
+ location: suite.location
93
+ ? `${suite.location.file}:${suite.location.line}:${suite.location.column}`
94
+ : undefined,
95
+ });
96
+ }
@@ -0,0 +1,4 @@
1
+ import { FullResult } from "@playwright/test/reporter";
2
+ import { StanterpriseReporterOptions } from "../types";
3
+ import * as grpc from "@grpc/grpc-js";
4
+ export declare function handleOnEndEvent(result: FullResult, runId: string, client: grpc.Client, options: StanterpriseReporterOptions): void;
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleOnEndEvent = handleOnEndEvent;
4
+ const grpcClient_1 = require("../client/grpcClient");
5
+ const utils_1 = require("../utils");
6
+ const events_1 = require("@stanterprise/protobuf/testsystem/v1/events");
7
+ const common_1 = require("@stanterprise/protobuf/testsystem/v1/common");
8
+ function mapTestStatus(status) {
9
+ switch (status) {
10
+ case "passed":
11
+ return common_1.TestStatus.PASSED;
12
+ case "failed":
13
+ return common_1.TestStatus.FAILED;
14
+ case "timedout":
15
+ return common_1.TestStatus.TIMEDOUT;
16
+ case "interrupted":
17
+ return common_1.TestStatus.INTERRUPTED;
18
+ default:
19
+ return common_1.TestStatus.UNKNOWN;
20
+ }
21
+ }
22
+ function handleOnEndEvent(result, runId, client, options) {
23
+ // Validate and sanitize inputs to prevent serialization failures
24
+ const startTimeMs = result.startTime?.getTime();
25
+ const duration = result.duration;
26
+ // Ensure valid numeric values (protobuf cannot serialize NaN or undefined)
27
+ const validStartTimeMs = typeof startTimeMs === "number" && !isNaN(startTimeMs)
28
+ ? startTimeMs
29
+ : Date.now();
30
+ const validDuration = typeof duration === "number" && !isNaN(duration) && duration >= 0
31
+ ? duration
32
+ : 0;
33
+ const request = new events_1.TestRunEndEventRequest({
34
+ run_id: runId,
35
+ final_status: mapTestStatus(result.status),
36
+ start_time: (0, utils_1.createTimestampFromMs)(validStartTimeMs),
37
+ duration: (0, utils_1.createDuration)(validDuration),
38
+ });
39
+ (0, grpcClient_1.reportUnary)(options, client, "/testsystem.v1.observer.TestEventCollector/ReportRunEnd", request, options.grpcTimeout).catch((error) => {
40
+ if (error instanceof Error) {
41
+ console.error(`Failed to report end event: ${error.message}`, {
42
+ stack: error.stack,
43
+ });
44
+ }
45
+ else {
46
+ console.error("Failed to report end event: Unknown error type", {
47
+ error,
48
+ });
49
+ }
50
+ });
51
+ }
@@ -0,0 +1,4 @@
1
+ import { TestError } from "@playwright/test/reporter";
2
+ import { StanterpriseReporterOptions } from "../types";
3
+ import * as grpc from "@grpc/grpc-js";
4
+ export declare function handleOnErrorEvent(error: TestError, runId: string, grpcClient: grpc.Client, options: StanterpriseReporterOptions): void;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleOnErrorEvent = handleOnErrorEvent;
4
+ const events_1 = require("@stanterprise/protobuf/testsystem/v1/events");
5
+ const timeHelpers_1 = require("../utils/timeHelpers");
6
+ const grpcClient_1 = require("../client/grpcClient");
7
+ function handleOnErrorEvent(error, runId, grpcClient, options) {
8
+ const request = new events_1.StdErrorEventRequest({
9
+ run_id: runId,
10
+ message: error.message,
11
+ timestamp: (0, timeHelpers_1.createTimestampFromMs)(Date.now()),
12
+ });
13
+ // Fire-and-forget to avoid slowing tests
14
+ (0, grpcClient_1.reportUnary)(options, grpcClient, "/testsystem.v1.observer.TestEventCollector/ReportStdError", request, options.grpcTimeout).catch((e) => console.error("Failed to report standard error", e));
15
+ }
@@ -0,0 +1,4 @@
1
+ import { TestCase, TestResult, TestStep } from "@playwright/test/reporter";
2
+ import { StanterpriseReporterOptions } from "../types";
3
+ import * as grpc from "@grpc/grpc-js";
4
+ export declare function handleOnStepBeginEvent(test: TestCase, result: TestResult, step: TestStep, runId: string, client: grpc.Client, options: StanterpriseReporterOptions): void;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleOnStepBeginEvent = handleOnStepBeginEvent;
4
+ const entities_1 = require("@stanterprise/protobuf/testsystem/v1/entities");
5
+ const events_1 = require("@stanterprise/protobuf/testsystem/v1/events");
6
+ const utils_1 = require("../utils");
7
+ const grpcClient_1 = require("../client/grpcClient");
8
+ const utils_2 = require("../utils");
9
+ const common_1 = require("@stanterprise/protobuf/testsystem/v1/common");
10
+ function handleOnStepBeginEvent(test, result, step, runId, client, options) {
11
+ // Build metadata from step annotations
12
+ const metadata = (0, utils_1.buildStepMetadata)(step);
13
+ // Get parent step ID if this step has a parent
14
+ const stepId = (0, utils_2.generateStepId)(step, test);
15
+ // Build and send the StepBegin event
16
+ const request = new events_1.StepBeginEventRequest({
17
+ step: new entities_1.StepRun({
18
+ id: stepId,
19
+ run_id: runId,
20
+ test_case_id: test.id,
21
+ title: step.title,
22
+ status: common_1.TestStatus.RUNNING,
23
+ type: step.category,
24
+ start_time: (0, utils_1.createTimestamp)(step.startTime),
25
+ location: step.location
26
+ ? `${step.location.file}:${step.location.line}:${step.location.column}`
27
+ : undefined,
28
+ metadata: (0, utils_1.toMetadataMap)(metadata),
29
+ parent_step_id: step.parent
30
+ ? (0, utils_2.generateStepId)(step.parent, test)
31
+ : undefined,
32
+ worker_index: result.workerIndex.toString(),
33
+ retry_index: result.retry,
34
+ }),
35
+ });
36
+ // Fire-and-forget to avoid slowing tests
37
+ (0, grpcClient_1.reportUnary)(options, client, "/testsystem.v1.observer.TestEventCollector/ReportStepBegin", request, options.grpcTimeout).catch((e) => console.error("Failed to report step begin", e));
38
+ }
@@ -0,0 +1,4 @@
1
+ import { TestCase, TestResult, TestStep } from "@playwright/test/reporter";
2
+ import { StanterpriseReporterOptions } from "../types";
3
+ import * as grpc from "@grpc/grpc-js";
4
+ export declare function handleOnStepEndEvent(test: TestCase, result: TestResult, step: TestStep, runId: string, client: grpc.Client, options: StanterpriseReporterOptions): void;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleOnStepEndEvent = handleOnStepEndEvent;
4
+ const entities_1 = require("@stanterprise/protobuf/testsystem/v1/entities");
5
+ const events_1 = require("@stanterprise/protobuf/testsystem/v1/events");
6
+ const utils_1 = require("../utils");
7
+ const grpcClient_1 = require("../client/grpcClient");
8
+ const utils_2 = require("../utils");
9
+ function handleOnStepEndEvent(test, result, step, runId, client, options) {
10
+ // Map step error to status
11
+ const stepStatus = (0, utils_1.mapStepStatus)(!!step.error);
12
+ // Build metadata from step annotations
13
+ const metadata = (0, utils_1.buildStepMetadata)(step);
14
+ const stepId = (0, utils_2.generateStepId)(step, test);
15
+ // Extract comprehensive error details if present
16
+ const errorMessage = step.error?.message || "";
17
+ const errorStack = step.error?.stack || "";
18
+ const errorValue = step.error?.value || "";
19
+ const errorSnippet = step.error?.snippet || "";
20
+ const errorLocation = step.error?.location
21
+ ? `${step.error.location.file}:${step.error.location.line}:${step.error.location.column}`
22
+ : "";
23
+ // Combine all error information into metadata for comprehensive error tracking
24
+ const errorMetadata = {};
25
+ if (errorStack)
26
+ errorMetadata.error_stack = (0, utils_1.truncateValue)(errorStack);
27
+ if (errorValue)
28
+ errorMetadata.error_value = (0, utils_1.truncateValue)(errorValue);
29
+ if (errorSnippet)
30
+ errorMetadata.error_snippet = (0, utils_1.truncateValue)(errorSnippet);
31
+ if (errorLocation)
32
+ errorMetadata.error_location = (0, utils_1.truncateValue)(errorLocation);
33
+ // Build and send the StepEnd event
34
+ const request = new events_1.StepEndEventRequest({
35
+ step: new entities_1.StepRun({
36
+ id: stepId,
37
+ run_id: runId,
38
+ test_case_id: test.id,
39
+ title: step.title,
40
+ type: step.category,
41
+ start_time: (0, utils_1.createTimestamp)(step.startTime),
42
+ duration: (0, utils_1.createDuration)(step.duration),
43
+ status: stepStatus,
44
+ error: errorMessage,
45
+ errors: errorMessage ? [errorMessage] : [],
46
+ location: step.location
47
+ ? `${step.location.file}:${step.location.line}:${step.location.column}`
48
+ : "",
49
+ metadata: (0, utils_1.toMetadataMap)({ ...metadata, ...errorMetadata }),
50
+ parent_step_id: step.parent
51
+ ? (0, utils_2.generateStepId)(step.parent, test)
52
+ : undefined,
53
+ worker_index: result.workerIndex.toString(),
54
+ retry_index: result.retry,
55
+ }),
56
+ });
57
+ // Fire-and-forget to avoid slowing tests
58
+ (0, grpcClient_1.reportUnary)(options, client, "/testsystem.v1.observer.TestEventCollector/ReportStepEnd", request, options.grpcTimeout).catch((e) => console.error("Failed to report step end", e));
59
+ }
@@ -0,0 +1,4 @@
1
+ import { TestCase, TestResult } from "@playwright/test/reporter";
2
+ import { StanterpriseReporterOptions } from "../types";
3
+ import * as grpc from "@grpc/grpc-js";
4
+ export declare function handleOnTestBeginEvent(test: TestCase, result: TestResult, runId: string, client: grpc.Client, options: StanterpriseReporterOptions): void;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleOnTestBeginEvent = handleOnTestBeginEvent;
4
+ const entities_1 = require("@stanterprise/protobuf/testsystem/v1/entities");
5
+ const events_1 = require("@stanterprise/protobuf/testsystem/v1/events");
6
+ const utils_1 = require("../utils");
7
+ const grpcClient_1 = require("../client/grpcClient");
8
+ const common_1 = require("@stanterprise/protobuf/testsystem/v1/common");
9
+ function handleOnTestBeginEvent(test, result, runId, client, options) {
10
+ // Build and send the TestBegin event via generic unary call.
11
+ const request = new events_1.TestBeginEventRequest({
12
+ test_case: new entities_1.TestCaseRun({
13
+ id: test.id,
14
+ name: test.title,
15
+ run_id: runId,
16
+ retry_index: result.retry,
17
+ retry_count: test.retries,
18
+ location: test.location
19
+ ? `${test.location.file}:${test.location.line}:${test.location.column}`
20
+ : undefined,
21
+ status: common_1.TestStatus.RUNNING,
22
+ test_suite_id: (0, utils_1.generateSuiteId)(test.parent),
23
+ start_time: (0, utils_1.createTimestamp)(result.startTime),
24
+ tags: test.tags,
25
+ }),
26
+ });
27
+ // Fire-and-forget to avoid slowing tests; log errors once.
28
+ (0, grpcClient_1.reportUnary)(options, client, "/testsystem.v1.observer.TestEventCollector/ReportTestBegin", request, options.grpcTimeout).catch((e) => {
29
+ const details = e instanceof Error ? `${e.message}` : String(e);
30
+ console.warn(`Failed to report test begin. Details: ${details}`);
31
+ });
32
+ }
@@ -0,0 +1,4 @@
1
+ import { TestCase, TestResult } from "@playwright/test/reporter";
2
+ import { StanterpriseReporterOptions } from "../types";
3
+ import * as grpc from "@grpc/grpc-js";
4
+ export declare function handleOnTestEndEvent(test: TestCase, result: TestResult, runId: string, client: grpc.Client, options: StanterpriseReporterOptions): void;
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleOnTestEndEvent = handleOnTestEndEvent;
4
+ const entities_1 = require("@stanterprise/protobuf/testsystem/v1/entities");
5
+ const events_1 = require("@stanterprise/protobuf/testsystem/v1/events");
6
+ const utils_1 = require("../utils");
7
+ const grpcClient_1 = require("../client/grpcClient");
8
+ const utils_2 = require("../utils");
9
+ /**
10
+ * Constant for converting bytes to megabytes
11
+ */
12
+ const BYTES_PER_MB = 1048576;
13
+ function handleOnTestEndEvent(test, result, runId, client, options) {
14
+ // Map Playwright test status to protobuf TestStatus
15
+ const testStatus = (0, utils_1.mapTestStatus)(result.status);
16
+ // Process attachments (screenshots, videos, etc.)
17
+ const attachments = (0, utils_1.processAttachments)(result, options.maxAttachmentSize || 10485760);
18
+ // Extract error information if the test failed
19
+ const { errorMessage, stackTrace, errors } = (0, utils_1.extractErrorInfo)(result);
20
+ // Get test suite run ID from parent suite if available, ensuring suite is reported
21
+ const suiteId = (0, utils_2.generateSuiteId)(test.parent);
22
+ // Build metadata from test annotations and result metadata
23
+ const metadata = (0, utils_1.buildTestMetadata)(test, result);
24
+ // Build and send the TestEnd event
25
+ const request = new events_1.TestEndEventRequest({
26
+ test_case: new entities_1.TestCaseRun({
27
+ id: test.id,
28
+ name: test.title,
29
+ run_id: runId,
30
+ test_suite_id: suiteId,
31
+ status: testStatus,
32
+ start_time: (0, utils_1.createTimestamp)(result.startTime),
33
+ duration: (0, utils_1.createDuration)(result.duration),
34
+ attachments: attachments,
35
+ error_message: errorMessage,
36
+ stack_trace: stackTrace,
37
+ errors: errors,
38
+ metadata: (0, utils_1.toMetadataMap)(metadata),
39
+ tags: test.tags,
40
+ retry_index: result.retry,
41
+ retry_count: test.retries,
42
+ }),
43
+ });
44
+ // Serialize once to capture payload size for potential error logging
45
+ const serializedPayload = request.serializeBinary();
46
+ const payloadSize = serializedPayload.length;
47
+ // Warn if payload is unusually large (>1MB)
48
+ if (payloadSize > 1048576) {
49
+ console.warn(`Large payload detected for test "${test.title}": ${(payloadSize / BYTES_PER_MB).toFixed(2)}MB. ` +
50
+ `Attachments: ${attachments.length}, Metadata keys: ${Object.keys(metadata).length}, ` +
51
+ `Error length: ${errorMessage.length + stackTrace.length} bytes`);
52
+ }
53
+ // Fire-and-forget to avoid slowing tests
54
+ (0, grpcClient_1.reportUnary)(options, client, "/testsystem.v1.observer.TestEventCollector/ReportTestEnd", request, options.grpcTimeout).catch((e) => {
55
+ console.error(`Failed to report test end for "${test.title}" (payload size: ${(payloadSize / BYTES_PER_MB).toFixed(2)}MB)`, e);
56
+ });
57
+ }
@@ -0,0 +1,4 @@
1
+ import { TestCase, TestResult } from "@playwright/test/reporter";
2
+ import { StanterpriseReporterOptions } from "../types";
3
+ import * as grpc from "@grpc/grpc-js";
4
+ export declare function handleOnTestFailEvent(test: TestCase, result: TestResult, runId: string, grpcClient: grpc.Client, options: StanterpriseReporterOptions): void;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleOnTestFailEvent = handleOnTestFailEvent;
4
+ const utils_1 = require("../utils");
5
+ const events_1 = require("@stanterprise/protobuf/testsystem/v1/events");
6
+ const grpcClient_1 = require("../client/grpcClient");
7
+ function handleOnTestFailEvent(test, result, runId, grpcClient, options) {
8
+ // Extract failure details
9
+ const { errorMessage: failureMessage, stackTrace } = (0, utils_1.extractErrorInfo)(result);
10
+ // Process attachments for failed tests
11
+ const attachments = (0, utils_1.processAttachments)(result);
12
+ // Build and send the TestFailure event
13
+ const request = new events_1.TestFailureEventRequest({
14
+ test_id: test.id,
15
+ run_id: runId,
16
+ failure_message: failureMessage,
17
+ stack_trace: stackTrace,
18
+ timestamp: (0, utils_1.createTimestampFromMs)(Date.now()),
19
+ attachments: attachments,
20
+ retry_index: result.retry,
21
+ });
22
+ // Fire-and-forget to avoid slowing tests
23
+ (0, grpcClient_1.reportUnary)(options, grpcClient, "/testsystem.v1.observer.TestEventCollector/ReportTestFailure", request, options.grpcTimeout).catch((e) => console.error("Failed to report test failure", e));
24
+ }
@@ -0,0 +1,3 @@
1
+ export { default } from "./reporter";
2
+ export { default as StanterpriseReporter } from "./reporter";
3
+ export type { StanterpriseReporterOptions, TestExecutionContext, StepExecutionContext } from "./types";
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.StanterpriseReporter = exports.default = void 0;
7
+ var reporter_1 = require("./reporter");
8
+ Object.defineProperty(exports, "default", { enumerable: true, get: function () { return __importDefault(reporter_1).default; } });
9
+ var reporter_2 = require("./reporter");
10
+ Object.defineProperty(exports, "StanterpriseReporter", { enumerable: true, get: function () { return __importDefault(reporter_2).default; } });
@@ -0,0 +1,22 @@
1
+ import type { Reporter, FullConfig, Suite, TestCase, TestResult, FullResult, TestStep, TestError } from "@playwright/test/reporter";
2
+ import { StanterpriseReporterOptions } from "./types";
3
+ export default class StanterpriseReporter implements Reporter {
4
+ private grpcClient;
5
+ private options;
6
+ private runId;
7
+ private runStartTime;
8
+ constructor(options?: StanterpriseReporterOptions);
9
+ onBegin(config: FullConfig, suite: Suite): void;
10
+ onExit(): Promise<void>;
11
+ onEnd(result: FullResult): Promise<{
12
+ status?: FullResult["status"];
13
+ } | undefined | void> | void;
14
+ onTestBegin(test: TestCase, result: TestResult): void;
15
+ onStepBegin(test: TestCase, result: TestResult, step: TestStep): Promise<void>;
16
+ onStepEnd(test: TestCase, result: TestResult, step: TestStep): void;
17
+ onTestEnd(test: TestCase, result: TestResult): void;
18
+ onTestFail(test: TestCase, result: TestResult): void;
19
+ onError(error: TestError): void;
20
+ onStdErr(chunk: string | Buffer, test: void | TestCase, result: void | TestResult): void;
21
+ onStdOut(chunk: string | Buffer, test: void | TestCase, result: void | TestResult): void;
22
+ }
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const crypto_1 = require("crypto");
7
+ const optionsMapper_1 = __importDefault(require("./utils/optionsMapper"));
8
+ const debugLogger_1 = require("./utils/debugLogger");
9
+ const grpcClient_1 = __importDefault(require("./client/grpcClient"));
10
+ const handlers_1 = require("./handlers");
11
+ class StanterpriseReporter {
12
+ constructor(options = {}) {
13
+ // Generic gRPC client (we call unary methods by path directly).
14
+ this.grpcClient = null;
15
+ this.options = {};
16
+ // Generate a unique run ID for this test run
17
+ this.runId = "";
18
+ this.runStartTime = new Date();
19
+ this.options = (0, optionsMapper_1.default)(options);
20
+ if (this.options.verbose) {
21
+ console.log("Stanterprise Reporter: Initialized with options:", {
22
+ grpcAddress: this.options.grpcAddress,
23
+ grpcEnabled: this.options.grpcEnabled,
24
+ grpcTimeout: this.options.grpcTimeout,
25
+ verbose: this.options.verbose,
26
+ });
27
+ }
28
+ // Generate a UUID for runId
29
+ this.runId = process.env.STANTERPRISE_RUN_ID || (0, crypto_1.randomUUID)();
30
+ // Initialize debug file (creates/truncates it) when debug mode is enabled
31
+ (0, debugLogger_1.initDebugFile)(this.options);
32
+ }
33
+ onBegin(config, suite) {
34
+ // Lazily create the client if enabled.
35
+ if (this.options.grpcEnabled) {
36
+ this.grpcClient = (0, grpcClient_1.default)(this.options);
37
+ if (!this.grpcClient) {
38
+ console.warn(`Stanterprise Reporter: Failed to create gRPC client. Disabling gRPC reporting.`);
39
+ this.options.grpcEnabled = false;
40
+ }
41
+ }
42
+ else {
43
+ if (this.options.verbose) {
44
+ console.log("Stanterprise Reporter: gRPC disabled via STANTERPRISE_GRPC_ENABLED=false");
45
+ }
46
+ }
47
+ if (this.options.verbose) {
48
+ console.log(`Stanterprise Reporter: Test run started with ID: ${this.runId}`);
49
+ console.log(`Number of tests: ${suite.allTests().length}`);
50
+ console.log(`Run started at: ${this.runStartTime.toISOString()}`);
51
+ if (config.shard) {
52
+ console.log(`Shard: ${config.shard.current} of ${config.shard.total}`);
53
+ }
54
+ }
55
+ if (this.options.grpcEnabled) {
56
+ (0, handlers_1.handleOnBeginEvent)(config, suite, process.env.STANTERPRISE_TEST_RUN_NAME || "Playwright Test Run", this.runId, this.grpcClient, this.options);
57
+ }
58
+ }
59
+ async onExit() {
60
+ console.log(`Stanterprise Reporter: Test run completed - Run ID: ${this.runId}`);
61
+ // Cleanup gRPC client
62
+ try {
63
+ this.grpcClient?.close();
64
+ }
65
+ catch (e) {
66
+ console.error("Stanterprise Reporter: Error during gRPC client cleanup in onExit:", e);
67
+ }
68
+ }
69
+ onEnd(result) {
70
+ const runDuration = Date.now() - this.runStartTime.getTime();
71
+ if (this.options.verbose) {
72
+ console.log(`Stanterprise Reporter: Test run ended - Run ID: ${this.runId}`);
73
+ console.log(`Final result: ${result.status}`);
74
+ console.log(`Run duration: ${runDuration}ms (Playwright duration: ${result.duration}ms)`);
75
+ console.log(`Run start time: ${this.runStartTime.toISOString()}`);
76
+ console.log(`Playwright start time: ${result.startTime.toISOString()}`);
77
+ }
78
+ if (this.options.grpcEnabled) {
79
+ (0, handlers_1.handleOnEndEvent)(result, this.runId, this.grpcClient, this.options);
80
+ }
81
+ return Promise.resolve();
82
+ }
83
+ onTestBegin(test, result) {
84
+ // Create unique test execution ID combining run ID and test ID
85
+ if (this.options.verbose) {
86
+ console.log(`Stanterprise Reporter: Test started - ${test.title}`);
87
+ console.log(` Run ID: ${this.runId}`);
88
+ console.log(` Test ID: ${test.id}`);
89
+ }
90
+ if (this.options.grpcEnabled) {
91
+ (0, handlers_1.handleOnTestBeginEvent)(test, result, this.runId, this.grpcClient, this.options);
92
+ }
93
+ }
94
+ async onStepBegin(test, result, step) {
95
+ if (this.options.verbose) {
96
+ console.log(`Stanterprise Reporter: Step started - ${step.title}`);
97
+ console.log(` Category: ${step.category}`);
98
+ }
99
+ if (this.options.grpcEnabled) {
100
+ (0, handlers_1.handleOnStepBeginEvent)(test, result, step, this.runId, this.grpcClient, this.options);
101
+ }
102
+ }
103
+ onStepEnd(test, result, step) {
104
+ if (this.options.verbose) {
105
+ console.log(`Stanterprise Reporter: Step ended - ${step.title}`);
106
+ console.log(` Duration: ${step.duration}ms`);
107
+ }
108
+ if (this.options.grpcEnabled) {
109
+ (0, handlers_1.handleOnStepEndEvent)(test, result, step, this.runId, this.grpcClient, this.options);
110
+ }
111
+ }
112
+ onTestEnd(test, result) {
113
+ if (this.options.verbose) {
114
+ console.log(`Stanterprise Reporter: Test ended - ${test.title}`);
115
+ console.log(` Status: ${result.status}`);
116
+ console.log(` Duration: ${result.duration}ms`);
117
+ }
118
+ if (this.options.grpcEnabled) {
119
+ (0, handlers_1.handleOnTestEndEvent)(test, result, this.runId, this.grpcClient, this.options);
120
+ }
121
+ }
122
+ onTestFail(test, result) {
123
+ if (this.options.verbose) {
124
+ console.log(`Stanterprise Reporter: Test failed - ${test.title}`);
125
+ }
126
+ if (this.options.grpcEnabled) {
127
+ (0, handlers_1.handleOnTestFailEvent)(test, result, this.runId, this.grpcClient, this.options);
128
+ }
129
+ }
130
+ onError(error) {
131
+ console.error("Stanterprise Reporter: An error occurred during the test run");
132
+ console.error(`Error: ${error.message}`);
133
+ if (error.stack) {
134
+ console.error(`Stack trace: ${error.stack}`);
135
+ }
136
+ if (this.options.grpcEnabled) {
137
+ (0, handlers_1.handleOnErrorEvent)(error, this.runId, this.grpcClient, this.options);
138
+ }
139
+ }
140
+ onStdErr(chunk, test, result) {
141
+ console.error(`Stanterprise Reporter: Standard error output - ${chunk.toString()}`);
142
+ }
143
+ onStdOut(chunk, test, result) {
144
+ if (this.options.verbose) {
145
+ console.log(`Stanterprise Reporter: Standard output - ${chunk.toString()}`);
146
+ }
147
+ }
148
+ }
149
+ exports.default = StanterpriseReporter;