laxy-verify 1.2.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,208 +1,208 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.isPlaywrightAvailable = isPlaywrightAvailable;
37
- exports.runPlaywrightE2E = runPlaywrightE2E;
38
- let _playwright;
39
- async function loadPlaywright() {
40
- if (_playwright !== undefined)
41
- return _playwright;
42
- try {
43
- _playwright = await Promise.resolve().then(() => __importStar(require("playwright")));
44
- return _playwright;
45
- }
46
- catch {
47
- _playwright = null;
48
- return null;
49
- }
50
- }
51
- async function isPlaywrightAvailable() {
52
- return (await loadPlaywright()) !== null;
53
- }
54
- async function runPlaywrightE2E(url, scenarios, browsers) {
55
- const pw = await loadPlaywright();
56
- if (!pw) {
57
- throw new Error("playwright is not installed. Run: npm install -D playwright && npx playwright install");
58
- }
59
- const allResults = [];
60
- for (const browserName of browsers) {
61
- const browserType = pw[browserName];
62
- if (!browserType) {
63
- console.error(` Unknown browser: ${browserName}, skipping`);
64
- continue;
65
- }
66
- console.log(` Running E2E on ${browserName}...`);
67
- const browser = await browserType.launch({ headless: true });
68
- try {
69
- const results = [];
70
- for (const scenario of scenarios) {
71
- const context = await browser.newContext({ viewport: { width: 1280, height: 720 } });
72
- const page = await context.newPage();
73
- const stepResults = [];
74
- const consoleErrors = [];
75
- page.on("console", (msg) => {
76
- if (msg.type() === "error") {
77
- consoleErrors.push(`Console error: ${msg.text().slice(0, 200)}`);
78
- }
79
- });
80
- page.on("pageerror", (err) => {
81
- consoleErrors.push(`Uncaught error: ${err.message.slice(0, 200)}`);
82
- });
83
- try {
84
- const targetUrl = scenario.initialUrl
85
- ? new URL(scenario.initialUrl, url).href
86
- : url;
87
- await page.goto(targetUrl, { waitUntil: "networkidle", timeout: 20000 });
88
- await page.waitForSelector("body", { timeout: 5000 });
89
- await page.waitForTimeout(1000);
90
- for (const step of scenario.steps) {
91
- const result = { description: step.description, passed: false };
92
- try {
93
- switch (step.type) {
94
- case "click":
95
- if (!step.selector)
96
- throw new Error("Missing selector");
97
- await page.locator(step.selector).first().click({ timeout: 8000 });
98
- break;
99
- case "fill":
100
- case "clear_fill":
101
- if (!step.selector)
102
- throw new Error("Missing selector");
103
- await page.locator(step.selector).first().click({ timeout: 8000 });
104
- await page.locator(step.selector).first().fill(step.value || "");
105
- break;
106
- case "check_visible":
107
- if (!step.selector)
108
- throw new Error("Missing selector");
109
- await page.locator(step.selector).first().waitFor({ state: "visible", timeout: 8000 });
110
- break;
111
- case "check_text": {
112
- if (!step.expectedText)
113
- throw new Error("Missing expectedText");
114
- const bodyText = await page.locator("body").innerText();
115
- if (!bodyText.includes(step.expectedText)) {
116
- throw new Error(`Expected text "${step.expectedText}" not found`);
117
- }
118
- break;
119
- }
120
- case "check_healthy_page": {
121
- const bodyText = await page.locator("body").innerText();
122
- const title = await page.title();
123
- const haystack = `${title}\n${bodyText.slice(0, 1200)}`.toLowerCase();
124
- const errorPatterns = [
125
- /internal server error/,
126
- /application error/,
127
- /\b404\b/,
128
- /\b500\b/,
129
- /server error/,
130
- /something went wrong/,
131
- ];
132
- if (errorPatterns.some((p) => p.test(haystack))) {
133
- throw new Error("Page looks like an error screen");
134
- }
135
- break;
136
- }
137
- case "check_validation":
138
- // Simplified check: look for any aria-invalid or role=alert
139
- if (!step.selector)
140
- throw new Error("Missing selector");
141
- await page.locator(step.selector).first().waitFor({ state: "visible", timeout: 8000 });
142
- break;
143
- case "wait":
144
- await page.waitForTimeout(step.duration ?? 1000);
145
- break;
146
- case "scroll":
147
- if (step.selector && step.selector !== "body") {
148
- await page.locator(step.selector).first().scrollIntoViewIfNeeded();
149
- }
150
- else {
151
- await page.evaluate(() => window.scrollBy(0, 300));
152
- }
153
- break;
154
- case "goto": {
155
- if (!step.gotoUrl)
156
- throw new Error("Missing gotoUrl");
157
- const gotoTarget = new URL(step.gotoUrl, page.url()).href;
158
- await page.goto(gotoTarget, { waitUntil: "networkidle", timeout: 20000 });
159
- await page.waitForSelector("body", { timeout: 5000 });
160
- break;
161
- }
162
- }
163
- result.passed = true;
164
- }
165
- catch (error) {
166
- result.passed = false;
167
- result.error = error instanceof Error ? error.message.slice(0, 200) : String(error).slice(0, 200);
168
- }
169
- stepResults.push(result);
170
- if (!result.passed)
171
- break;
172
- }
173
- results.push({
174
- name: scenario.name,
175
- passed: stepResults.every((s) => s.passed),
176
- steps: stepResults,
177
- consoleErrors,
178
- });
179
- }
180
- catch (error) {
181
- results.push({
182
- name: scenario.name,
183
- passed: false,
184
- steps: stepResults,
185
- error: error instanceof Error ? error.message.slice(0, 200) : String(error).slice(0, 200),
186
- consoleErrors,
187
- });
188
- }
189
- finally {
190
- await context.close();
191
- }
192
- }
193
- const passed = results.filter((r) => r.passed).length;
194
- const allConsoleErrors = Array.from(new Set(results.flatMap((r) => r.consoleErrors ?? []))).slice(0, 10);
195
- allResults.push({
196
- browser: browserName,
197
- results,
198
- passed,
199
- failed: results.length - passed,
200
- consoleErrors: allConsoleErrors,
201
- });
202
- }
203
- finally {
204
- await browser.close();
205
- }
206
- }
207
- return allResults;
208
- }
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.isPlaywrightAvailable = isPlaywrightAvailable;
37
+ exports.runPlaywrightE2E = runPlaywrightE2E;
38
+ let _playwright;
39
+ async function loadPlaywright() {
40
+ if (_playwright !== undefined)
41
+ return _playwright;
42
+ try {
43
+ _playwright = await Promise.resolve().then(() => __importStar(require("playwright")));
44
+ return _playwright;
45
+ }
46
+ catch {
47
+ _playwright = null;
48
+ return null;
49
+ }
50
+ }
51
+ async function isPlaywrightAvailable() {
52
+ return (await loadPlaywright()) !== null;
53
+ }
54
+ async function runPlaywrightE2E(url, scenarios, browsers) {
55
+ const pw = await loadPlaywright();
56
+ if (!pw) {
57
+ throw new Error("playwright is not installed. Run: npm install -D playwright && npx playwright install");
58
+ }
59
+ const allResults = [];
60
+ for (const browserName of browsers) {
61
+ const browserType = pw[browserName];
62
+ if (!browserType) {
63
+ console.error(` Unknown browser: ${browserName}, skipping`);
64
+ continue;
65
+ }
66
+ console.log(` Running E2E on ${browserName}...`);
67
+ const browser = await browserType.launch({ headless: true });
68
+ try {
69
+ const results = [];
70
+ for (const scenario of scenarios) {
71
+ const context = await browser.newContext({ viewport: { width: 1280, height: 720 } });
72
+ const page = await context.newPage();
73
+ const stepResults = [];
74
+ const consoleErrors = [];
75
+ page.on("console", (msg) => {
76
+ if (msg.type() === "error") {
77
+ consoleErrors.push(`Console error: ${msg.text().slice(0, 200)}`);
78
+ }
79
+ });
80
+ page.on("pageerror", (err) => {
81
+ consoleErrors.push(`Uncaught error: ${err.message.slice(0, 200)}`);
82
+ });
83
+ try {
84
+ const targetUrl = scenario.initialUrl
85
+ ? new URL(scenario.initialUrl, url).href
86
+ : url;
87
+ await page.goto(targetUrl, { waitUntil: "networkidle", timeout: 20000 });
88
+ await page.waitForSelector("body", { timeout: 5000 });
89
+ await page.waitForTimeout(1000);
90
+ for (const step of scenario.steps) {
91
+ const result = { description: step.description, passed: false };
92
+ try {
93
+ switch (step.type) {
94
+ case "click":
95
+ if (!step.selector)
96
+ throw new Error("Missing selector");
97
+ await page.locator(step.selector).first().click({ timeout: 8000 });
98
+ break;
99
+ case "fill":
100
+ case "clear_fill":
101
+ if (!step.selector)
102
+ throw new Error("Missing selector");
103
+ await page.locator(step.selector).first().click({ timeout: 8000 });
104
+ await page.locator(step.selector).first().fill(step.value || "");
105
+ break;
106
+ case "check_visible":
107
+ if (!step.selector)
108
+ throw new Error("Missing selector");
109
+ await page.locator(step.selector).first().waitFor({ state: "visible", timeout: 8000 });
110
+ break;
111
+ case "check_text": {
112
+ if (!step.expectedText)
113
+ throw new Error("Missing expectedText");
114
+ const bodyText = await page.locator("body").innerText();
115
+ if (!bodyText.includes(step.expectedText)) {
116
+ throw new Error(`Expected text "${step.expectedText}" not found`);
117
+ }
118
+ break;
119
+ }
120
+ case "check_healthy_page": {
121
+ const bodyText = await page.locator("body").innerText();
122
+ const title = await page.title();
123
+ const haystack = `${title}\n${bodyText.slice(0, 1200)}`.toLowerCase();
124
+ const errorPatterns = [
125
+ /internal server error/,
126
+ /application error/,
127
+ /\b404\b/,
128
+ /\b500\b/,
129
+ /server error/,
130
+ /something went wrong/,
131
+ ];
132
+ if (errorPatterns.some((p) => p.test(haystack))) {
133
+ throw new Error("Page looks like an error screen");
134
+ }
135
+ break;
136
+ }
137
+ case "check_validation":
138
+ // Simplified check: look for any aria-invalid or role=alert
139
+ if (!step.selector)
140
+ throw new Error("Missing selector");
141
+ await page.locator(step.selector).first().waitFor({ state: "visible", timeout: 8000 });
142
+ break;
143
+ case "wait":
144
+ await page.waitForTimeout(step.duration ?? 1000);
145
+ break;
146
+ case "scroll":
147
+ if (step.selector && step.selector !== "body") {
148
+ await page.locator(step.selector).first().scrollIntoViewIfNeeded();
149
+ }
150
+ else {
151
+ await page.evaluate(() => window.scrollBy(0, 300));
152
+ }
153
+ break;
154
+ case "goto": {
155
+ if (!step.gotoUrl)
156
+ throw new Error("Missing gotoUrl");
157
+ const gotoTarget = new URL(step.gotoUrl, page.url()).href;
158
+ await page.goto(gotoTarget, { waitUntil: "networkidle", timeout: 20000 });
159
+ await page.waitForSelector("body", { timeout: 5000 });
160
+ break;
161
+ }
162
+ }
163
+ result.passed = true;
164
+ }
165
+ catch (error) {
166
+ result.passed = false;
167
+ result.error = error instanceof Error ? error.message.slice(0, 200) : String(error).slice(0, 200);
168
+ }
169
+ stepResults.push(result);
170
+ if (!result.passed)
171
+ break;
172
+ }
173
+ results.push({
174
+ name: scenario.name,
175
+ passed: stepResults.every((s) => s.passed),
176
+ steps: stepResults,
177
+ consoleErrors,
178
+ });
179
+ }
180
+ catch (error) {
181
+ results.push({
182
+ name: scenario.name,
183
+ passed: false,
184
+ steps: stepResults,
185
+ error: error instanceof Error ? error.message.slice(0, 200) : String(error).slice(0, 200),
186
+ consoleErrors,
187
+ });
188
+ }
189
+ finally {
190
+ await context.close();
191
+ }
192
+ }
193
+ const passed = results.filter((r) => r.passed).length;
194
+ const allConsoleErrors = Array.from(new Set(results.flatMap((r) => r.consoleErrors ?? []))).slice(0, 10);
195
+ allResults.push({
196
+ browser: browserName,
197
+ results,
198
+ passed,
199
+ failed: results.length - passed,
200
+ consoleErrors: allConsoleErrors,
201
+ });
202
+ }
203
+ finally {
204
+ await browser.close();
205
+ }
206
+ }
207
+ return allResults;
208
+ }
@@ -1,39 +1,39 @@
1
- import type { E2EScenarioResult } from "./e2e.js";
2
- import type { LighthouseScores } from "./grade.js";
3
- import type { TierVerificationView, VerificationReport } from "./verification-core/index.js";
4
- import { type VisualDiffResult } from "./visual-diff.js";
5
- export interface MarkdownReportResult {
6
- grade: string;
7
- timestamp: string;
8
- build: {
9
- success: boolean;
10
- durationMs: number;
11
- errors: string[];
12
- };
13
- e2e?: {
14
- passed: number;
15
- failed: number;
16
- total: number;
17
- results: E2EScenarioResult[];
18
- };
19
- lighthouse: (LighthouseScores & {
20
- runs: number;
21
- }) | null;
22
- visualDiff?: VisualDiffResult | null;
23
- thresholds: {
24
- performance: number;
25
- accessibility: number;
26
- seo: number;
27
- bestPractices: number;
28
- };
29
- framework: string | null;
30
- _plan?: string;
31
- verification?: {
32
- tier: VerificationReport["tier"];
33
- report: VerificationReport;
34
- view: TierVerificationView;
35
- };
36
- }
37
- export declare function shouldWriteMarkdownReport(result: MarkdownReportResult): boolean;
38
- export declare function getMarkdownReportPath(projectDir: string): string;
39
- export declare function buildMarkdownReport(projectDir: string, result: MarkdownReportResult): string;
1
+ import type { E2EScenarioResult } from "./e2e.js";
2
+ import type { LighthouseScores } from "./grade.js";
3
+ import type { TierVerificationView, VerificationReport } from "./verification-core/index.js";
4
+ import { type VisualDiffResult } from "./visual-diff.js";
5
+ export interface MarkdownReportResult {
6
+ grade: string;
7
+ timestamp: string;
8
+ build: {
9
+ success: boolean;
10
+ durationMs: number;
11
+ errors: string[];
12
+ };
13
+ e2e?: {
14
+ passed: number;
15
+ failed: number;
16
+ total: number;
17
+ results: E2EScenarioResult[];
18
+ };
19
+ lighthouse: (LighthouseScores & {
20
+ runs: number;
21
+ }) | null;
22
+ visualDiff?: VisualDiffResult | null;
23
+ thresholds: {
24
+ performance: number;
25
+ accessibility: number;
26
+ seo: number;
27
+ bestPractices: number;
28
+ };
29
+ framework: string | null;
30
+ _plan?: string;
31
+ verification?: {
32
+ tier: VerificationReport["tier"];
33
+ report: VerificationReport;
34
+ view: TierVerificationView;
35
+ };
36
+ }
37
+ export declare function shouldWriteMarkdownReport(result: MarkdownReportResult): boolean;
38
+ export declare function getMarkdownReportPath(projectDir: string): string;
39
+ export declare function buildMarkdownReport(projectDir: string, result: MarkdownReportResult): string;