@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.
- package/LICENSE +15 -0
- package/README.md +472 -0
- package/dist/client/grpcClient.d.ts +10 -0
- package/dist/client/grpcClient.js +158 -0
- package/dist/handlers/index.d.ts +9 -0
- package/dist/handlers/index.js +19 -0
- package/dist/handlers/onBeginHandler.d.ts +5 -0
- package/dist/handlers/onBeginHandler.js +96 -0
- package/dist/handlers/onEndHandler.d.ts +4 -0
- package/dist/handlers/onEndHandler.js +51 -0
- package/dist/handlers/onErrorHandler.d.ts +4 -0
- package/dist/handlers/onErrorHandler.js +15 -0
- package/dist/handlers/onStepBeginHandler.d.ts +4 -0
- package/dist/handlers/onStepBeginHandler.js +38 -0
- package/dist/handlers/onStepEndHandler.d.ts +4 -0
- package/dist/handlers/onStepEndHandler.js +59 -0
- package/dist/handlers/onTestBeginHandler.d.ts +4 -0
- package/dist/handlers/onTestBeginHandler.js +32 -0
- package/dist/handlers/onTestEndHandler.d.ts +4 -0
- package/dist/handlers/onTestEndHandler.js +57 -0
- package/dist/handlers/onTestFailHandler.d.ts +4 -0
- package/dist/handlers/onTestFailHandler.js +24 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +10 -0
- package/dist/reporter.d.ts +22 -0
- package/dist/reporter.js +149 -0
- package/dist/types.d.ts +94 -0
- package/dist/types.js +5 -0
- package/dist/utils/attachmentProcessor.d.ts +21 -0
- package/dist/utils/attachmentProcessor.js +73 -0
- package/dist/utils/debugLogger.d.ts +13 -0
- package/dist/utils/debugLogger.js +75 -0
- package/dist/utils/envRetriever.d.ts +9 -0
- package/dist/utils/envRetriever.js +23 -0
- package/dist/utils/idGenerators.d.ts +20 -0
- package/dist/utils/idGenerators.js +40 -0
- package/dist/utils/index.d.ts +10 -0
- package/dist/utils/index.js +26 -0
- package/dist/utils/metadataHelpers.d.ts +42 -0
- package/dist/utils/metadataHelpers.js +91 -0
- package/dist/utils/optionsMapper.d.ts +7 -0
- package/dist/utils/optionsMapper.js +31 -0
- package/dist/utils/statusMapper.d.ts +12 -0
- package/dist/utils/statusMapper.js +29 -0
- package/dist/utils/timeHelpers.d.ts +26 -0
- package/dist/utils/timeHelpers.js +61 -0
- 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
|
+
}
|
package/dist/index.d.ts
ADDED
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
|
+
}
|
package/dist/reporter.js
ADDED
|
@@ -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;
|