@zohodesk/testinglibrary 4.1.9 → 4.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/build/core/playwright/builtInFixtures/actorContext.js +13 -10
- package/build/core/playwright/builtInFixtures/context.js +42 -3
- package/build/core/playwright/builtInFixtures/page.js +0 -1
- package/build/core/playwright/helpers/logCollector.js +167 -0
- package/build/core/playwright/readConfigFile.js +7 -1
- package/build/core/playwright/setup/custom-reporter.js +87 -1
- package/npm-shrinkwrap.json +21 -21
- package/package.json +1 -1
- package/unit_reports/unit-report.html +1 -1
package/README.md
CHANGED
|
@@ -17,6 +17,13 @@
|
|
|
17
17
|
|
|
18
18
|
- npm run report
|
|
19
19
|
|
|
20
|
+
### v4.1.9/v3.3.5 - 03-07-2026
|
|
21
|
+
|
|
22
|
+
#### Feature
|
|
23
|
+
- PortalDomain option provided in the settings.json.
|
|
24
|
+
- This lets customer portal and related UAT flows resolve the portal URL from configuration instead of hardcoding environment-specific links.
|
|
25
|
+
- It simplifies switching between setups such as dev, QA, and UAT without changing test code.
|
|
26
|
+
|
|
20
27
|
|
|
21
28
|
### v4.1.5/v3.3.3 - 19-06-2026
|
|
22
29
|
|
|
@@ -25,20 +25,20 @@ class ActorContext {
|
|
|
25
25
|
};
|
|
26
26
|
const additionalActors = (0, _additionalProfiles.additionProfiles)($tags);
|
|
27
27
|
await Promise.all(Object.entries(additionalActors).map(async ([role, actorInfo]) => {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
page,
|
|
28
|
+
const additionalContext = await browser.newContext();
|
|
29
|
+
const additionalPage = await additionalContext.newPage();
|
|
30
|
+
const ctxTestDetails = {
|
|
31
|
+
page: additionalPage,
|
|
32
32
|
$tags,
|
|
33
|
-
context,
|
|
33
|
+
context: additionalContext,
|
|
34
34
|
...actorInfo
|
|
35
35
|
};
|
|
36
|
-
await (0, _loginDefaultStepsHelper.executeDefaultLoginSteps)(
|
|
36
|
+
await (0, _loginDefaultStepsHelper.executeDefaultLoginSteps)(additionalContext, testInfo, ctxTestDetails, actorInfo);
|
|
37
37
|
this.actorsObj[role] = {
|
|
38
38
|
role,
|
|
39
39
|
browser,
|
|
40
|
-
context,
|
|
41
|
-
page,
|
|
40
|
+
context: additionalContext,
|
|
41
|
+
page: additionalPage,
|
|
42
42
|
executionContext: {
|
|
43
43
|
actorInfo
|
|
44
44
|
}
|
|
@@ -69,7 +69,10 @@ var _default = exports.default = {
|
|
|
69
69
|
}, use, testInfo) => {
|
|
70
70
|
const ctxObject = new ActorContext();
|
|
71
71
|
await ctxObject.setup(browser, $tags, testInfo, context, page, executionContext);
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
try {
|
|
73
|
+
await use(ctxObject);
|
|
74
|
+
} finally {
|
|
75
|
+
await ctxObject.cleanup();
|
|
76
|
+
}
|
|
74
77
|
}
|
|
75
78
|
};
|
|
@@ -1,13 +1,28 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
3
4
|
Object.defineProperty(exports, "__esModule", {
|
|
4
5
|
value: true
|
|
5
6
|
});
|
|
6
7
|
exports.default = void 0;
|
|
8
|
+
var _path = _interopRequireDefault(require("path"));
|
|
7
9
|
var _readConfigFile = require("../readConfigFile");
|
|
10
|
+
var _logCollector = require("../helpers/logCollector");
|
|
8
11
|
const {
|
|
9
|
-
testSetup
|
|
12
|
+
testSetup,
|
|
13
|
+
uatDirectory,
|
|
14
|
+
browserLogs = {}
|
|
10
15
|
} = (0, _readConfigFile.generateConfigFromFile)();
|
|
16
|
+
|
|
17
|
+
// Keep runtime logs OUTSIDE reportPath (HTML reporter wipes it on onEnd) and
|
|
18
|
+
// outside test-results (Playwright outputDir is cleaned each run).
|
|
19
|
+
const LOGS_DIR = _path.default.join(uatDirectory, 'runtime-logs');
|
|
20
|
+
const MAX_FILENAME_LENGTH = 120;
|
|
21
|
+
function sanitizeForFilename(name) {
|
|
22
|
+
if (!name) return 'test';
|
|
23
|
+
const cleaned = name.replace(/[^A-Za-z0-9._-]+/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '').slice(0, MAX_FILENAME_LENGTH);
|
|
24
|
+
return cleaned || 'test';
|
|
25
|
+
}
|
|
11
26
|
async function performDefaultContextSteps({
|
|
12
27
|
context
|
|
13
28
|
}) {
|
|
@@ -20,13 +35,37 @@ async function performDefaultContextSteps({
|
|
|
20
35
|
var _default = exports.default = {
|
|
21
36
|
context: async ({
|
|
22
37
|
context
|
|
23
|
-
}, use) => {
|
|
38
|
+
}, use, testInfo) => {
|
|
24
39
|
await context.addInitScript(() =>
|
|
25
40
|
// eslint-disable-next-line no-undef
|
|
26
41
|
window.localStorage.setItem('isDnBannerHide', true));
|
|
27
42
|
await performDefaultContextSteps({
|
|
28
43
|
context
|
|
29
44
|
});
|
|
30
|
-
|
|
45
|
+
const collector = new _logCollector.LogCollector(browserLogs.limits);
|
|
46
|
+
collector.attachToContext(context);
|
|
47
|
+
testInfo.runtimeLogs = collector;
|
|
48
|
+
try {
|
|
49
|
+
await use(context);
|
|
50
|
+
} finally {
|
|
51
|
+
collector.detach();
|
|
52
|
+
const failureOnly = browserLogs.mode === 'failure-only';
|
|
53
|
+
const isFailure = testInfo.status && testInfo.status !== testInfo.expectedStatus;
|
|
54
|
+
const shouldFlush = !failureOnly || isFailure;
|
|
55
|
+
const summary = collector.toSummary();
|
|
56
|
+
let filePath = null;
|
|
57
|
+
if (shouldFlush) {
|
|
58
|
+
const base = `w${testInfo.workerIndex}-${sanitizeForFilename(testInfo.title)}-${testInfo.retry}`;
|
|
59
|
+
filePath = collector.flushToFile(LOGS_DIR, base);
|
|
60
|
+
}
|
|
61
|
+
await testInfo.attach('runtime-log', {
|
|
62
|
+
contentType: 'application/json',
|
|
63
|
+
body: Buffer.from(JSON.stringify({
|
|
64
|
+
schemaVersion: 1,
|
|
65
|
+
summary,
|
|
66
|
+
file: filePath
|
|
67
|
+
}))
|
|
68
|
+
});
|
|
69
|
+
}
|
|
31
70
|
}
|
|
32
71
|
};
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.LogCollector = void 0;
|
|
8
|
+
var _path = _interopRequireDefault(require("path"));
|
|
9
|
+
var _fileUtils = require("../../../utils/fileUtils");
|
|
10
|
+
// Per-context Playwright runtime event collector — network failures,
|
|
11
|
+
// console errors, page errors and crashes. Buffered in-memory and flushed
|
|
12
|
+
// once per test via writeFileContents.
|
|
13
|
+
|
|
14
|
+
const DEFAULT_CONFIG = {
|
|
15
|
+
maxEvents: 2000,
|
|
16
|
+
maxBodyBytes: 0,
|
|
17
|
+
captureHeaders: false,
|
|
18
|
+
ignoreMessagePatterns: [/n\.enableDarkTheme is not a function/],
|
|
19
|
+
ignoreUrlPatterns: [/\.(png|jpe?g|gif|svg|webp|woff2?|ttf|css|map)(\?|$)/i, /google-analytics\.com|googletagmanager\.com|sentry\.io/i]
|
|
20
|
+
};
|
|
21
|
+
class LogCollector {
|
|
22
|
+
constructor(config = {}) {
|
|
23
|
+
this.config = {
|
|
24
|
+
...DEFAULT_CONFIG,
|
|
25
|
+
...config
|
|
26
|
+
};
|
|
27
|
+
this.events = [];
|
|
28
|
+
this.truncated = false;
|
|
29
|
+
this.counts = {
|
|
30
|
+
console: 0,
|
|
31
|
+
consoleError: 0,
|
|
32
|
+
pageError: 0,
|
|
33
|
+
request: 0,
|
|
34
|
+
response: 0,
|
|
35
|
+
failed: 0,
|
|
36
|
+
crash: 0
|
|
37
|
+
};
|
|
38
|
+
this._bound = [];
|
|
39
|
+
}
|
|
40
|
+
_push(evt) {
|
|
41
|
+
if (this.events.length >= this.config.maxEvents) {
|
|
42
|
+
this.truncated = true;
|
|
43
|
+
this.events.shift();
|
|
44
|
+
}
|
|
45
|
+
this.events.push({
|
|
46
|
+
ts: Date.now(),
|
|
47
|
+
...evt
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
_shouldIgnore(url) {
|
|
51
|
+
return this.config.ignoreUrlPatterns.some(re => re.test(url));
|
|
52
|
+
}
|
|
53
|
+
_shouldIgnoreMessage(message) {
|
|
54
|
+
if (!message) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
return this.config.ignoreMessagePatterns.some(re => re.test(message));
|
|
58
|
+
}
|
|
59
|
+
_bind(target, event, handler) {
|
|
60
|
+
target.on(event, handler);
|
|
61
|
+
this._bound.push([target, event, handler]);
|
|
62
|
+
}
|
|
63
|
+
attachToContext(context) {
|
|
64
|
+
context.pages().forEach(p => this._attachPage(p));
|
|
65
|
+
this._bind(context, 'page', p => this._attachPage(p));
|
|
66
|
+
this._bind(context, 'request', req => {
|
|
67
|
+
if (this._shouldIgnore(req.url())) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
this.counts.request++;
|
|
71
|
+
});
|
|
72
|
+
this._bind(context, 'response', res => {
|
|
73
|
+
const url = res.url();
|
|
74
|
+
if (this._shouldIgnore(url)) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
this.counts.response++;
|
|
78
|
+
if (res.status() >= 400) {
|
|
79
|
+
this._push({
|
|
80
|
+
kind: 'response',
|
|
81
|
+
status: res.status(),
|
|
82
|
+
method: res.request().method(),
|
|
83
|
+
url,
|
|
84
|
+
fromCache: res.fromServiceWorker()
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
this._bind(context, 'requestfailed', req => {
|
|
89
|
+
var _req$failure;
|
|
90
|
+
this.counts.failed++;
|
|
91
|
+
this._push({
|
|
92
|
+
kind: 'requestfailed',
|
|
93
|
+
method: req.method(),
|
|
94
|
+
url: req.url(),
|
|
95
|
+
failure: (_req$failure = req.failure()) === null || _req$failure === void 0 ? void 0 : _req$failure.errorText,
|
|
96
|
+
resourceType: req.resourceType()
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
_attachPage(page) {
|
|
101
|
+
this._bind(page, 'console', msg => {
|
|
102
|
+
const type = msg.type();
|
|
103
|
+
this.counts.console++;
|
|
104
|
+
if (type !== 'error') {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const text = msg.text();
|
|
108
|
+
if (this._shouldIgnoreMessage(text)) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
this.counts.consoleError++;
|
|
112
|
+
this._push({
|
|
113
|
+
kind: 'console',
|
|
114
|
+
level: type,
|
|
115
|
+
text,
|
|
116
|
+
location: msg.location()
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
this._bind(page, 'pageerror', err => {
|
|
120
|
+
if (this._shouldIgnoreMessage(err.message)) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
this.counts.pageError++;
|
|
124
|
+
this._push({
|
|
125
|
+
kind: 'pageerror',
|
|
126
|
+
name: err.name,
|
|
127
|
+
message: err.message,
|
|
128
|
+
stack: err.stack
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
this._bind(page, 'crash', () => {
|
|
132
|
+
this.counts.crash++;
|
|
133
|
+
this._push({
|
|
134
|
+
kind: 'crash',
|
|
135
|
+
url: page.url()
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
detach() {
|
|
140
|
+
for (const [target, event, handler] of this._bound) {
|
|
141
|
+
try {
|
|
142
|
+
target.removeListener(event, handler);
|
|
143
|
+
} catch {
|
|
144
|
+
// context may already be closed
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
this._bound.length = 0;
|
|
148
|
+
}
|
|
149
|
+
toSummary() {
|
|
150
|
+
return {
|
|
151
|
+
...this.counts,
|
|
152
|
+
total: this.events.length,
|
|
153
|
+
truncated: this.truncated
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
flushToFile(dir, baseName) {
|
|
157
|
+
if (this.events.length === 0) {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
const file = _path.default.join(dir, `${baseName}.jsonl`);
|
|
161
|
+
const body = this.events.map(e => JSON.stringify(e)).join('\n') + '\n';
|
|
162
|
+
(0, _fileUtils.writeFileContents)(file, body);
|
|
163
|
+
this.events.length = 0;
|
|
164
|
+
return file;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
exports.LogCollector = LogCollector;
|
|
@@ -56,7 +56,11 @@ function getDefaultConfig() {
|
|
|
56
56
|
featureFilesFolder: 'feature-files',
|
|
57
57
|
stepDefinitionsFolder: 'steps',
|
|
58
58
|
testSetup: {},
|
|
59
|
-
editionOrder: ['Free', 'Express', 'Standard', 'Professional', 'Enterprise']
|
|
59
|
+
editionOrder: ['Free', 'Express', 'Standard', 'Professional', 'Enterprise'],
|
|
60
|
+
showCaseTimings: false,
|
|
61
|
+
browserLogs: {
|
|
62
|
+
mode: 'failure-only'
|
|
63
|
+
}
|
|
60
64
|
};
|
|
61
65
|
}
|
|
62
66
|
function combineDefaultConfigWithUserConfig(userConfiguration) {
|
|
@@ -115,6 +119,8 @@ function combineDefaultConfigWithUserConfig(userConfiguration) {
|
|
|
115
119
|
* @property {string} testIdAttribute: Change the default data-testid attribute. configure what attribute to search while calling getByTestId
|
|
116
120
|
* @property {Array} editionOrder: Order in the form of larger editions in the back. Edition with the most privelages should be last
|
|
117
121
|
* @property {testSetupConfig} testSetup: Specify page and context functions that will be called while intilaizing fixtures.
|
|
122
|
+
* @property {boolean} showCaseTimings: When true, the console reporter prints per-case start/end wall-clock times (h:mm:ss AM/PM) and a case-timings.json sidecar is written to reportPath for the HTML report addon. Default: true.
|
|
123
|
+
* @property {Object} browserLogs: Runtime browser log capture. { mode: 'failure-only' | 'always', limits?: { maxEvents, captureHeaders, ignoreUrlPatterns, ignoreMessagePatterns } }. ignoreMessagePatterns is a list of RegExp matched against console-error text and pageerror messages; matching events are skipped. Default: { mode: 'failure-only' }.
|
|
118
124
|
*/
|
|
119
125
|
|
|
120
126
|
/**
|
|
@@ -24,6 +24,22 @@ function getProjectName(test) {
|
|
|
24
24
|
}
|
|
25
25
|
return '';
|
|
26
26
|
}
|
|
27
|
+
function formatTime(date) {
|
|
28
|
+
return date.toLocaleTimeString('en-US', {
|
|
29
|
+
hour: 'numeric',
|
|
30
|
+
minute: '2-digit',
|
|
31
|
+
second: '2-digit',
|
|
32
|
+
hour12: true
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
function formatDuration(ms) {
|
|
36
|
+
if (ms < 1000) return `${ms}ms`;
|
|
37
|
+
const totalSeconds = ms / 1000;
|
|
38
|
+
if (totalSeconds < 60) return `${totalSeconds.toFixed(2)}s`;
|
|
39
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
40
|
+
const seconds = (totalSeconds - minutes * 60).toFixed(2);
|
|
41
|
+
return `${minutes}m ${seconds}s`;
|
|
42
|
+
}
|
|
27
43
|
class JSONSummaryReporter {
|
|
28
44
|
constructor() {
|
|
29
45
|
this.durationInMS = -1;
|
|
@@ -38,12 +54,23 @@ class JSONSummaryReporter {
|
|
|
38
54
|
this.failedSteps = [];
|
|
39
55
|
this.status = 'unknown';
|
|
40
56
|
this.startedAt = 0;
|
|
41
|
-
|
|
57
|
+
const config = (0, _readConfigFile.generateConfigFromFile)();
|
|
58
|
+
this._open = config.openReportOn;
|
|
59
|
+
this._showCaseTimings = config.showCaseTimings !== false;
|
|
60
|
+
this._caseTimings = [];
|
|
42
61
|
this.failedProject = null;
|
|
43
62
|
}
|
|
44
63
|
onBegin() {
|
|
45
64
|
this.startedAt = Date.now();
|
|
46
65
|
}
|
|
66
|
+
onTestBegin(test) {
|
|
67
|
+
if (!this._showCaseTimings) return;
|
|
68
|
+
const {
|
|
69
|
+
fullTitle
|
|
70
|
+
} = this.getTitle(test);
|
|
71
|
+
const startedAtLabel = formatTime(new Date());
|
|
72
|
+
_logger.Logger.log(_logger.Logger.INFO_TYPE, `▶ ${fullTitle} — started at ${startedAtLabel}`);
|
|
73
|
+
}
|
|
47
74
|
getTitle(test) {
|
|
48
75
|
const title = [];
|
|
49
76
|
const fileName = [];
|
|
@@ -89,6 +116,55 @@ class JSONSummaryReporter {
|
|
|
89
116
|
this[status].push(fileName);
|
|
90
117
|
}
|
|
91
118
|
this[status].push(fileName);
|
|
119
|
+
if (this._showCaseTimings && result.startTime) {
|
|
120
|
+
const startDate = new Date(result.startTime);
|
|
121
|
+
const endDate = new Date(startDate.getTime() + (result.duration || 0));
|
|
122
|
+
const startLabel = formatTime(startDate);
|
|
123
|
+
const endLabel = formatTime(endDate);
|
|
124
|
+
const durationLabel = formatDuration(result.duration || 0);
|
|
125
|
+
const statusGlyph = result.status === 'passed' ? '✓' : result.status === 'skipped' ? '○' : '✗';
|
|
126
|
+
const logType = result.status === 'passed' ? _logger.Logger.SUCCESS_TYPE : result.status === 'skipped' ? _logger.Logger.INFO_TYPE : _logger.Logger.FAILURE_TYPE;
|
|
127
|
+
_logger.Logger.log(logType, `${statusGlyph} ${fullTitle} — ended at ${endLabel} (started ${startLabel}, took ${durationLabel})`);
|
|
128
|
+
const isFailure = result.status !== 'passed' && result.status !== 'skipped';
|
|
129
|
+
if (isFailure) {
|
|
130
|
+
var _result$error;
|
|
131
|
+
const runtimeAttachment = (result.attachments || []).find(a => a.name === 'runtime-log' && a.body);
|
|
132
|
+
let runtime = null;
|
|
133
|
+
if (runtimeAttachment) {
|
|
134
|
+
try {
|
|
135
|
+
runtime = JSON.parse(runtimeAttachment.body.toString('utf8'));
|
|
136
|
+
} catch {
|
|
137
|
+
// malformed attachment; skip
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
this._caseTimings.push({
|
|
141
|
+
title: fullTitle,
|
|
142
|
+
fileName,
|
|
143
|
+
status: result.status,
|
|
144
|
+
retry: result.retry,
|
|
145
|
+
startTime: startDate.toISOString(),
|
|
146
|
+
endTime: endDate.toISOString(),
|
|
147
|
+
startTimeFormatted: startLabel,
|
|
148
|
+
endTimeFormatted: endLabel,
|
|
149
|
+
duration: result.duration || 0,
|
|
150
|
+
durationFormatted: durationLabel,
|
|
151
|
+
errorMessage: (_result$error = result.error) === null || _result$error === void 0 ? void 0 : _result$error.message,
|
|
152
|
+
failedSteps: (result.steps || []).filter(step => step.error).map(step => {
|
|
153
|
+
var _step$error;
|
|
154
|
+
return {
|
|
155
|
+
title: step.title,
|
|
156
|
+
error: (_step$error = step.error) === null || _step$error === void 0 ? void 0 : _step$error.message
|
|
157
|
+
};
|
|
158
|
+
}),
|
|
159
|
+
...(runtime ? {
|
|
160
|
+
runtime: {
|
|
161
|
+
summary: runtime.summary,
|
|
162
|
+
logFile: runtime.file
|
|
163
|
+
}
|
|
164
|
+
} : {})
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
}
|
|
92
168
|
const isFailure = result.status !== 'passed' && result.status !== 'skipped';
|
|
93
169
|
if (isFailure && !this.failedProject) {
|
|
94
170
|
const projectName = getProjectName(test);
|
|
@@ -145,6 +221,16 @@ class JSONSummaryReporter {
|
|
|
145
221
|
reportPath
|
|
146
222
|
} = (0, _readConfigFile.generateConfigFromFile)();
|
|
147
223
|
(0, _fileUtils.writeFileContents)(_path.default.join(reportPath, './', (0, _configFileNameProvider.getReportFileName)()), JSON.stringify(this, null, ' '));
|
|
224
|
+
if (this._showCaseTimings && this._caseTimings.length > 0) {
|
|
225
|
+
const timingsPayload = {
|
|
226
|
+
suiteStartedAt: new Date(this.startedAt).toISOString(),
|
|
227
|
+
suiteEndedAt: new Date(this.startedAt + this.durationInMS).toISOString(),
|
|
228
|
+
suiteDurationMs: this.durationInMS,
|
|
229
|
+
failedCount: this._caseTimings.length,
|
|
230
|
+
cases: this._caseTimings
|
|
231
|
+
};
|
|
232
|
+
(0, _fileUtils.writeFileContents)(_path.default.join(reportPath, 'case-timings.json'), JSON.stringify(timingsPayload, null, ' '));
|
|
233
|
+
}
|
|
148
234
|
}
|
|
149
235
|
onExit() {
|
|
150
236
|
// Update .last-run.json with aborted tests due to timing out or interruption
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zohodesk/testinglibrary",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.10",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@zohodesk/testinglibrary",
|
|
9
|
-
"version": "4.1.
|
|
9
|
+
"version": "4.1.10",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "ISC",
|
|
12
12
|
"dependencies": {
|
|
@@ -5518,9 +5518,9 @@
|
|
|
5518
5518
|
}
|
|
5519
5519
|
},
|
|
5520
5520
|
"node_modules/baseline-browser-mapping": {
|
|
5521
|
-
"version": "2.10.
|
|
5522
|
-
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.
|
|
5523
|
-
"integrity": "sha512-
|
|
5521
|
+
"version": "2.10.42",
|
|
5522
|
+
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.42.tgz",
|
|
5523
|
+
"integrity": "sha512-c/jurFrDLyui7o1J86yLkRu4LMsTYcBohveus7/I2Hzdn9KIP2bdJPTue/lR1KH46enoPbD77GKeSYNdyPoD3Q==",
|
|
5524
5524
|
"license": "Apache-2.0",
|
|
5525
5525
|
"bin": {
|
|
5526
5526
|
"baseline-browser-mapping": "dist/cli.cjs"
|
|
@@ -5695,9 +5695,9 @@
|
|
|
5695
5695
|
}
|
|
5696
5696
|
},
|
|
5697
5697
|
"node_modules/caniuse-lite": {
|
|
5698
|
-
"version": "1.0.
|
|
5699
|
-
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.
|
|
5700
|
-
"integrity": "sha512-
|
|
5698
|
+
"version": "1.0.30001802",
|
|
5699
|
+
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001802.tgz",
|
|
5700
|
+
"integrity": "sha512-vmv8ub2xwTNmljSKf82mtCk5JH7hC+YgzLj3P5zotvA0tPQ9016tdNNOG8WRca1IxOnhSsivB+J0z5FeE5LOUw==",
|
|
5701
5701
|
"funding": [
|
|
5702
5702
|
{
|
|
5703
5703
|
"type": "opencollective",
|
|
@@ -6996,9 +6996,9 @@
|
|
|
6996
6996
|
}
|
|
6997
6997
|
},
|
|
6998
6998
|
"node_modules/electron-to-chromium": {
|
|
6999
|
-
"version": "1.5.
|
|
7000
|
-
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.
|
|
7001
|
-
"integrity": "sha512-
|
|
6999
|
+
"version": "1.5.387",
|
|
7000
|
+
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.387.tgz",
|
|
7001
|
+
"integrity": "sha512-TaxwufTFDufvPEoXdhwVrA3UdFWBeWGkYoJ1K8ldF1xe6gKfth6iRNS5lTQ5JPNOHdGQm8PT1QYKUqFLCiUefQ==",
|
|
7002
7002
|
"license": "ISC"
|
|
7003
7003
|
},
|
|
7004
7004
|
"node_modules/emittery": {
|
|
@@ -10932,9 +10932,9 @@
|
|
|
10932
10932
|
}
|
|
10933
10933
|
},
|
|
10934
10934
|
"node_modules/jest-util/node_modules/picomatch": {
|
|
10935
|
-
"version": "4.0.
|
|
10936
|
-
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.
|
|
10937
|
-
"integrity": "sha512-
|
|
10935
|
+
"version": "4.0.5",
|
|
10936
|
+
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz",
|
|
10937
|
+
"integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==",
|
|
10938
10938
|
"license": "MIT",
|
|
10939
10939
|
"engines": {
|
|
10940
10940
|
"node": ">=12"
|
|
@@ -12385,21 +12385,21 @@
|
|
|
12385
12385
|
}
|
|
12386
12386
|
},
|
|
12387
12387
|
"node_modules/msw/node_modules/tldts": {
|
|
12388
|
-
"version": "7.4.
|
|
12389
|
-
"resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.
|
|
12390
|
-
"integrity": "sha512-
|
|
12388
|
+
"version": "7.4.6",
|
|
12389
|
+
"resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.6.tgz",
|
|
12390
|
+
"integrity": "sha512-rbP0Gyx8b3Ae9yO//CU2wbSnQNoQ66m1nJdSbSHmnwKwzkkz/u8mERYU8T2rmlmy+bJvRNn84yNCW8gYqox44Q==",
|
|
12391
12391
|
"license": "MIT",
|
|
12392
12392
|
"dependencies": {
|
|
12393
|
-
"tldts-core": "^7.4.
|
|
12393
|
+
"tldts-core": "^7.4.6"
|
|
12394
12394
|
},
|
|
12395
12395
|
"bin": {
|
|
12396
12396
|
"tldts": "bin/cli.js"
|
|
12397
12397
|
}
|
|
12398
12398
|
},
|
|
12399
12399
|
"node_modules/msw/node_modules/tldts-core": {
|
|
12400
|
-
"version": "7.4.
|
|
12401
|
-
"resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.
|
|
12402
|
-
"integrity": "sha512-
|
|
12400
|
+
"version": "7.4.6",
|
|
12401
|
+
"resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.6.tgz",
|
|
12402
|
+
"integrity": "sha512-TkQNGJIhlEphpHCjKodMTSe23egUZr/g+flI2qkLgiJ/maAzSgXypSLRTNH3nCmqgayEmtcJBiLcfODSAr1xoA==",
|
|
12403
12403
|
"license": "MIT"
|
|
12404
12404
|
},
|
|
12405
12405
|
"node_modules/msw/node_modules/tough-cookie": {
|
package/package.json
CHANGED
|
@@ -274,4 +274,4 @@ header {
|
|
|
274
274
|
font-size: 1rem;
|
|
275
275
|
padding: 0 0.5rem;
|
|
276
276
|
}
|
|
277
|
-
</style></head><body><main class="jesthtml-content"><header><h1 id="title">Unit Report</h1></header><section id="metadata-container"><div id="timestamp">Started: 2026-07-01 12:44:59</div><div id="summary"><div id="suite-summary"><div class="summary-total">Suites (2)</div><div class="summary-passed ">2 passed</div><div class="summary-failed summary-empty">0 failed</div><div class="summary-pending summary-empty">0 pending</div></div><div id="test-summary"><div class="summary-total">Tests (31)</div><div class="summary-passed ">31 passed</div><div class="summary-failed summary-empty">0 failed</div><div class="summary-pending summary-empty">0 pending</div></div></div></section><details id="suite-1" class="suite-container" open=""><summary class="suite-info"><div class="suite-path">/Users/muthu-19817/git/testing-framework/src/test/core/playwright/helpers/__tests__/failureTagClassifier.test.js</div><div class="suite-time">0.493s</div></summary><div class="suite-tests"><div class="test-result passed"><div class="test-info"><div class="test-suitename">classifyFailureTags</div><div class="test-title">returns flaky and skips log analysis for flaky outcome</div><div class="test-status">passed</div><div class="test-duration">0.001s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">classifyFailureTags</div><div class="test-title">tags environment when a document abort is present</div><div class="test-status">passed</div><div class="test-duration">0.001s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">classifyFailureTags</div><div class="test-title">tags environment for a network/cert failure</div><div class="test-status">passed</div><div class="test-duration">0.001s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">classifyFailureTags</div><div class="test-title">tags code when an app undefined-property error is present</div><div class="test-status">passed</div><div class="test-duration">0.001s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">classifyFailureTags</div><div class="test-title">does not tag a non-document (xhr) abort as environment</div><div class="test-status">passed</div><div class="test-duration">0.001s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">classifyFailureTags</div><div class="test-title">tags tool when stderr reports a DATA_GENERATION_ERROR</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">classifyFailureTags</div><div class="test-title">tags tool for an "Error Type:" line in base64 stdout</div><div class="test-status">passed</div><div class="test-duration">0.001s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">classifyFailureTags</div><div class="test-title">does not tag tool for benign stdout/stderr</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">classifyFailureTags</div><div class="test-title">does not throw for malformed stdio chunk entries</div><div class="test-status">passed</div><div class="test-duration">0.001s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">classifyFailureTags</div><div class="test-title">leaves untagged when no environment or code pattern is present</div><div class="test-status">passed</div><div class="test-duration">0.001s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">mergeFailureTags</div><div class="test-title">places prefixed failure tags first, then existing tags</div><div class="test-status">passed</div><div class="test-duration">0.001s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">mergeFailureTags</div><div class="test-title">does not duplicate an already-present failure tag</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">regex safety</div><div class="test-title">resets stateful regex for tool pattern checks</div><div class="test-status">passed</div><div class="test-duration">0.001s</div></div></div></div></details><details id="suite-2" class="suite-container" open=""><summary class="suite-info"><div class="suite-path">/Users/muthu-19817/git/testing-framework/src/test/core/playwright/helpers/__tests__/runtimeLogNaming.test.js</div><div class="suite-time">0.089s</div></summary><div class="suite-tests"><div class="test-result passed"><div class="test-info"><div class="test-suitename">sanitizeForFilename</div><div class="test-title">replaces unsafe characters with dashes</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">sanitizeForFilename</div><div class="test-title">returns test for empty input</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">extractScenarioName</div><div class="test-title">extracts name from Scenario Outline segment</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">extractScenarioName</div><div class="test-title">extracts name from Scenario segment</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">extractScenarioName</div><div class="test-title">returns null when no scenario segment exists</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">isGenericExampleTitle</div><div class="test-title">matches generic example title</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">isGenericExampleTitle</div><div class="test-title">does not match numbered or regular titles</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">resolveRowKey</div><div class="test-title">uses Example #N from title when present</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">resolveRowKey</div><div class="test-title">uses parallelIndex when title is generic</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">resolveRowKey</div><div class="test-title">falls back to testId suffix</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">resolveRowKey</div><div class="test-title">falls back to 0 when no row key is available</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">resolveRuntimeLogBaseName</div><div class="test-title">uses test title for regular scenarios</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">resolveRuntimeLogBaseName</div><div class="test-title">uses scenario prefix and parallelIndex for example row 1</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">resolveRuntimeLogBaseName</div><div class="test-title">uses scenario prefix and parallelIndex for example row 2</div><div class="test-status">passed</div><div class="test-duration">0.001s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">resolveRuntimeLogBaseName</div><div class="test-title">differentiates two outlines with the same example title</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">resolveRuntimeLogBaseName</div><div class="test-title">truncates long scenario names while keeping worker and retry suffix</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">resolveRuntimeLogBaseName</div><div class="test-title">falls back to scenario-0 when outline title has no scenario segment</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">resolveRuntimeLogBaseName</div><div class="test-title">produces unique names for all example rows in SetupHomePageSearch</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div></div></details></main></body></html>
|
|
277
|
+
</style></head><body><main class="jesthtml-content"><header><h1 id="title">Unit Report</h1></header><section id="metadata-container"><div id="timestamp">Started: 2026-07-05 14:02:44</div><div id="summary"><div id="suite-summary"><div class="summary-total">Suites (3)</div><div class="summary-passed ">3 passed</div><div class="summary-failed summary-empty">0 failed</div><div class="summary-pending summary-empty">0 pending</div></div><div id="test-summary"><div class="summary-total">Tests (41)</div><div class="summary-passed ">41 passed</div><div class="summary-failed summary-empty">0 failed</div><div class="summary-pending summary-empty">0 pending</div></div></div></section><details id="suite-1" class="suite-container" open=""><summary class="suite-info"><div class="suite-path">/Users/muthu-19817/git/testing-framework/src/test/core/playwright/helpers/__tests__/failureTagClassifier.test.js</div><div class="suite-time">0.428s</div></summary><div class="suite-tests"><div class="test-result passed"><div class="test-info"><div class="test-suitename">classifyFailureTags</div><div class="test-title">returns flaky and skips log analysis for flaky outcome</div><div class="test-status">passed</div><div class="test-duration">0.002s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">classifyFailureTags</div><div class="test-title">tags environment when a document abort is present</div><div class="test-status">passed</div><div class="test-duration">0.002s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">classifyFailureTags</div><div class="test-title">tags environment for a network/cert failure</div><div class="test-status">passed</div><div class="test-duration">0.002s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">classifyFailureTags</div><div class="test-title">tags code when an app undefined-property error is present</div><div class="test-status">passed</div><div class="test-duration">0.001s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">classifyFailureTags</div><div class="test-title">does not tag a non-document (xhr) abort as environment</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">classifyFailureTags</div><div class="test-title">tags case and code when stderr reports DATA_GENERATION_ERROR</div><div class="test-status">passed</div><div class="test-duration">0.001s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">classifyFailureTags</div><div class="test-title">tags tool for a known tool pattern in base64 stdout</div><div class="test-status">passed</div><div class="test-duration">0.001s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">classifyFailureTags</div><div class="test-title">tags case and code when stderr matches a case pattern</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">classifyFailureTags</div><div class="test-title">does not tag tool for benign stdout/stderr</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">classifyFailureTags</div><div class="test-title">does not throw for malformed stdio chunk entries</div><div class="test-status">passed</div><div class="test-duration">0.001s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">classifyFailureTags</div><div class="test-title">leaves untagged when no environment or code pattern is present</div><div class="test-status">passed</div><div class="test-duration">0.001s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">classifyFailureDetails</div><div class="test-title">records the matching pattern for environment failures</div><div class="test-status">passed</div><div class="test-duration">0.001s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">classifyFailureDetails</div><div class="test-title">records the matching pattern for code failures from events</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">classifyFailureDetails</div><div class="test-title">records flaky outcome without a regex pattern</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">classifyFailureDetails</div><div class="test-title">records tool pattern from stdio</div><div class="test-status">passed</div><div class="test-duration">0.002s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">classifyFailureDetails</div><div class="test-title">records case pattern from stdio and implies code</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">classifyFailureDetails</div><div class="test-title">keeps runtime-log code match when case also matches</div><div class="test-status">passed</div><div class="test-duration">0.001s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">classifyFailureDetails</div><div class="test-title">implies code from case when no runtime log is present</div><div class="test-status">passed</div><div class="test-duration">0.001s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">failure tag metadata attachment</div><div class="test-title">builds a small JSON attachment when tags are present</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">failure tag metadata attachment</div><div class="test-title">returns null when no tags are present</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">failure tag metadata attachment</div><div class="test-title">replaces an existing metadata attachment</div><div class="test-status">passed</div><div class="test-duration">0.001s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">mergeFailureTags</div><div class="test-title">places suffixed failure tags first, then existing tags</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">mergeFailureTags</div><div class="test-title">emits the flaky category as FLAKY without a suffix</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">mergeFailureTags</div><div class="test-title">does not duplicate an already-present failure tag</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">mergeFailureTags</div><div class="test-title">formats case and code failure tags with suffix</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">regex safety</div><div class="test-title">resets stateful regex for tool pattern checks</div><div class="test-status">passed</div><div class="test-duration">0.001s</div></div></div></div></details><details id="suite-2" class="suite-container" open=""><summary class="suite-info"><div class="suite-path">/Users/muthu-19817/git/testing-framework/src/test/core/playwright/helpers/__tests__/logCollector.test.js</div><div class="suite-time">0.049s</div></summary><div class="suite-tests"><div class="test-result passed"><div class="test-info"><div class="test-suitename">LogCollector baseline-noise stripping</div><div class="test-title">drops ORB-blocked request failures (message pattern)</div><div class="test-status">passed</div><div class="test-duration">0.001s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">LogCollector baseline-noise stripping</div><div class="test-title">drops known noisy third-party URLs (url pattern)</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">LogCollector baseline-noise stripping</div><div class="test-title">drops noisy 4xx responses by URL (e.g. getHamburgerMenu)</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">LogCollector baseline-noise stripping</div><div class="test-title">drops CORS console errors (message pattern)</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">LogCollector baseline-noise stripping</div><div class="test-title">drops baseline pageerrors (Access is denied / enable* not a function)</div><div class="test-status">passed</div><div class="test-duration">0.001s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">LogCollector baseline-noise stripping</div><div class="test-title">keeps a real application pageerror</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">LogCollector baseline-noise stripping</div><div class="test-title">flushes captured events to a jsonl file</div><div class="test-status">passed</div><div class="test-duration">0.001s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">LogCollector baseline-noise stripping</div><div class="test-title">returns null from flushToFile when no events were captured</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">LogCollector baseline-noise stripping</div><div class="test-title">keeps a document-navigation abort (real environment signal)</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div></div></details><details id="suite-3" class="suite-container" open=""><summary class="suite-info"><div class="suite-path">/Users/muthu-19817/git/testing-framework/src/test/core/playwright/helpers/__tests__/runtimeLogReader.test.js</div><div class="suite-time">0.043s</div></summary><div class="suite-tests"><div class="test-result passed"><div class="test-info"><div class="test-suitename">readRuntimeLogEventsForResult</div><div class="test-title">reads project-side runtime log for a failing result</div><div class="test-status">passed</div><div class="test-duration">0.001s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">readRuntimeLogEventsForResult</div><div class="test-title">skips malformed jsonl lines</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">readRuntimeLogEventsForResult</div><div class="test-title">returns an empty array when the runtime log file is missing</div><div class="test-status">passed</div><div class="test-duration">0.001s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">readRuntimeLogEventsForResult</div><div class="test-title">returns an empty array when logsDir is missing</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">readRuntimeLogEvents</div><div class="test-title">reads events from a jsonl file path</div><div class="test-status">passed</div><div class="test-duration">0.001s</div></div></div><div class="test-result passed"><div class="test-info"><div class="test-suitename">readRuntimeLogEvents</div><div class="test-title">returns an empty array for a missing file</div><div class="test-status">passed</div><div class="test-duration"> </div></div></div></div></details></main></body></html>
|