mjolnir-qa 0.4.0 → 0.5.2
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 +1199 -28
- package/README.ar.md +667 -0
- package/README.bn.md +678 -0
- package/README.br.md +706 -0
- package/README.bs.md +690 -0
- package/README.da.md +698 -0
- package/README.de.md +711 -0
- package/README.es.md +709 -0
- package/README.fr.md +714 -0
- package/README.gr.md +705 -0
- package/README.he.md +664 -0
- package/README.it.md +709 -0
- package/README.ja.md +692 -0
- package/README.ko.md +681 -0
- package/README.md +425 -152
- package/README.no.md +696 -0
- package/README.pl.md +699 -0
- package/README.ru.md +701 -0
- package/README.th.md +672 -0
- package/README.tr.md +699 -0
- package/README.uk.md +693 -0
- package/README.vi.md +680 -0
- package/README.zh.md +652 -0
- package/README.zht.md +652 -0
- package/dist/cli.d.mts +469 -22
- package/dist/cli.mjs +9780 -5230
- package/package.json +25 -7
package/README.bs.md
ADDED
|
@@ -0,0 +1,690 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<img src="assets/readme/logo.png" alt="Mjölnir — Verification Trust Engine" width="800" />
|
|
4
|
+
|
|
5
|
+
### Tvoji testovi lažu. Mi to dokazujemo.
|
|
6
|
+
|
|
7
|
+
**Verification Trust Engine za QA.** Mjölnir audita test suite-ove i CI
|
|
8
|
+
pipeline-ove, izvještava ocjenjivački rezultat i pokazuje tačno gdje se
|
|
9
|
+
povjerenje lomi.
|
|
10
|
+
|
|
11
|
+
[](https://www.npmjs.com/package/mjolnir-qa)
|
|
12
|
+
[](https://github.com/Sergey-Bar/Mjolnir/actions/workflows/ci.yml)
|
|
13
|
+
[](LICENSE)
|
|
14
|
+
[](https://nodejs.org)
|
|
15
|
+
|
|
16
|
+
[English](README.md) | [简体中文](README.zh.md) | [繁體中文](README.zht.md) | [한국어](README.ko.md) | [Deutsch](README.de.md) | [Español](README.es.md) | [Français](README.fr.md) | [Italiano](README.it.md) | [Dansk](README.da.md) | [日本語](README.ja.md) | [Polski](README.pl.md) | [Русский](README.ru.md) | [Norsk](README.no.md) | [Português (Brasil)](README.br.md) | [ไทย](README.th.md) | [Türkçe](README.tr.md) | [Українська](README.uk.md) | [বাংলা](README.bn.md) | [Ελληνικά](README.gr.md) | [Tiếng Việt](README.vi.md) | [עברית](README.he.md) | [العربية](README.ar.md) | Bosanski
|
|
17
|
+
|
|
18
|
+
> 🤖 Machine-assisted translation. The [English README](README.md) is canonical. Last synced: 2026-09-04.
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx mjolnir-qa@latest
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Jesu li tvoji testovi dostojni povjerenja?**
|
|
25
|
+
|
|
26
|
+
[Vidi ga na djelu](#-vidi-ga-na-djelu) ·
|
|
27
|
+
[Brzi početak](#-brzi-početak) ·
|
|
28
|
+
[Šta provjerava](#-šta-mjölnir-provjerava) ·
|
|
29
|
+
[Bodovanje](#kako-radi-bodovanje) ·
|
|
30
|
+
[CI](#-ci-integracija) · [Konfiguracija](#konfiguracija) ·
|
|
31
|
+
[Dokumentacija](#-dokumentacija)
|
|
32
|
+
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 🎬 Vidi ga na djelu
|
|
38
|
+
|
|
39
|
+
<p align="center">
|
|
40
|
+
<img src="assets/readme/demo.svg" alt="Kompletan --verbose izvještaj Mjölnira nad demo repoom: WORTHINESS 75/100 NEEDS WORK, dijagnostika po kategorijama, lista FIX THIS FIRST i svaki nalaz sa ID-om pravila i brojem linije kroz CI, Playwright, test higijenu i Python pravila" width="900" />
|
|
41
|
+
</p>
|
|
42
|
+
|
|
43
|
+
<sub>Cjelokupan izlaz `npx mjolnir-qa ./examples/demo-repo --verbose`,
|
|
44
|
+
renderiran od pravog reportera — ništa skraćeno. Regenerira se preko
|
|
45
|
+
`npm run docs:demo`;
|
|
46
|
+
[`tests/demo-asset-reproducibility.spec.ts`](tests/demo-asset-reproducibility.spec.ts)
|
|
47
|
+
obara CI ako artefakt odskoči od onoga što alat ispisuje.</sub>
|
|
48
|
+
|
|
49
|
+
**Šta se upravo desilo:**
|
|
50
|
+
|
|
51
|
+
1. Mjölnir je pronašao Playwright specifikacije, svoju konfiguraciju,
|
|
52
|
+
CI workflow i Python test fajl — četiri jezika/formata, jedan prolaz.
|
|
53
|
+
2. Pronašao je dokaze koji slabe povjerenje u suite — `continue-on-error`
|
|
54
|
+
koji maskira job, `|| true` koji guta exit kod, tvrdi sleepovi,
|
|
55
|
+
krhki selektor, ugrađene staging URL-ove, `networkidle` čekanje.
|
|
56
|
+
3. Svaki je pretvorio u konkretan nalaz s ID-om pravila, lokacijom i
|
|
57
|
+
fixom — i u jedan rezultat na koji možeš gate-ovati PR.
|
|
58
|
+
|
|
59
|
+
### Jedan nalaz izbliza
|
|
60
|
+
|
|
61
|
+
Pokreni `mjolnir explain QA-CI-001` na prvom nalaženom iznad i dobiješ:
|
|
62
|
+
|
|
63
|
+
```text
|
|
64
|
+
▚▞ QA-CI-001 — continue-on-error masks a failing verification gate
|
|
65
|
+
|
|
66
|
+
Severity: error
|
|
67
|
+
Confidence: high
|
|
68
|
+
Evidence: E2
|
|
69
|
+
Measured FP: not yet measured — this rule ships on assumption (see docs/FP-AUDIT.md)
|
|
70
|
+
|
|
71
|
+
WHAT WAS FOUND (real detector output, not a mockup)
|
|
72
|
+
Job `security-scan` runs a verification gate under `continue-on-error: true`.
|
|
73
|
+
|
|
74
|
+
WHY IT MATTERS
|
|
75
|
+
This job can fail every day and CI will still show green. The checkmark
|
|
76
|
+
on this workflow cannot be trusted.
|
|
77
|
+
|
|
78
|
+
HOW TO FIX
|
|
79
|
+
Remove continue-on-error, or scope it to individual non-blocking steps only.
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
To je jedinica vrijednosti: ne sitnica stila, nego mjesto gdje ti CI
|
|
83
|
+
poručuje da je nešto prošlo, a nije prošlo.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## ⚡ Brzi početak
|
|
88
|
+
|
|
89
|
+
Pokreni ga nad repoom za kompletan izvještaj i ocjenjivački rezultat:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
npx mjolnir-qa@latest
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**U CI je proizvod jedna komanda.** Skenira samo ono što je grana
|
|
96
|
+
dotakla i izlazi s ne-nula kodom kod novih problema:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
npx mjolnir-qa@latest --scope changed
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Ubaci to kao check u PR — `mjolnir ci install` piše workflow — i
|
|
103
|
+
gotovo. Sve ostalo je opciono.
|
|
104
|
+
|
|
105
|
+
| Komanda | Šta radi |
|
|
106
|
+
| ----------------------------------- | ------------------------------------------------------- |
|
|
107
|
+
| `mjolnir` | Sken cijelog repoa + ocjenjivački rezultat |
|
|
108
|
+
| `mjolnir --scope changed` | Samo ono što je tvoja grana unijela — CI oblik |
|
|
109
|
+
| `mjolnir ci install` | Generiše savjetodavni PR workflow |
|
|
110
|
+
| `mjolnir explain QA-CI-001` | Šta / zašto / fix + izmjerena FP stopa za jedno pravilo |
|
|
111
|
+
| `mjolnir rules --unmeasured` | Pravila koja rade pretpostavkom, a ne mjerenjem |
|
|
112
|
+
| `mjolnir --json` / `--format sarif` | Mašinski čitljivo / GitHub Code Scanning |
|
|
113
|
+
| `mjolnir --strict` | Pokreće i pravila quarantine tier-a (veći rizik FP) |
|
|
114
|
+
|
|
115
|
+
<details>
|
|
116
|
+
<summary><strong>Kad je nešto flaky</strong></summary>
|
|
117
|
+
|
|
118
|
+
| Komanda | Šta radi |
|
|
119
|
+
| ----------------------------------- | -------------------------------------------------------- |
|
|
120
|
+
| `mjolnir forensics ./test-results/` | Stvarni podaci runova → presude `TRUE-FLAKE`, `FLAKY.md` |
|
|
121
|
+
| `mjolnir triage ./test-results/` | Prijedlog karantene iz historije izvršavanja |
|
|
122
|
+
| `mjolnir pw-report ./test-results/` | Sažetak Playwright runa — retry / flake / najsporiji |
|
|
123
|
+
| `mjolnir doctor:playwright` | Dubinski skan samo Playwright + Selector Health Score |
|
|
124
|
+
|
|
125
|
+
</details>
|
|
126
|
+
|
|
127
|
+
<details>
|
|
128
|
+
<summary><strong>Povremeno / izvještaji</strong></summary>
|
|
129
|
+
|
|
130
|
+
| Komanda | Šta radi |
|
|
131
|
+
| ------------------------------- | ------------------------------------------------- |
|
|
132
|
+
| `mjolnir fix --dry-run` / `fix` | Sigurne automatske popravke s dokazom |
|
|
133
|
+
| `mjolnir baseline` / `diff` | Snimak nalaza, pa izvještaj samo novih/pogoršanih |
|
|
134
|
+
| `mjolnir impact --since <ref>` | Šta se promijenilo od ranijeg commita |
|
|
135
|
+
| `mjolnir debt` | Registarr testnog duga s modelom troška |
|
|
136
|
+
| `mjolnir handover` | Karta onboardingu suite-a za novog QA |
|
|
137
|
+
| `mjolnir stats` | Lokalni ukupni brojači viđenih fixova |
|
|
138
|
+
| `mjolnir badge` | shields.io endpoint JSON + snippet |
|
|
139
|
+
| `mjolnir rules --md` | Potpuni katalog pravila (JSON ili Markdown) |
|
|
140
|
+
| `mjolnir doctor` | Samoaudit Mjölnirove vlastite baze pravila |
|
|
141
|
+
| `mjolnir create-rule <ID>` | Scafholduje novo pravilo + fixture |
|
|
142
|
+
| `mjolnir --format mermaid` | Dijagram test arhitekture za PR komentar |
|
|
143
|
+
|
|
144
|
+
</details>
|
|
145
|
+
|
|
146
|
+
Instaliraj globalno umjesto `npx` ako preferiraš: `npm i -g mjolnir-qa`.
|
|
147
|
+
Zahtijeva Node.js ≥ 22.18. Radi na Windows, macOS i Linux.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## 👥 Za koga je ovo?
|
|
152
|
+
|
|
153
|
+
- **QA / SDET** koji drže e2e ili integracioni suite i trebaju dokaz da
|
|
154
|
+
suite stvarno zaslužuje zeleni check koji proizvodi.
|
|
155
|
+
- **Platform / DevEx timovi** odgovorni za CI integritet i release
|
|
156
|
+
gateove — ljudi kojima je stalo da `continue-on-error` nikad ne
|
|
157
|
+
preboji crveni pipeline u zeleni u tišini.
|
|
158
|
+
- **OSS maintaineri** koji žele jeftin, uvijek uključen verifikacioni
|
|
159
|
+
gate koji radi lokalno i u CI bez mrežnih poziva.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## 🔨 Šta Mjölnir provjerava
|
|
164
|
+
|
|
165
|
+
| | |
|
|
166
|
+
| --- | --------------------------------------------------------------------------------------------------------------------- |
|
|
167
|
+
| ⚖️ | **Ocjenjivački rezultat** — jedan broj, transparentna tabela odbitaka, bez crne kutije |
|
|
168
|
+
| 🎭 | **Selector Health Score** — ocjenjuje tvoje Playwright locatore, ne samo prolaznost |
|
|
169
|
+
| 🔬 | **Runtime forenzika** — čita stvarne Playwright/JUnit podatke runova i hvata `TRUE-FLAKE`, ne samo statičke nagađanja |
|
|
170
|
+
| 🚨 | **Pravila CI integriteta** — hvata `continue-on-error`, `\|\| true` i druge trikove lažno zelenog |
|
|
171
|
+
| 🐍 | **Sva četiri Playwright bindinga** — TypeScript, Python, Java, C#/.NET — plus pytest, JUnit/TestNG i CI workflowi |
|
|
172
|
+
| 🔒 | **Local-first** — nula mrežnih poziva pri skeniranju, nula telemetrije, radi u sekundama |
|
|
173
|
+
|
|
174
|
+
### Pravila
|
|
175
|
+
|
|
176
|
+
Svako pravilo dolazi s must-fire **i** must-not-fire fixtureima.
|
|
177
|
+
Pravilo koje okida na svojoj negativnoj fixture ne može se isporučiti —
|
|
178
|
+
to je vatrozid lažnih pozitiva.
|
|
179
|
+
|
|
180
|
+
<details>
|
|
181
|
+
<summary><strong>Test higijena</strong></summary>
|
|
182
|
+
|
|
183
|
+
| ID | Pravilo | Severity |
|
|
184
|
+
| ----------- | ---------------------------------------------------- | -------- |
|
|
185
|
+
| QA-TEST-001 | Commitiran fokusirani test (`.only`, `fit`) | error |
|
|
186
|
+
| QA-TEST-002 | Preskočen test bez opravdanja | error |
|
|
187
|
+
| QA-TEST-002 | Preskočen test s evidentiranim opravdanjem | warning |
|
|
188
|
+
| QA-TEST-003 | Test bez asercija | error |
|
|
189
|
+
| QA-TEST-004 | Tvrdi sleep (`waitForTimeout`, `sleep()`, `delay()`) | warning |
|
|
190
|
+
| QA-TEST-006 | Zloupotreba retrya koja krije flakiness | warning |
|
|
191
|
+
| QA-TEST-010 | Prazno tijelo testa | error |
|
|
192
|
+
|
|
193
|
+
</details>
|
|
194
|
+
|
|
195
|
+
<details>
|
|
196
|
+
<summary><strong>Kvalitet testova</strong></summary>
|
|
197
|
+
|
|
198
|
+
| ID | Pravilo | Severity |
|
|
199
|
+
| ------------ | ----------------------------- | -------- |
|
|
200
|
+
| QA-TQUAL-001 | Verifikacija samo mockovima | info |
|
|
201
|
+
| QA-TQUAL-002 | Tautološka asercija | error |
|
|
202
|
+
| QA-TQUAL-009 | Asercija neawaitanog promisea | error |
|
|
203
|
+
| QA-TQUAL-011 | Komentarisani testovi | warning |
|
|
204
|
+
|
|
205
|
+
</details>
|
|
206
|
+
|
|
207
|
+
<details>
|
|
208
|
+
<summary><strong>Playwright 🎭</strong></summary>
|
|
209
|
+
|
|
210
|
+
| ID | Pravilo | Severity |
|
|
211
|
+
| --------- | ------------------------------------------ | -------- |
|
|
212
|
+
| QA-PW-002 | Asercija lokatora bez awaita | error |
|
|
213
|
+
| QA-PW-003 | `page.pause()` / `test.only()` commitirani | error |
|
|
214
|
+
| QA-PW-004 | Krhki CSS/XPath selektori | warning |
|
|
215
|
+
| QA-PW-005 | Poslovna logika unutar `page.evaluate()` | info |
|
|
216
|
+
| QA-PW-114 | Legacy element handleovi (`page.$`) | info |
|
|
217
|
+
| QA-PW-118 | `networkidle` čekanja (flaky po dizajnu) | info |
|
|
218
|
+
| QA-PW-123 | Ugrađeni URL-ovi okruženja | warning |
|
|
219
|
+
|
|
220
|
+
</details>
|
|
221
|
+
|
|
222
|
+
<details>
|
|
223
|
+
<summary><strong>CI integritet</strong></summary>
|
|
224
|
+
|
|
225
|
+
| ID | Pravilo | Severity |
|
|
226
|
+
| --------- | --------------------------------------------------------------- | -------- |
|
|
227
|
+
| QA-CI-001 | `continue-on-error` maskira padove | error |
|
|
228
|
+
| QA-CI-002 | `\|\| true` guta exit kodove | error |
|
|
229
|
+
| QA-CI-005 | Izvještaj se troši ali nikad ne generira | error |
|
|
230
|
+
| QA-CI-007 | Retry omotači oko testova | warning |
|
|
231
|
+
| QA-CI-008 | Uvijek uspješan step maskira padove | error |
|
|
232
|
+
| QA-CI-009 | Exit kod testa se ne propagira (`\|` bez pipefail, `;` lanci) | error |
|
|
233
|
+
| QA-CI-010 | Testovi preskaču se gdje moraju blokirati (skip-on-PR guardovi) | error |
|
|
234
|
+
|
|
235
|
+
</details>
|
|
236
|
+
|
|
237
|
+
<details>
|
|
238
|
+
<summary><strong>Python / pytest 🐍</strong></summary>
|
|
239
|
+
|
|
240
|
+
| ID | Pravilo | Severity |
|
|
241
|
+
| --------- | ------------------------------------------ | -------- |
|
|
242
|
+
| QA-PY-002 | Preskočen test (`skip`, nestrogi `xfail`) | warning |
|
|
243
|
+
| QA-PY-003 | Test funkcija bez asercija | error |
|
|
244
|
+
| QA-PY-005 | `time.sleep()` u testovima | warning |
|
|
245
|
+
| QA-PY-006 | Prazno tijelo testa (`pass`) | info |
|
|
246
|
+
| QA-PY-010 | Ovisnost o slučajnosti/vremenu bez freezea | info |
|
|
247
|
+
| QA-PY-012 | Tautološka asercija | error |
|
|
248
|
+
|
|
249
|
+
Ukupno 20 Python pravila (QA-PY-001…012 pytest higijena + QA-PY-101…108 Playwright-Python).
|
|
250
|
+
|
|
251
|
+
</details>
|
|
252
|
+
|
|
253
|
+
<details>
|
|
254
|
+
<summary><strong>Java / JUnit · TestNG ☕</strong></summary>
|
|
255
|
+
|
|
256
|
+
| ID | Pravilo | Severity |
|
|
257
|
+
| --------- | ----------------------------------------- | -------- |
|
|
258
|
+
| QA-JV-101 | Onemogućen test (`@Disabled`) | warning |
|
|
259
|
+
| QA-JV-102 | Tvrdi sleep (`Thread.sleep()`) | warning |
|
|
260
|
+
| QA-JV-103 | Test metoda bez asercija | error |
|
|
261
|
+
| QA-JV-105 | Tvrdi sleep Playwright `waitForTimeout()` | warning |
|
|
262
|
+
| QA-JV-106 | Krhki selektor umjesto role lokatora | warning |
|
|
263
|
+
| QA-JV-108 | Ugrađeni URL okruženja u testu | info |
|
|
264
|
+
| QA-JV-111 | Pokrivni mock `page.route("**")` | info |
|
|
265
|
+
|
|
266
|
+
</details>
|
|
267
|
+
|
|
268
|
+
<details>
|
|
269
|
+
<summary><strong>C# / .NET — NUnit · xUnit · MSTest 🟣</strong></summary>
|
|
270
|
+
|
|
271
|
+
| ID | Pravilo | Severity |
|
|
272
|
+
| --------- | -------------------------------------------- | -------- |
|
|
273
|
+
| QA-CS-101 | Preskočen test (`[Ignore]`, `[Fact(Skip=)]`) | warning |
|
|
274
|
+
| QA-CS-102 | Tvrdi sleep (`Thread.Sleep` / `Task.Delay`) | warning |
|
|
275
|
+
| QA-CS-103 | Test metoda bez asercija | error |
|
|
276
|
+
| QA-CS-105 | Tvrdi sleep `WaitForTimeoutAsync()` | warning |
|
|
277
|
+
| QA-CS-106 | Krhki selektor umjesto role lokatora | warning |
|
|
278
|
+
| QA-CS-108 | Ugrađeni URL okruženja u testu | info |
|
|
279
|
+
| QA-CS-111 | Pokrivni mock `page.RouteAsync("**")` | info |
|
|
280
|
+
|
|
281
|
+
</details>
|
|
282
|
+
|
|
283
|
+
> Potpuni živi katalog — svako pravilo s tierom, confidence, rizikom
|
|
284
|
+
> lažnih pozitiva i dostupnošću autofixa — generira se iz registra:
|
|
285
|
+
>
|
|
286
|
+
> ```bash
|
|
287
|
+
> mjolnir rules --md
|
|
288
|
+
> ```
|
|
289
|
+
>
|
|
290
|
+
> Stranice po pravilu žive u [`docs/rules/`](docs/rules/).
|
|
291
|
+
|
|
292
|
+
### Koliko je od ovoga izmjereno
|
|
293
|
+
|
|
294
|
+
**74 od 99 pravila nose stopu lažnih pozitiva izmjerenu nad stvarnim
|
|
295
|
+
OSS kodom** (≥ 10 ručno klasificiranih nalaza svako; vidi
|
|
296
|
+
[docs/FP-AUDIT.md](docs/FP-AUDIT.md)). Ostalih 19 izlazi na autorovoj
|
|
297
|
+
procjeni. Podnožje svakog skana kaže koliko od _okinutih_ pravila je
|
|
298
|
+
izmjereno; `mjolnir rules --unmeasured` izlista neizmjerena; stranica
|
|
299
|
+
`mjolnir explain` svakog pravila navodi njen status. Objavljujemo stopu
|
|
300
|
+
čak i kad je ružna — QA-CS-103 se audita na 95 % i u karanteni je radi
|
|
301
|
+
toga. Rast tog 78 je neprekidni rad projekta.
|
|
302
|
+
|
|
303
|
+
### Tierovi pravila i jezična zrelost
|
|
304
|
+
|
|
305
|
+
Svako pravilo je `core`, `extended` ili `quarantine`, dodijeljeno prema
|
|
306
|
+
njegovoj **izmjerenij** stopi lažnih pozitiva:
|
|
307
|
+
|
|
308
|
+
| Tier | Značenje | Zadani skan | `--strict` |
|
|
309
|
+
| ------------ | ---------------------------------------- | :---------: | :--------: |
|
|
310
|
+
| `core` | ≤ 10 % izmjerena FP | ✅ | ✅ |
|
|
311
|
+
| `extended` | ≤ 30 % izmjerena FP | ✅ | ✅ |
|
|
312
|
+
| `quarantine` | iznad 30 %, ili još neizmjereno (n < 10) | ❌ | ✅ |
|
|
313
|
+
|
|
314
|
+
| Jezik | Adapter | Pokrivenost danas |
|
|
315
|
+
| --------------- | -------------- | --------------------------------------------------------- |
|
|
316
|
+
| TypeScript / JS | AST kompajlera | najšira, najviše mjerena — pretežno `core`/`extended` |
|
|
317
|
+
| Python / pytest | Regex sloj | široka, auditrana na korpusu — pretežno `core`/`extended` |
|
|
318
|
+
| Java | Regex sloj | novija — pretežno `extended`/`quarantine` |
|
|
319
|
+
| C# / .NET | Regex sloj | novija — pretežno `extended`/`quarantine` |
|
|
320
|
+
|
|
321
|
+
TypeScript i Python imaju najširu izmjerenu pokrivenost. Java i C# su
|
|
322
|
+
isporučeni, dokumentirani i ostaju izvan glavnog broja dok se prava
|
|
323
|
+
korisnička suite (ne vlastiti testovi binding biblioteke) ne audita.
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
## Kako radi bodovanje
|
|
328
|
+
|
|
329
|
+
<p align="center">
|
|
330
|
+
<img src="assets/readme/terminal-hero.svg" alt="Terminalni izlaz Mjölnira — WORTHINESS 75/100 NEEDS WORK, dijagnostika po kategorijama i lista FIX THIS FIRST" width="820" />
|
|
331
|
+
</p>
|
|
332
|
+
|
|
333
|
+
<sub>Regenerira se preko `npm run docs:hero`;
|
|
334
|
+
[`tests/hero-asset-reproducibility.spec.ts`](tests/hero-asset-reproducibility.spec.ts)
|
|
335
|
+
obara CI ako artefakt odskoči od onoga što reporter stvarno ispisuje.</sub>
|
|
336
|
+
|
|
337
|
+
Bodovanje je transparentno: **error −8, warning −3, info −1**, pa
|
|
338
|
+
normalizirano izloženošću suite-a (odbitci po deklaraciji testa).
|
|
339
|
+
Odbitci ponderirani dokazima znače da slabi signali koštaju manje.
|
|
340
|
+
Terminal pokazuje iste popustljive brojeve koje koristi bodovanje —
|
|
341
|
+
bez crne kutije. Puna metoda: [docs/SCORING.md](docs/SCORING.md).
|
|
342
|
+
|
|
343
|
+
**Presude**
|
|
344
|
+
|
|
345
|
+
| Score | Presuda |
|
|
346
|
+
| ------- | ---------------- |
|
|
347
|
+
| ≥ 80 | ✓ **WORTHY** |
|
|
348
|
+
| 50 – 79 | ⚠ **NEEDS WORK** |
|
|
349
|
+
| < 50 | ✖ **UNWORTHY** |
|
|
350
|
+
|
|
351
|
+
**Nivoi dokaza** — svaki nalaz nosi jedan; on postavlja težinu nalaza u
|
|
352
|
+
bodovanju:
|
|
353
|
+
|
|
354
|
+
| Nivo | Značenje | Utjecaj na bodovanje | Primjer |
|
|
355
|
+
| ---- | ---------------------- | -------------------- | -------------------------------------------------- |
|
|
356
|
+
| E2 | Deterministički defekt | Potpuni odbitak | Commitirani `.only` — strukturno dokazivo |
|
|
357
|
+
| E1 | Heuristički obrazac | Polovina odbitka | Regexom pogođen `sleep()` — jak signal, nije dokaz |
|
|
358
|
+
| E0 | Zapažanje | Nula (samo info) | Prijavljeno ali nikad ne gate-uje CI niti odbija |
|
|
359
|
+
|
|
360
|
+
Većina pravila je **E1**. Slogan „we prove it" odnosi se na ovaj
|
|
361
|
+
sistem: E2 nalazi su strukturni dokaz; E1 nalazi su ispravno
|
|
362
|
+
pozicionirana upozorenja, ne formalni dokazi.
|
|
363
|
+
|
|
364
|
+
Prazan repo boduje `null`, nikad lažnih 100 — vidi
|
|
365
|
+
[Model povjerenja](#model-povjerenja).
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## 🎭 Selector Health Score
|
|
370
|
+
|
|
371
|
+
Vodeća metrika za Playwright suiteove — koliko su otporni tvoji
|
|
372
|
+
lokatori:
|
|
373
|
+
|
|
374
|
+
```text
|
|
375
|
+
▚▞ SELECTOR HEALTH — e2e/checkout.spec.ts
|
|
376
|
+
|
|
377
|
+
[█████████████████░░░] 83 / 100
|
|
378
|
+
role/text: 2 · testid: 1 · css-chains: 1 ⚠ · xpath: 0
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
Role-bazirani lokatori osvajaju pun bodovni rezultat. CSS lanac klasa i
|
|
382
|
+
XPath tone rezultat — lome se na svakom DOM refactoru ne govoreći ti
|
|
383
|
+
koje ponašanje je regresiralo.
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
## 🔬 Runtime dokazi
|
|
388
|
+
|
|
389
|
+
Statička detekcija flakinessa je nagađanje. Mjölnir čita **stvarne
|
|
390
|
+
podatke izvršavanja** — Playwright JSON izvještaje i JUnit XML od
|
|
391
|
+
bilo kojeg runnera:
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
mjolnir forensics ./test-results/
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
```text
|
|
398
|
+
▚▞ FLAKINESS LEADERBOARD
|
|
399
|
+
|
|
400
|
+
3 tests · 1 failed · 1 flaky · 1 retried
|
|
401
|
+
|
|
402
|
+
TRUE-FLAKE completes checkout with saved card (e2e/checkout.spec.ts)
|
|
403
|
+
████████████████████ 6.0s · 2 attempts
|
|
404
|
+
FAILING declines an expired card (e2e/checkout.spec.ts)
|
|
405
|
+
████░░░░░░░░░░░░░░░░ 1.1s · 1 attempt
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
Test koji prolazi tek od pokušaja ≥ 2 nije prolazni test — to je
|
|
409
|
+
sretan test. Označava se kao `TRUE-FLAKE` bez obzira na konačni zeleni
|
|
410
|
+
check.
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
## ⚡ Mjölnir nije još jedan linter
|
|
415
|
+
|
|
416
|
+
Linteri ti kažu prati li kod pravila. Mjölnir ti kaže može li se tvojoj
|
|
417
|
+
verifikaciji vjerovati.
|
|
418
|
+
|
|
419
|
+
| | ESLint / SonarQube | Coverage alati | Ručni review | **Mjölnir** |
|
|
420
|
+
| --------------------------------------------------------- | :----------------: | :------------: | :----------: | :---------: |
|
|
421
|
+
| CI workflow integritet (`continue-on-error`, `\|\| true`) | ❌ | ❌ | rijetko | ✅ |
|
|
422
|
+
| Unakrsno-jezično (TS, Python, Java, C#) iz jednog alata | ❌ | ❌ | ❌ | ✅ |
|
|
423
|
+
| Ocjenjuje otpornost Playwright lokatora (Selector Health) | ❌ | ❌ | rijetko | ✅ |
|
|
424
|
+
| Označava testove bez pravih asercija | ✅ (plugin)\* | ❌ | ponekad | ✅ |
|
|
425
|
+
| Hvata tvrde sleepove (`waitForTimeout`, `time.sleep`) | ✅ (plugin)\* | ❌ | ponekad | ✅ |
|
|
426
|
+
| Radi u sekundama, nula mrežnih poziva pri skeniranju | ✅ | ✅ | — | ✅ |
|
|
427
|
+
|
|
428
|
+
\*`eslint-plugin-jest` (`expect-expect`) i `eslint-plugin-playwright`
|
|
429
|
+
(`expect-expect`, `no-wait-for-timeout`) pokrivaju ovo za svoje
|
|
430
|
+
frameworkove.
|
|
431
|
+
|
|
432
|
+
**Runtime analiza** je odvojena kategorija od statičkog lintanja:
|
|
433
|
+
|
|
434
|
+
| | Playwright retry reporter | Allure / ReportPortal | **Mjölnir forensics** |
|
|
435
|
+
| --------------------------------------------------- | :-----------------------: | :-------------------: | :-------------------: |
|
|
436
|
+
| Čita stvarne podatke runova za presude `TRUE-FLAKE` | djelimično\* | djelimično (tag) | ✅ |
|
|
437
|
+
| Izvještaj flaky triaže iz historije izvršavanja | ❌ | ✅ | ✅ |
|
|
438
|
+
| Integrira se sa statičkim ocjenjivačkim rezultatom | ❌ | ❌ | ✅ |
|
|
439
|
+
|
|
440
|
+
\*Playwright interno prati retryje ali ne proizvodi samostalan izvještaj
|
|
441
|
+
flakinessa s oznakama presuda.
|
|
442
|
+
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
## 🤖 Zašto ne koristiti samo AI code review?
|
|
446
|
+
|
|
447
|
+
Drugi problem, drugi sloj. AI review može primijetiti sumnjivu promjenu
|
|
448
|
+
testa u diffu; ne dokazuje da je verifikacioni sistem kao cjelina
|
|
449
|
+
dostojan povjerenja — i vidi samo diff koji mu pokažeš.
|
|
450
|
+
|
|
451
|
+
| | AI code review (Copilot i sl.) | **Mjölnir** |
|
|
452
|
+
| ---------------------------------------- | :------------------------------: | :-----------------------------: |
|
|
453
|
+
| Trošak po skanu | Tokeni (raste s veličinom diffa) | **Nula** (lokalno, instalirano) |
|
|
454
|
+
| Vidi cijeli suite + sve CI konfiguracije | Samo PR diff koji pokažeš | **Sve, svaki put** |
|
|
455
|
+
| Deterministički (isti ulaz → isti izlaz) | ❌ (nedeterministički) | **✅** |
|
|
456
|
+
| Hvata obrasce dormantne mjesecima | Samo ako je u kontekstu | **✅** (skenira sve fajlove) |
|
|
457
|
+
| Pamti nalaze između runova | ❌ (nema memorije između sesija) | **✅** (baseline + diff) |
|
|
458
|
+
| Radi bez ljudskog okidača | Treba PR ili prompt | **✅** (CI hook, 3 sekunde) |
|
|
459
|
+
|
|
460
|
+
**Koristi oba.** AI hvata nijansu, namjeru i dizajnerske mane koje
|
|
461
|
+
nijedan regex ne nađe. Mjölnir hvata strukturne obrasce koje AI
|
|
462
|
+
zaobilazi jer izgledaju „namjerno" — commitirani `.only`, progutani
|
|
463
|
+
exit kod, `continue-on-error` na test jobu. To nisu bugovi koji trebaju
|
|
464
|
+
razmišljanje; to su činjenice koje trebaju skeniranje.
|
|
465
|
+
|
|
466
|
+
---
|
|
467
|
+
|
|
468
|
+
## 🤖 CI integracija
|
|
469
|
+
|
|
470
|
+
Jedna komanda generira PR workflow — po defaultu savjetodavan, nikad
|
|
471
|
+
blokirajući:
|
|
472
|
+
|
|
473
|
+
```bash
|
|
474
|
+
mjolnir ci install
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
Ili ga poveži nativno u GitHub Code Scanning preko SARIF-a:
|
|
478
|
+
|
|
479
|
+
```yaml
|
|
480
|
+
- run: npx mjolnir-qa@latest --format sarif > mjolnir.sarif
|
|
481
|
+
- uses: github/codeql-action/upload-sarif@v3
|
|
482
|
+
with:
|
|
483
|
+
sarif_file: mjolnir.sarif
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
Editor i pipeline postavka za SARIF:
|
|
487
|
+
[docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md).
|
|
488
|
+
|
|
489
|
+
### Pokrivenost promijenjenog opsega
|
|
490
|
+
|
|
491
|
+
`--scope changed` pripisuje nalazima linije dodane u tvojoj grani naspram
|
|
492
|
+
merge-base s `main`. Pokriva test fajlove (`*.spec.*`, `*.test.*`) plus
|
|
493
|
+
GitHub workflow fajlove i Playwright konfiguracije u diffu. Kad se
|
|
494
|
+
merge-base ne može razriješiti — shallow clone, detached HEAD, non-git
|
|
495
|
+
cilj, drugi zadani branch — pošteno degradira: nalazi se vraćaju na
|
|
496
|
+
atribuciju po cijelom fajlu i izvještaj to kaže. Prepiši baznu ref s
|
|
497
|
+
`--base <ref>`.
|
|
498
|
+
|
|
499
|
+
---
|
|
500
|
+
|
|
501
|
+
## Konfiguracija
|
|
502
|
+
|
|
503
|
+
Mjölnir je zero-config. Opcioni `mjolnir.config.json` (ili
|
|
504
|
+
`.mjolnir.json`) u korijenu repoa podešava severity, gating i opseg —
|
|
505
|
+
nikad ne mijenja semantiku detekcije.
|
|
506
|
+
|
|
507
|
+
| Key | Tip | Efekat |
|
|
508
|
+
| ------------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
509
|
+
| `exclude` | `string[]` | Dodatni ignore globovi (gitignore podskup), preko ugrađenih defaulta |
|
|
510
|
+
| `gate` | `"advisory" \| "error" \| "warning"` | Koji severity izlaze s ne-nula kodom (default `error`; `advisory` nikad ne blokira) |
|
|
511
|
+
| `severityOverrides` | `{ "<RULE-ID>": severity }` | Prerangiraje nalaze pravila za tvoj repo |
|
|
512
|
+
| `ignore` | `IgnoreEntry[]` | Potiskuje nalaze — **`reason` je obavezan**; unosi istječu nakon 90 dana (eksplicitni `expires` datum, ili vrijeme zadnje izmjene config fajla za unose bez njega) |
|
|
513
|
+
| `plugins` | `string[]` | Paketi pravila trećih strana (vidi [Model povjerenja](#model-povjerenja)) |
|
|
514
|
+
|
|
515
|
+
```json
|
|
516
|
+
{
|
|
517
|
+
"gate": "error",
|
|
518
|
+
"exclude": ["legacy/**"],
|
|
519
|
+
"severityOverrides": { "QA-PW-118": "warning" },
|
|
520
|
+
"ignore": [
|
|
521
|
+
{
|
|
522
|
+
"ruleId": "QA-TEST-004",
|
|
523
|
+
"files": ["e2e/legacy-login.spec.ts"],
|
|
524
|
+
"reason": "Third-party widget needs a settle delay; tracked in JIRA-4821",
|
|
525
|
+
"expires": "2026-12-31"
|
|
526
|
+
}
|
|
527
|
+
]
|
|
528
|
+
}
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
- **`.mjolnirignore`** — jednostavna gitignore-slična datoteka za
|
|
532
|
+
isključenja putanja, isti dijalekt kao `exclude`. Koristi je za
|
|
533
|
+
mašinski šum; koristi `exclude` kad lista pripadne version kontroli,
|
|
534
|
+
uz ostatak konfiguracije.
|
|
535
|
+
- **CLI nadjačavanja** — `--strict` (uključi quarantine pravila),
|
|
536
|
+
`--width <cols>` i `--ascii` / `--no-ascii` (terminalski render),
|
|
537
|
+
`--tone blunt` (oštrije poruke), `--max-duration <sec>` (ograničen
|
|
538
|
+
djelomični skan).
|
|
539
|
+
- Potiskivanje pravila i životni ciklus deprecacije:
|
|
540
|
+
[docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md).
|
|
541
|
+
|
|
542
|
+
`ignore` unosi hrane i samostalnu komandu `mjolnir suppressions`, koja
|
|
543
|
+
izlista šta je trenutno potisnuto i kada ističe svaki unos.
|
|
544
|
+
|
|
545
|
+
---
|
|
546
|
+
|
|
547
|
+
## 📐 Exit kodovi i ugovori
|
|
548
|
+
|
|
549
|
+
Zamrznuti — sigurni za gradnju CI logike:
|
|
550
|
+
|
|
551
|
+
| Exit kod | Značenje |
|
|
552
|
+
| -------- | ---------------------------------------------------------------------------------- |
|
|
553
|
+
| `0` | Čisto — nema nalaza na ili iznad gatea |
|
|
554
|
+
| `1` | Nalazi na ili iznad gatea |
|
|
555
|
+
| `2` | Djelimičan skan (potrošen vremenski budžet, nečitljivi fajlovi) — nikad ne blokira |
|
|
556
|
+
| `10` | Greška upotrebe (loš flag, nedostaje cilj) |
|
|
557
|
+
| `20` | Interna greška |
|
|
558
|
+
|
|
559
|
+
JSON/SARIF izvještaj je `schemaVersion: 1`. ID-jevi pravila
|
|
560
|
+
(`QA-<FAMILY>-NNN`) su nepromjenjivi jednom isporučeni i nikad se ne
|
|
561
|
+
ponovo koriste.
|
|
562
|
+
|
|
563
|
+
---
|
|
564
|
+
|
|
565
|
+
## Model povjerenja
|
|
566
|
+
|
|
567
|
+
- **Local-first** — nula mrežnih poziva tokom skeniranja. Nikad. Nula
|
|
568
|
+
telemetrije.
|
|
569
|
+
- **Bez lažnih dokaza** — radije kažemo „nepoznato" nego „verifikovano".
|
|
570
|
+
Prazan repo dobija `score: null`, nikad lažnih 100.
|
|
571
|
+
- **Djelimična iskrenost** — ako je analiza prekinuta, izlaz to kaže.
|
|
572
|
+
Nikad „complete" kad nije.
|
|
573
|
+
- **FP vatrozid** — detekcija radi na pregledu koda bez komentara i
|
|
574
|
+
stringova (TypeScript pravila koriste AST kompajlera): obrazac unutar
|
|
575
|
+
prosačnog komentara ili doc-primjera-stringa je dokumentacija, ne
|
|
576
|
+
nalaz.
|
|
577
|
+
- **Izmjereno, ne tvrđeno** — u glavne tierove ulaze samo pravila sa
|
|
578
|
+
stopom lažnih pozitiva iz stvarnog OSS koda (vidi
|
|
579
|
+
[Koliko je od ovoga izmjereno](#koliko-je-od-ovoga-izmjereno));
|
|
580
|
+
podnožje skana i `mjolnir rules --unmeasured` kažu koje su koje.
|
|
581
|
+
- **Povjerenje u pluginove** — pluginovi su npm paketi deklarirani pod
|
|
582
|
+
`"plugins"`. **Nema sandboxa**: plugin kod radi s punim Node
|
|
583
|
+
privilegijama, isti model povjerenja kao ESLint ili Vitest pluginovi.
|
|
584
|
+
Core prefiksi ID-jeva pravila su rezervirani i odbijaju se od
|
|
585
|
+
pluginova radi sprečavanja spoofinga.
|
|
586
|
+
- **Eksterna pravila lokalna workspaceu** (folder-bazirana, nula
|
|
587
|
+
mreže) — `mjolnir-rules/` direktorij pored skan cilja učitava
|
|
588
|
+
vlastita pravila: JSON fajlovi deklariraju regex obrasce (nikakav kod
|
|
589
|
+
se ne izvršava), `.mjs`/`.js` moduli eksportuju `rules` (potpuno Node
|
|
590
|
+
povjerenje, kao pluginovi). Eksterna pravila nose iste metadata
|
|
591
|
+
povjerenja kao core; nikad ne mogu ući u core tier (core traži
|
|
592
|
+
izmjerenu FP stopu iz corpus sidecara — deklarirani `tier: "core"`
|
|
593
|
+
se stega na `extended`), poštuju tier limite i provjeravaju se na
|
|
594
|
+
drift: `mjolnir rules --md --external` renderira katalog iz
|
|
595
|
+
učitanih fajlova (provenijencija `external`), a generator matrice
|
|
596
|
+
prima `--external <root>`.
|
|
597
|
+
|
|
598
|
+
---
|
|
599
|
+
|
|
600
|
+
## 🏗️ Arhitektura
|
|
601
|
+
|
|
602
|
+
<details>
|
|
603
|
+
<summary>Raširi stablo</summary>
|
|
604
|
+
|
|
605
|
+
```
|
|
606
|
+
mjolnir/
|
|
607
|
+
├── src/
|
|
608
|
+
│ ├── engine/ # LanguageAdapter interface + rule runner
|
|
609
|
+
│ ├── adapters/ # typescript · python · java · csharp · github-actions
|
|
610
|
+
│ ├── rules/ # rules across 8 families + the measured-FP table
|
|
611
|
+
│ ├── playwright/ # Selector Health Score engine
|
|
612
|
+
│ ├── discovery/ # workspace, frameworks, ignore resolution
|
|
613
|
+
│ ├── scope/ # git merge-base changed-scope engine
|
|
614
|
+
│ ├── scorer/ # transparent deduction table + prioritization
|
|
615
|
+
│ ├── reporter/ # terminal · JSON · SARIF 2.1 · Mermaid
|
|
616
|
+
│ ├── forensics/ # run-data ingestion · flake verdicts · triage
|
|
617
|
+
│ ├── config/ # mjolnir.config.json + suppressions
|
|
618
|
+
│ ├── plugins/ # third-party rule loading (no sandbox)
|
|
619
|
+
│ └── commands/ # every subcommand
|
|
620
|
+
└── tests/
|
|
621
|
+
├── fixtures/ # must-fire / must-not-fire per rule
|
|
622
|
+
└── golden/ # frozen score regression locks
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
</details>
|
|
626
|
+
|
|
627
|
+
- **Pravila su čiste funkcije** — `(SourceFileContext) → Finding[]`,
|
|
628
|
+
bez I/O-a, bez globala. Novi ekosistem = jedan adapter + njegova
|
|
629
|
+
pravila.
|
|
630
|
+
- **TypeScript/Playwright koristi AST kompajlera** (ts-morph). Python,
|
|
631
|
+
Java i C# rade na zajedničkom regex sloju s maskiranim komentarima i
|
|
632
|
+
stringovima.
|
|
633
|
+
- Tree-sitter WASM AST sloj za Javu i C# postoji i sljedeći je korak
|
|
634
|
+
preciznosti — još nije povezan u sinhroni skan pipeline.
|
|
635
|
+
|
|
636
|
+
---
|
|
637
|
+
|
|
638
|
+
## 📚 Dokumentacija
|
|
639
|
+
|
|
640
|
+
| Dokument | Šta je unutra |
|
|
641
|
+
| ------------------------------------------------------ | ----------------------------------------------- |
|
|
642
|
+
| [docs/SCORING.md](docs/SCORING.md) | Normalizacija rezultata + ponderiranje dokazima |
|
|
643
|
+
| [docs/FP-AUDIT.md](docs/FP-AUDIT.md) | Izmjerene stope lažnih pozitiva + metodologija |
|
|
644
|
+
| [docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md) | Stanja pravila, potiskivanje, deprecacija |
|
|
645
|
+
| [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md) | SARIF izlaz + editor/CI postavka |
|
|
646
|
+
| [docs/rules/](docs/rules/) | Generirani katalog po pravilu |
|
|
647
|
+
| [CONTRIBUTING.md](CONTRIBUTING.md) | Dev postavka + workflow doprinosa |
|
|
648
|
+
| [CHANGELOG.md](CHANGELOG.md) | Historija izdanja |
|
|
649
|
+
| [SECURITY.md](SECURITY.md) | Prijavljivanje ranjivosti |
|
|
650
|
+
|
|
651
|
+
---
|
|
652
|
+
|
|
653
|
+
## 📈 Status
|
|
654
|
+
|
|
655
|
+
**v0.5.x · otvorena beta.** JSON shema i exit kodovi su zamrznuti
|
|
656
|
+
ugovori. TypeScript i Python imaju najširu izmjerenu pokrivenost; Java
|
|
657
|
+
i C# su noviji — čitaj ih kroz
|
|
658
|
+
[tabelu tierova](#tierovi-pravila-i-jezična-zrelost).
|
|
659
|
+
|
|
660
|
+
---
|
|
661
|
+
|
|
662
|
+
## 🤝 Doprinos
|
|
663
|
+
|
|
664
|
+
Nova pravila su najlakši prvi doprinos — jedna komanda scaffolduje
|
|
665
|
+
pravilo plus njegove must-fire **i** must-not-fire fixture (generirano
|
|
666
|
+
pravilo namjerno pada na fixtureima dok ne implementiraš stvarnu
|
|
667
|
+
detekciju — stub se ne može isporučiti):
|
|
668
|
+
|
|
669
|
+
```bash
|
|
670
|
+
mjolnir create-rule QA-PW-140 --title "Screenshot without diff bound"
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
Potpuni dev setup, komande stalnog gatea i zakoni anti-creep / fixture
|
|
674
|
+
vatrozida su u [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
675
|
+
|
|
676
|
+
---
|
|
677
|
+
|
|
678
|
+
<div align="center">
|
|
679
|
+
|
|
680
|
+
**Prestani isporučivati testovima kojima ne možeš vjerovati.**
|
|
681
|
+
|
|
682
|
+
```bash
|
|
683
|
+
npx mjolnir-qa@latest
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
**Star ⭐ · Watch 👀 · Contribute 🤝**
|
|
687
|
+
|
|
688
|
+
Izgradio [Sergey Bar](https://www.linkedin.com/in/sergeybar/)
|
|
689
|
+
|
|
690
|
+
</div>
|