qaify-playwright-reporter 0.3.1 → 0.4.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/README.md CHANGED
@@ -78,15 +78,21 @@ Catatan:
78
78
 
79
79
  Untuk aplikasi yang repo FE dan BE-nya terpisah dan belum memasang Playwright, Qaify bisa mengaudit keduanya dari satu **repo runner**. Repo FE dan BE tidak diubah sama sekali.
80
80
 
81
- 1. Buat repo kosong (mis. `qaify-runner`), lalu jalankan `npx qaify-playwright-reporter init-runner` di dalamnya. Perintah ini menulis `.github/workflows/qaify-audit.yml`.
81
+ 1. Pilih repo runner: repo kosong (mis. `qaify-runner`) atau repo aplikasinya sendiri. Jalankan `npx qaify-playwright-reporter init-runner` di dalamnya. Perintah ini menulis `.github/workflows/qaify-audit.yml`.
82
82
  2. Pasang GitHub App Qaify di repo runner, repo FE, dan repo BE.
83
- 3. Di repo runner, isi secret `QA_FACTORY_TOKEN` (token reporter repo runner), variable `QA_FACTORY_URL`, dan secret `CLAUDE_CODE_OAUTH_TOKEN`.
83
+ 3. Di repo runner, isi secret `QA_FACTORY_TOKEN` (token reporter repo runner), dan variable `QA_FACTORY_URL`. Secret `CLAUDE_CODE_OAUTH_TOKEN` bersifat opsional.
84
+
85
+ - Tanpa secret itu, audit berjalan **tanpa AI** (`qaify audit-static`): build, test, `composer audit` / `npm audit`, route GET publik BE, dan smoke test Playwright FE (desktop + mobile, screenshot setiap halaman untuk lampiran laporan PDF). Smoke test juga memeriksa elemen yang meluap, gambar rusak, tombol yang tertutup elemen lain, error JavaScript, request API, dan aset yang gagal. Setiap jenis masalah difoto lagi dengan kotak merah di elemennya atau banner berisi pesan errornya. Temuan smoke diberi halaman dan berkas sumber bila bisa ditebak (route FE → komponen halaman, route BE → method controller). Request FE yang gagal dipetakan ke controller BE, dan route BE yang error dihubungkan ke halaman FE yang memanggilnya.
86
+ - Dengan secret itu, Claude yang mengaudit. Hasilnya lebih dalam, termasuk logika bisnis dan kontrak API.
87
+ - Mode bisa dipaksa lewat variable `QA_FACTORY_AUDIT_MODE` (`static` / `claude`).
84
88
  4. Di Qaify → **Aplikasi**, tambahkan aplikasi (repo FE, BE, runner), lalu klik **Audit sekarang**.
85
89
 
86
90
  Alur di workflow:
87
91
 
88
92
  ```bash
89
93
  qaify audit-context --audit <id> --dir "$WORK" # clone apps/fe + apps/be, lalu cabut token clone
94
+ qaify audit-static --dir "$WORK" --out claude.json # mode static: tanpa AI
95
+ # atau mode claude:
90
96
  qaify audit-schema --out schema.json --instructions instructions.txt
91
97
  claude -p … # Bash + Playwright MCP: jalankan BE/FE, jelajahi UI, tulis temuan
92
98
  qaify audit-submit --audit <id> --results claude.json --evidence "$WORK/evidence" --context "$WORK/context.json"
@@ -0,0 +1,136 @@
1
+ import type { AuditFinding, AuditPage } from './audit.js';
2
+ /** usage.model untuk audit tanpa AI; dipakai backend/PDF untuk menampilkan mode audit. */
3
+ export declare const STATIC_MODEL = "qaify-static";
4
+ export interface ShellResult {
5
+ code: number;
6
+ output: string;
7
+ }
8
+ export interface Shell {
9
+ run(cmd: string, opts: {
10
+ cwd: string;
11
+ timeoutMs: number;
12
+ env?: NodeJS.ProcessEnv;
13
+ }): Promise<ShellResult>;
14
+ /** Proses latar (server dev); kembalian menghentikannya. */
15
+ background(cmd: string, opts: {
16
+ cwd: string;
17
+ logFile: string;
18
+ env?: NodeJS.ProcessEnv;
19
+ }): () => void;
20
+ }
21
+ /** Subset Playwright yang dipakai smoke test (playwright-core di runner, palsu di test). */
22
+ export interface BrowserLike {
23
+ newContext(opts: {
24
+ viewport: {
25
+ width: number;
26
+ height: number;
27
+ };
28
+ }): Promise<ContextLike>;
29
+ close(): Promise<void>;
30
+ }
31
+ export interface ContextLike {
32
+ newPage(): Promise<PageLike>;
33
+ close(): Promise<void>;
34
+ }
35
+ export interface PageLike {
36
+ on(event: 'console' | 'pageerror' | 'response' | 'requestfailed', fn: (arg: any) => void): void;
37
+ goto(url: string, opts: {
38
+ waitUntil: 'networkidle';
39
+ timeout: number;
40
+ }): Promise<unknown>;
41
+ url(): string;
42
+ evaluate(expression: string): Promise<unknown>;
43
+ screenshot(opts: {
44
+ path: string;
45
+ }): Promise<unknown>;
46
+ locator(selector: string): {
47
+ count(): Promise<number>;
48
+ first(): {
49
+ fill(value: string): Promise<void>;
50
+ press(key: string): Promise<void>;
51
+ };
52
+ };
53
+ waitForLoadState(state: 'networkidle', opts: {
54
+ timeout: number;
55
+ }): Promise<void>;
56
+ }
57
+ export interface StaticDeps {
58
+ shell: Shell;
59
+ fetch: typeof fetch;
60
+ /** null = playwright-core tidak tersedia; smoke FE dilewati. */
61
+ launch: () => Promise<BrowserLike | null>;
62
+ log: (msg: string) => void;
63
+ }
64
+ /** Request FE (method + path) → berkas controller BE yang melayaninya. */
65
+ export type ApiLocator = (method: string, path: string) => Promise<SourceLocation | null>;
66
+ export interface StaticAudit {
67
+ summary: Record<'fe' | 'be', {
68
+ score: number;
69
+ verdict: string;
70
+ booted: boolean;
71
+ notes: string;
72
+ }>;
73
+ findings: AuditFinding[];
74
+ pages: AuditPage[];
75
+ }
76
+ /** Berkas sumber (relatif root repo) yang paling mungkin terkait temuan. */
77
+ export interface SourceLocation {
78
+ file: string;
79
+ line?: number;
80
+ }
81
+ /** Folder kerja hasil audit-context: apps/fe, apps/be, context.json, evidence/. */
82
+ export declare function auditStatic(dir: string, deps: StaticDeps): Promise<StaticAudit>;
83
+ /** Bentuk keluaran `claude -p --output-format json` agar parseAuditOutput / audit-submit tidak berubah. */
84
+ export declare function toAuditOutput(audit: StaticAudit, durationMs: number): string;
85
+ /**
86
+ * Jelajah link same-origin (BFS) di desktop, lalu ulangi halaman yang sama di mobile.
87
+ * Setiap halaman difoto polos (galeri laporan); setiap jenis masalah difoto lagi dengan tanda (kotak merah di elemen,
88
+ * atau banner pesan error) sebagai bukti temuannya.
89
+ * locate: route → berkas sumber halaman (best effort) untuk kolom file temuan dan galeri.
90
+ * api: request XHR/fetch yang gagal → controller BE (related_files).
91
+ */
92
+ export declare function smokeUi(browser: BrowserLike, baseUrl: string, evidenceDir: string, login: Login | null, log?: (msg: string) => void, locate?: (path: string) => Promise<SourceLocation | null>, api?: ApiLocator): Promise<{
93
+ findings: AuditFinding[];
94
+ pages: number;
95
+ loggedIn: boolean;
96
+ visited: AuditPage[];
97
+ calls: Map<string, Set<string>>;
98
+ }>;
99
+ /** Test gagal / error dari laporan JUnit PHPUnit / Pest. */
100
+ export declare function parseJunit(xml: string, root?: string): AuditFinding[];
101
+ /** `composer audit --format=json` → satu temuan per advisory. */
102
+ export declare function parseComposerAudit(output: string): AuditFinding[];
103
+ /** `npm audit --json` (npm 7+) → satu temuan per paket berseverity high/critical. */
104
+ export declare function parseNpmAudit(output: string): AuditFinding[];
105
+ /** URI route GET tanpa parameter dan tanpa middleware autentikasi dari `route:list --json`. */
106
+ export declare function pickSmokeRoutes(output: string): string[];
107
+ /** URI → action (mis. App\Http\Controllers\ProdukController@index) dari `route:list --json`. */
108
+ export declare function routeActions(output: string): Map<string, string>;
109
+ /**
110
+ * Request FE (method + path, mis. GET /api/produk/12) → action route BE dari `route:list --json`.
111
+ * {param} cocok dengan satu segmen, {param?} opsional; bila beberapa cocok, route dengan segmen statis terbanyak menang.
112
+ */
113
+ export declare function matchRoute(output: string, method: string, path: string): string | null;
114
+ /** Action controller → berkas (PSR-4 App\ → app/) + baris method-nya; controller invokable → __invoke. */
115
+ export declare function controllerLocation(root: string, action: string): Promise<SourceLocation | null>;
116
+ /**
117
+ * Path halaman FE → komponen yang merender (best effort, tanpa menjalankan kode):
118
+ * 1. definisi route Vue Router / React Router (`path: '/produk'`, `path="/produk"`, termasuk :param dan child relatif)
119
+ * → komponen dari import('…') / import X from '…' di dekatnya, atau baris definisi route bila komponen tak ketemu;
120
+ * 2. routing berbasis berkas (pages/, app/ ala Nuxt / Next).
121
+ */
122
+ export declare function resolveRouteFile(root: string, path: string): Promise<SourceLocation | null>;
123
+ export declare function scoreRepo(findings: AuditFinding[], booted: boolean): number;
124
+ export interface Login {
125
+ email: string;
126
+ password: string;
127
+ }
128
+ /** Akun login dari catatan aplikasi, mis. "Login admin@pos.test / password". */
129
+ export declare function parseLogin(instructions: string): Login | null;
130
+ /** Variabel VITE_* berisi URL http diarahkan ke BE lokal; path (mis. /api) dipertahankan. */
131
+ export declare function localApiEnv(example: string): string;
132
+ /** Ganti / tambah KEY=VALUE di isi file .env. */
133
+ export declare function setEnv(content: string, values: Record<string, string>): string;
134
+ export declare const defaultShell: Shell;
135
+ /** playwright-core dipasang global di runner bersama qaify; Google Chrome sudah ada di ubuntu-latest. */
136
+ export declare function defaultLaunch(): Promise<BrowserLike | null>;