@fixsense/cypress-plugin 0.2.0 → 0.2.1

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/dist/local.d.ts CHANGED
@@ -43,6 +43,10 @@ export declare const MAX_RUNS = 50;
43
43
  export declare const MIN_RUNS_FOR_VERDICT = 5;
44
44
  /** At or above this score a test is called flaky. */
45
45
  export declare const FLAKY_SCORE_THRESHOLD = 70;
46
+ /** Runs the runner itself called flaky before that alone is a verdict. */
47
+ export declare const MIN_FLAKY_RUNS = 2;
48
+ /** And how often, so a long-settled test is not judged on old history. */
49
+ export declare const MIN_FLAKY_RATE = 0.2;
46
50
  export type Verdict = "stable" | "broken" | "flaky" | "suspect";
47
51
  export interface FlakinessReport {
48
52
  score: number;
@@ -103,6 +107,15 @@ export declare function renderMarkdown(verdicts: TestVerdict[], totalRuns: numbe
103
107
  * page it is the first thing a reviewer sees.
104
108
  */
105
109
  export declare function writeStepSummary(markdown: string): void;
110
+ /**
111
+ * One entry per test per run, whatever the runner reported.
112
+ *
113
+ * A run that listed the same test twice would count as two runs for it, and
114
+ * a retried test would read as several times as flaky as it is. The last
115
+ * entry wins: for a runner that reports each attempt, it is the one that
116
+ * knows how the test finally ended.
117
+ */
118
+ export declare function dedupe(tests: StoredTest[]): StoredTest[];
106
119
  /**
107
120
  * Record this run and report what the history now says.
108
121
  *
package/dist/local.js CHANGED
@@ -18,7 +18,7 @@
18
18
  * asserts the two copies are the same file, so they cannot drift.
19
19
  */
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
- exports.FLAKY_SCORE_THRESHOLD = exports.MIN_RUNS_FOR_VERDICT = exports.MAX_RUNS = exports.HISTORY_FILE = exports.HISTORY_DIR = void 0;
21
+ exports.MIN_FLAKY_RATE = exports.MIN_FLAKY_RUNS = exports.FLAKY_SCORE_THRESHOLD = exports.MIN_RUNS_FOR_VERDICT = exports.MAX_RUNS = exports.HISTORY_FILE = exports.HISTORY_DIR = void 0;
22
22
  exports.countTransitions = countTransitions;
23
23
  exports.computeFlakiness = computeFlakiness;
24
24
  exports.historyPath = historyPath;
@@ -30,6 +30,7 @@ exports.scoreHistory = scoreHistory;
30
30
  exports.renderSummary = renderSummary;
31
31
  exports.renderMarkdown = renderMarkdown;
32
32
  exports.writeStepSummary = writeStepSummary;
33
+ exports.dedupe = dedupe;
33
34
  exports.recordAndReport = recordAndReport;
34
35
  const fs_1 = require("fs");
35
36
  const path_1 = require("path");
@@ -46,6 +47,10 @@ exports.MAX_RUNS = 50;
46
47
  exports.MIN_RUNS_FOR_VERDICT = 5;
47
48
  /** At or above this score a test is called flaky. */
48
49
  exports.FLAKY_SCORE_THRESHOLD = 70;
50
+ /** Runs the runner itself called flaky before that alone is a verdict. */
51
+ exports.MIN_FLAKY_RUNS = 2;
52
+ /** And how often, so a long-settled test is not judged on old history. */
53
+ exports.MIN_FLAKY_RATE = 0.2;
49
54
  function toPassFail(outcome) {
50
55
  if (outcome === "skipped")
51
56
  return null;
@@ -88,12 +93,19 @@ function computeFlakiness(history) {
88
93
  const selfReportedFlakyRate = selfReportedFlaky / history.length;
89
94
  const transitions = countTransitions(sequence);
90
95
  const transitionRate = runs > 1 ? transitions / (runs - 1) : 0;
96
+ // The score says how bad; this says whether we are sure. A run the runner
97
+ // itself called flaky is direct evidence — the test failed and then passed
98
+ // inside one run, which nothing but flakiness explains. A test that did
99
+ // that in a fifth of its runs is flaky even though the score, weighted to
100
+ // rank the worst offenders first, leaves it below the threshold. Two such
101
+ // runs are required so a single retry on a bad afternoon is not a verdict.
102
+ const isDirectlyEvidencedFlaky = selfReportedFlaky >= exports.MIN_FLAKY_RUNS && selfReportedFlakyRate >= exports.MIN_FLAKY_RATE;
91
103
  const score = Math.round(Math.min(100, selfReportedFlakyRate * 100 * 0.75 + transitionRate * 100 * 0.25));
92
104
  let verdict;
93
105
  if (runs < exports.MIN_RUNS_FOR_VERDICT) {
94
106
  verdict = score > 0 ? "suspect" : "stable";
95
107
  }
96
- else if (score >= exports.FLAKY_SCORE_THRESHOLD) {
108
+ else if (score >= exports.FLAKY_SCORE_THRESHOLD || isDirectlyEvidencedFlaky) {
97
109
  verdict = "flaky";
98
110
  }
99
111
  else if (failureRate >= 0.9 && transitionRate <= 0.1 && selfReportedFlakyRate <= 0.1) {
@@ -257,6 +269,25 @@ function writeStepSummary(markdown) {
257
269
  // The step summary is a nicety; losing it is not worth a word.
258
270
  }
259
271
  }
272
+ /**
273
+ * One entry per test per run, whatever the runner reported.
274
+ *
275
+ * A run that listed the same test twice would count as two runs for it, and
276
+ * a retried test would read as several times as flaky as it is. The last
277
+ * entry wins: for a runner that reports each attempt, it is the one that
278
+ * knows how the test finally ended.
279
+ */
280
+ function dedupe(tests) {
281
+ const byKey = new Map();
282
+ for (const t of tests) {
283
+ byKey.set(`${t.file ?? ""}\u0000${t.title}`, {
284
+ title: t.title,
285
+ file: t.file,
286
+ outcome: t.outcome,
287
+ });
288
+ }
289
+ return [...byKey.values()];
290
+ }
260
291
  /**
261
292
  * Record this run and report what the history now says.
262
293
  *
@@ -265,7 +296,7 @@ function writeStepSummary(markdown) {
265
296
  function recordAndReport(cwd, tests, now = new Date()) {
266
297
  const history = appendRun(readHistory(cwd), {
267
298
  at: now.toISOString(),
268
- tests: tests.map((t) => ({ title: t.title, file: t.file, outcome: t.outcome })),
299
+ tests: dedupe(tests),
269
300
  });
270
301
  writeHistory(cwd, history);
271
302
  const verdicts = scoreHistory(history);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fixsense/cypress-plugin",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Cypress plugin that records test outcomes across runs so flaky tests can be identified over time.",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",