qa-core-flaky 0.0.0-stage → 0.1.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/CHANGELOG.md +16 -0
- package/LICENSE +21 -0
- package/README.md +104 -2
- package/dist/causes/environment.d.ts +7 -0
- package/dist/causes/environment.js +31 -0
- package/dist/causes/index.d.ts +12 -0
- package/dist/causes/index.js +491 -0
- package/dist/causes/selectors.d.ts +8 -0
- package/dist/causes/selectors.js +64 -0
- package/dist/causes/test-data.d.ts +24 -0
- package/dist/causes/test-data.js +44 -0
- package/dist/causes/text.d.ts +11 -0
- package/dist/causes/text.js +48 -0
- package/dist/causes/timing.d.ts +17 -0
- package/dist/causes/timing.js +119 -0
- package/dist/causes/types.d.ts +51 -0
- package/dist/causes/types.js +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +809 -0
- package/dist/fixes/templates.d.ts +7 -0
- package/dist/fixes/templates.js +40 -0
- package/dist/heal/client.d.ts +42 -0
- package/dist/heal/client.js +470 -0
- package/dist/heal/findings-guard.d.ts +12 -0
- package/dist/heal/findings-guard.js +75 -0
- package/dist/heal/findings.d.ts +118 -0
- package/dist/heal/findings.js +452 -0
- package/dist/heal/handoff.d.ts +32 -0
- package/dist/heal/handoff.js +83 -0
- package/dist/heal/patch-write.d.ts +27 -0
- package/dist/heal/patch-write.js +167 -0
- package/dist/heal/patch.d.ts +44 -0
- package/dist/heal/patch.js +98 -0
- package/dist/heal/proposal.d.ts +41 -0
- package/dist/heal/proposal.js +305 -0
- package/dist/heal/redact.d.ts +25 -0
- package/dist/heal/redact.js +221 -0
- package/dist/heal/run.d.ts +43 -0
- package/dist/heal/run.js +207 -0
- package/dist/heal/selector.d.ts +7 -0
- package/dist/heal/selector.js +94 -0
- package/dist/id.d.ts +18 -0
- package/dist/id.js +64 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.js +30 -0
- package/dist/model.d.ts +128 -0
- package/dist/model.js +1 -0
- package/dist/parsers/detect.d.ts +14 -0
- package/dist/parsers/detect.js +97 -0
- package/dist/parsers/junit.d.ts +13 -0
- package/dist/parsers/junit.js +561 -0
- package/dist/parsers/playwright-json.d.ts +10 -0
- package/dist/parsers/playwright-json.js +330 -0
- package/dist/redact.d.ts +9 -0
- package/dist/redact.js +47 -0
- package/dist/report/html-template.d.ts +7 -0
- package/dist/report/html-template.js +473 -0
- package/dist/report/html.d.ts +20 -0
- package/dist/report/html.js +537 -0
- package/dist/report/json.d.ts +31 -0
- package/dist/report/json.js +241 -0
- package/dist/report/markdown.d.ts +7 -0
- package/dist/report/markdown.js +156 -0
- package/dist/report/pair.d.ts +17 -0
- package/dist/report/pair.js +77 -0
- package/dist/report/schema.d.ts +167 -0
- package/dist/report/schema.js +1 -0
- package/dist/report-path.d.ts +177 -0
- package/dist/report-path.js +1583 -0
- package/dist/rerun/merge.d.ts +11 -0
- package/dist/rerun/merge.js +55 -0
- package/dist/rerun/plan.d.ts +142 -0
- package/dist/rerun/plan.js +378 -0
- package/dist/rerun/quote.d.ts +4 -0
- package/dist/rerun/quote.js +8 -0
- package/dist/rerun/run.d.ts +94 -0
- package/dist/rerun/run.js +749 -0
- package/dist/signals/order.d.ts +11 -0
- package/dist/signals/order.js +52 -0
- package/dist/signature.d.ts +28 -0
- package/dist/signature.js +167 -0
- package/dist/verdict.d.ts +60 -0
- package/dist/verdict.js +422 -0
- package/package.json +66 -4
- package/schemas/heal-findings.v1.schema.json +421 -0
- package/schemas/heal-proposal.v1.schema.json +110 -0
- package/schemas/heal-results.v1.schema.json +502 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 - 2026-10-29
|
|
4
|
+
|
|
5
|
+
First public release.
|
|
6
|
+
|
|
7
|
+
- Normalize a Playwright JSON report into one record per test, and keep every retry attempt.
|
|
8
|
+
- Parse a JUnit XML report. The format is detected from the file contents.
|
|
9
|
+
- Name a likely cause for each failed or flaky test, with evidence quoted from the error text.
|
|
10
|
+
- Write a triage report as JSON and Markdown. Each row has a verdict, a suggested fix, and a next step.
|
|
11
|
+
- Rerun failing tests with Playwright in `repeat`, `isolated`, and `in-order` modes, then merge the new attempts. This needs `@playwright/test` in the project under test.
|
|
12
|
+
- Write a self-contained HTML report with `--html`.
|
|
13
|
+
- Write a heal findings file with `--heal-findings`.
|
|
14
|
+
- Ask qa-core-heal for a dry run with `--heal` and store the proposal. qa-core-heal 0.4.0 or later can return a re-run-verified fix. qa-core-heal 0.3.x uses the older dry-run mode.
|
|
15
|
+
- Include a seeded SauceDemo demo in the repository.
|
|
16
|
+
- Import the parsers, cause rules, and report builders from `qa-core-flaky` in Node. The package sets `main` and `types` for this.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 SprintSynergy
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,105 @@
|
|
|
1
|
-
#
|
|
1
|
+
# qa-core-flaky
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
qa-core-flaky triages flaky Playwright tests. It separates a likely real bug from an unstable test, names the likely cause, and suggests a fix for an engineer to review. It reads a Playwright JSON report or a JUnit XML report and prints one normalized record per test. It also names a likely cause for each failed or flaky test, with the evidence quoted from the error text. The JSON parser keeps every retry attempt. The JUnit parser keeps one attempt per test, because Playwright's default JUnit report does not list retries separately.
|
|
4
|
+
|
|
5
|
+
## Status
|
|
6
|
+
|
|
7
|
+
Version 0.1.0. The commands are `parse`, `causes`, `triage`, and `rerun`.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
Node.js 22.6 or later is required.
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
npm i -D qa-core-flaky
|
|
15
|
+
npx qa-core-flaky --help
|
|
16
|
+
npx qa-core-flaky triage <report> --out-dir out --html
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`rerun` needs `@playwright/test` 1.60.0 or later installed in the project that contains the tests. It is an optional peer dependency of this package.
|
|
20
|
+
|
|
21
|
+
The heal handoff needs `qa-core-heal` 0.4.0 or later for a re-run-verified fix. `qa-core-heal` 0.3.x gives only the older dry-run mode, which is not re-run verified. Install it in the same project when you use `--heal`.
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
npx qa-core-flaky parse <report.json>
|
|
27
|
+
npx qa-core-flaky parse <report.junit.xml>
|
|
28
|
+
npx qa-core-flaky causes <report.json>
|
|
29
|
+
npx qa-core-flaky triage <report.json> --out-dir out --html
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
`rerun` needs a Playwright browser in the project under test. This example keeps one failing test and runs it once in each default mode:
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
npx qa-core-flaky rerun --from <report.json> --config playwright.config.ts --max-tests 1 --times 1
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The format is detected from the file contents. The root element must be `testsuites` or `testsuite` for JUnit. A later mention of `<testsuite` is not enough. `--format json` or `--format junit` overrides that detection. Optional flags `--commit`, `--branch`, and `--run-id` are copied onto each record by `parse`. `--commit` applies to every report in that command. When it is omitted, a Playwright JSON report uses `config.metadata.gitCommit` when that field is a non-empty string. `--redact` hides home usernames in `parse` output. Without it, `parse` returns the original error text. `--out` writes the output to a file instead of stdout.
|
|
39
|
+
|
|
40
|
+
`causes` prints one block per failed or flaky test. `--json` prints a JSON array of `{ id, findings }`. `--test-timeout` supplies the timeout used by the near-timeout rule. The rule list is in [docs/causes.md](docs/causes.md).
|
|
41
|
+
|
|
42
|
+
`triage` writes `triage.json` and `triage.md` for each failed or flaky test. The JSON schema is [docs/report-schema.md](docs/report-schema.md). The verdict rows are [docs/verdicts.md](docs/verdicts.md). The default exit code is 2 when the report has at least one entry, and 0 when it has none. `--fail-on never` exits 0 after the files are written. A tool error exits 1. Do not point `--out-dir` at a directory under `/proc`. Creating a directory there can hang, which is a Node bug, and the command does not probe `/proc`.
|
|
43
|
+
|
|
44
|
+
`--heal-findings <file>` writes a findings file for qa-core-heal. `--heal` asks qa-core-heal for a dry run and stores the result on `healProposal`. The program is `npx --no-install qa-core-heal`, so a missing local install is not downloaded from the registry. A copy already in the npx cache can still run, so install qa-core-heal as a dev dependency for predictable results. Without `--heal`, that field stays null. The command never passes `--apply`, `--yes`, or `--no-verify`. The fields, the five handoff gates, and the redaction rules are in [docs/heal-contract.md](docs/heal-contract.md).
|
|
45
|
+
|
|
46
|
+
## HTML Report
|
|
47
|
+
|
|
48
|
+
`--html` writes `triage.html` in `--out-dir`, beside `triage.json` and `triage.md`. `rerun` accepts the same flag when it writes a triage report.
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
npx qa-core-flaky triage <report.json> --out-dir out --html --fail-on never
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The page is one file. CSS and script are inline. It does not call the network, load a font, or load an image. Open it from disk, or attach the file to a message. The table is still readable when script is off. Filters, sorting, and the copy button need script.
|
|
55
|
+
|
|
56
|
+
The header is the report title. It shows the generated time when the JSON has a UTC `generatedAt`, for example 26 Oct 2026, 18:07 UTC. It shows a commit when a signal names 7 to 40 hex characters, and then only the first 7, in monospace. Summary cards count flagged tests and each verdict. A zero card is muted. A bar list counts the primary cause. The table lists the test, verdict, cause, confidence, failed attempts out of the total, and runs seen. The test title is shown with the file and project under it. Open a row for the evidence, the signals, the suggested fix, the next step, the attempts, rerun counts when the JSON has them, and the review status. The next step command is a block, with Copy Command under it. Attempts read as the total, the failed count, the passed count, and whether a pass and a fail used the same code. When a test was seen in more than one run, the row says so in words. On a narrow screen each test is a stacked card, and a Sort By control replaces the column buttons. Above that width the column buttons stay and Sort By is hidden. Printing opens every row and keeps the column headings. The footer is `Generated by qa-core-flaky` plus the version, then `Built by SprintSynergy.`
|
|
57
|
+
|
|
58
|
+
Home usernames are hidden, with the same rules as `parse --redact`. That is the file to share. `--html-no-redact` leaves those names visible. Token-like strings stay hidden. The JSON and Markdown reports still hide home names. Do not share a file made with that flag.
|
|
59
|
+
|
|
60
|
+
The screenshots are a SauceDemo run stored in `fixtures/reports/saucedemo-kit-triage.json`. The report lists 6 flaky tests. Tests that passed are not listed.
|
|
61
|
+
|
|
62
|
+

|
|
63
|
+
|
|
64
|
+

|
|
65
|
+
|
|
66
|
+

|
|
67
|
+
|
|
68
|
+

|
|
69
|
+
|
|
70
|
+
`rerun` runs the failing tests again with Playwright and merges the new attempts. `--retries` defaults to 0 so a retry cannot hide the first failure. `--root` is the JUnit project root. The modes and the safety rules are in [docs/rerun.md](docs/rerun.md). Unit tests do not launch a browser.
|
|
71
|
+
|
|
72
|
+
## Demo
|
|
73
|
+
|
|
74
|
+
`demo/saucedemo` is a Playwright suite for the public SauceDemo practice app. Some tests fail on purpose from a seed. `npm test` does not run it and does not call that site. The recorded reports and the run notes are in [demo/saucedemo/README.md](demo/saucedemo/README.md).
|
|
75
|
+
|
|
76
|
+
## Model
|
|
77
|
+
|
|
78
|
+
Each test becomes a record with a stable id, a file path, a project name, a title path, an expected status, an outcome, and every attempt. The outcome is passed, flaky, failed, or skipped. The full field list is in [docs/model.md](docs/model.md).
|
|
79
|
+
|
|
80
|
+
## Contributors
|
|
81
|
+
|
|
82
|
+
From a local clone, install dependencies, build, and run the commands against the committed fixtures:
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
git clone https://github.com/sprintsynergyhq/qa-core-flaky.git
|
|
86
|
+
cd qa-core-flaky
|
|
87
|
+
npm ci
|
|
88
|
+
npm run build
|
|
89
|
+
node dist/cli.js parse fixtures/reports/pw-1.60.0-outcomes.json
|
|
90
|
+
node dist/cli.js parse fixtures/reports/pw-1.60.0-outcomes.junit.xml
|
|
91
|
+
node dist/cli.js causes fixtures/reports/pw-1.60.0-outcomes.json
|
|
92
|
+
node dist/cli.js triage fixtures/reports/pw-1.60.0-outcomes.json --out-dir /tmp/qa-core-flaky-triage
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
`node dist/cli.js --help` lists the commands. See [CONTRIBUTING.md](CONTRIBUTING.md), [CHANGELOG.md](CHANGELOG.md), and [SECURITY.md](SECURITY.md).
|
|
96
|
+
|
|
97
|
+
## Regenerating Fixtures
|
|
98
|
+
|
|
99
|
+
`npm run fixtures` runs the local Playwright project in `fixtures/pw-project` and rewrites `fixtures/reports/pw-1.60.0-outcomes.json` and `fixtures/reports/pw-1.60.0-outcomes.junit.xml` from that same run. Run it from the repository root. The script ignores the test process exit code, because some fixture tests are meant to fail. It then replaces volatile values with fixed placeholders: start times, durations, worker indexes, absolute paths, and a machine hostname when one is present. Playwright writes the project name in the JUnit `hostname` attribute, and that project name is left as-is. ANSI escape codes are removed. Repeated locator lines in error text are rewritten to a fixed count, because that count changes between runs.
|
|
100
|
+
|
|
101
|
+
Tests and CI use the committed report. They do not install browsers and they do not call the network. Regenerating the fixture needs the Playwright browser installed on the machine that runs the script.
|
|
102
|
+
|
|
103
|
+
## License
|
|
104
|
+
|
|
105
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RuleMatch } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Environment rules.
|
|
4
|
+
* `selectorEvidence` is true when this same text also matches a selector rule.
|
|
5
|
+
* A closed browser that still has locator evidence is not `ENV-BROWSER`.
|
|
6
|
+
*/
|
|
7
|
+
export declare function environmentMatches(text: string, selectorEvidence: boolean): RuleMatch[];
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { isQuotedContextLine, lineContaining } from './text.js';
|
|
2
|
+
const NET = /net::ERR_[A-Z0-9_]+|ECONNREFUSED|ECONNRESET|ENOTFOUND|EAI_AGAIN|socket hang up/;
|
|
3
|
+
/**
|
|
4
|
+
* An HTTP status from 500 to 599. A bare number is not enough: `5000ms` and
|
|
5
|
+
* an expected value of 512 do not match. The status needs a status word, an
|
|
6
|
+
* HTTP reason phrase, an `apiRequestContext` error, or a `Received:` line
|
|
7
|
+
* whose value is the status (`Received: 503`, including a quoted `503`).
|
|
8
|
+
*/
|
|
9
|
+
const HTTP_5XX = /\b(?:status(?:\s+code)?|HTTP\/\d(?:\.\d)?)\s*[:=]?\s*5\d\d\b|\b5\d\d\s+(?:Internal Server Error|Not Implemented|Bad Gateway|Service Unavailable|Gateway Timeout|HTTP Version Not Supported)\b|apiRequestContext\.\w+:\s*5\d\d\b|^[ \t]*Received:[ \t]*"?5\d\d"?(?=$|[\s"])/i;
|
|
10
|
+
const LAUNCH = /browserType\.launch/;
|
|
11
|
+
const CLOSED = /Target page, context or browser has been closed/;
|
|
12
|
+
/**
|
|
13
|
+
* Environment rules.
|
|
14
|
+
* `selectorEvidence` is true when this same text also matches a selector rule.
|
|
15
|
+
* A closed browser that still has locator evidence is not `ENV-BROWSER`.
|
|
16
|
+
*/
|
|
17
|
+
export function environmentMatches(text, selectorEvidence) {
|
|
18
|
+
const hits = [];
|
|
19
|
+
const net = lineContaining(text, NET, isQuotedContextLine);
|
|
20
|
+
if (net)
|
|
21
|
+
hits.push({ ruleId: 'ENV-NET', evidence: [net] });
|
|
22
|
+
const http = lineContaining(text, HTTP_5XX, isQuotedContextLine);
|
|
23
|
+
if (http)
|
|
24
|
+
hits.push({ ruleId: 'ENV-HTTP5XX', evidence: [http] });
|
|
25
|
+
if (LAUNCH.test(text) || (CLOSED.test(text) && !selectorEvidence)) {
|
|
26
|
+
const evidence = lineContaining(text, LAUNCH) ?? lineContaining(text, CLOSED);
|
|
27
|
+
if (evidence)
|
|
28
|
+
hits.push({ ruleId: 'ENV-BROWSER', evidence: [evidence] });
|
|
29
|
+
}
|
|
30
|
+
return hits;
|
|
31
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { TestRecord } from '../model.js';
|
|
2
|
+
import type { CauseFinding, ClassifyOptions } from './types.js';
|
|
3
|
+
export type { Cause, CauseFinding, ClassifyOptions, Confidence, OrderDependencyHook } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Read one test record and return the likely causes.
|
|
6
|
+
*
|
|
7
|
+
* Message and stack are both read. A failed attempt with no error text
|
|
8
|
+
* becomes one Unknown finding (`UNK-EMPTY`) and does not throw.
|
|
9
|
+
* Findings are sorted by confidence, then by selectors, environment, timing,
|
|
10
|
+
* test-data. The same input returns the same array.
|
|
11
|
+
*/
|
|
12
|
+
export declare function classifyCauses(record: TestRecord, options?: ClassifyOptions): CauseFinding[];
|