kwikqa 0.0.0-stage → 0.1.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/LICENSE +122 -0
- package/README.md +240 -2
- package/dist/THIRD_PARTY_NOTICES.md +54 -0
- package/dist/cypress-capture.js +190 -0
- package/dist/cypress-reporter.cjs +282 -0
- package/dist/cypress-reporter.d.cts +20 -0
- package/dist/kwikqa.mjs +127 -0
- package/dist/parse-check.mjs +11 -0
- package/dist/pnp-resolver.mjs +5 -0
- package/dist/wdio-capture.d.mts +11 -0
- package/dist/wdio-capture.mjs +261 -0
- package/dist/wdio-reporter.d.mts +12 -0
- package/dist/wdio-reporter.mjs +243 -0
- package/package.json +60 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
KwikQA End User License Agreement
|
|
2
|
+
|
|
3
|
+
Effective 23 October 2026
|
|
4
|
+
Copyright (c) 2026 KwikQA. All rights reserved.
|
|
5
|
+
|
|
6
|
+
KwikQA is proprietary software. It is not open source, and this agreement does not grant any
|
|
7
|
+
open-source license to it.
|
|
8
|
+
|
|
9
|
+
This agreement is between you and KwikQA ("we"). It governs the KwikQA command-line software,
|
|
10
|
+
including the reporter and failure-capture files it installs into your test projects (together,
|
|
11
|
+
the "Software"), and your use of the KwikQA hosted service the Software connects to (the
|
|
12
|
+
"Service"). The Terms of Service at https://kwikqa.com/terms/ also apply to the Service, and the
|
|
13
|
+
Privacy Policy at https://kwikqa.com/privacy/ explains how personal data is handled. If this
|
|
14
|
+
agreement and the Terms of Service conflict about the Software, this agreement governs.
|
|
15
|
+
|
|
16
|
+
By installing, copying, or using the Software you accept this agreement. If you use it for an
|
|
17
|
+
organization, you confirm that you may accept it for that organization, and "you" includes it. If
|
|
18
|
+
you do not accept, do not install or use the Software.
|
|
19
|
+
|
|
20
|
+
1. License. Subject to this agreement and to the plan you hold, we grant you a limited,
|
|
21
|
+
non-exclusive, non-transferable, non-sublicensable, revocable license to install and run the
|
|
22
|
+
Software, on machines and in continuous-integration environments you control, to analyze and
|
|
23
|
+
repair the test suites of software that you or your organization develop. The reporter and
|
|
24
|
+
capture files may be kept in your test projects and run as part of your own test runs, only for
|
|
25
|
+
that purpose.
|
|
26
|
+
|
|
27
|
+
2. Restrictions. You may not, and may not allow anyone else to:
|
|
28
|
+
(a) copy, modify, merge, or distribute the Software, except to install and run it under this
|
|
29
|
+
license and to keep the files described in section 1 in your projects;
|
|
30
|
+
(b) decompile, disassemble, or reverse engineer the Software, except to the extent applicable
|
|
31
|
+
law permits this despite this restriction;
|
|
32
|
+
(c) sell, rent, lease, lend, sublicense, or provide the Software or the Service to third parties
|
|
33
|
+
as a hosted or managed service;
|
|
34
|
+
(d) use the Software or the Service to build or offer a competing product or service;
|
|
35
|
+
(e) circumvent plan limits, usage metering, authentication, request approval, or any other
|
|
36
|
+
technical control, including by changing the Software so that it does not report usage;
|
|
37
|
+
(f) remove or alter any proprietary, copyright, or license notice; or
|
|
38
|
+
(g) use the Software or the Service in violation of applicable law, including export control
|
|
39
|
+
and sanctions laws.
|
|
40
|
+
|
|
41
|
+
3. Third-party components. The Software includes open-source components, each licensed under its
|
|
42
|
+
own license. They are listed, with their license texts, in THIRD_PARTY_NOTICES.md, which is
|
|
43
|
+
distributed with the Software. Those licenses govern those components, and nothing in this
|
|
44
|
+
agreement limits your rights under them.
|
|
45
|
+
|
|
46
|
+
4. Plans, fees, and refunds. Plans, prices, and monthly limits are described at
|
|
47
|
+
https://kwikqa.com/pricing/. Usage is counted per AI request as described there. Paid plans are
|
|
48
|
+
sold by Paddle.com, our merchant of record, renew monthly or yearly until cancelled, and are
|
|
49
|
+
refunded as described at https://kwikqa.com/refunds/, including a full refund of your first
|
|
50
|
+
payment if you cancel within 14 days of it, once in any 12 months. We may change plans or
|
|
51
|
+
prices with at least 30 days' notice; a change applies from your next billing period after the
|
|
52
|
+
notice ends.
|
|
53
|
+
|
|
54
|
+
5. Your data. You keep all rights in your code, test reports, evidence, and the changes the
|
|
55
|
+
Software makes to your code. The Software builds a redacted, size-limited evidence packet on
|
|
56
|
+
your machine and shows you a preview of each AI request before anything is sent.
|
|
57
|
+
(a) On hosted plans, an approved packet goes to the Service, which checks it, counts it toward
|
|
58
|
+
your plan, and forwards it unchanged to OpenRouter, which sends it to the model endpoint
|
|
59
|
+
named in the preview. The Service requires that every such request is routed only to an
|
|
60
|
+
endpoint with a zero-data-retention policy. The Service stores account, plan, usage, and
|
|
61
|
+
request metadata and a hash of each request; it does not store the evidence, your source
|
|
62
|
+
code, or the model's answer, which it holds only in memory until your Software collects it
|
|
63
|
+
(at most 15 minutes).
|
|
64
|
+
(b) On bring-your-own-key plans, requests go from your machine directly to OpenRouter under your
|
|
65
|
+
own OpenRouter account and its terms, and you are responsible for those charges. The
|
|
66
|
+
Software reports each request's kind, model, provider, and test framework to the Service so
|
|
67
|
+
it counts toward your plan.
|
|
68
|
+
(c) If your team's owner turns on team insights, the Software also shares the names, files, and
|
|
69
|
+
projects of failing and flaky tests and the outcome of each fix with your team.
|
|
70
|
+
(d) Run records, patches, transaction journals, captures, and validation output stay on your
|
|
71
|
+
machine.
|
|
72
|
+
You are responsible for making sure that what you approve sending does not include data you
|
|
73
|
+
are not permitted to share. https://kwikqa.com/security/ describes this in detail.
|
|
74
|
+
|
|
75
|
+
6. AI output. Diagnoses and proposed repairs are generated with AI models and may be incomplete or
|
|
76
|
+
wrong. The Software checks proposals against its repair rules, applies a change only after you
|
|
77
|
+
approve it, and validates applied changes by running your tests, but none of this guarantees
|
|
78
|
+
that a diagnosis is correct or that a change is suitable for your code. You are responsible for
|
|
79
|
+
reviewing and accepting changes to your code and for how you use the output.
|
|
80
|
+
|
|
81
|
+
7. Ownership and feedback. The Software and the Service, and all intellectual property in them,
|
|
82
|
+
belong to KwikQA and its licensors. This agreement grants no rights except those stated in it.
|
|
83
|
+
If you send us suggestions or feedback, we may use them without obligation to you.
|
|
84
|
+
|
|
85
|
+
8. Updates. We may update the Software and the Service, and may stop supporting older versions of
|
|
86
|
+
the Software when the Service changes. This agreement applies to every update unless an update
|
|
87
|
+
comes with a different agreement.
|
|
88
|
+
|
|
89
|
+
9. Term and termination. This agreement lasts until it is terminated. It ends automatically if you
|
|
90
|
+
breach it, and you may end it at any time by deleting the Software. When it ends you must stop
|
|
91
|
+
using the Software and delete it. Sections 2, 3, 5, 6, 7, 9, 10, 11, 12, and 13 survive
|
|
92
|
+
termination.
|
|
93
|
+
|
|
94
|
+
10. No warranty. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE AND THE SERVICE ARE PROVIDED
|
|
95
|
+
"AS IS" AND "AS AVAILABLE", WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED, OR STATUTORY,
|
|
96
|
+
INCLUDING ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, OR
|
|
97
|
+
NON-INFRINGEMENT, AND ANY WARRANTY THAT THE SOFTWARE OR THE SERVICE WILL BE UNINTERRUPTED OR
|
|
98
|
+
ERROR-FREE, OR THAT ANY DIAGNOSIS OR REPAIR WILL BE CORRECT OR WILL MAKE A TEST PASS.
|
|
99
|
+
|
|
100
|
+
11. Limitation of liability. TO THE MAXIMUM EXTENT PERMITTED BY LAW: (a) KWIKQA IS NOT LIABLE FOR
|
|
101
|
+
ANY INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, EXEMPLARY, OR PUNITIVE DAMAGES, OR FOR ANY
|
|
102
|
+
LOSS OF DATA, PROFITS, REVENUE, OR GOODWILL, HOWEVER CAUSED, EVEN IF ADVISED OF THEIR
|
|
103
|
+
POSSIBILITY; AND (b) KWIKQA'S TOTAL LIABILITY FOR ALL CLAIMS ARISING OUT OF OR RELATING TO THIS
|
|
104
|
+
AGREEMENT, THE SOFTWARE, OR THE SERVICE IS LIMITED TO THE GREATER OF THE AMOUNT YOU PAID FOR THE
|
|
105
|
+
SERVICE IN THE TWELVE MONTHS BEFORE THE EVENT GIVING RISE TO THE CLAIM AND ONE HUNDRED US
|
|
106
|
+
DOLLARS (USD 100). NOTHING IN THIS AGREEMENT LIMITS LIABILITY THAT CANNOT BE LIMITED UNDER
|
|
107
|
+
APPLICABLE LAW, OR ANY RIGHTS YOU HAVE AS A CONSUMER THAT CANNOT BE WAIVED.
|
|
108
|
+
|
|
109
|
+
12. Governing law. This agreement is governed by the laws of India, without regard to its
|
|
110
|
+
conflict-of-laws rules. The courts of India have jurisdiction over disputes arising from it,
|
|
111
|
+
except that we may seek urgent relief to protect our intellectual property in any competent
|
|
112
|
+
court. If you are a consumer, this does not take away the protection of the mandatory laws of
|
|
113
|
+
the country where you live.
|
|
114
|
+
|
|
115
|
+
13. General. This agreement, together with the Terms of Service, is the entire agreement about the
|
|
116
|
+
Software and supersedes any prior agreement about it. You may not assign it without our
|
|
117
|
+
consent; we may assign it to a successor of our business. If a provision is unenforceable, the
|
|
118
|
+
rest remains in effect. Not enforcing a provision is not a waiver of it. We may update this
|
|
119
|
+
agreement; the version in effect when you install or update the Software applies to that
|
|
120
|
+
version, and material changes are announced on https://kwikqa.com.
|
|
121
|
+
|
|
122
|
+
Contact: support@kwikqa.com (help), security@kwikqa.com (security), privacy@kwikqa.com (privacy).
|
package/README.md
CHANGED
|
@@ -1,3 +1,241 @@
|
|
|
1
|
-
#
|
|
1
|
+
# KwikQA
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
KwikQA reads a failed **Playwright**, **Cypress**, or **WebdriverIO** run and tells you why it
|
|
4
|
+
failed, using the evidence in your report, the page at the moment of failure, and your test source.
|
|
5
|
+
When the test itself is at fault, it proposes a small repair to your test code, shows you the exact
|
|
6
|
+
diff, applies it only after you approve, and keeps it only if your tests then pass.
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
npm i -D kwikqa
|
|
10
|
+
npx playwright test # or: npx cypress run, npx wdio run wdio.conf.ts
|
|
11
|
+
npx kwikqa analyze
|
|
12
|
+
npx kwikqa fix
|
|
13
|
+
npx kwikqa validate
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Using pnpm, Yarn, or Bun? See [Package managers and monorepos](#package-managers-and-monorepos).
|
|
17
|
+
|
|
18
|
+
## What it will and won't do
|
|
19
|
+
|
|
20
|
+
- **Diagnoses with evidence.** Every cause it reports cites the report fields, trace events, or source
|
|
21
|
+
lines that support it, and it says so when the evidence isn't enough.
|
|
22
|
+
- **Repairs only test code.** It edits specs, page objects, fixtures, and helpers that your
|
|
23
|
+
`kwikqa.config.json` allows. It never edits application code, dependencies, or lockfiles.
|
|
24
|
+
- **Never weakens a test.** It refuses edits that skip or focus tests, add fixed waits
|
|
25
|
+
(`waitForTimeout`, `cy.wait(1000)`, `browser.pause`) or retries, force actions past Cypress's
|
|
26
|
+
checks, remove or swap assertions and `should` chainers, or swallow errors.
|
|
27
|
+
- **Nothing happens without you.** You see each AI request and each patch before it happens. Applying a
|
|
28
|
+
patch always asks, even in CI mode.
|
|
29
|
+
- **Keeps a repair only if it validates.** `validate` reruns the failing test in a fresh process with
|
|
30
|
+
your project's own Playwright, Cypress, or WebdriverIO. Cypress runs the test's spec with every
|
|
31
|
+
other test skipped except the ones that passed before, which must still pass. If anything required
|
|
32
|
+
fails, the patch is rolled back. One retry is allowed, then it stops.
|
|
33
|
+
- **Leaves your other work alone.** It won't touch files you have already modified, and rollback
|
|
34
|
+
restores only the bytes it changed.
|
|
35
|
+
|
|
36
|
+
## Requirements
|
|
37
|
+
|
|
38
|
+
- Node.js 20.11 or later
|
|
39
|
+
- Playwright Test, Cypress, or WebdriverIO (Mocha or Jasmine) installed in your project with npm,
|
|
40
|
+
pnpm, Yarn, or Bun. KwikQA runs your project's own copy and never installs packages or browsers.
|
|
41
|
+
- A git repository
|
|
42
|
+
|
|
43
|
+
## Setup
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
npm i -D kwikqa
|
|
47
|
+
npx kwikqa init
|
|
48
|
+
npx kwikqa login
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`init` proposes a `kwikqa.config.json` that lists which files KwikQA may edit, and offers to add
|
|
52
|
+
`.kwikqa/` (local run records) to `.gitignore`. Review and commit the config like any other code.
|
|
53
|
+
|
|
54
|
+
Then point KwikQA at your runs:
|
|
55
|
+
|
|
56
|
+
**Playwright.** Add a JSON reporter to `playwright.config.ts`, and keep traces for failures:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
export default defineConfig({
|
|
60
|
+
reporter: [["list"], ["json", { outputFile: "test-results/kwikqa-report.json" }]],
|
|
61
|
+
use: { trace: "retain-on-failure" },
|
|
62
|
+
});
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Cypress.** Add KwikQA's reporter to `cypress.config.ts`. It keeps every retry attempt, where each
|
|
66
|
+
test is declared, and each error's code frame:
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
export default defineConfig({
|
|
70
|
+
reporter: "node_modules/kwikqa/dist/cypress-reporter.cjs",
|
|
71
|
+
// ...
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Already writing mochawesome or JUnit reports? KwikQA reads those too:
|
|
76
|
+
`npx kwikqa analyze --report mochawesome-report`.
|
|
77
|
+
|
|
78
|
+
**WebdriverIO.** Add KwikQA's reporter to `wdio.conf.ts`, next to your own:
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import KwikqaReporter from "kwikqa/wdio-reporter";
|
|
82
|
+
|
|
83
|
+
export const config = {
|
|
84
|
+
reporters: ["spec", [KwikqaReporter, {}]],
|
|
85
|
+
// ...
|
|
86
|
+
};
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`@wdio/json-reporter` and JUnit reports work too: `npx kwikqa analyze --report <directory>`.
|
|
90
|
+
|
|
91
|
+
KwikQA's reporters write to `test-results/kwikqa/`, which `analyze` finds on its own. Cypress and
|
|
92
|
+
WebdriverIO keep no trace of a failure; run `npx kwikqa analyze --capture` and KwikQA re-runs the
|
|
93
|
+
failing specs and records each failure's page (see below).
|
|
94
|
+
|
|
95
|
+
`login` signs you in with GitHub; the free plan needs no payment details.
|
|
96
|
+
|
|
97
|
+
### Package managers and monorepos
|
|
98
|
+
|
|
99
|
+
This page uses npm's commands. With another package manager, install and run KwikQA the same way:
|
|
100
|
+
|
|
101
|
+
| | Install | Run |
|
|
102
|
+
| --- | --- | --- |
|
|
103
|
+
| npm | `npm i -D kwikqa` | `npx kwikqa analyze` |
|
|
104
|
+
| pnpm | `pnpm add -D kwikqa` | `pnpm exec kwikqa analyze` |
|
|
105
|
+
| Yarn | `yarn add -D kwikqa` | `yarn kwikqa analyze` |
|
|
106
|
+
| Bun | `bun add -d kwikqa` | `bunx kwikqa analyze` |
|
|
107
|
+
|
|
108
|
+
The commands KwikQA suggests use the same form as the one you ran.
|
|
109
|
+
|
|
110
|
+
In a monorepo, install KwikQA in the package that holds your tests, and run it from that package's
|
|
111
|
+
folder, where its `kwikqa.config.json` goes. KwikQA finds that package's Playwright, Cypress, or
|
|
112
|
+
WebdriverIO wherever your package manager installed it inside the repository, including the root's
|
|
113
|
+
`node_modules`. It never runs one from outside the repository, so pnpm's global virtual store
|
|
114
|
+
(`enableGlobalVirtualStore`) isn't supported.
|
|
115
|
+
|
|
116
|
+
## Commands
|
|
117
|
+
|
|
118
|
+
| Command | What it does |
|
|
119
|
+
| --- | --- |
|
|
120
|
+
| `npx kwikqa analyze` | Diagnose the failures in the latest report. `--report <path>` picks a report file or a directory of one run's reports; `--framework` names the framework of a JUnit report; `--local` builds the evidence summary without sending anything; `--no-changes` leaves out recent code changes (see below). |
|
|
121
|
+
| `npx kwikqa analyze --capture` | First re-run the failing tests so every failure has full evidence. Playwright runs with full tracing; with Playwright 1.59+ and [Playwright CLI](https://www.npmjs.com/package/@playwright/cli) installed, it also pauses locator failures at the failing line and asks Playwright for locators of the closest elements (`--no-probe` skips this). Cypress and WebdriverIO re-run the failing specs with your own config plus KwikQA's reporter and failure capture, which records each failed attempt's DOM, command log, console, and network. Asks before running anything; `--yes` approves in CI. |
|
|
122
|
+
| `npx kwikqa fix` | Propose a repair for a test-side cause, show the diff and validation commands, and apply it if you approve. First it offers to re-run the failing tests once: a test that passes now is flaky, so KwikQA reports it and requests no repair. It starts with the failure group whose test-side diagnosis is strongest; if the model declines, or its proposal fails KwikQA's checks, it asks about the next such group, at most three, each with its own preview. One `fix` counts as one fix however many groups it tries. `--group <n>` repairs only group n, as `analyze` numbered it. `--propose-only` stops after the proposal. |
|
|
123
|
+
| `npx kwikqa validate` | Run the approved validation. The repaired test must pass three times in a row, with retries off. Passing keeps the patch; failing rolls it back. When other tests failed with the same cause, it then offers to re-run them once and names any that still fail, so you can run `fix` again for them; the patch stays either way. |
|
|
124
|
+
| `npx kwikqa fix --retry` | After a failed validation, re-diagnose from the new evidence and propose one revised patch. |
|
|
125
|
+
| `npx kwikqa status` | Show your plan, team, and this month's usage. |
|
|
126
|
+
| `npx kwikqa upgrade [plan]` | Show plans, or get a checkout link for one. `--annual` bills yearly; `--seats <n>` sets seats on team plans. On a paid plan it points you to Billing in the dashboard. While the paid plans are coming soon, it lists them without a link. |
|
|
127
|
+
| `npx kwikqa billing` | Open Paddle's customer portal to update your payment method or download invoices. |
|
|
128
|
+
| `npx kwikqa init` / `login` / `logout` | Set up the project, sign in, sign out (`logout` also revokes the token). |
|
|
129
|
+
|
|
130
|
+
Exit codes: `0` success or an informative result, `1` the repair or validation did not succeed, `2`
|
|
131
|
+
usage error, `3` sign-in, plan, or usage-limit problem.
|
|
132
|
+
|
|
133
|
+
## Plans
|
|
134
|
+
|
|
135
|
+
| Plan | Monthly | Annual | Analyses / month | Fixes / month |
|
|
136
|
+
| --- | --- | --- | --- | --- |
|
|
137
|
+
| Free | $0 | – | 10 | 3 |
|
|
138
|
+
| Pro | $20 | $200 | 90 | 20 |
|
|
139
|
+
| Team (3+ seats) | $25 / seat | $250 / seat | 100 / seat, shared | 25 / seat, shared |
|
|
140
|
+
| BYOK | $10 | $100 | 500 | 150 |
|
|
141
|
+
| BYOK Team (3+ seats) | $15 / seat | $150 / seat | Unlimited | Unlimited |
|
|
142
|
+
|
|
143
|
+
One analysis is one diagnosis sent to the AI. One fix is one repair attempt, validated by
|
|
144
|
+
`npx kwikqa validate`, and its one retry is included. Local-only analysis is free, and so is any
|
|
145
|
+
request you decline or that stops before sending. `fix` reuses the diagnosis `analyze` already
|
|
146
|
+
produced for the same run, so it doesn't use another analysis.
|
|
147
|
+
|
|
148
|
+
The paid plans are coming soon: until they open, every account uses Free.
|
|
149
|
+
|
|
150
|
+
Annual billing gives two months free. Cancel within 14 days of your first payment, monthly or
|
|
151
|
+
annual, and it is refunded in full, once in any 12 months. After that, cancelling an annual plan from the dashboard refunds
|
|
152
|
+
its unused months; monthly plans stay active until the end of the paid month. Payments go through
|
|
153
|
+
Paddle, the merchant of record.
|
|
154
|
+
|
|
155
|
+
### Teams
|
|
156
|
+
|
|
157
|
+
On Team and BYOK Team, the owner invites people by GitHub username at
|
|
158
|
+
https://kwikqa.com/dashboard/team/. Everyone, including CI tokens they create, draws from one
|
|
159
|
+
monthly pool.
|
|
160
|
+
|
|
161
|
+
The owner can also turn on **team insights**: the flakiest tests, fix history, acceptance rate,
|
|
162
|
+
and repair success at https://kwikqa.com/dashboard/insights/. While insights are on, the CLI shares
|
|
163
|
+
the names, files, and projects of failing and flaky tests and each fix's outcome with the team, and
|
|
164
|
+
says so after each command. It never shares evidence, source, diffs, or error messages, and
|
|
165
|
+
`analyze --local` shares nothing. `npx kwikqa status` shows whether insights are on.
|
|
166
|
+
|
|
167
|
+
### Bring your own key
|
|
168
|
+
|
|
169
|
+
On the BYOK plans, KwikQA sends requests straight to OpenRouter with your key, and your evidence
|
|
170
|
+
never passes through KwikQA's servers. The CLI reports each request's kind, model, and provider to
|
|
171
|
+
KwikQA so it counts toward your plan:
|
|
172
|
+
|
|
173
|
+
```sh
|
|
174
|
+
export OPENROUTER_API_KEY=sk-or-...
|
|
175
|
+
# Optional: choose your own models as author/model@provider
|
|
176
|
+
export KWIKQA_DIAGNOSIS_MODEL=anthropic/claude-haiku-5.5@anthropic
|
|
177
|
+
export KWIKQA_REPAIR_MODEL=openai/gpt-6.1-sol@openai
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## What is sent, and where
|
|
181
|
+
|
|
182
|
+
Before any request, KwikQA builds a bounded evidence packet on your machine from your failing tests
|
|
183
|
+
only. It contains selected report fields, trace events or the Cypress and WebdriverIO command log,
|
|
184
|
+
the elements around each failed locator, the accessibility snapshot of the page at the failure,
|
|
185
|
+
short source excerpts, and recent code changes that mention the failure. Secrets,
|
|
186
|
+
credentials, password fields, and sensitive fields are removed from that packet before you see the
|
|
187
|
+
preview. Redaction recognizes credentials, not every kind of personal data: names or email
|
|
188
|
+
addresses in your test data can still appear in page text, so test with data you may share.
|
|
189
|
+
Screenshots and videos are described by size and dimensions only; their pixels are never sent. Full
|
|
190
|
+
files, full diffs, and your whole repository are never sent.
|
|
191
|
+
|
|
192
|
+
Recent code changes tell a deliberately changed app from a broken one. KwikQA searches your
|
|
193
|
+
uncommitted changes and your branch's commits since it left the default branch (on the default
|
|
194
|
+
branch, the last 20 commits from the past 30 days). It looks for changed lines that contain what
|
|
195
|
+
the failure names: locator text and test ids, expected and received values, and failed request
|
|
196
|
+
paths. Only matching hunks of source files are kept, at most 12, each with its commit's subject
|
|
197
|
+
line. The subjects of the commits searched (at most 20) and the names of source files with
|
|
198
|
+
uncommitted changes are listed too. Author names, emails, commit bodies, and documentation are
|
|
199
|
+
never read. The preview says how
|
|
200
|
+
many changed hunks a request carries. `--no-changes` on `analyze` and `fix` leaves them out.
|
|
201
|
+
|
|
202
|
+
- **Free, Pro, Team:** the redacted packet goes to the KwikQA service, which forwards it unchanged to
|
|
203
|
+
OpenRouter and the model endpoint shown in the preview. Requests go only to endpoints with a
|
|
204
|
+
zero-data-retention policy (Claude on Google Cloud Vertex AI, GPT on Microsoft Azure): the
|
|
205
|
+
service refuses a request that doesn't ask for that, and OpenRouter refuses rather than route it
|
|
206
|
+
to an endpoint that would keep it. The service keeps only account, usage, token, and cost
|
|
207
|
+
metadata and a hash of the request. It never stores your evidence, your source, or the model's
|
|
208
|
+
answer, which it holds in memory until your CLI collects it, for at most 15 minutes.
|
|
209
|
+
- **BYOK, BYOK Team:** the packet goes from your machine directly to OpenRouter, under your
|
|
210
|
+
OpenRouter account and its settings. KwikQA's default routes ask for zero data retention there
|
|
211
|
+
too; a route you set with `KWIKQA_DIAGNOSIS_MODEL` or `KWIKQA_REPAIR_MODEL` does not. The CLI
|
|
212
|
+
reports only the request's kind, model, provider, and test framework to KwikQA, to count it.
|
|
213
|
+
|
|
214
|
+
Run records, transaction journals, captures, and validation output stay on your machine in
|
|
215
|
+
`.kwikqa/`. [Security and data handling](https://kwikqa.com/security/) and the
|
|
216
|
+
[privacy policy](https://kwikqa.com/privacy/) have the details.
|
|
217
|
+
|
|
218
|
+
## CI
|
|
219
|
+
|
|
220
|
+
`analyze` can run unattended; `fix` cannot, because applying a patch always needs a person.
|
|
221
|
+
|
|
222
|
+
```sh
|
|
223
|
+
export KWIKQA_TOKEN=... # create a CI token at https://kwikqa.com/dashboard/account/
|
|
224
|
+
npx playwright test || npx kwikqa analyze --yes
|
|
225
|
+
npx cypress run || npx kwikqa analyze --yes
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Account and billing
|
|
229
|
+
|
|
230
|
+
The dashboard at https://kwikqa.com/dashboard/ shows your plan, usage, and recent requests. There
|
|
231
|
+
you can change your plan, seats, or billing period, cancel, manage your team, create and revoke
|
|
232
|
+
CLI and CI tokens, download your data, or delete your account.
|
|
233
|
+
|
|
234
|
+
## Support and license
|
|
235
|
+
|
|
236
|
+
KwikQA is proprietary software licensed under the end user license agreement in the package's
|
|
237
|
+
`LICENSE` file; it is not open source. The open-source components bundled with it, and their
|
|
238
|
+
licenses, are listed in `dist/THIRD_PARTY_NOTICES.md` in the package. The hosted service is also
|
|
239
|
+
covered by the [terms of service](https://kwikqa.com/terms/), the
|
|
240
|
+
[privacy policy](https://kwikqa.com/privacy/), and the [refund policy](https://kwikqa.com/refunds/).
|
|
241
|
+
Questions and support: https://kwikqa.com/support
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
KwikQA is proprietary software (see LICENSE). It includes the following open-source
|
|
4
|
+
components, each licensed under its own license, reproduced here.
|
|
5
|
+
|
|
6
|
+
## @babel/parser 7.29.9 (MIT)
|
|
7
|
+
|
|
8
|
+
```text
|
|
9
|
+
Copyright (C) 2012-2014 by various contributors (see AUTHORS)
|
|
10
|
+
|
|
11
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
12
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
13
|
+
in the Software without restriction, including without limitation the rights
|
|
14
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
15
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
16
|
+
furnished to do so, subject to the following conditions:
|
|
17
|
+
|
|
18
|
+
The above copyright notice and this permission notice shall be included in
|
|
19
|
+
all copies or substantial portions of the Software.
|
|
20
|
+
|
|
21
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
22
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
23
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
24
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
25
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
26
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
27
|
+
THE SOFTWARE.
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## fflate 0.8.3 (MIT)
|
|
31
|
+
|
|
32
|
+
```text
|
|
33
|
+
MIT License
|
|
34
|
+
|
|
35
|
+
Copyright (c) 2026 Arjun Barrett
|
|
36
|
+
|
|
37
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
38
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
39
|
+
in the Software without restriction, including without limitation the rights
|
|
40
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
41
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
42
|
+
furnished to do so, subject to the following conditions:
|
|
43
|
+
|
|
44
|
+
The above copyright notice and this permission notice shall be included in all
|
|
45
|
+
copies or substantial portions of the Software.
|
|
46
|
+
|
|
47
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
48
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
49
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
50
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
51
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
52
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
53
|
+
SOFTWARE.
|
|
54
|
+
```
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
// KwikQA's Cypress failure capture (KQA-081). `npx kwikqa analyze --capture` loads it through a
|
|
2
|
+
// generated support file that imports the project's own support file first, so custom commands
|
|
3
|
+
// and settings are unchanged. It never runs in a normal `cypress run`.
|
|
4
|
+
//
|
|
5
|
+
// When a test attempt fails it records, from the page under test: the DOM (as KwikQA's snapshot
|
|
6
|
+
// tree), the Cypress command log with each command's state and error, console errors and
|
|
7
|
+
// warnings, uncaught page errors, the network requests Cypress logged, and the paths of the
|
|
8
|
+
// failure screenshots. Each attempt is written with cy.writeFile under the capture directory set
|
|
9
|
+
// by the generated support file, named so KwikQA's reporter can attach it to the attempt.
|
|
10
|
+
/* global Cypress, cy, afterEach, beforeEach */
|
|
11
|
+
|
|
12
|
+
const settings = globalThis.__kwikqaCapture || {};
|
|
13
|
+
const OUT = settings.directory || ".kwikqa/capture/cypress";
|
|
14
|
+
// Validation runs only the tests a repair is accountable for: Cypress cannot select tests by name,
|
|
15
|
+
// so every other test is skipped before its own hooks run, and the run's exit code covers just these.
|
|
16
|
+
const ONLY = Array.isArray(settings.only) ? new Set(settings.only) : undefined;
|
|
17
|
+
|
|
18
|
+
if (ONLY) {
|
|
19
|
+
beforeEach(function kwikqaOnly() {
|
|
20
|
+
const test = this.currentTest;
|
|
21
|
+
if (test && !ONLY.has(test.titlePath().join(" "))) this.skip();
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
const MAX_NODES = 20000;
|
|
25
|
+
const MAX_TEXT = 2000;
|
|
26
|
+
const MAX_LOG = 300;
|
|
27
|
+
const SKIPPED_TAGS = new Set(["SCRIPT", "STYLE", "NOSCRIPT", "TEMPLATE", "LINK", "META"]);
|
|
28
|
+
const FORM_FIELDS = new Set(["INPUT", "TEXTAREA", "SELECT"]);
|
|
29
|
+
|
|
30
|
+
function fnv1a(text) {
|
|
31
|
+
let hash = 0x811c9dc5;
|
|
32
|
+
for (const byte of new TextEncoder().encode(text)) {
|
|
33
|
+
hash ^= byte;
|
|
34
|
+
hash = Math.imul(hash, 0x01000193) >>> 0;
|
|
35
|
+
}
|
|
36
|
+
return hash.toString(16).padStart(8, "0");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Must match captureKey in cypress-reporter.cjs. */
|
|
40
|
+
function captureKey(spec, titlePath, retry) {
|
|
41
|
+
const slug = String(spec)
|
|
42
|
+
.replace(/[^A-Za-z0-9]+/g, "_")
|
|
43
|
+
.slice(-60);
|
|
44
|
+
return `${slug}--${fnv1a(`${spec}\u0000${titlePath.join("\u0000")}`)}--${retry}`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** The page as `[TAG, {attributes}, ...children]`, text as strings: KwikQA's snapshot tree. */
|
|
48
|
+
function serialize(root) {
|
|
49
|
+
let budget = MAX_NODES;
|
|
50
|
+
const visit = (node) => {
|
|
51
|
+
if (budget <= 0) return undefined;
|
|
52
|
+
if (node.nodeType === 3) {
|
|
53
|
+
const value = node.textContent || "";
|
|
54
|
+
return value.trim() === "" ? undefined : value.slice(0, MAX_TEXT);
|
|
55
|
+
}
|
|
56
|
+
if (node.nodeType !== 1) return undefined;
|
|
57
|
+
if (SKIPPED_TAGS.has(node.tagName)) return undefined;
|
|
58
|
+
budget -= 1;
|
|
59
|
+
const attributes = {};
|
|
60
|
+
for (const attribute of Array.from(node.attributes)) {
|
|
61
|
+
attributes[attribute.name] = String(attribute.value).slice(0, MAX_TEXT);
|
|
62
|
+
}
|
|
63
|
+
// Form state is a property, not an attribute; the snapshot records what the user saw, under
|
|
64
|
+
// the names KwikQA's DOM renderer already reads from Playwright snapshots.
|
|
65
|
+
if (FORM_FIELDS.has(node.tagName) && typeof node.value === "string") {
|
|
66
|
+
attributes.__playwright_value_ = node.value.slice(0, MAX_TEXT);
|
|
67
|
+
}
|
|
68
|
+
if (node.checked === true) attributes.__playwright_checked_ = "true";
|
|
69
|
+
const children = [];
|
|
70
|
+
const childNodes = node.shadowRoot
|
|
71
|
+
? [...Array.from(node.shadowRoot.childNodes), ...Array.from(node.childNodes)]
|
|
72
|
+
: Array.from(node.childNodes);
|
|
73
|
+
for (const child of childNodes) {
|
|
74
|
+
const value = visit(child);
|
|
75
|
+
if (value !== undefined) children.push(value);
|
|
76
|
+
}
|
|
77
|
+
return [node.tagName, attributes, ...children];
|
|
78
|
+
};
|
|
79
|
+
return { tree: visit(root), truncated: budget <= 0 };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
let commands = [];
|
|
83
|
+
let consoleEntries = [];
|
|
84
|
+
let screenshots = [];
|
|
85
|
+
|
|
86
|
+
function brief(attributes) {
|
|
87
|
+
const props = attributes.renderProps || {};
|
|
88
|
+
const message = props.message !== undefined ? props.message : attributes.message;
|
|
89
|
+
return {
|
|
90
|
+
id: attributes.id,
|
|
91
|
+
name: String(attributes.name || ""),
|
|
92
|
+
...(attributes.displayName ? { displayName: String(attributes.displayName) } : {}),
|
|
93
|
+
message: String(message === undefined ? "" : message).slice(0, MAX_TEXT),
|
|
94
|
+
state: String(attributes.state || ""),
|
|
95
|
+
...(attributes.err
|
|
96
|
+
? { error: String(attributes.err.message || attributes.err).slice(0, MAX_TEXT) }
|
|
97
|
+
: {}),
|
|
98
|
+
...(attributes.url ? { url: String(attributes.url) } : {}),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
Cypress.on("test:before:run", () => {
|
|
103
|
+
commands = [];
|
|
104
|
+
consoleEntries = [];
|
|
105
|
+
screenshots = [];
|
|
106
|
+
});
|
|
107
|
+
Cypress.on("log:added", (attributes) => {
|
|
108
|
+
if (commands.length < MAX_LOG) commands.push(brief(attributes));
|
|
109
|
+
});
|
|
110
|
+
Cypress.on("log:changed", (attributes) => {
|
|
111
|
+
const index = commands.findIndex((entry) => entry.id === attributes.id);
|
|
112
|
+
if (index >= 0) commands[index] = brief(attributes);
|
|
113
|
+
});
|
|
114
|
+
Cypress.on("window:before:load", (win) => {
|
|
115
|
+
for (const level of ["error", "warn"]) {
|
|
116
|
+
const original = win.console[level];
|
|
117
|
+
win.console[level] = (...args) => {
|
|
118
|
+
if (consoleEntries.length < MAX_LOG) {
|
|
119
|
+
consoleEntries.push({
|
|
120
|
+
level,
|
|
121
|
+
text: args
|
|
122
|
+
.map((arg) => String(arg))
|
|
123
|
+
.join(" ")
|
|
124
|
+
.slice(0, MAX_TEXT),
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
return original.apply(win.console, args);
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
win.addEventListener("error", (event) => {
|
|
131
|
+
consoleEntries.push({ level: "pageerror", text: String(event.message).slice(0, MAX_TEXT) });
|
|
132
|
+
});
|
|
133
|
+
win.addEventListener("unhandledrejection", (event) => {
|
|
134
|
+
consoleEntries.push({
|
|
135
|
+
level: "pageerror",
|
|
136
|
+
text: `Unhandled rejection: ${String(event.reason).slice(0, MAX_TEXT)}`,
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
Cypress.Screenshot.defaults({
|
|
141
|
+
onAfterScreenshot(_element, props) {
|
|
142
|
+
screenshots.push({ path: props.path, testFailure: props.testFailure === true });
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
afterEach(function kwikqaCapture() {
|
|
147
|
+
const test = this.currentTest;
|
|
148
|
+
if (test?.state !== "failed") return;
|
|
149
|
+
const titlePath = test.titlePath();
|
|
150
|
+
const retry =
|
|
151
|
+
typeof test.currentRetry === "function" ? test.currentRetry() : test._currentRetry || 0;
|
|
152
|
+
const spec = Cypress.spec.relative;
|
|
153
|
+
cy.document({ log: false }).then((doc) => {
|
|
154
|
+
const snapshot = serialize(doc.documentElement);
|
|
155
|
+
const network = commands
|
|
156
|
+
.filter(
|
|
157
|
+
(entry) =>
|
|
158
|
+
entry.name === "request" ||
|
|
159
|
+
entry.name === "xhr" ||
|
|
160
|
+
entry.displayName === "fetch" ||
|
|
161
|
+
entry.displayName === "xhr",
|
|
162
|
+
)
|
|
163
|
+
.map((entry) => ({
|
|
164
|
+
message: entry.message,
|
|
165
|
+
state: entry.state,
|
|
166
|
+
...(entry.url ? { url: entry.url } : {}),
|
|
167
|
+
}));
|
|
168
|
+
const capture = {
|
|
169
|
+
schema: "kwikqa-capture",
|
|
170
|
+
schemaVersion: "1.0",
|
|
171
|
+
framework: "cypress",
|
|
172
|
+
spec,
|
|
173
|
+
titlePath,
|
|
174
|
+
retry,
|
|
175
|
+
url: doc.location ? doc.location.href : "",
|
|
176
|
+
title: doc.title,
|
|
177
|
+
viewport: {
|
|
178
|
+
width: Cypress.config("viewportWidth"),
|
|
179
|
+
height: Cypress.config("viewportHeight"),
|
|
180
|
+
},
|
|
181
|
+
dom: snapshot.tree,
|
|
182
|
+
domTruncated: snapshot.truncated,
|
|
183
|
+
commands: commands.map(({ id, ...rest }) => rest),
|
|
184
|
+
console: consoleEntries,
|
|
185
|
+
network,
|
|
186
|
+
screenshots,
|
|
187
|
+
};
|
|
188
|
+
cy.writeFile(`${OUT}/${captureKey(spec, titlePath, retry)}.json`, capture, { log: false });
|
|
189
|
+
});
|
|
190
|
+
});
|