@qualflare/cypress 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -1
- package/dist/index.cjs +38 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -1
- package/dist/plugin/index.cjs +8 -4
- package/dist/plugin/index.cjs.map +1 -1
- package/dist/plugin/index.d.cts +6 -0
- package/dist/plugin/index.d.ts +6 -0
- package/dist/plugin/index.js +8 -4
- package/dist/plugin/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
[](./LICENSE)
|
|
6
6
|
|
|
7
7
|
A native Cypress reporter for [Qualflare](https://qualflare.com) — captures test results directly
|
|
8
|
-
from your Cypress run: suite/test status,
|
|
8
|
+
from your Cypress run: suite/test status, per-attempt retry history, screenshots, step-by-step command
|
|
9
9
|
traces, and author-facing metadata (labels, links, tags, custom attachments) — and writes them into
|
|
10
10
|
a report directory that [`qualflare-cli`](https://github.com/Qualflare/qualflare-cli) uploads. No
|
|
11
11
|
post-hoc file parsing, no intermediate report format to hand-roll, no network access needed from
|
|
@@ -120,6 +120,23 @@ wrong value cannot fail at run time — this package makes no network calls —
|
|
|
120
120
|
CLIs merge as before.
|
|
121
121
|
- **Command-log step nesting is two levels only** (Cypress's own API limit) — `qualflare.step()`
|
|
122
122
|
supports arbitrary nesting depth.
|
|
123
|
+
- **An all-passing spec's video is not captured by default.** Cypress records one video per spec,
|
|
124
|
+
and it is only copied when a case in that spec failed. Set `videoOnFailureOnly: false` to keep a
|
|
125
|
+
green spec's video too; uploading it is separately opt-in via the CLI's `--upload-artifacts`.
|
|
126
|
+
- **Step timing is an approximation** — command-log steps are timed from log events, not from
|
|
127
|
+
instrumented start/stop boundaries. `qualflare.step()` timing is exact.
|
|
128
|
+
- **`parameter()` outside a step is not masked** — `masked` is a display hint for the UI; the
|
|
129
|
+
server never redacts the value, so never put a real secret in one. See
|
|
130
|
+
[`docs/LIMITATIONS.md`](./docs/LIMITATIONS.md#qualflareparameter-outside-a-step-has-no-masking).
|
|
131
|
+
- **Attachment caps are two budgets, not one pool** — `maxAttachmentBytes` bounds a single
|
|
132
|
+
attachment and `maxTotalAttachmentBytes` the whole run; anything over either is dropped
|
|
133
|
+
outright rather than truncated. Raising them is the easiest way to push a request past
|
|
134
|
+
`/collect`'s body limit. See
|
|
135
|
+
[`docs/LIMITATIONS.md`](./docs/LIMITATIONS.md#per-caseper-attachment-caps-are-independent-not-pooled).
|
|
136
|
+
- **Retries carry per-attempt errors, but everything else is the final attempt** — `Case.attempts`
|
|
137
|
+
records each attempt's status, duration and error; steps, labels, links, tags, priority,
|
|
138
|
+
properties and attachments come from the last attempt only, so an abandoned attempt's step trace
|
|
139
|
+
is discarded rather than replayed alongside the final one.
|
|
123
140
|
|
|
124
141
|
Full details in [`docs/LIMITATIONS.md`](./docs/LIMITATIONS.md).
|
|
125
142
|
|
package/dist/index.cjs
CHANGED
|
@@ -45,6 +45,8 @@ var MAX_LABELS_PER_CASE = 100;
|
|
|
45
45
|
var MAX_LINKS_PER_CASE = 20;
|
|
46
46
|
var MAX_TAGS_PER_CASE = 64;
|
|
47
47
|
var MAX_TAG_LENGTH = 255;
|
|
48
|
+
var MAX_ATTEMPTS_PER_CASE = 50;
|
|
49
|
+
var MAX_ATTEMPT_MESSAGE_RUNES = 8192;
|
|
48
50
|
var MAX_VIDEO_UPLOAD_BYTES = 50 * 1024 * 1024;
|
|
49
51
|
var MAX_STEPS_PER_TEST_ATTEMPT = 300;
|
|
50
52
|
|
|
@@ -298,6 +300,18 @@ function registerCommandLogListener(buffer) {
|
|
|
298
300
|
});
|
|
299
301
|
}
|
|
300
302
|
|
|
303
|
+
// src/shared/text.ts
|
|
304
|
+
function truncateRunes(value, maxRunes) {
|
|
305
|
+
if (value.length <= maxRunes) {
|
|
306
|
+
return value;
|
|
307
|
+
}
|
|
308
|
+
const runes = Array.from(value);
|
|
309
|
+
if (runes.length <= maxRunes) {
|
|
310
|
+
return value;
|
|
311
|
+
}
|
|
312
|
+
return runes.slice(0, maxRunes).join("");
|
|
313
|
+
}
|
|
314
|
+
|
|
301
315
|
// src/browser/case-builder.ts
|
|
302
316
|
function combineSteps(autoSteps, manualSteps) {
|
|
303
317
|
const auto = autoSteps ?? [];
|
|
@@ -314,6 +328,26 @@ function combineSteps(autoSteps, manualSteps) {
|
|
|
314
328
|
});
|
|
315
329
|
return [...auto, ...offsetManual];
|
|
316
330
|
}
|
|
331
|
+
function buildAttempts(attempts) {
|
|
332
|
+
if (attempts.length < 2) {
|
|
333
|
+
return void 0;
|
|
334
|
+
}
|
|
335
|
+
let kept = attempts;
|
|
336
|
+
if (attempts.length > MAX_ATTEMPTS_PER_CASE) {
|
|
337
|
+
kept = [...attempts.slice(0, MAX_ATTEMPTS_PER_CASE - 1), attempts[attempts.length - 1]];
|
|
338
|
+
}
|
|
339
|
+
return kept.map((a, i) => {
|
|
340
|
+
const attempt = {
|
|
341
|
+
attempt: i + 1,
|
|
342
|
+
status: a.status,
|
|
343
|
+
duration: msToNs(a.duration)
|
|
344
|
+
};
|
|
345
|
+
if (a.error) {
|
|
346
|
+
attempt.message = truncateRunes(a.error, MAX_ATTEMPT_MESSAGE_RUNES);
|
|
347
|
+
}
|
|
348
|
+
return attempt;
|
|
349
|
+
});
|
|
350
|
+
}
|
|
317
351
|
function collapseAttempts(attempts) {
|
|
318
352
|
if (attempts.length === 0) {
|
|
319
353
|
throw new Error("collapseAttempts: at least one attempt is required");
|
|
@@ -322,11 +356,13 @@ function collapseAttempts(attempts) {
|
|
|
322
356
|
const retryCount = attempts.length - 1;
|
|
323
357
|
const isFlaky = retryCount > 0 && final.status === "passed" && attempts.some((a) => a.status !== "passed");
|
|
324
358
|
const duration = attempts.reduce((sum, a) => sum + a.duration, 0);
|
|
359
|
+
const attemptHistory = buildAttempts(attempts);
|
|
325
360
|
return {
|
|
326
361
|
status: final.status,
|
|
327
362
|
duration,
|
|
328
363
|
retryCount,
|
|
329
364
|
isFlaky,
|
|
365
|
+
...attemptHistory ? { attempts: attemptHistory } : {},
|
|
330
366
|
error: final.status === "passed" ? void 0 : final.error,
|
|
331
367
|
steps: combineSteps(final.steps, final.manualSteps),
|
|
332
368
|
labels: final.labels,
|
|
@@ -353,6 +389,8 @@ function flushCase(test, attempts) {
|
|
|
353
389
|
duration: msToNs(collapsed.duration),
|
|
354
390
|
retryCount: collapsed.retryCount,
|
|
355
391
|
isFlaky: collapsed.isFlaky,
|
|
392
|
+
// Already nanoseconds — collapseAttempts converts, unlike `duration` above.
|
|
393
|
+
attempts: collapsed.attempts,
|
|
356
394
|
error: collapsed.error,
|
|
357
395
|
steps: collapsed.steps,
|
|
358
396
|
// qualflare.* author-facing metadata API calls (labels/links/tags/
|